Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5eeff5d24d |
@ -4,20 +4,17 @@ 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, onScroll: ((CGPoint) -> Void)? = nil, @ViewBuilder content: () -> Content) {
|
init(isRefreshing: Binding<Bool>, onRefresh: @escaping () -> Void, @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)
|
||||||
@ -44,6 +41,7 @@ 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()
|
||||||
}
|
}
|
||||||
@ -56,7 +54,7 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
|
|||||||
Coordinator(self)
|
Coordinator(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Coordinator: NSObject, UIScrollViewDelegate {
|
class Coordinator: NSObject {
|
||||||
var parent: RefreshableScrollView
|
var parent: RefreshableScrollView
|
||||||
var hostingController: UIHostingController<Content>?
|
var hostingController: UIHostingController<Content>?
|
||||||
|
|
||||||
@ -67,9 +65,5 @@ struct RefreshableScrollView<Content: View>: UIViewRepresentable {
|
|||||||
@objc func handleRefresh() {
|
@objc func handleRefresh() {
|
||||||
parent.onRefresh()
|
parent.onRefresh()
|
||||||
}
|
}
|
||||||
|
|
||||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
|
||||||
parent.onScroll?(scrollView.contentOffset)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,104 +0,0 @@
|
|||||||
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@*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"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.
|
Before Width: | Height: | Size: 3.0 KiB |
@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"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.
|
Before Width: | Height: | Size: 173 KiB |
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"data" : [
|
|
||||||
{
|
|
||||||
"filename" : "placeholderVideo.mp4",
|
|
||||||
"idiom" : "universal"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"info" : {
|
|
||||||
"author" : "xcode",
|
|
||||||
"version" : 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 173 KiB |
Binary file not shown.
@ -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: UUID // Автор
|
let authorID: String // Автор
|
||||||
let authorUsername: String // Имя пользователя автора
|
let authorUsername: String // Имя пользователя автора
|
||||||
let hashtags: [String]? // Хэштеги
|
let hashtags: [String]? // Хэштеги
|
||||||
let location: String? // Гео
|
let location: String? // Гео
|
||||||
@ -30,7 +30,6 @@ struct Post: Identifiable, Codable {
|
|||||||
|
|
||||||
enum MediaType: String, Codable {
|
enum MediaType: String, Codable {
|
||||||
case photo
|
case photo
|
||||||
case live
|
|
||||||
case video
|
case video
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -96,13 +96,10 @@ 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 = UUID()
|
let authorId = "user_\(Int.random(in: 1...5))"
|
||||||
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],
|
||||||
@ -122,7 +119,7 @@ class PostService {
|
|||||||
isLikedByCurrentUser: Bool.random(),
|
isLikedByCurrentUser: Bool.random(),
|
||||||
isSavedByCurrentUser: Bool.random(),
|
isSavedByCurrentUser: Bool.random(),
|
||||||
authorID: authorId,
|
authorID: authorId,
|
||||||
authorUsername: authorUserName,
|
authorUsername: "username_\(authorId.split(separator: "_").last ?? "")",
|
||||||
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"],
|
||||||
|
|||||||
@ -1,53 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,32 +0,0 @@
|
|||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,12 +9,16 @@ import SwiftUI
|
|||||||
|
|
||||||
struct ChatsTab: View {
|
struct ChatsTab: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
|
NavigationView {
|
||||||
VStack {
|
VStack {
|
||||||
Text("Здесь будут чаты")
|
Text("Чаты")
|
||||||
.font(.title)
|
.font(.largeTitle)
|
||||||
.foregroundColor(.gray)
|
.bold()
|
||||||
|
.padding()
|
||||||
|
|
||||||
Spacer()
|
Spacer()
|
||||||
}
|
}
|
||||||
|
.navigationTitle("Чаты")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,84 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -5,18 +5,15 @@ 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(
|
RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
|
||||||
isRefreshing: $isRefreshing,
|
fetchData()
|
||||||
onRefresh: { fetchData() },
|
}) {
|
||||||
onScroll: onScroll
|
|
||||||
) {
|
|
||||||
LazyVStack(spacing: 24) {
|
LazyVStack(spacing: 24) {
|
||||||
ForEach(posts) { post in
|
ForEach(posts) { post in
|
||||||
PostDetailView(post: post)
|
PostDetailView(post: post)
|
||||||
@ -25,12 +22,18 @@ 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 {
|
||||||
|
|||||||
@ -1,137 +1,53 @@
|
|||||||
|
//
|
||||||
|
// 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 {
|
||||||
NavigationView {
|
TabView(selection: $selectedTab) {
|
||||||
ZStack(alignment: .leading) { // Выравниваем ZStack по левому краю
|
HomeTab()
|
||||||
// Основной контент
|
.tabItem {
|
||||||
VStack(spacing: 0) {
|
Image(systemName: "list.bullet.rectangle")
|
||||||
TopBarView(
|
Text("Лента")
|
||||||
title: tabTitle,
|
}
|
||||||
selectedAccount: $selectedAccount,
|
.tag(0)
|
||||||
sheetType: $sheetType,
|
|
||||||
accounts: accounts,
|
|
||||||
viewModel: viewModel,
|
|
||||||
isSideMenuPresented: $isSideMenuPresented
|
|
||||||
)
|
|
||||||
|
|
||||||
ZStack {
|
|
||||||
NewHomeTab(viewModel: newHomeTabViewModel)
|
|
||||||
.opacity(selectedTab == 0 ? 1 : 0)
|
|
||||||
|
|
||||||
SearchTab()
|
SearchTab()
|
||||||
.opacity(selectedTab == 1 ? 1 : 0)
|
.tabItem {
|
||||||
|
Image(systemName: "magnifyingglass")
|
||||||
|
Text("Поиск")
|
||||||
|
}
|
||||||
|
.tag(1)
|
||||||
|
|
||||||
|
// PublicsTab()
|
||||||
|
// .tabItem {
|
||||||
|
// Image(systemName: "")
|
||||||
|
// Text("Свайп")
|
||||||
|
// }
|
||||||
|
// .tag(1)
|
||||||
|
|
||||||
ChatsTab()
|
ChatsTab()
|
||||||
.opacity(selectedTab == 2 ? 1 : 0)
|
.tabItem {
|
||||||
|
Image(systemName: "bubble.left.and.bubble.right.fill")
|
||||||
|
Text("Чаты")
|
||||||
|
}
|
||||||
|
.tag(2)
|
||||||
|
|
||||||
ProfileTab(viewModel: viewModel, sheetType: $sheetType, selectedAccount: $selectedAccount, accounts: $accounts, onScroll: { _ in })
|
ProfileTab(viewModel: viewModel)
|
||||||
.opacity(selectedTab == 3 ? 1 : 0)
|
.tabItem {
|
||||||
}
|
Image(systemName: "person.crop.square")
|
||||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
Text("Лицо")
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,114 +0,0 @@
|
|||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -43,6 +43,7 @@ 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)
|
||||||
|
|||||||
@ -4,16 +4,13 @@ struct ProfileTab: View {
|
|||||||
@ObservedObject var viewModel: LoginViewModel
|
@ObservedObject var viewModel: LoginViewModel
|
||||||
@State private var isContentLoaded = true
|
@State private var isContentLoaded = true
|
||||||
|
|
||||||
// Привязки к состояниям в MainView
|
@State private var accounts = ["@user1", "@user2", "@user3"]
|
||||||
@Binding var sheetType: SheetType?
|
@State private var selectedAccount = "@user1"
|
||||||
@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 }
|
||||||
@ -29,7 +26,7 @@ struct ProfileTab: View {
|
|||||||
@State private var isShowingFollowing = false
|
@State private var isShowingFollowing = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VStack {
|
NavigationView {
|
||||||
if !isContentLoaded {
|
if !isContentLoaded {
|
||||||
SplashScreenView()
|
SplashScreenView()
|
||||||
} else {
|
} else {
|
||||||
@ -49,13 +46,12 @@ struct ProfileTab: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RefreshableScrollView(
|
RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: {
|
||||||
isRefreshing: $isRefreshing,
|
fetchData()
|
||||||
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))
|
||||||
|
|
||||||
@ -70,8 +66,52 @@ struct ProfileTab: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .principal) {
|
||||||
|
Button(action: { sheetType = .accountShare }) {
|
||||||
|
HStack(spacing: 4) {
|
||||||
|
Text(selectedAccount)
|
||||||
|
.font(.headline)
|
||||||
|
.foregroundColor(.primary)
|
||||||
|
Image(systemName: "chevron.down")
|
||||||
|
.font(.subheadline)
|
||||||
|
.foregroundColor(.gray)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
ToolbarItem(placement: .navigationBarLeading) {
|
||||||
|
Button(action: {
|
||||||
|
// TODO: Действие для создания поста
|
||||||
|
}) {
|
||||||
|
Image(systemName: "plus")
|
||||||
|
.imageScale(.large)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|||||||
@ -4,17 +4,13 @@ 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(
|
NavigationLink(destination: ProfileTab(viewModel: LoginViewModel())) { // Placeholder destination
|
||||||
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()
|
||||||
@ -26,6 +22,8 @@ struct SearchTab: View {
|
|||||||
}
|
}
|
||||||
.listStyle(PlainListStyle())
|
.listStyle(PlainListStyle())
|
||||||
}
|
}
|
||||||
|
.navigationTitle("Поиск")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,259 +0,0 @@
|
|||||||
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())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -7,24 +7,31 @@
|
|||||||
|
|
||||||
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 {
|
||||||
@StateObject private var themeManager = ThemeManager()
|
@AppStorage("isDarkMode") private var isDarkMode: Bool = true
|
||||||
@StateObject private var viewModel = LoginViewModel()
|
@StateObject private var viewModel = LoginViewModel()
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup {
|
||||||
Group {
|
ZStack {
|
||||||
|
Color(isDarkMode ? .black : .white) // ✅ Фон в зависимости от темы
|
||||||
|
|
||||||
if viewModel.isLoading{
|
if viewModel.isLoading{
|
||||||
SplashScreenView()
|
SplashScreenView()
|
||||||
} else if viewModel.isLoggedIn {
|
}else{
|
||||||
|
if viewModel.isLoggedIn {
|
||||||
MainView(viewModel: viewModel)
|
MainView(viewModel: viewModel)
|
||||||
} else {
|
} else {
|
||||||
LoginView(viewModel: viewModel)
|
LoginView(viewModel: viewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.environmentObject(themeManager)
|
}
|
||||||
.preferredColorScheme(themeManager.theme.colorScheme)
|
.preferredColorScheme(isDarkMode ? .dark : .light)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,6 @@
|
|||||||
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 */; };
|
||||||
@ -29,19 +28,9 @@
|
|||||||
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 */; };
|
||||||
@ -50,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 */; };
|
||||||
@ -61,7 +51,6 @@
|
|||||||
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>"; };
|
||||||
@ -74,7 +63,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; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; tabWidth = 4; };
|
1A7940B52DF77F21002569DA /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||||
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>"; };
|
||||||
@ -84,19 +73,9 @@
|
|||||||
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>"; };
|
||||||
@ -105,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>"; };
|
||||||
@ -143,8 +123,7 @@
|
|||||||
1A7940792DF77BC2002569DA /* Shared */ = {
|
1A7940792DF77BC2002569DA /* Shared */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
1A9B01502E4BF49200887E0B /* Media */,
|
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */,
|
||||||
1AB7F5132E32EBF1003756F3 /* Components */,
|
|
||||||
1A7940FA2DF7B898002569DA /* Resources */,
|
1A7940FA2DF7B898002569DA /* Resources */,
|
||||||
1A7940E52DF7B341002569DA /* Services */,
|
1A7940E52DF7B341002569DA /* Services */,
|
||||||
1A7940A02DF77DCD002569DA /* Network */,
|
1A7940A02DF77DCD002569DA /* Network */,
|
||||||
@ -200,7 +179,6 @@
|
|||||||
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 */,
|
||||||
);
|
);
|
||||||
@ -229,7 +207,6 @@
|
|||||||
1A7940E52DF7B341002569DA /* Services */ = {
|
1A7940E52DF7B341002569DA /* Services */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */,
|
|
||||||
1A7940E12DF7B1C5002569DA /* KeychainService.swift */,
|
1A7940E12DF7B1C5002569DA /* KeychainService.swift */,
|
||||||
);
|
);
|
||||||
path = Services;
|
path = Services;
|
||||||
@ -243,26 +220,6 @@
|
|||||||
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 = (
|
||||||
@ -293,10 +250,7 @@
|
|||||||
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 */,
|
||||||
@ -402,12 +356,8 @@
|
|||||||
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;
|
||||||
};
|
};
|
||||||
@ -429,31 +379,24 @@
|
|||||||
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 */,
|
||||||
@ -466,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;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -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>1</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
<key>yobble (macOS).xcscheme_^#shared#^_</key>
|
<key>yobble (macOS).xcscheme_^#shared#^_</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>0</integer>
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
Reference in New Issue
Block a user