open chat everywhere
This commit is contained in:
		
							parent
							
								
									3658d5a963
								
							
						
					
					
						commit
						ed91efacf5
					
				@ -9,6 +9,7 @@ struct TopBarView: View {
 | 
			
		||||
    var accounts: [String]
 | 
			
		||||
//    var viewModel: LoginViewModel
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
    @Binding var isSettingsPresented: Bool
 | 
			
		||||
    
 | 
			
		||||
    // Привязка для управления боковым меню
 | 
			
		||||
    @Binding var isSideMenuPresented: Bool
 | 
			
		||||
@ -101,7 +102,9 @@ struct TopBarView: View {
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                } else if isProfileTab {
 | 
			
		||||
                    NavigationLink(destination: SettingsView(viewModel: viewModel)) {
 | 
			
		||||
                    NavigationLink(isActive: $isSettingsPresented) {
 | 
			
		||||
                        SettingsView(viewModel: viewModel)
 | 
			
		||||
                    } label: {
 | 
			
		||||
                        Image(systemName: "wrench")
 | 
			
		||||
                            .imageScale(.large)
 | 
			
		||||
                            .foregroundColor(.primary)
 | 
			
		||||
@ -213,6 +216,7 @@ struct TopBarView_Previews: PreviewProvider {
 | 
			
		||||
        @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(
 | 
			
		||||
@ -220,6 +224,7 @@ struct TopBarView_Previews: PreviewProvider {
 | 
			
		||||
                selectedAccount: $selectedAccount,
 | 
			
		||||
                accounts: [selectedAccount],
 | 
			
		||||
                viewModel: viewModel,
 | 
			
		||||
                isSettingsPresented: $isSettingsPresented,
 | 
			
		||||
                isSideMenuPresented: $isSideMenuPresented,
 | 
			
		||||
                chatSearchRevealProgress: $revealProgress,
 | 
			
		||||
                chatSearchText: $searchText
 | 
			
		||||
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
import Foundation
 | 
			
		||||
 | 
			
		||||
struct ChatDeepLink: Identifiable {
 | 
			
		||||
    let id = UUID()
 | 
			
		||||
    let chatId: String
 | 
			
		||||
    let chatProfile: ChatProfile?
 | 
			
		||||
    let message: MessageItem?
 | 
			
		||||
}
 | 
			
		||||
@ -3,7 +3,7 @@ import Combine
 | 
			
		||||
 | 
			
		||||
final class IncomingMessageCenter: ObservableObject {
 | 
			
		||||
    @Published private(set) var banner: IncomingMessageBanner?
 | 
			
		||||
    @Published var pendingDeepLink: ChatDeepLink?
 | 
			
		||||
    @Published var presentedChat: PrivateChatListItem?
 | 
			
		||||
    var currentUserId: String?
 | 
			
		||||
 | 
			
		||||
    private var dismissWorkItem: DispatchWorkItem?
 | 
			
		||||
@ -29,11 +29,7 @@ final class IncomingMessageCenter: ObservableObject {
 | 
			
		||||
 | 
			
		||||
    func openCurrentChat() {
 | 
			
		||||
        guard let banner else { return }
 | 
			
		||||
        pendingDeepLink = ChatDeepLink(
 | 
			
		||||
            chatId: banner.message.chatId,
 | 
			
		||||
            chatProfile: banner.message.senderData,
 | 
			
		||||
            message: banner.message
 | 
			
		||||
        )
 | 
			
		||||
        presentedChat = makeChatItem(from: banner.message)
 | 
			
		||||
        dismissBanner()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -85,6 +81,18 @@ final class IncomingMessageCenter: ObservableObject {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func makeChatItem(from message: MessageItem) -> PrivateChatListItem {
 | 
			
		||||
        let profile = message.senderData
 | 
			
		||||
        return PrivateChatListItem(
 | 
			
		||||
            chatId: message.chatId,
 | 
			
		||||
            chatType: .privateChat,
 | 
			
		||||
            chatData: profile,
 | 
			
		||||
            lastMessage: message,
 | 
			
		||||
            createdAt: message.createdAt,
 | 
			
		||||
            unreadCount: 0
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private func scheduleDismiss(after delay: TimeInterval = 5) {
 | 
			
		||||
        dismissWorkItem?.cancel()
 | 
			
		||||
        let workItem = DispatchWorkItem { [weak self] in
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,6 @@ import UIKit
 | 
			
		||||
 | 
			
		||||
struct ChatsTab: View {
 | 
			
		||||
    @ObservedObject private var loginViewModel: LoginViewModel
 | 
			
		||||
    @Binding private var pendingDeepLink: ChatDeepLink?
 | 
			
		||||
    @Binding var searchRevealProgress: CGFloat
 | 
			
		||||
    @Binding var searchText: String
 | 
			
		||||
    private let searchService = SearchService()
 | 
			
		||||
@ -41,12 +40,10 @@ struct ChatsTab: View {
 | 
			
		||||
 | 
			
		||||
    init(
 | 
			
		||||
        loginViewModel: LoginViewModel,
 | 
			
		||||
        pendingDeepLink: Binding<ChatDeepLink?>,
 | 
			
		||||
        searchRevealProgress: Binding<CGFloat>,
 | 
			
		||||
        searchText: Binding<String>
 | 
			
		||||
    ) {
 | 
			
		||||
        self._loginViewModel = ObservedObject(wrappedValue: loginViewModel)
 | 
			
		||||
        self._pendingDeepLink = pendingDeepLink
 | 
			
		||||
        self._searchRevealProgress = searchRevealProgress
 | 
			
		||||
        self._searchText = searchText
 | 
			
		||||
    }
 | 
			
		||||
@ -100,13 +97,6 @@ struct ChatsTab: View {
 | 
			
		||||
                globalSearchTask?.cancel()
 | 
			
		||||
                globalSearchTask = nil
 | 
			
		||||
            }
 | 
			
		||||
            .onChange(of: pendingDeepLink?.id) { _ in
 | 
			
		||||
                guard let link = pendingDeepLink else { return }
 | 
			
		||||
                handle(chatDeepLink: link)
 | 
			
		||||
                DispatchQueue.main.async {
 | 
			
		||||
                    pendingDeepLink = nil
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @ViewBuilder
 | 
			
		||||
@ -552,44 +542,6 @@ private extension ChatsTab {
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func handle(chatDeepLink: ChatDeepLink) {
 | 
			
		||||
        dismissKeyboard()
 | 
			
		||||
        if !searchText.isEmpty {
 | 
			
		||||
            searchText = ""
 | 
			
		||||
        }
 | 
			
		||||
        if searchRevealProgress > 0 {
 | 
			
		||||
            withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
 | 
			
		||||
                searchRevealProgress = 0
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let existingChat = viewModel.chats.first(where: { $0.chatId == chatDeepLink.chatId })
 | 
			
		||||
        pendingChatItem = existingChat ?? makeChatItem(from: chatDeepLink)
 | 
			
		||||
        selectedChatId = chatDeepLink.chatId
 | 
			
		||||
        isPendingChatActive = true
 | 
			
		||||
 | 
			
		||||
        if existingChat == nil {
 | 
			
		||||
            if loginViewModel.chatLoadingState != .loading {
 | 
			
		||||
                loginViewModel.chatLoadingState = .loading
 | 
			
		||||
            }
 | 
			
		||||
            viewModel.refresh()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func makeChatItem(from deepLink: ChatDeepLink) -> PrivateChatListItem {
 | 
			
		||||
        let profile = deepLink.chatProfile ?? deepLink.message?.senderData
 | 
			
		||||
        let lastMessage = deepLink.message
 | 
			
		||||
        let createdAt = deepLink.message?.createdAt
 | 
			
		||||
        return PrivateChatListItem(
 | 
			
		||||
            chatId: deepLink.chatId,
 | 
			
		||||
            chatType: .privateChat,
 | 
			
		||||
            chatData: profile,
 | 
			
		||||
            lastMessage: lastMessage,
 | 
			
		||||
            createdAt: createdAt,
 | 
			
		||||
            unreadCount: 0
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    func handleSearchQueryChange(_ query: String) {
 | 
			
		||||
        let trimmed = query.trimmingCharacters(in: .whitespacesAndNewlines)
 | 
			
		||||
 | 
			
		||||
@ -1209,12 +1161,10 @@ struct ChatsTab_Previews: PreviewProvider {
 | 
			
		||||
        @State private var progress: CGFloat = 1
 | 
			
		||||
        @State private var searchText: String = ""
 | 
			
		||||
        @StateObject private var loginViewModel = LoginViewModel()
 | 
			
		||||
        @State private var deepLink: ChatDeepLink?
 | 
			
		||||
 | 
			
		||||
        var body: some View {
 | 
			
		||||
            ChatsTab(
 | 
			
		||||
                loginViewModel: loginViewModel,
 | 
			
		||||
                pendingDeepLink: $deepLink,
 | 
			
		||||
                searchRevealProgress: $progress,
 | 
			
		||||
                searchText: $searchText
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@ import SwiftUI
 | 
			
		||||
 | 
			
		||||
struct MainView: View {
 | 
			
		||||
    @ObservedObject var viewModel: LoginViewModel
 | 
			
		||||
    @EnvironmentObject private var messageCenter: IncomingMessageCenter
 | 
			
		||||
    @State private var selectedTab: Int = 0
 | 
			
		||||
//    @StateObject private var newHomeTabViewModel = NewHomeTabViewModel()
 | 
			
		||||
    
 | 
			
		||||
@ -16,6 +15,7 @@ struct MainView: View {
 | 
			
		||||
    @State private var menuOffset: CGFloat = 0
 | 
			
		||||
    @State private var chatSearchRevealProgress: CGFloat = 0
 | 
			
		||||
    @State private var chatSearchText: String = ""
 | 
			
		||||
    @State private var isSettingsPresented = false
 | 
			
		||||
 | 
			
		||||
    private var tabTitle: String {
 | 
			
		||||
        switch selectedTab {
 | 
			
		||||
@ -42,6 +42,7 @@ struct MainView: View {
 | 
			
		||||
                            selectedAccount: $selectedAccount,
 | 
			
		||||
                            accounts: accounts,
 | 
			
		||||
                            viewModel: viewModel,
 | 
			
		||||
                            isSettingsPresented: $isSettingsPresented,
 | 
			
		||||
                            isSideMenuPresented: $isSideMenuPresented,
 | 
			
		||||
                            chatSearchRevealProgress: $chatSearchRevealProgress,
 | 
			
		||||
                            chatSearchText: $chatSearchText
 | 
			
		||||
@ -56,10 +57,6 @@ struct MainView: View {
 | 
			
		||||
 | 
			
		||||
                            ChatsTab(
 | 
			
		||||
                                loginViewModel: viewModel,
 | 
			
		||||
                                pendingDeepLink: Binding(
 | 
			
		||||
                                    get: { messageCenter.pendingDeepLink },
 | 
			
		||||
                                    set: { messageCenter.pendingDeepLink = $0 }
 | 
			
		||||
                                ),
 | 
			
		||||
                                searchRevealProgress: $chatSearchRevealProgress,
 | 
			
		||||
                                searchText: $chatSearchText
 | 
			
		||||
                            )
 | 
			
		||||
@ -140,23 +137,6 @@ struct MainView: View {
 | 
			
		||||
                menuOffset = presented ? menuWidth : 0
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .onAppear {
 | 
			
		||||
            messageCenter.currentUserId = viewModel.userId.isEmpty ? nil : viewModel.userId
 | 
			
		||||
        }
 | 
			
		||||
        .onChange(of: viewModel.userId) { newValue in
 | 
			
		||||
            messageCenter.currentUserId = newValue.isEmpty ? nil : newValue
 | 
			
		||||
        }
 | 
			
		||||
        .onChange(of: messageCenter.pendingDeepLink?.id) { _ in
 | 
			
		||||
            guard messageCenter.pendingDeepLink != nil else { return }
 | 
			
		||||
            withAnimation(.easeInOut) {
 | 
			
		||||
                selectedTab = 2
 | 
			
		||||
                isSideMenuPresented = false
 | 
			
		||||
                menuOffset = 0
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        .onDisappear {
 | 
			
		||||
            messageCenter.currentUserId = nil
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -164,7 +144,6 @@ struct MainView_Previews: PreviewProvider {
 | 
			
		||||
    static var previews: some View {
 | 
			
		||||
        let mockViewModel = LoginViewModel()
 | 
			
		||||
        MainView(viewModel: mockViewModel)
 | 
			
		||||
            .environmentObject(IncomingMessageCenter())
 | 
			
		||||
            .environmentObject(ThemeManager())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -41,10 +41,31 @@ struct yobbleApp: App {
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .animation(.spring(response: 0.35, dampingFraction: 0.8), value: messageCenter.banner != nil)
 | 
			
		||||
            .sheet(item: $messageCenter.presentedChat) { chatItem in
 | 
			
		||||
                NavigationView {
 | 
			
		||||
                    PrivateChatView(
 | 
			
		||||
                        chat: chatItem,
 | 
			
		||||
                        currentUserId: messageCenter.currentUserId
 | 
			
		||||
                    )
 | 
			
		||||
                        .toolbar {
 | 
			
		||||
                            ToolbarItem(placement: .cancellationAction) {
 | 
			
		||||
                                Button(NSLocalizedString("Закрыть", comment: "")) {
 | 
			
		||||
                                    messageCenter.presentedChat = nil
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .environmentObject(messageCenter)
 | 
			
		||||
            .environmentObject(themeManager)
 | 
			
		||||
            .preferredColorScheme(themeManager.theme.colorScheme)
 | 
			
		||||
            .environment(\.managedObjectContext, persistenceController.viewContext)
 | 
			
		||||
            .onAppear {
 | 
			
		||||
                messageCenter.currentUserId = viewModel.userId.isEmpty ? nil : viewModel.userId
 | 
			
		||||
            }
 | 
			
		||||
            .onChange(of: viewModel.userId) { newValue in
 | 
			
		||||
                messageCenter.currentUserId = newValue.isEmpty ? nil : newValue
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user