Compare commits

..

26 Commits
FAB ... 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 1003 additions and 207 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,7 +43,6 @@ struct ProfileContentTabbedGrid: View {
.cornerRadius(8) .cornerRadius(8)
.font(.subheadline) .font(.subheadline)
} 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,11 +29,10 @@ 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 {
ZStack(alignment: .bottomTrailing) {
VStack(spacing: 0) { VStack(spacing: 0) {
// Скрытые NavigationLink для программного перехода // Скрытые NavigationLink для программного перехода
NavigationLink(destination: FollowersView(followers: followers), isActive: $isShowingFollowers) { EmptyView() } NavigationLink(destination: FollowersView(followers: followers), isActive: $isShowingFollowers) { EmptyView() }
@ -47,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))
@ -67,58 +70,8 @@ struct ProfileTab: View {
} }
} }
} }
// FAB
Button(action: {
// TODO: Действие для создания поста
}) {
Image(systemName: "plus")
.font(.system(size: 24, weight: .bold))
.foregroundColor(.white)
.padding()
.background(Color.blue)
.clipShape(Circle())
.shadow(radius: 5)
}
.padding()
}
.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>