244 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			8.5 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
import SwiftUI
 | 
						||
 | 
						||
struct TopBarView: View {
 | 
						||
    var title: String
 | 
						||
    
 | 
						||
    let isMessengerModeEnabled: Bool
 | 
						||
    // Состояния для ProfileTab
 | 
						||
    @Binding var selectedAccount: String
 | 
						||
//    @Binding var sheetType: ProfileTab.SheetType?
 | 
						||
    var accounts: [String]
 | 
						||
//    var viewModel: LoginViewModel
 | 
						||
    @ObservedObject var viewModel: LoginViewModel
 | 
						||
    @Binding var isSettingsPresented: Bool
 | 
						||
    
 | 
						||
    // Привязка для управления боковым меню
 | 
						||
    @Binding var isSideMenuPresented: Bool
 | 
						||
    @Binding var chatSearchRevealProgress: CGFloat
 | 
						||
    @Binding var chatSearchText: String
 | 
						||
    
 | 
						||
    var isHomeTab: Bool {
 | 
						||
        return title == "Home"
 | 
						||
    }
 | 
						||
    
 | 
						||
    var isChatsTab: Bool {
 | 
						||
        return title == "Chats"
 | 
						||
    }
 | 
						||
    
 | 
						||
    var isProfileTab: Bool {
 | 
						||
        return title == "Profile"
 | 
						||
    }
 | 
						||
 | 
						||
    private var statusMessage: String? {
 | 
						||
        if viewModel.chatLoadingState == .loading {
 | 
						||
            return NSLocalizedString("Загрузка чатов", comment: "")
 | 
						||
        }
 | 
						||
        if viewModel.socketState == .connecting {
 | 
						||
            return NSLocalizedString("Подключение", comment: "")
 | 
						||
        }
 | 
						||
        return nil
 | 
						||
    }
 | 
						||
 | 
						||
    var body: some View {
 | 
						||
        VStack(spacing: 0) {
 | 
						||
            HStack {
 | 
						||
                
 | 
						||
                if !isMessengerModeEnabled{
 | 
						||
                    // Кнопка "Гамбургер" для открытия меню
 | 
						||
                    Button(action: {
 | 
						||
                        withAnimation {
 | 
						||
                            isSideMenuPresented.toggle()
 | 
						||
                        }
 | 
						||
                    }) {
 | 
						||
                        Image(systemName: "line.horizontal.3")
 | 
						||
                            .imageScale(.large)
 | 
						||
                            .foregroundColor(.primary)
 | 
						||
                    }
 | 
						||
                }
 | 
						||
//                Spacer()
 | 
						||
                
 | 
						||
                if let statusMessage {
 | 
						||
                    connectionStatusView(message: statusMessage)
 | 
						||
                    Spacer()
 | 
						||
                } else if isHomeTab{
 | 
						||
                    Text("Yobble")
 | 
						||
                        .font(.largeTitle)
 | 
						||
                        .fontWeight(.bold)
 | 
						||
                    Spacer()
 | 
						||
                } else if isProfileTab {
 | 
						||
                    Spacer()
 | 
						||
                    Button(action: { }) {
 | 
						||
                        HStack(spacing: 4) {
 | 
						||
                            Text("@\(viewModel.username)")
 | 
						||
                                .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(isActive: $isSettingsPresented) {
 | 
						||
                        SettingsView(viewModel: viewModel)
 | 
						||
                    } label: {
 | 
						||
                        Image(systemName: "wrench")
 | 
						||
                            .imageScale(.large)
 | 
						||
                            .foregroundColor(.primary)
 | 
						||
                    }
 | 
						||
                }
 | 
						||
                
 | 
						||
//                else if isChatsTab {
 | 
						||
//                    Button(action: {
 | 
						||
//                        NotificationCenter.default.post(name: .debugRefreshChats, object: nil)
 | 
						||
//                    }) {
 | 
						||
//                        Text(NSLocalizedString("DEBUG UPDATE", comment: ""))
 | 
						||
//                            .foregroundColor(.primary)
 | 
						||
//                    }
 | 
						||
//                }
 | 
						||
            }
 | 
						||
            .padding()
 | 
						||
            .frame(height: 50) // Стандартная высота для нав. бара
 | 
						||
            
 | 
						||
            if isChatsTab {
 | 
						||
                revealableSearchBar
 | 
						||
            }
 | 
						||
 | 
						||
            Divider()
 | 
						||
        }
 | 
						||
        .background(Color(UIColor.systemBackground))
 | 
						||
        .onChange(of: isChatsTab) { isChats in
 | 
						||
            let hasSearchText = !chatSearchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty
 | 
						||
            if !isChats {
 | 
						||
                guard !hasSearchText else { return }
 | 
						||
                withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
 | 
						||
                    chatSearchRevealProgress = 0
 | 
						||
                }
 | 
						||
            } else if hasSearchText {
 | 
						||
                withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
 | 
						||
                    chatSearchRevealProgress = 1
 | 
						||
                }
 | 
						||
            }
 | 
						||
        }
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
private extension TopBarView {
 | 
						||
    func connectionStatusView(message: String) -> some View {
 | 
						||
        HStack(spacing: 8) {
 | 
						||
            ProgressView()
 | 
						||
                .progressViewStyle(.circular)
 | 
						||
            Text(message)
 | 
						||
                .font(.headline)
 | 
						||
                .foregroundColor(.primary)
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    private var normalizedRevealProgress: CGFloat {
 | 
						||
        guard isChatsTab else { return 0 }
 | 
						||
        return max(0, min(chatSearchRevealProgress, 1))
 | 
						||
    }
 | 
						||
 | 
						||
    private var revealableSearchBar: some View {
 | 
						||
        let progress = normalizedRevealProgress
 | 
						||
        return VStack(spacing: 0) {
 | 
						||
            searchBar
 | 
						||
                .padding(.horizontal)
 | 
						||
                .padding(.bottom, searchBarBottomSpacing)
 | 
						||
                .opacity(progress)
 | 
						||
        }
 | 
						||
        .frame(height: searchBarRevealHeight * progress, alignment: .top)
 | 
						||
        .clipped()
 | 
						||
        .allowsHitTesting(progress > 0.9)
 | 
						||
        .accessibilityHidden(progress < 0.9)
 | 
						||
    }
 | 
						||
 | 
						||
    private var searchBarRevealHeight: CGFloat { searchBarBaseHeight + searchBarBottomSpacing }
 | 
						||
 | 
						||
    // 36 min height + 6 * 2 vertical padding inside searchBar
 | 
						||
    private var searchBarBaseHeight: CGFloat { 48 }
 | 
						||
 | 
						||
    private var searchBarBottomSpacing: CGFloat { 0 }
 | 
						||
 | 
						||
    var searchBar: some View {
 | 
						||
        HStack(spacing: 8) {
 | 
						||
            Image(systemName: "magnifyingglass")
 | 
						||
                .foregroundColor(.secondary)
 | 
						||
            TextField(NSLocalizedString("Поиск", comment: ""), text: $chatSearchText)
 | 
						||
                .textFieldStyle(.plain)
 | 
						||
                .textInputAutocapitalization(.never)
 | 
						||
                .autocorrectionDisabled()
 | 
						||
            if !chatSearchText.isEmpty {
 | 
						||
                Button(action: { chatSearchText = "" }) {
 | 
						||
                    Image(systemName: "xmark.circle.fill")
 | 
						||
                        .foregroundColor(.secondary)
 | 
						||
                }
 | 
						||
                .buttonStyle(.plain)
 | 
						||
            }
 | 
						||
        }
 | 
						||
        .padding(.horizontal, 12)
 | 
						||
        .padding(.vertical, 6)
 | 
						||
        .frame(minHeight: 36)
 | 
						||
        .background(
 | 
						||
            RoundedRectangle(cornerRadius: 12, style: .continuous)
 | 
						||
                .fill(Color(UIColor.secondarySystemBackground))
 | 
						||
        )
 | 
						||
    }
 | 
						||
}
 | 
						||
 | 
						||
struct TopBarView_Previews: PreviewProvider {
 | 
						||
    struct Wrapper: View {
 | 
						||
        @State private var selectedAccount = "@user"
 | 
						||
        @State private var isSideMenuPresented = false
 | 
						||
        @State private var revealProgress: CGFloat = 1
 | 
						||
        @StateObject private var viewModel = LoginViewModel()
 | 
						||
        @State private var searchText: String = ""
 | 
						||
        @State private var isSettingsPresented = false
 | 
						||
 | 
						||
        var body: some View {
 | 
						||
            TopBarView(
 | 
						||
                title: "Chats",
 | 
						||
                isMessengerModeEnabled: false,
 | 
						||
                selectedAccount: $selectedAccount,
 | 
						||
                accounts: [selectedAccount],
 | 
						||
                viewModel: viewModel,
 | 
						||
                isSettingsPresented: $isSettingsPresented,
 | 
						||
                isSideMenuPresented: $isSideMenuPresented,
 | 
						||
                chatSearchRevealProgress: $revealProgress,
 | 
						||
                chatSearchText: $searchText,
 | 
						||
            )
 | 
						||
        }
 | 
						||
    }
 | 
						||
 | 
						||
    static var previews: some View {
 | 
						||
        Wrapper()
 | 
						||
            .environmentObject(ThemeManager())
 | 
						||
    }
 | 
						||
}
 |