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
|
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 {
|
struct HomeTab: View {
|
||||||
@State private var posts: [Post] = []
|
@State private var posts: [Post] = []
|
||||||
@State private var isLoading = true
|
@State private var isLoading = true
|
||||||
|
@State private var isRefreshing = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
@ -10,7 +11,9 @@ struct HomeTab: View {
|
|||||||
if isLoading {
|
if isLoading {
|
||||||
ProgressView("Загрузка ленты...")
|
ProgressView("Загрузка ленты...")
|
||||||
} else {
|
} else {
|
||||||
ScrollView {
|
RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
|
||||||
|
fetchData()
|
||||||
|
}) {
|
||||||
LazyVStack(spacing: 24) {
|
LazyVStack(spacing: 24) {
|
||||||
ForEach(posts) { post in
|
ForEach(posts) { post in
|
||||||
PostDetailView(post: post)
|
PostDetailView(post: post)
|
||||||
@ -22,12 +25,26 @@ struct HomeTab: View {
|
|||||||
.navigationTitle("Лента")
|
.navigationTitle("Лента")
|
||||||
.onAppear {
|
.onAppear {
|
||||||
if posts.isEmpty {
|
if posts.isEmpty {
|
||||||
PostService.shared.fetchAllPosts { fetchedPosts in
|
fetchData(isInitialLoad: true)
|
||||||
self.posts = fetchedPosts
|
|
||||||
self.isLoading = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.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 selectedCategory: String
|
||||||
let allPosts: [Post]
|
let allPosts: [Post]
|
||||||
let isLoading: Bool
|
let isLoading: Bool
|
||||||
|
let onPostTapped: (Post, [Post]) -> Void
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(alignment: .leading, spacing: 0) {
|
VStack(alignment: .leading, spacing: 0) {
|
||||||
@ -28,7 +29,7 @@ struct ProfileContentGrid: View {
|
|||||||
} else {
|
} else {
|
||||||
LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 3), spacing: 2) {
|
LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 3), spacing: 2) {
|
||||||
ForEach(filteredPosts) { post in
|
ForEach(filteredPosts) { post in
|
||||||
NavigationLink(destination: PostFeedView(posts: filteredPosts, selectedPostID: post.id)) {
|
Button(action: { onPostTapped(post, filteredPosts) }) {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(Color.gray.opacity(0.2))
|
.fill(Color.gray.opacity(0.2))
|
||||||
.aspectRatio(1, contentMode: .fit)
|
.aspectRatio(1, contentMode: .fit)
|
||||||
|
|||||||
@ -2,12 +2,13 @@ import SwiftUI
|
|||||||
|
|
||||||
struct ProfileContentTabbedGrid: View {
|
struct ProfileContentTabbedGrid: View {
|
||||||
let isContentLoaded: Bool
|
let isContentLoaded: Bool
|
||||||
|
@Binding var allPosts: [Post]
|
||||||
|
@Binding var isLoading: Bool
|
||||||
|
let onPostTapped: (Post, [Post]) -> Void
|
||||||
@State private var selectedTabIndex = 0
|
@State private var selectedTabIndex = 0
|
||||||
@State private var selectedCategory = "#все"
|
@State private var selectedCategory = "#все"
|
||||||
@State private var searchQuery = ""
|
@State private var searchQuery = ""
|
||||||
@State private var selectedSort = "По дате"
|
@State private var selectedSort = "По дате"
|
||||||
@State private var allPosts: [Post] = []
|
|
||||||
@State private var isLoading = true
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack(spacing: 0) {
|
VStack(spacing: 0) {
|
||||||
@ -70,18 +71,10 @@ struct ProfileContentTabbedGrid: View {
|
|||||||
searchQuery: searchQuery,
|
searchQuery: searchQuery,
|
||||||
selectedCategory: selectedCategory,
|
selectedCategory: selectedCategory,
|
||||||
allPosts: allPosts,
|
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: - Вкладка с меню
|
// MARK: - Вкладка с меню
|
||||||
|
|||||||
@ -2,13 +2,6 @@ import SwiftUI
|
|||||||
|
|
||||||
struct ProfileTab: View {
|
struct ProfileTab: View {
|
||||||
@ObservedObject var viewModel: LoginViewModel
|
@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 isContentLoaded = true
|
||||||
|
|
||||||
@State private var accounts = ["@user1", "@user2", "@user3"]
|
@State private var accounts = ["@user1", "@user2", "@user3"]
|
||||||
@ -20,84 +13,112 @@ struct ProfileTab: View {
|
|||||||
@State private var sheetType: SheetType? = nil
|
@State private var sheetType: SheetType? = nil
|
||||||
enum SheetType: Identifiable {
|
enum SheetType: Identifiable {
|
||||||
case accountShare
|
case accountShare
|
||||||
|
var id: Int { self.hashValue }
|
||||||
|
}
|
||||||
|
|
||||||
var id: Int {
|
@State private var allPosts: [Post] = []
|
||||||
switch self {
|
@State private var isLoading = true
|
||||||
case .accountShare: return 1
|
@State private var isRefreshing = false
|
||||||
|
|
||||||
|
@State private var selectedPostData: (Post, [Post])?
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
NavigationView {
|
||||||
|
if !isContentLoaded {
|
||||||
|
SplashScreenView()
|
||||||
|
} else {
|
||||||
|
VStack(spacing: 0) {
|
||||||
|
// Скрытый 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: 300)
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.background(Color(.systemBackground))
|
||||||
|
|
||||||
|
ProfileContentTabbedGrid(
|
||||||
|
isContentLoaded: isContentLoaded,
|
||||||
|
allPosts: $allPosts,
|
||||||
|
isLoading: $isLoading,
|
||||||
|
onPostTapped: { post, posts in
|
||||||
|
self.selectedPostData = (post, posts)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .principal) {
|
||||||
|
Button(action: { sheetType = .accountShare }) {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Text("custom_user_name")
|
||||||
|
.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 {
|
||||||
|
if allPosts.isEmpty {
|
||||||
|
fetchData(isInitialLoad: true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var body: some View {
|
private func fetchData(isInitialLoad: Bool = false) {
|
||||||
NavigationView {
|
if isInitialLoad {
|
||||||
if !isContentLoaded{
|
isLoading = true
|
||||||
SplashScreenView()
|
} else {
|
||||||
} else {
|
isRefreshing = true
|
||||||
GeometryReader { geometry in
|
|
||||||
VStack(spacing: 0) {
|
|
||||||
ScrollView {
|
|
||||||
// ───── Шапка профиля (занимает ~50% экрана) ─────
|
|
||||||
header
|
|
||||||
.frame(minHeight: geometry.size.height * 0.5)
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
.background(Color(.systemBackground))
|
|
||||||
|
|
||||||
// ───── Скролл с контентом ─────
|
|
||||||
|
|
||||||
ProfileContentTabbedGrid(isContentLoaded: isContentLoaded)
|
|
||||||
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity)
|
|
||||||
}
|
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
||||||
}
|
|
||||||
.navigationBarTitleDisplayMode(.inline)
|
|
||||||
.toolbar {
|
|
||||||
ToolbarItem(placement: .principal) {
|
|
||||||
Button(action: {
|
|
||||||
sheetType = .accountShare
|
|
||||||
}) {
|
|
||||||
HStack(spacing: 4) {
|
|
||||||
Text("custom_user_name")
|
|
||||||
.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
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PostService.shared.fetchAllPosts { fetchedPosts in
|
||||||
|
self.allPosts = fetchedPosts
|
||||||
|
|
||||||
|
if isInitialLoad {
|
||||||
|
self.isLoading = false
|
||||||
|
}
|
||||||
|
self.isRefreshing = false
|
||||||
}
|
}
|
||||||
.navigationViewStyle(StackNavigationViewStyle())
|
|
||||||
// .onAppear {
|
|
||||||
// if !isContentLoaded {
|
|
||||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
|
||||||
// isContentLoaded = true
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Шапка профиля
|
// MARK: - Шапка профиля
|
||||||
|
|||||||
@ -1,16 +1,68 @@
|
|||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
struct SearchTab: View {
|
struct SearchTab: View {
|
||||||
|
@StateObject private var viewModel = SearchViewModel()
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
NavigationView {
|
NavigationView {
|
||||||
VStack {
|
VStack {
|
||||||
Text("Поиск")
|
SearchBar(text: $viewModel.searchText)
|
||||||
.font(.largeTitle)
|
.padding(.top, 8)
|
||||||
.bold()
|
|
||||||
.padding()
|
List(viewModel.users) { user in
|
||||||
Spacer()
|
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("Поиск")
|
.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 */
|
/* Begin PBXBuildFile section */
|
||||||
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 */; };
|
||||||
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 */; };
|
||||||
@ -38,6 +39,7 @@
|
|||||||
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 */; };
|
||||||
@ -48,6 +50,7 @@
|
|||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
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>"; };
|
||||||
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>"; };
|
||||||
@ -81,6 +84,7 @@
|
|||||||
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>"; };
|
||||||
@ -119,6 +123,7 @@
|
|||||||
1A7940792DF77BC2002569DA /* Shared */ = {
|
1A7940792DF77BC2002569DA /* Shared */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */,
|
||||||
1A7940FA2DF7B898002569DA /* Resources */,
|
1A7940FA2DF7B898002569DA /* Resources */,
|
||||||
1A7940E52DF7B341002569DA /* Services */,
|
1A7940E52DF7B341002569DA /* Services */,
|
||||||
1A7940A02DF77DCD002569DA /* Network */,
|
1A7940A02DF77DCD002569DA /* Network */,
|
||||||
@ -174,6 +179,7 @@
|
|||||||
1A79409E2DF77DBD002569DA /* ViewModels */ = {
|
1A79409E2DF77DBD002569DA /* ViewModels */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
1A2302102E3050C60067BF4F /* SearchViewModel.swift */,
|
||||||
1A7940A92DF77E05002569DA /* LoginViewModel.swift */,
|
1A7940A92DF77E05002569DA /* LoginViewModel.swift */,
|
||||||
);
|
);
|
||||||
path = ViewModels;
|
path = ViewModels;
|
||||||
@ -384,6 +390,7 @@
|
|||||||
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 */,
|
||||||
|
1A2302112E3050C60067BF4F /* SearchViewModel.swift in Sources */,
|
||||||
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */,
|
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */,
|
||||||
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
|
1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
|
||||||
1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
|
1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
|
||||||
@ -402,6 +409,7 @@
|
|||||||
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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user