add profile sceleton
This commit is contained in:
		
							parent
							
								
									8ebaecf902
								
							
						
					
					
						commit
						1c0c41ecac
					
				@ -12,8 +12,8 @@ class AuthService {
 | 
			
		||||
    func autoLogin(completion: @escaping (Bool, String?) -> Void) {
 | 
			
		||||
        // 1️⃣ Проверяем наличие текущего пользователя
 | 
			
		||||
        if let currentUser = UserDefaults.standard.string(forKey: "currentUser"),
 | 
			
		||||
           let accessToken = KeychainService.shared.get(forKey: "access_token", service: currentUser),
 | 
			
		||||
           let refreshToken = KeychainService.shared.get(forKey: "refresh_token", service: currentUser) {
 | 
			
		||||
           let _ = KeychainService.shared.get(forKey: "access_token", service: currentUser),
 | 
			
		||||
           let _ = KeychainService.shared.get(forKey: "refresh_token", service: currentUser) {
 | 
			
		||||
            if AppConfig.DEBUG{ print("AutoLogin: найден текущий пользователь — \(currentUser)")}
 | 
			
		||||
            completion(true, nil)
 | 
			
		||||
            return
 | 
			
		||||
@ -44,7 +44,7 @@ class AuthService {
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    func login(username: String, password: String, completion: @escaping (Bool, String?) -> Void) {
 | 
			
		||||
        let url = URL(string: "\(AppConfig.API_SERVER)/auth/login")!
 | 
			
		||||
        let url = URL(string: "\(AppConfig.API_SERVER)/v1/auth/login")!
 | 
			
		||||
        var request = URLRequest(url: url)
 | 
			
		||||
        request.httpMethod = "POST"
 | 
			
		||||
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
 | 
			
		||||
@ -116,7 +116,7 @@ class AuthService {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func register(username: String, password: String, invite: String?, completion: @escaping (Bool, String?) -> Void) {
 | 
			
		||||
        let url = URL(string: "\(AppConfig.API_SERVER)/auth/register")!
 | 
			
		||||
        let url = URL(string: "\(AppConfig.API_SERVER)/v1/auth/register")!
 | 
			
		||||
        var request = URLRequest(url: url)
 | 
			
		||||
        request.httpMethod = "POST"
 | 
			
		||||
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
"LoginView_error" = "Login error";
 | 
			
		||||
"LoginView_button_register" = "Register";
 | 
			
		||||
"LoginView_error_username_invalid" = "Username must be 3 to 32 characters (letters, digits, or _)";
 | 
			
		||||
"LoginView_error_password_invalid" = "Password must be 6 to 32 characters long";
 | 
			
		||||
"LoginView_error_password_invalid" = "Password must be 8 to 128 characters long";
 | 
			
		||||
 | 
			
		||||
/* RegistrationView */
 | 
			
		||||
"RegistrationView_title" = "Registration";
 | 
			
		||||
@ -25,7 +25,7 @@
 | 
			
		||||
"RegistrationView_login" = "Login";
 | 
			
		||||
"RegistrationView_error_username_invalid" = "Username must be 3 to 32 characters (letters, digits, or _)";
 | 
			
		||||
"RegistrationView_password" = "Password";
 | 
			
		||||
"RegistrationView_error_password_invalid" = "Password must be 6 to 32 characters long";
 | 
			
		||||
"RegistrationView_error_password_invalid" = "Password must be 8 to 128 characters long";
 | 
			
		||||
"RegistrationView_confirm_password" = "Confirm password";
 | 
			
		||||
"RegistrationView_error_confirm_password_invalid" = "Passwords do not match";
 | 
			
		||||
"RegistrationView_invite" = "Invite code (optional)";
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
"LoginView_error" = "Ошибка авторизации";
 | 
			
		||||
"LoginView_button_register" = "Регистрация";
 | 
			
		||||
"LoginView_error_username_invalid" = "Логин должен быть от 3 до 32 символов (английские буквы, цифры, _)";
 | 
			
		||||
"LoginView_error_password_invalid" = "Пароль должен быть от 6 до 32 символов";
 | 
			
		||||
"LoginView_error_password_invalid" = "Пароль должен быть от 8 до 128 символов";
 | 
			
		||||
 | 
			
		||||
/* RegistrationView */
 | 
			
		||||
"RegistrationView_title" = "Регистрация";
 | 
			
		||||
@ -24,7 +24,7 @@
 | 
			
		||||
"RegistrationView_login" = "Логин";
 | 
			
		||||
"RegistrationView_error_username_invalid" = "Логин должен быть от 3 до 32 символов (английские буквы, цифры, _)";
 | 
			
		||||
"RegistrationView_password" = "Пароль";
 | 
			
		||||
"RegistrationView_error_password_invalid" = "Пароль должен быть от 6 до 32 символов";
 | 
			
		||||
"RegistrationView_error_password_invalid" = "Пароль должен быть от 8 до 128 символов";
 | 
			
		||||
"RegistrationView_confirm_password" = "Подтверждение пароля";
 | 
			
		||||
"RegistrationView_error_confirm_password_invalid" = "Пароли не совпадают";
 | 
			
		||||
"RegistrationView_invite" = "Инвайт-код (необязательно)";
 | 
			
		||||
 | 
			
		||||
@ -1,38 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  MainView.swift
 | 
			
		||||
//  VolnahubApp
 | 
			
		||||
//
 | 
			
		||||
//  Created by cheykrym on 09/06/2025.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct MainView: View {
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
    @State private var selectedTab: Int = 1 // Начинаем с Чатов (индекс 1)
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        TabView(selection: $selectedTab) {
 | 
			
		||||
            ContactsTab()
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "person.2.fill")
 | 
			
		||||
                    Text(NSLocalizedString("MainView_contacts", comment: ""))
 | 
			
		||||
                }
 | 
			
		||||
                .tag(0)
 | 
			
		||||
            
 | 
			
		||||
            ChatsTab()
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "bubble.left.and.bubble.right.fill")
 | 
			
		||||
                    Text(NSLocalizedString("MainView_chats", comment: ""))
 | 
			
		||||
                }
 | 
			
		||||
                .tag(1)
 | 
			
		||||
            
 | 
			
		||||
            SettingsTab(viewModel: viewModel)
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "gearshape.fill")
 | 
			
		||||
                    Text(NSLocalizedString("MainView_settings", comment: ""))
 | 
			
		||||
                }
 | 
			
		||||
                .tag(2)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -1,35 +0,0 @@
 | 
			
		||||
//
 | 
			
		||||
//  SettingsTab.swift
 | 
			
		||||
//  VolnahubApp
 | 
			
		||||
//
 | 
			
		||||
//  Created by cheykrym on 09/06/2025.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct SettingsTab: View {
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            VStack {
 | 
			
		||||
                Text("Настройки")
 | 
			
		||||
                    .font(.largeTitle)
 | 
			
		||||
                    .bold()
 | 
			
		||||
                    .padding()
 | 
			
		||||
                
 | 
			
		||||
                Spacer()
 | 
			
		||||
                
 | 
			
		||||
                Button(action: {
 | 
			
		||||
                    viewModel.logoutCurrentUser()
 | 
			
		||||
                }) {
 | 
			
		||||
                    Text("Выйти из текущего пользователя")
 | 
			
		||||
                        .foregroundColor(.red)
 | 
			
		||||
                }
 | 
			
		||||
                .padding()
 | 
			
		||||
                
 | 
			
		||||
            }
 | 
			
		||||
            .navigationTitle("Настройки")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -19,7 +19,7 @@ struct LoginView: View {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private var isPasswordValid: Bool {
 | 
			
		||||
        return viewModel.password.count >= 6 && viewModel.password.count <= 32
 | 
			
		||||
        return viewModel.password.count >= 8 && viewModel.password.count <= 128
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
@ -27,7 +27,7 @@ struct RegistrationView: View {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private var isPasswordValid: Bool {
 | 
			
		||||
        password.count >= 6 && password.count <= 32
 | 
			
		||||
        password.count >= 8 && password.count <= 128
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private var isConfirmPasswordValid: Bool {
 | 
			
		||||
							
								
								
									
										16
									
								
								Shared/Views/tab/HomeTab.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Shared/Views/tab/HomeTab.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct HomeTab: View {
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            VStack {
 | 
			
		||||
                Text("Домой")
 | 
			
		||||
                    .font(.largeTitle)
 | 
			
		||||
                    .bold()
 | 
			
		||||
                    .padding()
 | 
			
		||||
                Spacer()
 | 
			
		||||
            }
 | 
			
		||||
            .navigationTitle("Домой")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										53
									
								
								Shared/Views/tab/MainView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								Shared/Views/tab/MainView.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,53 @@
 | 
			
		||||
//
 | 
			
		||||
//  MainView.swift
 | 
			
		||||
//  VolnahubApp
 | 
			
		||||
//
 | 
			
		||||
//  Created by cheykrym on 09/06/2025.
 | 
			
		||||
//
 | 
			
		||||
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct MainView: View {
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
    @State private var selectedTab: Int = 0
 | 
			
		||||
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        TabView(selection: $selectedTab) {
 | 
			
		||||
            HomeTab()
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "list.bullet.rectangle")
 | 
			
		||||
                    Text("Лента")
 | 
			
		||||
                }
 | 
			
		||||
                .tag(0)
 | 
			
		||||
            
 | 
			
		||||
            SearchTab()
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "magnifyingglass")
 | 
			
		||||
                    Text("Поиск")
 | 
			
		||||
                }
 | 
			
		||||
                .tag(1)
 | 
			
		||||
            
 | 
			
		||||
//            PublicsTab()
 | 
			
		||||
//                .tabItem {
 | 
			
		||||
//                    Image(systemName: "")
 | 
			
		||||
//                    Text("Свайп")
 | 
			
		||||
//                }
 | 
			
		||||
//                .tag(1)
 | 
			
		||||
          
 | 
			
		||||
            ChatsTab()
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "bubble.left.and.bubble.right.fill")
 | 
			
		||||
                    Text("Чаты")
 | 
			
		||||
                }
 | 
			
		||||
                .tag(2)
 | 
			
		||||
            
 | 
			
		||||
            ProfileTab(viewModel: viewModel)
 | 
			
		||||
                .tabItem {
 | 
			
		||||
                    Image(systemName: "person.crop.square")
 | 
			
		||||
                    Text("Лицо")
 | 
			
		||||
                }
 | 
			
		||||
                .tag(3)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										16
									
								
								Shared/Views/tab/PublicsTab.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Shared/Views/tab/PublicsTab.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct PublicsTab: View {
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            VStack {
 | 
			
		||||
                Text("Паблики")
 | 
			
		||||
                    .font(.largeTitle)
 | 
			
		||||
                    .bold()
 | 
			
		||||
                    .padding()
 | 
			
		||||
                Spacer()
 | 
			
		||||
            }
 | 
			
		||||
            .navigationTitle("Паблики")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										16
									
								
								Shared/Views/tab/SearchTab.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Shared/Views/tab/SearchTab.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct SearchTab: View {
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            VStack {
 | 
			
		||||
                Text("Поиск")
 | 
			
		||||
                    .font(.largeTitle)
 | 
			
		||||
                    .bold()
 | 
			
		||||
                    .padding()
 | 
			
		||||
                Spacer()
 | 
			
		||||
            }
 | 
			
		||||
            .navigationTitle("Поиск")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										196
									
								
								Shared/Views/tab/profile/ProfileTab.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								Shared/Views/tab/profile/ProfileTab.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,196 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct ProfileTab: View {
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
    @State private var showingAccountSwitch = false
 | 
			
		||||
    @State private var selectedTabIndex = 0
 | 
			
		||||
    @State private var selectedSort = "По дате"
 | 
			
		||||
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        NavigationView {
 | 
			
		||||
            GeometryReader { geometry in
 | 
			
		||||
                VStack(spacing: 0) {
 | 
			
		||||
                    ScrollView {
 | 
			
		||||
                        VStack(spacing: 12) {
 | 
			
		||||
                            // Аватар и имя
 | 
			
		||||
                            VStack(spacing: 6) {
 | 
			
		||||
                                Image(systemName: "person.crop.circle.fill")
 | 
			
		||||
                                    .resizable()
 | 
			
		||||
                                    .frame(width: 72, height: 72)
 | 
			
		||||
                                    .foregroundColor(.gray)
 | 
			
		||||
 | 
			
		||||
                                Text("@username")
 | 
			
		||||
                                    .font(.headline)
 | 
			
		||||
                            }
 | 
			
		||||
                            .padding(.top, 16)
 | 
			
		||||
 | 
			
		||||
                            // Статистика
 | 
			
		||||
                            HStack(spacing: 32) {
 | 
			
		||||
                                statView("24", "Посты")
 | 
			
		||||
                                statView("1.2k", "Подписчики")
 | 
			
		||||
                                statView("156", "Подписки")
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            // Кнопка редактирования
 | 
			
		||||
                            Button(action: {
 | 
			
		||||
                                // редактировать профиль
 | 
			
		||||
                            }) {
 | 
			
		||||
                                Text("Редактировать профиль")
 | 
			
		||||
                                    .font(.subheadline)
 | 
			
		||||
                                    .padding(.horizontal, 24)
 | 
			
		||||
                                    .padding(.vertical, 8)
 | 
			
		||||
                                    .overlay(
 | 
			
		||||
                                        RoundedRectangle(cornerRadius: 8)
 | 
			
		||||
                                            .stroke(Color.gray, lineWidth: 1)
 | 
			
		||||
                                    )
 | 
			
		||||
                            }
 | 
			
		||||
                            .padding(.top, 8)
 | 
			
		||||
 | 
			
		||||
                            // Вкладки профиля
 | 
			
		||||
                            HStack(spacing: 32) {
 | 
			
		||||
                                menuTab(index: 0)
 | 
			
		||||
                                tabButton(index: 1, systemIcon: "lock")
 | 
			
		||||
                                tabButton(index: 2, systemIcon: "bookmark")
 | 
			
		||||
                                tabButton(index: 3, systemIcon: "heart")
 | 
			
		||||
                            }
 | 
			
		||||
                            .padding(.vertical, 12)
 | 
			
		||||
                        }
 | 
			
		||||
                        .padding(.horizontal)
 | 
			
		||||
                        .frame(width: geometry.size.width)
 | 
			
		||||
                        
 | 
			
		||||
                        // Контентная часть
 | 
			
		||||
                        TabView(selection: $selectedTabIndex) {
 | 
			
		||||
                            ForEach(0..<4) { index in
 | 
			
		||||
                                LazyVGrid(columns: Array(repeating: .init(.flexible()), count: 3), spacing: 2) {
 | 
			
		||||
                                    ForEach(0..<36) { _ in
 | 
			
		||||
                                        Rectangle()
 | 
			
		||||
                                            .fill(contentColor(for: index))
 | 
			
		||||
                                            .aspectRatio(1, contentMode: .fit)
 | 
			
		||||
                                            .overlay(
 | 
			
		||||
                                                index == 0 ?
 | 
			
		||||
                                                Text(selectedSort)
 | 
			
		||||
                                                    .font(.caption2)
 | 
			
		||||
                                                    .foregroundColor(.gray)
 | 
			
		||||
                                                    .padding(4) : nil,
 | 
			
		||||
                                                alignment: .bottomTrailing
 | 
			
		||||
                                            )
 | 
			
		||||
                                    }
 | 
			
		||||
                                }
 | 
			
		||||
                                .padding(.horizontal)
 | 
			
		||||
                                .tag(index)
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        .tabViewStyle(PageTabViewStyle(indexDisplayMode: .never))
 | 
			
		||||
//                        .frame(height: geometry.size.width * 1.2) // Динамическая высота
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .navigationBarTitleDisplayMode(.inline)
 | 
			
		||||
            .toolbar {
 | 
			
		||||
                ToolbarItem(placement: .principal) {
 | 
			
		||||
                    Button(action: { showingAccountSwitch.toggle() }) {
 | 
			
		||||
                        HStack(spacing: 4) {
 | 
			
		||||
                            Text("custom_user_name")
 | 
			
		||||
                                .font(.headline)
 | 
			
		||||
                                .foregroundColor(.primary)
 | 
			
		||||
                            Image(systemName: "chevron.down")
 | 
			
		||||
                                .font(.subheadline)
 | 
			
		||||
                                .foregroundColor(.gray)
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ToolbarItem(placement: .navigationBarTrailing) {
 | 
			
		||||
                    Button(action: {
 | 
			
		||||
                        // перейти к настройкам
 | 
			
		||||
                    }) {
 | 
			
		||||
                        Image(systemName: "gearshape")
 | 
			
		||||
                            .imageScale(.large)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .sheet(isPresented: $showingAccountSwitch) {
 | 
			
		||||
                VStack {
 | 
			
		||||
                    Text("Выбор аккаунта")
 | 
			
		||||
                        .font(.title)
 | 
			
		||||
                        .padding()
 | 
			
		||||
                    Button("Закрыть") {
 | 
			
		||||
                        showingAccountSwitch = false
 | 
			
		||||
                    }
 | 
			
		||||
                    .padding()
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Статистика
 | 
			
		||||
    func statView(_ value: String, _ label: String) -> some View {
 | 
			
		||||
        VStack {
 | 
			
		||||
            Text(value)
 | 
			
		||||
                .font(.headline)
 | 
			
		||||
            Text(label)
 | 
			
		||||
                .font(.caption)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Вкладка с меню
 | 
			
		||||
    @ViewBuilder
 | 
			
		||||
    func menuTab(index: Int) -> some View {
 | 
			
		||||
        Menu {
 | 
			
		||||
            if selectedTabIndex == index {
 | 
			
		||||
                Button("По дате") { selectedSort = "По дате" }
 | 
			
		||||
                Button("По популярности") { selectedSort = "По популярности" }
 | 
			
		||||
            }
 | 
			
		||||
        } label: {
 | 
			
		||||
            VStack(spacing: 4) {
 | 
			
		||||
                HStack(spacing: 4) {
 | 
			
		||||
                    Image(systemName: "rectangle.grid.3x2")
 | 
			
		||||
                        .font(.system(size: 18, weight: .medium))
 | 
			
		||||
                        .foregroundColor(.primary)
 | 
			
		||||
                    
 | 
			
		||||
                    // Показываем стрелку вниз только если вкладка активна
 | 
			
		||||
                    if selectedTabIndex == index {
 | 
			
		||||
                        Image(systemName: "chevron.down")
 | 
			
		||||
                            .font(.system(size: 10))
 | 
			
		||||
                            .foregroundColor(.gray)
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                Rectangle()
 | 
			
		||||
                    .frame(height: 2)
 | 
			
		||||
                    .foregroundColor(selectedTabIndex == index ? .primary : .clear)
 | 
			
		||||
            }
 | 
			
		||||
            .frame(maxWidth: .infinity)
 | 
			
		||||
        }
 | 
			
		||||
        .onTapGesture {
 | 
			
		||||
            selectedTabIndex = index
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Остальные вкладки
 | 
			
		||||
    @ViewBuilder
 | 
			
		||||
    func tabButton(index: Int, systemIcon: String) -> some View {
 | 
			
		||||
        VStack(spacing: 4) {
 | 
			
		||||
            Image(systemName: systemIcon)
 | 
			
		||||
                .font(.system(size: 18, weight: .medium))
 | 
			
		||||
                .foregroundColor(selectedTabIndex == index ? .primary : .gray)
 | 
			
		||||
            Rectangle()
 | 
			
		||||
                .frame(height: 2)
 | 
			
		||||
                .foregroundColor(selectedTabIndex == index ? .primary : .clear)
 | 
			
		||||
        }
 | 
			
		||||
        .frame(maxWidth: .infinity)
 | 
			
		||||
        .onTapGesture {
 | 
			
		||||
            selectedTabIndex = index
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // MARK: - Цвет контента
 | 
			
		||||
    func contentColor(for tab: Int) -> Color {
 | 
			
		||||
        switch tab {
 | 
			
		||||
        case 0: return Color.gray.opacity(0.3)
 | 
			
		||||
        case 1: return Color.blue.opacity(0.3)
 | 
			
		||||
        case 2: return Color.green.opacity(0.3)
 | 
			
		||||
        case 3: return Color.red.opacity(0.3)
 | 
			
		||||
        default: return Color.gray.opacity(0.3)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -4,9 +4,9 @@ struct AppConfig {
 | 
			
		||||
    static var DEBUG: Bool = true
 | 
			
		||||
    static let SERVICE = Bundle.main.bundleIdentifier ?? "default.service"
 | 
			
		||||
    static let PROTOCOL = "https"
 | 
			
		||||
    static let API_SERVER = "\(PROTOCOL)://api.volnahub.ru"
 | 
			
		||||
    static let API_SERVER = "\(PROTOCOL)://api.yobble.org"
 | 
			
		||||
    static let SERVER_TIMEZONE = "GMT+3"
 | 
			
		||||
    static let USER_AGENT = "volnahub ios"
 | 
			
		||||
    static let USER_AGENT = "yobble ios"
 | 
			
		||||
    static let APP_BUILD = "freestore"
 | 
			
		||||
    static let APP_VERSION = "0.1"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -4,6 +4,8 @@
 | 
			
		||||
<dict>
 | 
			
		||||
	<key>CFBundleDevelopmentRegion</key>
 | 
			
		||||
	<string>$(DEVELOPMENT_LANGUAGE)</string>
 | 
			
		||||
	<key>CFBundleDisplayName</key>
 | 
			
		||||
	<string>yobble</string>
 | 
			
		||||
	<key>CFBundleExecutable</key>
 | 
			
		||||
	<string>$(EXECUTABLE_NAME)</string>
 | 
			
		||||
	<key>CFBundleIdentifier</key>
 | 
			
		||||
 | 
			
		||||
@ -9,7 +9,7 @@
 | 
			
		||||
/* Begin PBXBuildFile section */
 | 
			
		||||
		1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276022DF909F900D8BC53 /* refreshtokenex.swift */; };
 | 
			
		||||
		1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A0276102DF9247000D8BC53 /* CustomTextField.swift */; };
 | 
			
		||||
		1A79408D2DF77BC3002569DA /* volnahubApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* volnahubApp.swift */; };
 | 
			
		||||
		1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407A2DF77BC2002569DA /* yobbleApp.swift */; };
 | 
			
		||||
		1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
 | 
			
		||||
		1A7940902DF77BC3002569DA /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79407B2DF77BC2002569DA /* ContentView.swift */; };
 | 
			
		||||
		1A7940912DF77BC3002569DA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1A79407C2DF77BC3002569DA /* Assets.xcassets */; };
 | 
			
		||||
@ -21,23 +21,26 @@
 | 
			
		||||
		1A7940B62DF77F21002569DA /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940B52DF77F21002569DA /* MainView.swift */; };
 | 
			
		||||
		1A7940C62DF7A98E002569DA /* ContactsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940C52DF7A98E002569DA /* ContactsTab.swift */; };
 | 
			
		||||
		1A7940CA2DF7A99B002569DA /* ChatsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940C92DF7A99B002569DA /* ChatsTab.swift */; };
 | 
			
		||||
		1A7940CE2DF7A9AA002569DA /* SettingsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940CD2DF7A9AA002569DA /* SettingsTab.swift */; };
 | 
			
		||||
		1A7940CE2DF7A9AA002569DA /* ProfileTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940CD2DF7A9AA002569DA /* ProfileTab.swift */; };
 | 
			
		||||
		1A7940DE2DF7B0D7002569DA /* config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940DD2DF7B0D7002569DA /* config.swift */; };
 | 
			
		||||
		1A7940E22DF7B1C5002569DA /* KeychainService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940E12DF7B1C5002569DA /* KeychainService.swift */; };
 | 
			
		||||
		1A7940E72DF7B5E5002569DA /* SplashScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A7940E62DF7B5E5002569DA /* SplashScreenView.swift */; };
 | 
			
		||||
		1A7940F02DF7B7A3002569DA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1A7940F22DF7B7A3002569DA /* Localizable.strings */; };
 | 
			
		||||
		1A79410C2DF7C81D002569DA /* RegistrationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A79410B2DF7C81D002569DA /* RegistrationView.swift */; };
 | 
			
		||||
		1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; };
 | 
			
		||||
		1AEE5EAF2E21A84500A3DCA3 /* PublicsTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAE2E21A84500A3DCA3 /* PublicsTab.swift */; };
 | 
			
		||||
		1AEE5EB32E21A85800A3DCA3 /* SearchTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EB22E21A85800A3DCA3 /* SearchTab.swift */; };
 | 
			
		||||
/* End PBXBuildFile section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXFileReference section */
 | 
			
		||||
		1A0276022DF909F900D8BC53 /* refreshtokenex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = refreshtokenex.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A0276102DF9247000D8BC53 /* CustomTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomTextField.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A79407A2DF77BC2002569DA /* volnahubApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = volnahubApp.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A79407A2DF77BC2002569DA /* yobbleApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = yobbleApp.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A79407B2DF77BC2002569DA /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A79407C2DF77BC3002569DA /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940812DF77BC3002569DA /* volnahub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = volnahub.app; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		1A7940812DF77BC3002569DA /* yobble.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = yobble.app; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		1A7940842DF77BC3002569DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940892DF77BC3002569DA /* volnahub.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = volnahub.app; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		1A7940892DF77BC3002569DA /* yobble.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = yobble.app; sourceTree = BUILT_PRODUCTS_DIR; };
 | 
			
		||||
		1A79408B2DF77BC3002569DA /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 | 
			
		||||
		1A79408C2DF77BC3002569DA /* macOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = macOS.entitlements; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940A12DF77DE9002569DA /* AuthService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthService.swift; sourceTree = "<group>"; };
 | 
			
		||||
@ -47,13 +50,16 @@
 | 
			
		||||
		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>"; };
 | 
			
		||||
		1A7940C92DF7A99B002569DA /* ChatsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatsTab.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940CD2DF7A9AA002569DA /* SettingsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTab.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940CD2DF7A9AA002569DA /* ProfileTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileTab.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940DD2DF7B0D7002569DA /* config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = config.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940E12DF7B1C5002569DA /* KeychainService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainService.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A7940E62DF7B5E5002569DA /* SplashScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SplashScreenView.swift; 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>"; };
 | 
			
		||||
		1A79410B2DF7C81D002569DA /* RegistrationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegistrationView.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1AEE5EAE2E21A84500A3DCA3 /* PublicsTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicsTab.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1AEE5EB22E21A85800A3DCA3 /* SearchTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchTab.swift; sourceTree = "<group>"; };
 | 
			
		||||
/* End PBXFileReference section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXFrameworksBuildPhase section */
 | 
			
		||||
@ -93,7 +99,7 @@
 | 
			
		||||
				1A79409F2DF77DC4002569DA /* Models */,
 | 
			
		||||
				1A79409E2DF77DBD002569DA /* ViewModels */,
 | 
			
		||||
				1A79409D2DF77DB5002569DA /* Views */,
 | 
			
		||||
				1A79407A2DF77BC2002569DA /* volnahubApp.swift */,
 | 
			
		||||
				1A79407A2DF77BC2002569DA /* yobbleApp.swift */,
 | 
			
		||||
				1A79407C2DF77BC3002569DA /* Assets.xcassets */,
 | 
			
		||||
				1A7940DD2DF7B0D7002569DA /* config.swift */,
 | 
			
		||||
			);
 | 
			
		||||
@ -103,8 +109,8 @@
 | 
			
		||||
		1A7940822DF77BC3002569DA /* Products */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1A7940812DF77BC3002569DA /* volnahub.app */,
 | 
			
		||||
				1A7940892DF77BC3002569DA /* volnahub.app */,
 | 
			
		||||
				1A7940812DF77BC3002569DA /* yobble.app */,
 | 
			
		||||
				1A7940892DF77BC3002569DA /* yobble.app */,
 | 
			
		||||
			);
 | 
			
		||||
			name = Products;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
@ -129,14 +135,11 @@
 | 
			
		||||
		1A79409D2DF77DB5002569DA /* Views */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1AEE5EA92E21A4FC00A3DCA3 /* tab */,
 | 
			
		||||
				1AEE5EA62E2194CD00A3DCA3 /* contacts */,
 | 
			
		||||
				1AEE5EA52E21947B00A3DCA3 /* login */,
 | 
			
		||||
				1A79407B2DF77BC2002569DA /* ContentView.swift */,
 | 
			
		||||
				1A7940AF2DF77E26002569DA /* LoginView.swift */,
 | 
			
		||||
				1A7940B52DF77F21002569DA /* MainView.swift */,
 | 
			
		||||
				1A7940C52DF7A98E002569DA /* ContactsTab.swift */,
 | 
			
		||||
				1A7940C92DF7A99B002569DA /* ChatsTab.swift */,
 | 
			
		||||
				1A7940CD2DF7A9AA002569DA /* SettingsTab.swift */,
 | 
			
		||||
				1A7940E62DF7B5E5002569DA /* SplashScreenView.swift */,
 | 
			
		||||
				1A79410B2DF7C81D002569DA /* RegistrationView.swift */,
 | 
			
		||||
				1A0276102DF9247000D8BC53 /* CustomTextField.swift */,
 | 
			
		||||
			);
 | 
			
		||||
			path = Views;
 | 
			
		||||
@ -183,12 +186,50 @@
 | 
			
		||||
			path = Resources;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		1AEE5EA52E21947B00A3DCA3 /* login */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1A7940AF2DF77E26002569DA /* LoginView.swift */,
 | 
			
		||||
				1A79410B2DF7C81D002569DA /* RegistrationView.swift */,
 | 
			
		||||
			);
 | 
			
		||||
			path = login;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		1AEE5EA62E2194CD00A3DCA3 /* contacts */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
			);
 | 
			
		||||
			path = contacts;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		1AEE5EA92E21A4FC00A3DCA3 /* tab */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1AEE5ECC2E21C9D100A3DCA3 /* profile */,
 | 
			
		||||
				1A7940C52DF7A98E002569DA /* ContactsTab.swift */,
 | 
			
		||||
				1A7940C92DF7A99B002569DA /* ChatsTab.swift */,
 | 
			
		||||
				1A7940B52DF77F21002569DA /* MainView.swift */,
 | 
			
		||||
				1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */,
 | 
			
		||||
				1AEE5EAE2E21A84500A3DCA3 /* PublicsTab.swift */,
 | 
			
		||||
				1AEE5EB22E21A85800A3DCA3 /* SearchTab.swift */,
 | 
			
		||||
			);
 | 
			
		||||
			path = tab;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
		1AEE5ECC2E21C9D100A3DCA3 /* profile */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1A7940CD2DF7A9AA002569DA /* ProfileTab.swift */,
 | 
			
		||||
			);
 | 
			
		||||
			path = profile;
 | 
			
		||||
			sourceTree = "<group>";
 | 
			
		||||
		};
 | 
			
		||||
/* End PBXGroup section */
 | 
			
		||||
 | 
			
		||||
/* Begin PBXNativeTarget section */
 | 
			
		||||
		1A7940802DF77BC3002569DA /* volnahub (iOS) */ = {
 | 
			
		||||
		1A7940802DF77BC3002569DA /* yobble (iOS) */ = {
 | 
			
		||||
			isa = PBXNativeTarget;
 | 
			
		||||
			buildConfigurationList = 1A7940952DF77BC3002569DA /* Build configuration list for PBXNativeTarget "volnahub (iOS)" */;
 | 
			
		||||
			buildConfigurationList = 1A7940952DF77BC3002569DA /* Build configuration list for PBXNativeTarget "yobble (iOS)" */;
 | 
			
		||||
			buildPhases = (
 | 
			
		||||
				1A79407D2DF77BC3002569DA /* Sources */,
 | 
			
		||||
				1A79407E2DF77BC3002569DA /* Frameworks */,
 | 
			
		||||
@ -198,14 +239,14 @@
 | 
			
		||||
			);
 | 
			
		||||
			dependencies = (
 | 
			
		||||
			);
 | 
			
		||||
			name = "volnahub (iOS)";
 | 
			
		||||
			name = "yobble (iOS)";
 | 
			
		||||
			productName = "volnahub (iOS)";
 | 
			
		||||
			productReference = 1A7940812DF77BC3002569DA /* volnahub.app */;
 | 
			
		||||
			productReference = 1A7940812DF77BC3002569DA /* yobble.app */;
 | 
			
		||||
			productType = "com.apple.product-type.application";
 | 
			
		||||
		};
 | 
			
		||||
		1A7940882DF77BC3002569DA /* volnahub (macOS) */ = {
 | 
			
		||||
		1A7940882DF77BC3002569DA /* yobble (macOS) */ = {
 | 
			
		||||
			isa = PBXNativeTarget;
 | 
			
		||||
			buildConfigurationList = 1A7940982DF77BC3002569DA /* Build configuration list for PBXNativeTarget "volnahub (macOS)" */;
 | 
			
		||||
			buildConfigurationList = 1A7940982DF77BC3002569DA /* Build configuration list for PBXNativeTarget "yobble (macOS)" */;
 | 
			
		||||
			buildPhases = (
 | 
			
		||||
				1A7940852DF77BC3002569DA /* Sources */,
 | 
			
		||||
				1A7940862DF77BC3002569DA /* Frameworks */,
 | 
			
		||||
@ -215,9 +256,9 @@
 | 
			
		||||
			);
 | 
			
		||||
			dependencies = (
 | 
			
		||||
			);
 | 
			
		||||
			name = "volnahub (macOS)";
 | 
			
		||||
			name = "yobble (macOS)";
 | 
			
		||||
			productName = "volnahub (macOS)";
 | 
			
		||||
			productReference = 1A7940892DF77BC3002569DA /* volnahub.app */;
 | 
			
		||||
			productReference = 1A7940892DF77BC3002569DA /* yobble.app */;
 | 
			
		||||
			productType = "com.apple.product-type.application";
 | 
			
		||||
		};
 | 
			
		||||
/* End PBXNativeTarget section */
 | 
			
		||||
@ -237,7 +278,7 @@
 | 
			
		||||
					};
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
			buildConfigurationList = 1A7940782DF77BC2002569DA /* Build configuration list for PBXProject "volnahub" */;
 | 
			
		||||
			buildConfigurationList = 1A7940782DF77BC2002569DA /* Build configuration list for PBXProject "yobble" */;
 | 
			
		||||
			compatibilityVersion = "Xcode 9.3";
 | 
			
		||||
			developmentRegion = en;
 | 
			
		||||
			hasScannedForEncodings = 0;
 | 
			
		||||
@ -251,8 +292,8 @@
 | 
			
		||||
			projectDirPath = "";
 | 
			
		||||
			projectRoot = "";
 | 
			
		||||
			targets = (
 | 
			
		||||
				1A7940802DF77BC3002569DA /* volnahub (iOS) */,
 | 
			
		||||
				1A7940882DF77BC3002569DA /* volnahub (macOS) */,
 | 
			
		||||
				1A7940802DF77BC3002569DA /* yobble (iOS) */,
 | 
			
		||||
				1A7940882DF77BC3002569DA /* yobble (macOS) */,
 | 
			
		||||
			);
 | 
			
		||||
		};
 | 
			
		||||
/* End PBXProject section */
 | 
			
		||||
@ -282,22 +323,25 @@
 | 
			
		||||
			isa = PBXSourcesBuildPhase;
 | 
			
		||||
			buildActionMask = 2147483647;
 | 
			
		||||
			files = (
 | 
			
		||||
				1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */,
 | 
			
		||||
				1A7940C62DF7A98E002569DA /* ContactsTab.swift in Sources */,
 | 
			
		||||
				1A7940E72DF7B5E5002569DA /* SplashScreenView.swift in Sources */,
 | 
			
		||||
				1A7940B02DF77E26002569DA /* LoginView.swift in Sources */,
 | 
			
		||||
				1A79410C2DF7C81D002569DA /* RegistrationView.swift in Sources */,
 | 
			
		||||
				1A0276112DF9247000D8BC53 /* CustomTextField.swift in Sources */,
 | 
			
		||||
				1A7940CE2DF7A9AA002569DA /* SettingsTab.swift in Sources */,
 | 
			
		||||
				1A7940CE2DF7A9AA002569DA /* ProfileTab.swift in Sources */,
 | 
			
		||||
				1A7940DE2DF7B0D7002569DA /* config.swift in Sources */,
 | 
			
		||||
				1A0276032DF909F900D8BC53 /* refreshtokenex.swift in Sources */,
 | 
			
		||||
				1A7940B62DF77F21002569DA /* MainView.swift in Sources */,
 | 
			
		||||
				1A7940E22DF7B1C5002569DA /* KeychainService.swift in Sources */,
 | 
			
		||||
				1A7940A62DF77DF5002569DA /* User.swift in Sources */,
 | 
			
		||||
				1A7940A22DF77DE9002569DA /* AuthService.swift in Sources */,
 | 
			
		||||
				1AEE5EB32E21A85800A3DCA3 /* SearchTab.swift in Sources */,
 | 
			
		||||
				1A79408F2DF77BC3002569DA /* ContentView.swift in Sources */,
 | 
			
		||||
				1AEE5EAF2E21A84500A3DCA3 /* PublicsTab.swift in Sources */,
 | 
			
		||||
				1A7940CA2DF7A99B002569DA /* ChatsTab.swift in Sources */,
 | 
			
		||||
				1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */,
 | 
			
		||||
				1A79408D2DF77BC3002569DA /* volnahubApp.swift in Sources */,
 | 
			
		||||
				1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */,
 | 
			
		||||
			);
 | 
			
		||||
			runOnlyForDeploymentPostprocessing = 0;
 | 
			
		||||
		};
 | 
			
		||||
@ -454,8 +498,8 @@
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
				);
 | 
			
		||||
				MARKETING_VERSION = 0.1;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = ckp2.volnahub;
 | 
			
		||||
				PRODUCT_NAME = volnahub;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = org.yobble.app;
 | 
			
		||||
				PRODUCT_NAME = yobble;
 | 
			
		||||
				PROVISIONING_PROFILE_SPECIFIER = "";
 | 
			
		||||
				SDKROOT = iphoneos;
 | 
			
		||||
				SWIFT_VERSION = 5.0;
 | 
			
		||||
@ -480,8 +524,8 @@
 | 
			
		||||
					"@executable_path/Frameworks",
 | 
			
		||||
				);
 | 
			
		||||
				MARKETING_VERSION = 0.1;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = ckp2.volnahub;
 | 
			
		||||
				PRODUCT_NAME = volnahub;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = org.yobble.app;
 | 
			
		||||
				PRODUCT_NAME = yobble;
 | 
			
		||||
				PROVISIONING_PROFILE_SPECIFIER = "";
 | 
			
		||||
				SDKROOT = iphoneos;
 | 
			
		||||
				SWIFT_VERSION = 5.0;
 | 
			
		||||
@ -506,7 +550,7 @@
 | 
			
		||||
				);
 | 
			
		||||
				MACOSX_DEPLOYMENT_TARGET = 11.0;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = ckp.volnahub;
 | 
			
		||||
				PRODUCT_NAME = volnahub;
 | 
			
		||||
				PRODUCT_NAME = yobble;
 | 
			
		||||
				SDKROOT = macosx;
 | 
			
		||||
				SWIFT_VERSION = 5.0;
 | 
			
		||||
			};
 | 
			
		||||
@ -528,7 +572,7 @@
 | 
			
		||||
				);
 | 
			
		||||
				MACOSX_DEPLOYMENT_TARGET = 11.0;
 | 
			
		||||
				PRODUCT_BUNDLE_IDENTIFIER = ckp.volnahub;
 | 
			
		||||
				PRODUCT_NAME = volnahub;
 | 
			
		||||
				PRODUCT_NAME = yobble;
 | 
			
		||||
				SDKROOT = macosx;
 | 
			
		||||
				SWIFT_VERSION = 5.0;
 | 
			
		||||
			};
 | 
			
		||||
@ -537,7 +581,7 @@
 | 
			
		||||
/* End XCBuildConfiguration section */
 | 
			
		||||
 | 
			
		||||
/* Begin XCConfigurationList section */
 | 
			
		||||
		1A7940782DF77BC2002569DA /* Build configuration list for PBXProject "volnahub" */ = {
 | 
			
		||||
		1A7940782DF77BC2002569DA /* Build configuration list for PBXProject "yobble" */ = {
 | 
			
		||||
			isa = XCConfigurationList;
 | 
			
		||||
			buildConfigurations = (
 | 
			
		||||
				1A7940932DF77BC3002569DA /* Debug */,
 | 
			
		||||
@ -546,7 +590,7 @@
 | 
			
		||||
			defaultConfigurationIsVisible = 0;
 | 
			
		||||
			defaultConfigurationName = Release;
 | 
			
		||||
		};
 | 
			
		||||
		1A7940952DF77BC3002569DA /* Build configuration list for PBXNativeTarget "volnahub (iOS)" */ = {
 | 
			
		||||
		1A7940952DF77BC3002569DA /* Build configuration list for PBXNativeTarget "yobble (iOS)" */ = {
 | 
			
		||||
			isa = XCConfigurationList;
 | 
			
		||||
			buildConfigurations = (
 | 
			
		||||
				1A7940962DF77BC3002569DA /* Debug */,
 | 
			
		||||
@ -555,7 +599,7 @@
 | 
			
		||||
			defaultConfigurationIsVisible = 0;
 | 
			
		||||
			defaultConfigurationName = Release;
 | 
			
		||||
		};
 | 
			
		||||
		1A7940982DF77BC3002569DA /* Build configuration list for PBXNativeTarget "volnahub (macOS)" */ = {
 | 
			
		||||
		1A7940982DF77BC3002569DA /* Build configuration list for PBXNativeTarget "yobble (macOS)" */ = {
 | 
			
		||||
			isa = XCConfigurationList;
 | 
			
		||||
			buildConfigurations = (
 | 
			
		||||
				1A7940992DF77BC3002569DA /* Debug */,
 | 
			
		||||
@ -2,6 +2,6 @@
 | 
			
		||||
<Workspace
 | 
			
		||||
   version = "1.0">
 | 
			
		||||
   <FileRef
 | 
			
		||||
      location = "self:">
 | 
			
		||||
      location = "self:/Volumes/Untitled/xcode/volnahub/yobble.xcodeproj">
 | 
			
		||||
   </FileRef>
 | 
			
		||||
</Workspace>
 | 
			
		||||
@ -7,12 +7,12 @@
 | 
			
		||||
		<key>volnahub (iOS).xcscheme_^#shared#^_</key>
 | 
			
		||||
		<dict>
 | 
			
		||||
			<key>orderHint</key>
 | 
			
		||||
			<integer>0</integer>
 | 
			
		||||
			<integer>1</integer>
 | 
			
		||||
		</dict>
 | 
			
		||||
		<key>volnahub (macOS).xcscheme_^#shared#^_</key>
 | 
			
		||||
		<dict>
 | 
			
		||||
			<key>orderHint</key>
 | 
			
		||||
			<integer>1</integer>
 | 
			
		||||
			<integer>0</integer>
 | 
			
		||||
		</dict>
 | 
			
		||||
	</dict>
 | 
			
		||||
</dict>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user