Compare commits
	
		
			4 Commits
		
	
	
		
			bb8c9a2b91
			...
			32dd59e635
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					32dd59e635 | ||
| 
						 | 
					ebb34b672a | ||
| 
						 | 
					a716b296d5 | ||
| 
						 | 
					8fd955d3cb | 
							
								
								
									
										68
									
								
								Shared/Components/RefreshableScrollView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								Shared/Components/RefreshableScrollView.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,68 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
import UIKit
 | 
			
		||||
 | 
			
		||||
struct RefreshableScrollView<Content: View>: UIViewRepresentable {
 | 
			
		||||
    var content: Content
 | 
			
		||||
    var onRefresh: () -> Void
 | 
			
		||||
    var isRefreshing: Binding<Bool>
 | 
			
		||||
 | 
			
		||||
    init(isRefreshing: Binding<Bool>, onRefresh: @escaping () -> Void, @ViewBuilder content: () -> Content) {
 | 
			
		||||
        self.content = content()
 | 
			
		||||
        self.onRefresh = onRefresh
 | 
			
		||||
        self.isRefreshing = isRefreshing
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func makeUIView(context: Context) -> UIScrollView {
 | 
			
		||||
        let scrollView = UIScrollView()
 | 
			
		||||
        
 | 
			
		||||
        let refreshControl = UIRefreshControl()
 | 
			
		||||
        refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged)
 | 
			
		||||
        scrollView.refreshControl = refreshControl
 | 
			
		||||
 | 
			
		||||
        let hostingController = UIHostingController(rootView: content)
 | 
			
		||||
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
 | 
			
		||||
        scrollView.addSubview(hostingController.view)
 | 
			
		||||
 | 
			
		||||
        NSLayoutConstraint.activate([
 | 
			
		||||
            hostingController.view.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
 | 
			
		||||
            hostingController.view.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
 | 
			
		||||
            hostingController.view.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
 | 
			
		||||
            hostingController.view.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
 | 
			
		||||
            hostingController.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
 | 
			
		||||
        ])
 | 
			
		||||
        
 | 
			
		||||
        context.coordinator.hostingController = hostingController
 | 
			
		||||
        
 | 
			
		||||
        return scrollView
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func updateUIView(_ uiView: UIScrollView, context: Context) {
 | 
			
		||||
        if isRefreshing.wrappedValue {
 | 
			
		||||
            uiView.refreshControl?.beginRefreshing()
 | 
			
		||||
        } else {
 | 
			
		||||
            // Отложенное завершение, чтобы избежать цикла обновлений
 | 
			
		||||
            DispatchQueue.main.async {
 | 
			
		||||
                uiView.refreshControl?.endRefreshing()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        context.coordinator.hostingController?.rootView = content
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func makeCoordinator() -> Coordinator {
 | 
			
		||||
        Coordinator(self)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    class Coordinator: NSObject {
 | 
			
		||||
        var parent: RefreshableScrollView
 | 
			
		||||
        var hostingController: UIHostingController<Content>?
 | 
			
		||||
 | 
			
		||||
        init(_ parent: RefreshableScrollView) {
 | 
			
		||||
            self.parent = parent
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        @objc func handleRefresh() {
 | 
			
		||||
            parent.onRefresh()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
//
 | 
			
		||||
//  User.swift
 | 
			
		||||
//  volnahub (iOS)
 | 
			
		||||
//
 | 
			
		||||
//  Created by cheykrym on 09/06/2025.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import Foundation
 | 
			
		||||
 | 
			
		||||
struct User: Identifiable, Decodable {
 | 
			
		||||
    let id: String
 | 
			
		||||
    let username: String
 | 
			
		||||
    let email: String
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										41
									
								
								Shared/ViewModels/SearchViewModel.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								Shared/ViewModels/SearchViewModel.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
import Combine
 | 
			
		||||
 | 
			
		||||
class SearchViewModel: ObservableObject {
 | 
			
		||||
    @Published var searchText = ""
 | 
			
		||||
    @Published var users = [User]()
 | 
			
		||||
    
 | 
			
		||||
    private var cancellables = Set<AnyCancellable>()
 | 
			
		||||
    
 | 
			
		||||
    init() {
 | 
			
		||||
        $searchText
 | 
			
		||||
            .debounce(for: .milliseconds(500), scheduler: RunLoop.main)
 | 
			
		||||
            .removeDuplicates()
 | 
			
		||||
            .flatMap { query -> AnyPublisher<[User], Error> in
 | 
			
		||||
                if query.isEmpty {
 | 
			
		||||
                    return Just([])
 | 
			
		||||
                        .setFailureType(to: Error.self)
 | 
			
		||||
                        .eraseToAnyPublisher()
 | 
			
		||||
                } else {
 | 
			
		||||
                    return self.searchUsers(query: query)
 | 
			
		||||
                        .eraseToAnyPublisher()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .catch { _ in Just([]) } // При ошибке возвращаем пустой массив
 | 
			
		||||
            .receive(on: RunLoop.main)
 | 
			
		||||
            .assign(to: \.users, on: self)
 | 
			
		||||
            .store(in: &cancellables)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func searchUsers(query: String) -> Future<[User], Error> {
 | 
			
		||||
        Future { promise in
 | 
			
		||||
            // Имитация сетевого запроса
 | 
			
		||||
            let mockUsers = [
 | 
			
		||||
                User(id: "1", username: "testuser1", email: "test1@test.com"),
 | 
			
		||||
                User(id: "2", username: "testuser2", email: "test2@test.com"),
 | 
			
		||||
                User(id: "3", username: query, email: "test3@test.com")
 | 
			
		||||
            ]
 | 
			
		||||
            promise(.success(mockUsers))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -3,6 +3,7 @@ import SwiftUI
 | 
			
		||||
struct HomeTab: View {
 | 
			
		||||
    @State private var posts: [Post] = []
 | 
			
		||||
    @State private var isLoading = true
 | 
			
		||||
    @State private var isRefreshing = false
 | 
			
		||||
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
@ -10,7 +11,9 @@ struct HomeTab: View {
 | 
			
		||||
                if isLoading {
 | 
			
		||||
                    ProgressView("Загрузка ленты...")
 | 
			
		||||
                } else {
 | 
			
		||||
                    ScrollView {
 | 
			
		||||
                    RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
 | 
			
		||||
                        fetchData()
 | 
			
		||||
                    }) {
 | 
			
		||||
                        LazyVStack(spacing: 24) {
 | 
			
		||||
                            ForEach(posts) { post in
 | 
			
		||||
                                PostDetailView(post: post)
 | 
			
		||||
@ -22,12 +25,26 @@ struct HomeTab: View {
 | 
			
		||||
            .navigationTitle("Лента")
 | 
			
		||||
            .onAppear {
 | 
			
		||||
                if posts.isEmpty {
 | 
			
		||||
                    fetchData(isInitialLoad: true)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .navigationViewStyle(StackNavigationViewStyle())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func fetchData(isInitialLoad: Bool = false) {
 | 
			
		||||
        if isInitialLoad {
 | 
			
		||||
            isLoading = true
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        PostService.shared.fetchAllPosts { fetchedPosts in
 | 
			
		||||
            self.posts = fetchedPosts
 | 
			
		||||
            
 | 
			
		||||
            if isInitialLoad {
 | 
			
		||||
                print("content updated")
 | 
			
		||||
                self.isLoading = false
 | 
			
		||||
            }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            self.isRefreshing = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -8,6 +8,7 @@ struct ProfileContentGrid: View {
 | 
			
		||||
    let selectedCategory: String
 | 
			
		||||
    let allPosts: [Post]
 | 
			
		||||
    let isLoading: Bool
 | 
			
		||||
    let onPostTapped: (Post, [Post]) -> Void
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        VStack(alignment: .leading, spacing: 0) {
 | 
			
		||||
@ -28,7 +29,7 @@ struct ProfileContentGrid: View {
 | 
			
		||||
            } else {
 | 
			
		||||
                LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 3), spacing: 2) {
 | 
			
		||||
                    ForEach(filteredPosts) { post in
 | 
			
		||||
                        NavigationLink(destination: PostFeedView(posts: filteredPosts, selectedPostID: post.id)) {
 | 
			
		||||
                        Button(action: { onPostTapped(post, filteredPosts) }) {
 | 
			
		||||
                            Rectangle()
 | 
			
		||||
                                .fill(Color.gray.opacity(0.2))
 | 
			
		||||
                                .aspectRatio(1, contentMode: .fit)
 | 
			
		||||
 | 
			
		||||
@ -2,12 +2,13 @@ import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct ProfileContentTabbedGrid: View {
 | 
			
		||||
    let isContentLoaded: Bool
 | 
			
		||||
    @Binding var allPosts: [Post]
 | 
			
		||||
    @Binding var isLoading: Bool
 | 
			
		||||
    let onPostTapped: (Post, [Post]) -> Void
 | 
			
		||||
    @State private var selectedTabIndex = 0
 | 
			
		||||
    @State private var selectedCategory = "#все"
 | 
			
		||||
    @State private var searchQuery = ""
 | 
			
		||||
    @State private var selectedSort = "По дате"
 | 
			
		||||
    @State private var allPosts: [Post] = []
 | 
			
		||||
    @State private var isLoading = true
 | 
			
		||||
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        VStack(spacing: 0) {
 | 
			
		||||
@ -70,18 +71,10 @@ struct ProfileContentTabbedGrid: View {
 | 
			
		||||
                searchQuery: searchQuery,
 | 
			
		||||
                selectedCategory: selectedCategory,
 | 
			
		||||
                allPosts: allPosts,
 | 
			
		||||
                isLoading: isLoading
 | 
			
		||||
                isLoading: isLoading,
 | 
			
		||||
                onPostTapped: onPostTapped
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
        .onAppear {
 | 
			
		||||
            if allPosts.isEmpty {
 | 
			
		||||
                isLoading = true
 | 
			
		||||
                PostService.shared.fetchAllPosts { result in
 | 
			
		||||
                    self.allPosts = result
 | 
			
		||||
                    self.isLoading = false
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Вкладка с меню
 | 
			
		||||
 | 
			
		||||
@ -2,13 +2,6 @@ import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct ProfileTab: View {
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
//    @State private var selectedTabIndex = 0
 | 
			
		||||
//    @State private var selectedSort = "По дате"
 | 
			
		||||
//    @State private var selectedCategory = "#все"
 | 
			
		||||
//    @State private var searchQuery = ""
 | 
			
		||||
//    @State private var searchQueryArchive = ""
 | 
			
		||||
//    @State private var searchQuerySaved = ""
 | 
			
		||||
//    @State private var searchQueryLiked = ""
 | 
			
		||||
    @State private var isContentLoaded = true
 | 
			
		||||
 | 
			
		||||
    @State private var accounts = ["@user1", "@user2", "@user3"]
 | 
			
		||||
@ -20,43 +13,57 @@ struct ProfileTab: View {
 | 
			
		||||
    @State private var sheetType: SheetType? = nil
 | 
			
		||||
    enum SheetType: Identifiable {
 | 
			
		||||
        case accountShare
 | 
			
		||||
        var id: Int { self.hashValue }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        var id: Int {
 | 
			
		||||
            switch self {
 | 
			
		||||
            case .accountShare: return 1
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    @State private var allPosts: [Post] = []
 | 
			
		||||
    @State private var isLoading = true
 | 
			
		||||
    @State private var isRefreshing = false
 | 
			
		||||
 | 
			
		||||
    @State private var selectedPostData: (Post, [Post])?
 | 
			
		||||
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            if !isContentLoaded {
 | 
			
		||||
                SplashScreenView()
 | 
			
		||||
            } else {
 | 
			
		||||
            GeometryReader { geometry in
 | 
			
		||||
                VStack(spacing: 0) {
 | 
			
		||||
                    ScrollView {
 | 
			
		||||
                        // ───── Шапка профиля (занимает ~50% экрана) ─────
 | 
			
		||||
                    // Скрытый NavigationLink для программного перехода
 | 
			
		||||
                    if let (post, posts) = selectedPostData {
 | 
			
		||||
                        NavigationLink(
 | 
			
		||||
                            destination: PostFeedView(posts: posts, selectedPostID: post.id),
 | 
			
		||||
                            isActive: Binding(
 | 
			
		||||
                                get: { selectedPostData != nil },
 | 
			
		||||
                                set: { if !$0 { selectedPostData = nil } }
 | 
			
		||||
                            ),
 | 
			
		||||
                            label: { EmptyView() }
 | 
			
		||||
                        )
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
 | 
			
		||||
                        fetchData()
 | 
			
		||||
                    }) {
 | 
			
		||||
                        VStack(spacing: 0) {
 | 
			
		||||
                            header
 | 
			
		||||
                            .frame(minHeight: geometry.size.height * 0.5)
 | 
			
		||||
                                .frame(minHeight: 300)
 | 
			
		||||
                                .frame(maxWidth: .infinity)
 | 
			
		||||
                                .background(Color(.systemBackground))
 | 
			
		||||
                            
 | 
			
		||||
                        // ───── Скролл с контентом ─────
 | 
			
		||||
                    
 | 
			
		||||
                        ProfileContentTabbedGrid(isContentLoaded: isContentLoaded)
 | 
			
		||||
                        
 | 
			
		||||
                            ProfileContentTabbedGrid(
 | 
			
		||||
                                isContentLoaded: isContentLoaded,
 | 
			
		||||
                                allPosts: $allPosts,
 | 
			
		||||
                                isLoading: $isLoading,
 | 
			
		||||
                                onPostTapped: { post, posts in
 | 
			
		||||
                                    self.selectedPostData = (post, posts)
 | 
			
		||||
                                }
 | 
			
		||||
                            )
 | 
			
		||||
                        }
 | 
			
		||||
                    .frame(maxWidth: .infinity)
 | 
			
		||||
                    }
 | 
			
		||||
                .frame(maxWidth: .infinity, maxHeight: .infinity)
 | 
			
		||||
                }
 | 
			
		||||
                .navigationBarTitleDisplayMode(.inline)
 | 
			
		||||
                .toolbar {
 | 
			
		||||
                    ToolbarItem(placement: .principal) {
 | 
			
		||||
                    Button(action: {
 | 
			
		||||
                        sheetType = .accountShare
 | 
			
		||||
                    }) {
 | 
			
		||||
                        Button(action: { sheetType = .accountShare }) {
 | 
			
		||||
                            HStack(spacing: 4) {
 | 
			
		||||
                                Text("custom_user_name")
 | 
			
		||||
                                    .font(.headline)
 | 
			
		||||
@ -67,7 +74,6 @@ struct ProfileTab: View {
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    ToolbarItem(placement: .navigationBarTrailing) {
 | 
			
		||||
                        NavigationLink(destination: SettingsView(viewModel: viewModel)) {
 | 
			
		||||
                            Image(systemName: "wrench")
 | 
			
		||||
@ -91,13 +97,28 @@ struct ProfileTab: View {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .navigationViewStyle(StackNavigationViewStyle())
 | 
			
		||||
//        .onAppear {
 | 
			
		||||
//            if !isContentLoaded {
 | 
			
		||||
//                DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
 | 
			
		||||
//                    isContentLoaded = true
 | 
			
		||||
//                }
 | 
			
		||||
//            }
 | 
			
		||||
//        }
 | 
			
		||||
        .onAppear {
 | 
			
		||||
            if allPosts.isEmpty {
 | 
			
		||||
                fetchData(isInitialLoad: true)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func fetchData(isInitialLoad: Bool = false) {
 | 
			
		||||
        if isInitialLoad {
 | 
			
		||||
            isLoading = true
 | 
			
		||||
        } else {
 | 
			
		||||
            isRefreshing = true
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        PostService.shared.fetchAllPosts { fetchedPosts in
 | 
			
		||||
            self.allPosts = fetchedPosts
 | 
			
		||||
            
 | 
			
		||||
            if isInitialLoad {
 | 
			
		||||
                self.isLoading = false
 | 
			
		||||
            }
 | 
			
		||||
            self.isRefreshing = false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Шапка профиля
 | 
			
		||||
 | 
			
		||||
@ -1,16 +1,68 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct SearchTab: View {
 | 
			
		||||
    @StateObject private var viewModel = SearchViewModel()
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            VStack {
 | 
			
		||||
                Text("Поиск")
 | 
			
		||||
                    .font(.largeTitle)
 | 
			
		||||
                    .bold()
 | 
			
		||||
                    .padding()
 | 
			
		||||
                Spacer()
 | 
			
		||||
                SearchBar(text: $viewModel.searchText)
 | 
			
		||||
                    .padding(.top, 8)
 | 
			
		||||
                
 | 
			
		||||
                List(viewModel.users) { user in
 | 
			
		||||
                    NavigationLink(destination: ProfileTab(viewModel: LoginViewModel())) { // Placeholder destination
 | 
			
		||||
                        HStack {
 | 
			
		||||
                            Image(systemName: "person.crop.circle")
 | 
			
		||||
                                .resizable()
 | 
			
		||||
                                .frame(width: 40, height: 40)
 | 
			
		||||
                                .clipShape(Circle())
 | 
			
		||||
                            Text(user.username)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                .listStyle(PlainListStyle())
 | 
			
		||||
            }
 | 
			
		||||
            .navigationTitle("Поиск")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SearchBar: View {
 | 
			
		||||
    @Binding var text: String
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        HStack {
 | 
			
		||||
            TextField("Поиск...", text: $text)
 | 
			
		||||
                .padding(8)
 | 
			
		||||
                .padding(.horizontal, 25)
 | 
			
		||||
                .background(Color(.systemGray6))
 | 
			
		||||
                .cornerRadius(8)
 | 
			
		||||
                .overlay(
 | 
			
		||||
                    HStack {
 | 
			
		||||
                        Image(systemName: "magnifyingglass")
 | 
			
		||||
                            .foregroundColor(.gray)
 | 
			
		||||
                            .frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
 | 
			
		||||
                            .padding(.leading, 8)
 | 
			
		||||
                        
 | 
			
		||||
                        if !text.isEmpty {
 | 
			
		||||
                            Button(action: {
 | 
			
		||||
                                self.text = ""
 | 
			
		||||
                            }) {
 | 
			
		||||
                                Image(systemName: "multiply.circle.fill")
 | 
			
		||||
                                    .foregroundColor(.gray)
 | 
			
		||||
                                    .padding(.trailing, 8)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                )
 | 
			
		||||
        }
 | 
			
		||||
        .padding(.horizontal, 10)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SearchTab_Previews: PreviewProvider {
 | 
			
		||||
    static var previews: some View {
 | 
			
		||||
        SearchTab()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,6 +9,7 @@
 | 
			
		||||
/* Begin PBXBuildFile section */
 | 
			
		||||
		1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */; };
 | 
			
		||||
		1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276102DF9247000D8BC53 /* CustomTextField.swift */; };
 | 
			
		||||
		1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2302102E3050C60067BF4F /* SearchViewModel.swift */; };
 | 
			
		||||
		1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* yobbleApp.swift */; };
 | 
			
		||||
		1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
 | 
			
		||||
		1A7940902DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
 | 
			
		||||
@ -38,6 +39,7 @@
 | 
			
		||||
		1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; };
 | 
			
		||||
		1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.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 */; };
 | 
			
		||||
		1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; };
 | 
			
		||||
		1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; };
 | 
			
		||||
@ -48,6 +50,7 @@
 | 
			
		||||
/* Begin PBXFileReference section */
 | 
			
		||||
		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>"; };
 | 
			
		||||
		1A2302102E3050C60067BF4F /* SearchViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SearchViewModel.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>"; };
 | 
			
		||||
		1A79407C2DF77BC3002569DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 | 
			
		||||
@ -81,6 +84,7 @@
 | 
			
		||||
		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>"; };
 | 
			
		||||
		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>"; };
 | 
			
		||||
		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>"; };
 | 
			
		||||
@ -119,6 +123,7 @@
 | 
			
		||||
		1A7940792DF77BC2002569DA /* Shared */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */,
 | 
			
		||||
				1A7940FA2DF7B898002569DA /* Resources */,
 | 
			
		||||
				1A7940E52DF7B341002569DA /* Services */,
 | 
			
		||||
				1A7940A02DF77DCD002569DA /* Network */,
 | 
			
		||||
@ -174,6 +179,7 @@
 | 
			
		||||
		1A79409E2DF77DBD002569DA /* ViewModels */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1A2302102E3050C60067BF4F /* SearchViewModel.swift */,
 | 
			
		||||
				1A7940A92DF77E05002569DA /* LoginViewModel.swift */,
 | 
			
		||||
			);
 | 
			
		||||
			path = ViewModels;
 | 
			
		||||
@ -384,6 +390,7 @@
 | 
			
		||||
				1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */,
 | 
			
		||||
				1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */,
 | 
			
		||||
				1A7940DE2DF7B0D7002569DA /* config.swift in Sources */,
 | 
			
		||||
				1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */,
 | 
			
		||||
				1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */,
 | 
			
		||||
				1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
 | 
			
		||||
				1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
 | 
			
		||||
@ -402,6 +409,7 @@
 | 
			
		||||
				1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */,
 | 
			
		||||
				1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */,
 | 
			
		||||
				1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */,
 | 
			
		||||
				1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user