Compare commits

...
This repository has been archived on 2025-11-05. You can view files and clone it, but cannot push or open issues or pull requests.

26 Commits
TOPBAR ... main

Author SHA1 Message Date
cheykrym
f7c8c1c0a0 солнышко по выше 2025-08-14 04:10:27 +03:00
cheykrym
73bf1ee6fc fix preview crash 2025-08-14 04:01:36 +03:00
cheykrym
c5906f42b7 switcher theme in BM 2025-08-14 03:59:41 +03:00
cheykrym
27a6ce7ce3 switcher account animation 2025-08-14 03:48:28 +03:00
cheykrym
82168755e2 change title 2025-08-14 03:37:28 +03:00
cheykrym
6c7716ec16 account switcher 2025-08-14 03:33:21 +03:00
cheykrym
d8b683d570 BM change title 2025-08-14 03:16:33 +03:00
cheykrym
1fdc8dbf45 burger menu profile scroll 2025-08-14 03:12:32 +03:00
cheykrym
58e3488a9d bar changes 2025-08-14 03:00:59 +03:00
cheykrym
d7067db1d6 исправлено мерцание бургер меню 2025-08-14 02:44:04 +03:00
cheykrym
927ac45ec8 burger menu pos 2025-08-14 02:27:34 +03:00
cheykrym
f172e33123 burger menu fix pos 2025-08-14 02:21:34 +03:00
cheykrym
05a0d85c09 burger menu swipe 2025-08-14 02:19:09 +03:00
cheykrym
478020f6f2 post edit 2025-08-13 14:50:50 +03:00
cheykrym
f5e5d1f72f save position 2025-08-13 03:14:37 +03:00
cheykrym
d64457ad35 refresh home 2025-08-13 03:11:49 +03:00
cheykrym
c8d71996d9 бургер меню 2025-08-13 02:57:40 +03:00
cheykrym
fc214ed696 left bar 2025-08-13 02:49:21 +03:00
cheykrym
4ec99934e4 отступы между карточек 2025-08-13 02:32:18 +03:00
cheykrym
b0d5429ae6 карточки в ленте 2025-08-13 02:12:23 +03:00
cheykrym
d089276b39 карточки в ленте 2025-08-13 02:12:06 +03:00
cheykrym
db12fca1c3 topbar update 2025-08-13 01:11:14 +03:00
cheykrym
2052492912 top bar test 2025-07-25 01:58:34 +03:00
cheykrym
975802dc88 top bar update 2025-07-25 01:50:56 +03:00
cheykrym
76642b89d5 top bar update 2025-07-25 01:50:39 +03:00
cheykrym
4f46f715aa tab bar update 2025-07-25 00:20:25 +03:00
28 changed files with 975 additions and 171 deletions

View File

@ -4,17 +4,20 @@ import UIKit
struct RefreshableScrollView<Content: View>: UIViewRepresentable { struct RefreshableScrollView<Content: View>: UIViewRepresentable {
var content: Content var content: Content
var onRefresh: () -> Void var onRefresh: () -> Void
var onScroll: ((CGPoint) -> Void)?
var isRefreshing: Binding<Bool> var isRefreshing: Binding<Bool>
init(isRefreshing: Binding<Bool>, onRefresh: @escaping () -> Void, @ViewBuilder content: () -> Content) { init(isRefreshing: Binding<Bool>, onRefresh: @escaping () -> Void, onScroll: ((CGPoint) -> Void)? = nil, @ViewBuilder content: () -> Content) {
self.content = content() self.content = content()
self.onRefresh = onRefresh self.onRefresh = onRefresh
self.onScroll = onScroll
self.isRefreshing = isRefreshing self.isRefreshing = isRefreshing
} }
func makeUIView(context: Context) -> UIScrollView { func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView() let scrollView = UIScrollView()
scrollView.delaysContentTouches = false scrollView.delaysContentTouches = false
scrollView.delegate = context.coordinator
let refreshControl = UIRefreshControl() let refreshControl = UIRefreshControl()
refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged) refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged)
@ -41,7 +44,6 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
if isRefreshing.wrappedValue { if isRefreshing.wrappedValue {
uiView.refreshControl?.beginRefreshing() uiView.refreshControl?.beginRefreshing()
} else { } else {
// Отложенное завершение, чтобы избежать цикла обновлений
DispatchQueue.main.async { DispatchQueue.main.async {
uiView.refreshControl?.endRefreshing() uiView.refreshControl?.endRefreshing()
} }
@ -54,7 +56,7 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
Coordinator(self) Coordinator(self)
} }
class Coordinator: NSObject { class Coordinator: NSObject, UIScrollViewDelegate {
var parent: RefreshableScrollView var parent: RefreshableScrollView
var hostingController: UIHostingController<Content>? var hostingController: UIHostingController<Content>?
@ -65,5 +67,9 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
@objc func handleRefresh() { @objc func handleRefresh() {
parent.onRefresh() parent.onRefresh()
} }
func scrollViewDidScroll(_ scrollView: UIScrollView) {
parent.onScroll?(scrollView.contentOffset)
}
} }
} }

View File

@ -0,0 +1,104 @@
import SwiftUI
struct TopBarView: View {
var title: String
// Состояния для ProfileTab
@Binding var selectedAccount: String
@Binding var sheetType: ProfileTab.SheetType?
var accounts: [String]
var viewModel: LoginViewModel
// Привязка для управления боковым меню
@Binding var isSideMenuPresented: Bool
var isHomeTab: Bool {
return title == "Home"
}
var isProfileTab: Bool {
return title == "Profile"
}
var body: some View {
VStack(spacing: 0) {
HStack {
// Кнопка "Гамбургер" для открытия меню
Button(action: {
withAnimation {
isSideMenuPresented.toggle()
}
}) {
Image(systemName: "line.horizontal.3")
.imageScale(.large)
.foregroundColor(.primary)
}
// Spacer()
if isHomeTab{
Text("Yobble")
.font(.largeTitle)
.fontWeight(.bold)
Spacer()
} else if isProfileTab {
Spacer()
Button(action: { sheetType = .accountShare }) {
HStack(spacing: 4) {
Text(selectedAccount)
.font(.headline)
.foregroundColor(.primary)
Image(systemName: "chevron.down")
.font(.subheadline)
.foregroundColor(.gray)
}
}
Spacer()
} else {
Text(title)
.font(.largeTitle)
.fontWeight(.bold)
Spacer()
}
if isHomeTab{
HStack(spacing: 20) {
// Кнопка поиска
Button(action: {
// пока ничего не делаем
}) {
Image(systemName: "magnifyingglass")
.imageScale(.large)
.foregroundColor(.primary)
}
// Кнопка уведомлений
Button(action: {
// пока ничего не делаем
}) {
Image(systemName: "bell")
.imageScale(.large)
.foregroundColor(.primary)
}
}
} else if isProfileTab {
NavigationLink(destination: SettingsView(viewModel: viewModel)) {
Image(systemName: "wrench")
.imageScale(.large)
.foregroundColor(.primary)
}
}
}
.padding()
.frame(height: 50) // Стандартная высота для нав. бара
Divider()
}
.background(Color(UIColor.systemBackground))
}
}
struct TopBarView_Previews: PreviewProvider {
static var previews: some View {
/*@START_MENU_TOKEN@*/Text("Hello, World!")/*@END_MENU_TOKEN@*/
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "placeholderPhoto.jpg",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "placeholderPhotoSquare.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View File

@ -0,0 +1,12 @@
{
"data" : [
{
"filename" : "placeholderVideo.mp4",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

Binary file not shown.

View File

@ -10,7 +10,7 @@ struct Post: Identifiable, Codable {
let description: String? // Описание поста let description: String? // Описание поста
let media: [MediaItem] // Массив медиафайлов let media: [MediaItem] // Массив медиафайлов
let mediaOrder: [UUID]? // Порядок отображения медиа let mediaOrder: [UUID]? // Порядок отображения медиа
let thumbnailID: UUID? // Превью для видео let thumbnailID: UUID // Превью
let duration: Double? // Длительность видео/аудио let duration: Double? // Длительность видео/аудио
let createdAt: Date // Дата создания let createdAt: Date // Дата создания
let updatedAt: Date // Дата обновления let updatedAt: Date // Дата обновления
@ -20,7 +20,7 @@ struct Post: Identifiable, Codable {
let commentsCount: Int // Кол-во комментариев let commentsCount: Int // Кол-во комментариев
let isLikedByCurrentUser: Bool // Лайк текущим юзером let isLikedByCurrentUser: Bool // Лайк текущим юзером
let isSavedByCurrentUser: Bool // Сохранено текущим юзером let isSavedByCurrentUser: Bool // Сохранено текущим юзером
let authorID: String // Автор let authorID: UUID // Автор
let authorUsername: String // Имя пользователя автора let authorUsername: String // Имя пользователя автора
let hashtags: [String]? // Хэштеги let hashtags: [String]? // Хэштеги
let location: String? // Гео let location: String? // Гео
@ -30,6 +30,7 @@ struct Post: Identifiable, Codable {
enum MediaType: String, Codable { enum MediaType: String, Codable {
case photo case photo
case live
case video case video
} }

View File

@ -96,10 +96,13 @@ class PostService {
for i in 0..<32 { for i in 0..<32 {
let mediaID = UUID() let mediaID = UUID()
let thumbID = Bool.random() ? UUID() : nil // let thumbID = Bool.random() ? UUID() : nil
let thumbID = UUID()
let postID = UUID() let postID = UUID()
let authorId = "user_\(Int.random(in: 1...5))" let authorId = UUID()
let authorUserName = "username_\(Int.random(in: 1...5))"
// let authorId = "user_\(Int.random(in: 1...5))"
let post = Post( let post = Post(
id: postID, id: postID,
title: sampleTitles[i], title: sampleTitles[i],
@ -119,7 +122,7 @@ class PostService {
isLikedByCurrentUser: Bool.random(), isLikedByCurrentUser: Bool.random(),
isSavedByCurrentUser: Bool.random(), isSavedByCurrentUser: Bool.random(),
authorID: authorId, authorID: authorId,
authorUsername: "username_\(authorId.split(separator: "_").last ?? "")", authorUsername: authorUserName,
hashtags: ["#тест", "#видео", "#swiftui", "#ui"].shuffled().prefix(2).map { $0 }, hashtags: ["#тест", "#видео", "#swiftui", "#ui"].shuffled().prefix(2).map { $0 },
location: Bool.random() ? "Москва" : nil, location: Bool.random() ? "Москва" : nil,
languageCode: Bool.random() ? ["ru", "en"] : ["ru"], languageCode: Bool.random() ? ["ru", "en"] : ["ru"],

View File

@ -0,0 +1,53 @@
import SwiftUI
// Enum to represent the three theme options
enum Theme: String, CaseIterable {
case system = "System"
case light = "Light"
case dark = "Dark"
var colorScheme: ColorScheme? {
switch self {
case .system:
return nil
case .light:
return .light
case .dark:
return .dark
}
}
}
// Observable class to manage the theme state
class ThemeManager: ObservableObject {
@AppStorage("selectedTheme") private var selectedThemeValue: String = Theme.system.rawValue
@Published var theme: Theme
init() {
// Read directly from UserDefaults to avoid using self before initialization is complete.
let storedThemeValue = UserDefaults.standard.string(forKey: "selectedTheme") ?? ""
self.theme = Theme(rawValue: storedThemeValue) ?? .system
}
func setTheme(_ theme: Theme) {
self.theme = theme
selectedThemeValue = theme.rawValue
}
// This will be called from the button
func toggleTheme(from currentSystemScheme: ColorScheme) {
let newTheme: Theme
switch theme {
case .system:
// If system is active, toggle to the opposite of the current system theme
newTheme = currentSystemScheme == .dark ? .light : .dark
case .light:
newTheme = .dark
case .dark:
newTheme = .light
}
setTheme(newTheme)
}
}

View File

@ -0,0 +1,32 @@
import Foundation
import Combine
class NewHomeTabViewModel: ObservableObject {
@Published var posts: [Post] = []
@Published var isLoading = true
@Published var isRefreshing = false
private var hasLoadedData = false
func fetchDataIfNeeded() {
guard !hasLoadedData else { return }
refreshData()
}
func refreshData() {
DispatchQueue.main.async {
self.isRefreshing = true
}
PostService.shared.fetchAllPosts { [weak self] fetchedPosts in
guard let self = self else { return }
DispatchQueue.main.async {
self.posts = fetchedPosts
self.isLoading = false
self.hasLoadedData = true
self.isRefreshing = false
}
}
}
}

View File

@ -9,16 +9,12 @@ import SwiftUI
struct ChatsTab: View { struct ChatsTab: View {
var body: some View { var body: some View {
NavigationView {
VStack { VStack {
Text("Чаты") Text("Здесь будут чаты")
.font(.largeTitle) .font(.title)
.bold() .foregroundColor(.gray)
.padding()
Spacer() Spacer()
} }
.navigationTitle("Чаты")
}
} }
} }

View File

@ -0,0 +1,84 @@
import SwiftUI
struct CustomTabBar: View {
@Binding var selectedTab: Int
var onCreate: () -> Void
var body: some View {
HStack {
// Tab 1: Feed
TabBarButton(systemName: "list.bullet.rectangle", text: "Лента", isSelected: selectedTab == 0) {
selectedTab = 0
}
// Tab 2: Search
TabBarButton(systemName: "magnifyingglass", text: "Поиск", isSelected: selectedTab == 1) {
selectedTab = 1
}
// Create Button
CreateButton {
onCreate()
}
// Tab 3: Chats
TabBarButton(systemName: "bubble.left.and.bubble.right.fill", text: "Чаты", isSelected: selectedTab == 2) {
selectedTab = 2
}
// Tab 4: Profile
TabBarButton(systemName: "person.crop.square", text: "Лицо", isSelected: selectedTab == 3) {
selectedTab = 3
}
}
.padding(.horizontal)
.padding(.top, 1)
.padding(.bottom, 30) // Добавляем отступ снизу
// .background(Color(.systemGray6))
}
}
struct TabBarButton: View {
let systemName: String
let text: String
let isSelected: Bool
let action: () -> Void
var body: some View {
Button(action: action) {
VStack(spacing: 4) {
Image(systemName: systemName)
.font(.system(size: 22))
Text(text)
// .font(.caption)
.font(.system(size: 12))
}
.foregroundColor(isSelected ? .accentColor : .gray)
}
.frame(maxWidth: .infinity)
}
}
struct CreateButton: View {
let action: () -> Void
var body: some View {
Button(action: action) {
Image(systemName: "plus")
.font(.system(size: 24, weight: .bold))
.foregroundColor(.white)
.padding(16)
// .background(Color.accentColor)
.background(
LinearGradient(
gradient: Gradient(colors: [.blue, .white]),
startPoint: .top,
endPoint: .bottom
)
)
.clipShape(Circle())
.shadow(radius: 4)
}
.offset(y: -3)
}
}

View File

@ -5,15 +5,18 @@ struct HomeTab: View {
@State private var isLoading = true @State private var isLoading = true
@State private var isRefreshing = false @State private var isRefreshing = false
var onScroll: ((CGPoint) -> Void)?
var body: some View { var body: some View {
NavigationView {
VStack { VStack {
if isLoading { if isLoading {
ProgressView("Загрузка ленты...") ProgressView("Загрузка ленты...")
} else { } else {
RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: { RefreshableScrollView(
fetchData() isRefreshing: $isRefreshing,
}) { onRefresh: { fetchData() },
onScroll: onScroll
) {
LazyVStack(spacing: 24) { LazyVStack(spacing: 24) {
ForEach(posts) { post in ForEach(posts) { post in
PostDetailView(post: post) PostDetailView(post: post)
@ -22,18 +25,12 @@ struct HomeTab: View {
} }
} }
} }
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {}
}
.onAppear { .onAppear {
if posts.isEmpty { if posts.isEmpty {
fetchData(isInitialLoad: true) fetchData(isInitialLoad: true)
} }
} }
} }
.navigationViewStyle(StackNavigationViewStyle())
}
private func fetchData(isInitialLoad: Bool = false) { private func fetchData(isInitialLoad: Bool = false) {
if isInitialLoad { if isInitialLoad {

View File

@ -1,53 +1,137 @@
//
// MainView.swift
// VolnahubApp
//
// Created by cheykrym on 09/06/2025.
//
import SwiftUI import SwiftUI
struct MainView: View { struct MainView: View {
@ObservedObject var viewModel: LoginViewModel @ObservedObject var viewModel: LoginViewModel
@State private var selectedTab: Int = 0 @State private var selectedTab: Int = 0
@StateObject private var newHomeTabViewModel = NewHomeTabViewModel()
// Состояния для TopBarView
@State private var selectedAccount = "@user1"
@State private var accounts = ["@user1", "@user2", "@user3"]
@State private var sheetType: ProfileTab.SheetType? = nil
// Состояния для бокового меню
@State private var isSideMenuPresented = false
@State private var menuOffset: CGFloat = 0
private var tabTitle: String {
switch selectedTab {
case 0: return "Home"
case 1: return "Search"
case 2: return "Chats"
case 3: return "Profile"
default: return "Home"
}
}
private var menuWidth: CGFloat {
UIScreen.main.bounds.width * 0.8
}
var body: some View { var body: some View {
TabView(selection: $selectedTab) { NavigationView {
HomeTab() ZStack(alignment: .leading) { // Выравниваем ZStack по левому краю
.tabItem { // Основной контент
Image(systemName: "list.bullet.rectangle") VStack(spacing: 0) {
Text("Лента") TopBarView(
} title: tabTitle,
.tag(0) selectedAccount: $selectedAccount,
sheetType: $sheetType,
accounts: accounts,
viewModel: viewModel,
isSideMenuPresented: $isSideMenuPresented
)
ZStack {
NewHomeTab(viewModel: newHomeTabViewModel)
.opacity(selectedTab == 0 ? 1 : 0)
SearchTab() SearchTab()
.tabItem { .opacity(selectedTab == 1 ? 1 : 0)
Image(systemName: "magnifyingglass")
Text("Поиск")
}
.tag(1)
// PublicsTab()
// .tabItem {
// Image(systemName: "")
// Text("Свайп")
// }
// .tag(1)
ChatsTab() ChatsTab()
.tabItem { .opacity(selectedTab == 2 ? 1 : 0)
Image(systemName: "bubble.left.and.bubble.right.fill")
Text("Чаты")
}
.tag(2)
ProfileTab(viewModel: viewModel) ProfileTab(viewModel: viewModel, sheetType: $sheetType, selectedAccount: $selectedAccount, accounts: $accounts, onScroll: { _ in })
.tabItem { .opacity(selectedTab == 3 ? 1 : 0)
Image(systemName: "person.crop.square") }
Text("Лицо") .frame(maxWidth: .infinity, maxHeight: .infinity)
CustomTabBar(selectedTab: $selectedTab) {
print("Create button tapped")
}
}
.frame(maxWidth: .infinity, maxHeight: .infinity) // Убедимся, что основной контент занимает все пространство
.ignoresSafeArea(edges: .bottom)
.navigationBarHidden(true)
.sheet(item: $sheetType) { type in
// ... sheet presentation logic
}
// Затемнение и закрытие по тапу
Color.black
.opacity(Double(menuOffset / menuWidth) * 0.4)
.ignoresSafeArea()
.onTapGesture {
withAnimation(.easeInOut) {
isSideMenuPresented = false
}
}
.allowsHitTesting(menuOffset > 0)
// Боковое меню
SideMenuView(isPresented: $isSideMenuPresented)
.frame(width: menuWidth)
.offset(x: -menuWidth + menuOffset) // Новая логика смещения
.ignoresSafeArea(edges: .vertical)
}
.gesture(
DragGesture()
.onChanged { gesture in
if !isSideMenuPresented && gesture.startLocation.x > 60 { return }
let translation = gesture.translation.width
// Определяем базовое смещение в зависимости от того, открыто меню или нет
let baseOffset = isSideMenuPresented ? menuWidth : 0
// Новое смещение это база плюс текущий свайп
let newOffset = baseOffset + translation
// Жестко ограничиваем итоговое смещение между 0 и шириной меню
self.menuOffset = max(0, min(menuWidth, newOffset))
}
.onEnded { gesture in
if !isSideMenuPresented && gesture.startLocation.x > 60 { return }
let threshold = menuWidth * 0.4
withAnimation(.easeInOut) {
if self.menuOffset > threshold {
isSideMenuPresented = true
} else {
isSideMenuPresented = false
}
// Устанавливаем финальное смещение после анимации
self.menuOffset = isSideMenuPresented ? menuWidth : 0
}
}
)
}
.navigationViewStyle(StackNavigationViewStyle())
.onChange(of: isSideMenuPresented) { presented in
// Плавная анимация при нажатии на кнопку, а не только при жесте
withAnimation(.easeInOut) {
menuOffset = presented ? menuWidth : 0
} }
.tag(3)
} }
} }
} }
struct MainView_Previews: PreviewProvider {
static var previews: some View {
let mockViewModel = LoginViewModel()
MainView(viewModel: mockViewModel)
.environmentObject(ThemeManager())
}
}

View File

@ -0,0 +1,114 @@
import SwiftUI
struct NewHomeTab: View {
@ObservedObject var viewModel: NewHomeTabViewModel
private var column1Posts: [Post] {
viewModel.posts.enumerated().filter { $0.offset % 2 == 0 }.map { $0.element }
}
private var column2Posts: [Post] {
viewModel.posts.enumerated().filter { $0.offset % 2 != 0 }.map { $0.element }
}
var body: some View {
VStack {
if viewModel.isLoading {
ProgressView("Загрузка ленты...")
} else {
RefreshableScrollView(isRefreshing: $viewModel.isRefreshing, onRefresh: {
viewModel.refreshData()
}) {
HStack(alignment: .top, spacing: 6) {
LazyVStack(spacing: 6) {
ForEach(column1Posts) { post in
PostGridItem(post: post)
}
}
LazyVStack(spacing: 6) {
ForEach(column2Posts) { post in
PostGridItem(post: post)
}
}
}
.padding(.horizontal, 4)
}
}
}
.onAppear {
viewModel.fetchDataIfNeeded()
}
.background(Color(.secondarySystemBackground)) // Фон для всей вкладки
}
}
struct PostGridItem: View {
let post: Post
private var randomHeight: CGFloat {
CGFloat.random(in: 150...300)
}
var body: some View {
VStack(alignment: .leading, spacing: 0) { // Убираем отступ между картинкой и текстом
// 1. Медиа контент
if let _ = post.media.first {
Image("placeholderPhoto")
.resizable()
.aspectRatio(contentMode: .fill)
.frame(height: randomHeight)
}
// Контейнер для текста, который создает эффект "расширения"
VStack(alignment: .leading, spacing: 8) {
// 2. Название поста
if let title = post.title, !title.isEmpty {
Text(title)
.font(.subheadline)
.lineLimit(2)
}
// 3. Информация об авторе и лайки
HStack {
Button(action: {
// пока ничего не делаем
}) {
HStack(spacing: 4) {
Image(systemName: "person.circle.fill")
.resizable()
.frame(width: 20, height: 20)
.foregroundColor(.gray)
Text(post.authorUsername)
.font(.footnote)
.lineLimit(1)
.foregroundColor(.primary)
}
}
.contentShape(Rectangle())
Spacer()
Button(action: {
// пока ничего не делаем
}) {
HStack(spacing: 4) {
Image(systemName: post.isLikedByCurrentUser ? "heart.fill" : "heart")
.foregroundColor(post.isLikedByCurrentUser ? .red : .primary)
Text("\(post.likes)")
.font(.subheadline)
.foregroundColor(.primary)
}
}
.contentShape(Rectangle())
}
}
.padding(8)
.background(Color(UIColor.systemBackground)) // Фон только для текстовой части
}
.cornerRadius(6) // Закругляем всю карточку
.clipped() // Обрезаем дочерние вью по закругленной форме родителя
.shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2)
}
}

View File

@ -43,15 +43,6 @@ struct ProfileContentTabbedGrid: View {
.cornerRadius(8) .cornerRadius(8)
.font(.subheadline) .font(.subheadline)
Button {
// Создать пост
} label: {
Label("Создать", systemImage: "plus")
.font(.subheadline)
.padding(8)
.background(Color.blue.opacity(0.2))
.cornerRadius(8)
}
} else { } else {
TextField("Поиск", text: $searchQuery) TextField("Поиск", text: $searchQuery)
.padding(.horizontal, 10) .padding(.horizontal, 10)

View File

@ -4,13 +4,16 @@ struct ProfileTab: View {
@ObservedObject var viewModel: LoginViewModel @ObservedObject var viewModel: LoginViewModel
@State private var isContentLoaded = true @State private var isContentLoaded = true
@State private var accounts = ["@user1", "@user2", "@user3"] // Привязки к состояниям в MainView
@State private var selectedAccount = "@user1" @Binding var sheetType: SheetType?
@Binding var selectedAccount: String
@Binding var accounts: [String]
var onScroll: ((CGPoint) -> Void)?
let followers = ["@alice", "@bob", "@charlie"] let followers = ["@alice", "@bob", "@charlie"]
let following = ["@dev", "@design", "@ios"] let following = ["@dev", "@design", "@ios"]
@State private var sheetType: SheetType? = nil
enum SheetType: Identifiable { enum SheetType: Identifiable {
case accountShare case accountShare
var id: Int { self.hashValue } var id: Int { self.hashValue }
@ -26,7 +29,7 @@ struct ProfileTab: View {
@State private var isShowingFollowing = false @State private var isShowingFollowing = false
var body: some View { var body: some View {
NavigationView { VStack {
if !isContentLoaded { if !isContentLoaded {
SplashScreenView() SplashScreenView()
} else { } else {
@ -46,12 +49,13 @@ struct ProfileTab: View {
) )
} }
RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: { RefreshableScrollView(
fetchData() isRefreshing: $isRefreshing,
}) { onRefresh: { fetchData() },
onScroll: onScroll
) {
VStack(spacing: 12) { VStack(spacing: 12) {
header header
// .frame(minHeight: 300)
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
.background(Color(.systemBackground)) .background(Color(.systemBackground))
@ -66,43 +70,8 @@ struct ProfileTab: View {
} }
} }
} }
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .principal) {
Button(action: { sheetType = .accountShare }) {
HStack(spacing: 4) {
Text(selectedAccount)
.font(.headline)
.foregroundColor(.primary)
Image(systemName: "chevron.down")
.font(.subheadline)
.foregroundColor(.gray)
} }
} }
}
ToolbarItem(placement: .navigationBarTrailing) {
NavigationLink(destination: SettingsView(viewModel: viewModel)) {
Image(systemName: "wrench")
.imageScale(.large)
}
}
}
.sheet(item: $sheetType) { type in
switch type {
case .accountShare:
AccountShareSheet(
isPresented: Binding(
get: { sheetType != nil },
set: { if !$0 { sheetType = nil } }
),
selectedAccount: $selectedAccount,
accounts: accounts
)
}
}
}
}
.navigationViewStyle(StackNavigationViewStyle())
.onAppear { .onAppear {
if allPosts.isEmpty { if allPosts.isEmpty {
fetchData(isInitialLoad: true) fetchData(isInitialLoad: true)

View File

@ -4,13 +4,17 @@ struct SearchTab: View {
@StateObject private var viewModel = SearchViewModel() @StateObject private var viewModel = SearchViewModel()
var body: some View { var body: some View {
NavigationView {
VStack { VStack {
SearchBar(text: $viewModel.searchText) SearchBar(text: $viewModel.searchText)
.padding(.top, 8) .padding(.top, 8)
List(viewModel.users) { user in List(viewModel.users) { user in
NavigationLink(destination: ProfileTab(viewModel: LoginViewModel())) { // Placeholder destination NavigationLink(destination: ProfileTab(
viewModel: LoginViewModel(),
sheetType: .constant(nil),
selectedAccount: .constant("@\(user.username)"),
accounts: .constant(["@\(user.username)"]))
) {
HStack { HStack {
Image(systemName: "person.crop.circle") Image(systemName: "person.crop.circle")
.resizable() .resizable()
@ -22,8 +26,6 @@ struct SearchTab: View {
} }
.listStyle(PlainListStyle()) .listStyle(PlainListStyle())
} }
.navigationTitle("Поиск")
}
} }
} }

View File

@ -0,0 +1,259 @@
import SwiftUI
// --- HELPER STRUCTS & EXTENSIONS ---
// Dummy data for the account list
struct Account: Identifiable {
let id = UUID()
let name: String
let username: String
let isCurrent: Bool
}
// Custom Transition for older Xcode versions
extension AnyTransition {
static var slideAndFade: AnyTransition {
let insertion = AnyTransition.move(edge: .top).combined(with: .opacity)
let removal = AnyTransition.move(edge: .top).combined(with: .opacity)
return .asymmetric(insertion: insertion, removal: removal)
}
}
// Helper Views for buttons
struct SideMenuButton: View {
let icon: String
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
HStack(spacing: 15) {
Image(systemName: icon)
.font(.title3)
.frame(width: 30)
Text(title)
.font(.subheadline)
}
.foregroundColor(.primary)
.padding(.vertical, 8)
}
}
}
struct SideMenuFooterButton: View {
let icon: String
let title: String
let action: () -> Void
var body: some View {
Button(action: action) {
VStack {
Image(systemName: icon)
.font(.title2)
Text(title)
.font(.caption2)
}
.foregroundColor(.primary)
}
}
}
// --- MAIN VIEW ---
struct SideMenuView: View {
@EnvironmentObject var themeManager: ThemeManager
@Environment(\.colorScheme) var colorScheme
@Binding var isPresented: Bool
@State private var isAccountListExpanded = false
// Adjustable paddings
private let topPadding: CGFloat = 66
private let bottomPadding: CGFloat = 34
// Dummy account data
private let accounts: [Account] = [
Account(name: "Your Name", username: "@yourusername", isCurrent: true),
Account(name: "Second Account", username: "@second", isCurrent: false),
Account(name: "Another One", username: "@another", isCurrent: false),
Account(name: "Test User", username: "@test", isCurrent: false),
Account(name: "Creative Profile", username: "@creative", isCurrent: false)
]
private var themeToggleButton: some View {
Button(action: {
themeManager.toggleTheme(from: colorScheme)
}) {
Image(systemName: iconName)
.font(.title2)
.foregroundColor(.primary)
}
}
private var iconName: String {
let effectiveScheme: ColorScheme
switch themeManager.theme {
case .system:
effectiveScheme = colorScheme
case .light:
effectiveScheme = .light
case .dark:
effectiveScheme = .dark
}
return effectiveScheme == .dark ? "sun.max.fill" : "moon.fill"
}
var body: some View {
VStack(alignment: .leading, spacing: 0) {
ScrollView {
VStack(alignment: .leading, spacing: 0) { // Parent VStack
// --- Header ---
HStack(alignment: .top) {
Button(action: { }) {
Image(systemName: "person.circle.fill")
.resizable()
.frame(width: 60, height: 60)
.foregroundColor(.gray)
}
Spacer()
themeToggleButton
}
.padding(.horizontal, 20)
.padding(.top, topPadding)
.padding(.bottom, 10)
// --- Header Button ---
Button(action: {
withAnimation(.spring()) {
isAccountListExpanded.toggle()
}
}) {
HStack {
VStack(alignment: .leading) {
Text("Your Name")
.font(.title3).bold()
Text("@yourusername")
.font(.footnote)
}
.foregroundColor(.primary)
Spacer()
Image(systemName: isAccountListExpanded ? "chevron.up" : "chevron.down")
.font(.headline)
.foregroundColor(.secondary)
}
}
.padding(.horizontal, 20)
.padding(.bottom, 10)
// --- Collapsible Account List in a clipped container ---
VStack {
if isAccountListExpanded {
VStack(alignment: .leading, spacing: 15) {
ForEach(accounts) { account in
HStack {
Button(action: { }) {
ZStack {
Image(systemName: "person.circle.fill")
.resizable()
.frame(width: 32, height: 32) // Smaller icon
.foregroundColor(.secondary)
if account.isCurrent {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.blue)
.background(Circle().fill(Color(UIColor.systemBackground)))
.font(.body) // Smaller checkmark
.offset(x: 11, y: 11) // Adjusted offset
}
}
VStack(alignment: .leading) {
Text(account.name).font(.footnote).bold() // Smaller text
Text(account.username).font(.caption2) // Smaller text
}
.foregroundColor(.primary)
}
Spacer()
}
}
}
.padding(.horizontal, 20)
.padding(.vertical, 10)
.transition(.slideAndFade)
}
}
.clipped()
// Menu Items
VStack(alignment: .leading, spacing: 20) {
// Section 1
VStack(alignment: .leading, spacing: 7) {
SideMenuButton(icon: "person.2.fill", title: "People You May Like", action: {})
SideMenuButton(icon: "star.fill", title: "Fun Fest", action: {})
SideMenuButton(icon: "lightbulb.fill", title: "Creator Center", action: {})
}
Divider()
// Section 2
VStack(alignment: .leading, spacing: 7) {
Text("CATEGORY").font(.caption2).foregroundColor(.secondary)
SideMenuButton(icon: "doc.text", title: "Drafts", action: {})
SideMenuButton(icon: "bubble.left", title: "My Comments", action: {})
SideMenuButton(icon: "clock", title: "History", action: {})
SideMenuButton(icon: "arrow.down.circle", title: "My Downloads", action: {})
}
Divider()
// Section 3
VStack(alignment: .leading, spacing: 7) {
Text("SERVICES").font(.caption2).foregroundColor(.secondary)
SideMenuButton(icon: "shippingbox", title: "Orders", action: {})
SideMenuButton(icon: "cart", title: "Cart", action: {})
SideMenuButton(icon: "wallet.pass", title: "Wallet", action: {})
}
Divider()
// Section 4
VStack(alignment: .leading, spacing: 15) {
SideMenuButton(icon: "square.grid.2x2", title: "Applets", action: {})
}
}
.padding()
}
.frame(maxWidth: .infinity, alignment: .leading) // Align to the left
}
.clipped()
Spacer()
// Footer
HStack(spacing: 20) {
Spacer()
SideMenuFooterButton(icon: "qrcode.viewfinder", title: "Scan", action: {})
SideMenuFooterButton(icon: "questionmark.circle", title: "Help Center", action: {})
SideMenuFooterButton(icon: "gear", title: "Settings", action: {})
Spacer()
}
.padding()
.padding(.bottom, bottomPadding)
}
.background(Color(UIColor.systemBackground))
}
}
// --- PREVIEW ---
struct SideMenuView_Previews: PreviewProvider {
static var previews: some View {
SideMenuView(isPresented: .constant(true))
.environmentObject(ThemeManager())
}
}

View File

@ -7,31 +7,24 @@
import SwiftUI import SwiftUI
//@AppStorage("isLoggedIn") var isLoggedIn: Bool = false
//@AppStorage("isDarkMode") private var isDarkMode: Bool = false
//@AppStorage("currentUser") var currentUser: String = ""
@main @main
struct volnahubApp: App { struct volnahubApp: App {
@AppStorage("isDarkMode") private var isDarkMode: Bool = true @StateObject private var themeManager = ThemeManager()
@StateObject private var viewModel = LoginViewModel() @StateObject private var viewModel = LoginViewModel()
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
ZStack { Group {
Color(isDarkMode ? .black : .white) // Фон в зависимости от темы
if viewModel.isLoading { if viewModel.isLoading {
SplashScreenView() SplashScreenView()
}else{ } else if viewModel.isLoggedIn {
if viewModel.isLoggedIn {
MainView(viewModel: viewModel) MainView(viewModel: viewModel)
} else { } else {
LoginView(viewModel: viewModel) LoginView(viewModel: viewModel)
} }
} }
} .environmentObject(themeManager)
.preferredColorScheme(isDarkMode ? .dark : .light) .preferredColorScheme(themeManager.theme.colorScheme)
} }
} }
} }

View File

@ -10,6 +10,7 @@
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */; }; 1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */; };
1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276102DF9247000D8BC53 /* CustomTextField.swift */; }; 1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276102DF9247000D8BC53 /* CustomTextField.swift */; };
1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2302102E3050C60067BF4F /* SearchViewModel.swift */; }; 1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2302102E3050C60067BF4F /* SearchViewModel.swift */; };
1A6FB9552E32D2B200E89EBE /* CustomTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A6FB9542E32D2B200E89EBE /* CustomTabBar.swift */; };
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* yobbleApp.swift */; }; 1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* yobbleApp.swift */; };
1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; }; 1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
1A7940902DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; }; 1A7940902DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
@ -28,9 +29,19 @@
1A7940E72DF7B5E5002569DA /* SplashScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940E62DF7B5E5002569DA /* SplashScreenView.swift */; }; 1A7940E72DF7B5E5002569DA /* SplashScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940E62DF7B5E5002569DA /* SplashScreenView.swift */; };
1A7940F02DF7B7A3002569DA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1A7940F22DF7B7A3002569DA /* Localizable.strings */; }; 1A7940F02DF7B7A3002569DA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1A7940F22DF7B7A3002569DA /* Localizable.strings */; };
1A79410C2DF7C81D002569DA /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79410B2DF7C81D002569DA /* RegistrationView.swift */; }; 1A79410C2DF7C81D002569DA /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79410B2DF7C81D002569DA /* RegistrationView.swift */; };
1A9B014B2E4BF3CD00887E0B /* NewHomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B014A2E4BF3CD00887E0B /* NewHomeTab.swift */; };
1A9B01582E4BF50D00887E0B /* placeholderVideo.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 1A9B01572E4BF50D00887E0B /* placeholderVideo.mp4 */; };
1A9B015F2E4BF9C000887E0B /* placeholderPhotoSquare.png in Resources */ = {isa = PBXBuildFile; fileRef = 1A9B015D2E4BF9C000887E0B /* placeholderPhotoSquare.png */; };
1A9B01602E4BF9C000887E0B /* placeholderPhoto.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 1A9B015E2E4BF9C000887E0B /* placeholderPhoto.jpg */; };
1A9B01662E4BFA3600887E0B /* Media.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A9B01652E4BFA3600887E0B /* Media.xcassets */; };
1A9B016E2E4BFB9000887E0B /* NewHomeTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */; };
1A9B017C2E4C087F00887E0B /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B017B2E4C087F00887E0B /* SideMenuView.swift */; };
1A9E4FB32E4D6A67002249D6 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */; };
1AB4F8CD2E22E341002B6E40 /* AccountShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */; }; 1AB4F8CD2E22E341002B6E40 /* AccountShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */; };
1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */; }; 1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */; };
1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */; }; 1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */; };
1AB7F5162E32EC1C003756F3 /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB7F5142E32EC1C003756F3 /* RefreshableScrollView.swift */; };
1AB7F5172E32EC1C003756F3 /* TopBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB7F5152E32EC1C003756F3 /* TopBarView.swift */; };
1ACE60F82E22F3DC00B37AC5 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE60F72E22F3DC00B37AC5 /* SettingsView.swift */; }; 1ACE60F82E22F3DC00B37AC5 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE60F72E22F3DC00B37AC5 /* SettingsView.swift */; };
1ACE61012E22F55C00B37AC5 /* EditProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61002E22F55C00B37AC5 /* EditProfileView.swift */; }; 1ACE61012E22F55C00B37AC5 /* EditProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61002E22F55C00B37AC5 /* EditProfileView.swift */; };
1ACE61052E22F56800B37AC5 /* SecuritySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61042E22F56800B37AC5 /* SecuritySettingsView.swift */; }; 1ACE61052E22F56800B37AC5 /* SecuritySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61042E22F56800B37AC5 /* SecuritySettingsView.swift */; };
@ -39,7 +50,6 @@
1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; }; 1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; };
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */; }; 1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */; };
1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */; }; 1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */; };
1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */; };
1AE587052E23264800254F06 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587042E23264800254F06 /* PostService.swift */; }; 1AE587052E23264800254F06 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587042E23264800254F06 /* PostService.swift */; };
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; }; 1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; };
1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; }; 1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; };
@ -51,6 +61,7 @@
1A0276022DF909F900D8BC53 /* refreshtokenex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = refreshtokenex.swift; sourceTree = "<group>"; }; 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = refreshtokenex.swift; sourceTree = "<group>"; };
1A0276102DF9247000D8BC53 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; }; 1A0276102DF9247000D8BC53 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
1A2302102E3050C60067BF4F /* SearchViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; }; 1A2302102E3050C60067BF4F /* SearchViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; };
1A6FB9542E32D2B200E89EBE /* CustomTabBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomTabBar.swift; sourceTree = "<group>"; };
1A79407A2DF77BC2002569DA /* yobbleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = yobbleApp.swift; sourceTree = "<group>"; }; 1A79407A2DF77BC2002569DA /* yobbleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = yobbleApp.swift; sourceTree = "<group>"; };
1A79407B2DF77BC2002569DA /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; }; 1A79407B2DF77BC2002569DA /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
1A79407C2DF77BC3002569DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 1A79407C2DF77BC3002569DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@ -63,7 +74,7 @@
1A7940A52DF77DF5002569DA /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; }; 1A7940A52DF77DF5002569DA /* User.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
1A7940A92DF77E05002569DA /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; }; 1A7940A92DF77E05002569DA /* LoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewModel.swift; sourceTree = "<group>"; };
1A7940AF2DF77E26002569DA /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; }; 1A7940AF2DF77E26002569DA /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
1A7940B52DF77F21002569DA /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; }; 1A7940B52DF77F21002569DA /* MainView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; tabWidth = 4; };
1A7940C52DF7A98E002569DA /* ContactsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsTab.swift; sourceTree = "<group>"; }; 1A7940C52DF7A98E002569DA /* ContactsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsTab.swift; sourceTree = "<group>"; };
1A7940C92DF7A99B002569DA /* ChatsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTab.swift; sourceTree = "<group>"; }; 1A7940C92DF7A99B002569DA /* ChatsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTab.swift; sourceTree = "<group>"; };
1A7940CD2DF7A9AA002569DA /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; }; 1A7940CD2DF7A9AA002569DA /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; };
@ -73,9 +84,19 @@
1A7940F12DF7B7A3002569DA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; }; 1A7940F12DF7B7A3002569DA /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
1A7940F72DF7B7EC002569DA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; }; 1A7940F72DF7B7EC002569DA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
1A79410B2DF7C81D002569DA /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; }; 1A79410B2DF7C81D002569DA /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; };
1A9B014A2E4BF3CD00887E0B /* NewHomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewHomeTab.swift; sourceTree = "<group>"; };
1A9B01572E4BF50D00887E0B /* placeholderVideo.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; name = placeholderVideo.mp4; path = ../../../../Volumes/Untitled/xcode/volnahub/Shared/Media/placeholderVideo.mp4; sourceTree = DEVELOPER_DIR; };
1A9B015D2E4BF9C000887E0B /* placeholderPhotoSquare.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = placeholderPhotoSquare.png; path = ../../../../Volumes/Untitled/xcode/volnahub/Shared/Media/placeholderPhotoSquare.png; sourceTree = DEVELOPER_DIR; };
1A9B015E2E4BF9C000887E0B /* placeholderPhoto.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = placeholderPhoto.jpg; path = ../../../../Volumes/Untitled/xcode/volnahub/Shared/Media/placeholderPhoto.jpg; sourceTree = DEVELOPER_DIR; };
1A9B01652E4BFA3600887E0B /* Media.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Media.xcassets; sourceTree = "<group>"; };
1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewHomeTabViewModel.swift; sourceTree = "<group>"; };
1A9B017B2E4C087F00887E0B /* SideMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountShareSheet.swift; sourceTree = "<group>"; }; 1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountShareSheet.swift; sourceTree = "<group>"; };
1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersView.swift; sourceTree = "<group>"; }; 1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersView.swift; sourceTree = "<group>"; };
1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; }; 1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
1AB7F5142E32EC1C003756F3 /* RefreshableScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RefreshableScrollView.swift; sourceTree = "<group>"; };
1AB7F5152E32EC1C003756F3 /* TopBarView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TopBarView.swift; sourceTree = "<group>"; };
1ACE60F72E22F3DC00B37AC5 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; }; 1ACE60F72E22F3DC00B37AC5 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
1ACE61002E22F55C00B37AC5 /* EditProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfileView.swift; sourceTree = "<group>"; }; 1ACE61002E22F55C00B37AC5 /* EditProfileView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditProfileView.swift; sourceTree = "<group>"; };
1ACE61042E22F56800B37AC5 /* SecuritySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecuritySettingsView.swift; sourceTree = "<group>"; }; 1ACE61042E22F56800B37AC5 /* SecuritySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecuritySettingsView.swift; sourceTree = "<group>"; };
@ -84,7 +105,6 @@
1ACE61182E22FF1400B37AC5 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; }; 1ACE61182E22FF1400B37AC5 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentTabbedGrid.swift; sourceTree = "<group>"; }; 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentTabbedGrid.swift; sourceTree = "<group>"; };
1AD757CC2E27608C0069C1FD /* PostFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostFeedView.swift; sourceTree = "<group>"; }; 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostFeedView.swift; sourceTree = "<group>"; };
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RefreshableScrollView.swift; path = Components/RefreshableScrollView.swift; sourceTree = "<group>"; };
1AE587042E23264800254F06 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; }; 1AE587042E23264800254F06 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; };
1AE587242E23337000254F06 /* ProfileContentGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentGrid.swift; sourceTree = "<group>"; }; 1AE587242E23337000254F06 /* ProfileContentGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentGrid.swift; sourceTree = "<group>"; };
1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; }; 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; };
@ -123,7 +143,8 @@
1A7940792DF77BC2002569DA /* Shared */ = { 1A7940792DF77BC2002569DA /* Shared */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */, 1A9B01502E4BF49200887E0B /* Media */,
1AB7F5132E32EBF1003756F3 /* Components */,
1A7940FA2DF7B898002569DA /* Resources */, 1A7940FA2DF7B898002569DA /* Resources */,
1A7940E52DF7B341002569DA /* Services */, 1A7940E52DF7B341002569DA /* Services */,
1A7940A02DF77DCD002569DA /* Network */, 1A7940A02DF77DCD002569DA /* Network */,
@ -179,6 +200,7 @@
1A79409E2DF77DBD002569DA /* ViewModels */ = { 1A79409E2DF77DBD002569DA /* ViewModels */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */,
1A2302102E3050C60067BF4F /* SearchViewModel.swift */, 1A2302102E3050C60067BF4F /* SearchViewModel.swift */,
1A7940A92DF77E05002569DA /* LoginViewModel.swift */, 1A7940A92DF77E05002569DA /* LoginViewModel.swift */,
); );
@ -207,6 +229,7 @@
1A7940E52DF7B341002569DA /* Services */ = { 1A7940E52DF7B341002569DA /* Services */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */,
1A7940E12DF7B1C5002569DA /* KeychainService.swift */, 1A7940E12DF7B1C5002569DA /* KeychainService.swift */,
); );
path = Services; path = Services;
@ -220,6 +243,26 @@
path = Resources; path = Resources;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
1A9B01502E4BF49200887E0B /* Media */ = {
isa = PBXGroup;
children = (
1A9B01652E4BFA3600887E0B /* Media.xcassets */,
1A9B015E2E4BF9C000887E0B /* placeholderPhoto.jpg */,
1A9B015D2E4BF9C000887E0B /* placeholderPhotoSquare.png */,
1A9B01572E4BF50D00887E0B /* placeholderVideo.mp4 */,
);
path = Media;
sourceTree = "<group>";
};
1AB7F5132E32EBF1003756F3 /* Components */ = {
isa = PBXGroup;
children = (
1AB7F5142E32EC1C003756F3 /* RefreshableScrollView.swift */,
1AB7F5152E32EC1C003756F3 /* TopBarView.swift */,
);
path = Components;
sourceTree = "<group>";
};
1ACE60FF2E22F54700B37AC5 /* Settings */ = { 1ACE60FF2E22F54700B37AC5 /* Settings */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -250,7 +293,10 @@
1AEE5EA92E21A4FC00A3DCA3 /* Tab */ = { 1AEE5EA92E21A4FC00A3DCA3 /* Tab */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1A9B017B2E4C087F00887E0B /* SideMenuView.swift */,
1A6FB9542E32D2B200E89EBE /* CustomTabBar.swift */,
1A7940B52DF77F21002569DA /* MainView.swift */, 1A7940B52DF77F21002569DA /* MainView.swift */,
1A9B014A2E4BF3CD00887E0B /* NewHomeTab.swift */,
1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */, 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */,
1AEE5EB22E21A85800A3DCA3 /* SearchTab.swift */, 1AEE5EB22E21A85800A3DCA3 /* SearchTab.swift */,
1A7940C92DF7A99B002569DA /* ChatsTab.swift */, 1A7940C92DF7A99B002569DA /* ChatsTab.swift */,
@ -356,8 +402,12 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
1A9B01582E4BF50D00887E0B /* placeholderVideo.mp4 in Resources */,
1A7940912DF77BC3002569DA /* Assets.xcassets in Resources */, 1A7940912DF77BC3002569DA /* Assets.xcassets in Resources */,
1A7940F02DF7B7A3002569DA /* Localizable.strings in Resources */, 1A7940F02DF7B7A3002569DA /* Localizable.strings in Resources */,
1A9B01602E4BF9C000887E0B /* placeholderPhoto.jpg in Resources */,
1A9B01662E4BFA3600887E0B /* Media.xcassets in Resources */,
1A9B015F2E4BF9C000887E0B /* placeholderPhotoSquare.png in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -379,24 +429,31 @@
1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */, 1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */,
1ACE60F82E22F3DC00B37AC5 /* SettingsView.swift in Sources */, 1ACE60F82E22F3DC00B37AC5 /* SettingsView.swift in Sources */,
1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */, 1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */,
1A9B017C2E4C087F00887E0B /* SideMenuView.swift in Sources */,
1A7940C62DF7A98E002569DA /* ContactsTab.swift in Sources */, 1A7940C62DF7A98E002569DA /* ContactsTab.swift in Sources */,
1ACE61092E22F57100B37AC5 /* AppPreferencesView.swift in Sources */, 1ACE61092E22F57100B37AC5 /* AppPreferencesView.swift in Sources */,
1ACE61052E22F56800B37AC5 /* SecuritySettingsView.swift in Sources */, 1ACE61052E22F56800B37AC5 /* SecuritySettingsView.swift in Sources */,
1A9B016E2E4BFB9000887E0B /* NewHomeTabViewModel.swift in Sources */,
1A7940E72DF7B5E5002569DA /* SplashScreenView.swift in Sources */, 1A7940E72DF7B5E5002569DA /* SplashScreenView.swift in Sources */,
1A7940B02DF77E26002569DA /* LoginView.swift in Sources */, 1A7940B02DF77E26002569DA /* LoginView.swift in Sources */,
1A79410C2DF7C81D002569DA /* RegistrationView.swift in Sources */, 1A79410C2DF7C81D002569DA /* RegistrationView.swift in Sources */,
1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */, 1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */,
1AB7F5172E32EC1C003756F3 /* TopBarView.swift in Sources */,
1A7940CE2DF7A9AA002569DA /* ProfileTab.swift in Sources */, 1A7940CE2DF7A9AA002569DA /* ProfileTab.swift in Sources */,
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */, 1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */,
1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */, 1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */,
1A7940DE2DF7B0D7002569DA /* config.swift in Sources */, 1A7940DE2DF7B0D7002569DA /* config.swift in Sources */,
1A9B014B2E4BF3CD00887E0B /* NewHomeTab.swift in Sources */,
1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */, 1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */,
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */, 1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */,
1A6FB9552E32D2B200E89EBE /* CustomTabBar.swift in Sources */,
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */, 1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
1A7940B62DF77F21002569DA /* MainView.swift in Sources */, 1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
1AB7F5162E32EC1C003756F3 /* RefreshableScrollView.swift in Sources */,
1A7940E22DF7B1C5002569DA /* KeychainService.swift in Sources */, 1A7940E22DF7B1C5002569DA /* KeychainService.swift in Sources */,
1A7940A62DF77DF5002569DA /* User.swift in Sources */, 1A7940A62DF77DF5002569DA /* User.swift in Sources */,
1A7940A22DF77DE9002569DA /* AuthService.swift in Sources */, 1A7940A22DF77DE9002569DA /* AuthService.swift in Sources */,
1A9E4FB32E4D6A67002249D6 /* ThemeManager.swift in Sources */,
1AEE5EB32E21A85800A3DCA3 /* SearchTab.swift in Sources */, 1AEE5EB32E21A85800A3DCA3 /* SearchTab.swift in Sources */,
1ACE61152E22FE2000B37AC5 /* PostDetailView.swift in Sources */, 1ACE61152E22FE2000B37AC5 /* PostDetailView.swift in Sources */,
1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */, 1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */,
@ -409,7 +466,6 @@
1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */, 1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */,
1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */, 1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */,
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */, 1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */,
1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };

View File

@ -17,12 +17,12 @@
<key>yobble (iOS).xcscheme_^#shared#^_</key> <key>yobble (iOS).xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>0</integer> <integer>1</integer>
</dict> </dict>
<key>yobble (macOS).xcscheme_^#shared#^_</key> <key>yobble (macOS).xcscheme_^#shared#^_</key>
<dict> <dict>
<key>orderHint</key> <key>orderHint</key>
<integer>1</integer> <integer>0</integer>
</dict> </dict>
</dict> </dict>
</dict> </dict>