From ed91efacf5cedade09f92cc27a408cf17f533b67 Mon Sep 17 00:00:00 2001 From: cheykrym Date: Tue, 21 Oct 2025 20:26:20 +0300 Subject: [PATCH] open chat everywhere --- yobble/Components/TopBarView.swift | 7 ++- yobble/Models/ChatDeepLink.swift | 8 ---- yobble/Services/IncomingMessageCenter.swift | 20 ++++++--- yobble/Views/Tab/ChatsTab.swift | 50 --------------------- yobble/Views/Tab/MainView.swift | 25 +---------- yobble/yobbleApp.swift | 21 +++++++++ 6 files changed, 43 insertions(+), 88 deletions(-) delete mode 100644 yobble/Models/ChatDeepLink.swift diff --git a/yobble/Components/TopBarView.swift b/yobble/Components/TopBarView.swift index 35e96fa..e3bbaa0 100644 --- a/yobble/Components/TopBarView.swift +++ b/yobble/Components/TopBarView.swift @@ -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 diff --git a/yobble/Models/ChatDeepLink.swift b/yobble/Models/ChatDeepLink.swift deleted file mode 100644 index 07a0d46..0000000 --- a/yobble/Models/ChatDeepLink.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation - -struct ChatDeepLink: Identifiable { - let id = UUID() - let chatId: String - let chatProfile: ChatProfile? - let message: MessageItem? -} diff --git a/yobble/Services/IncomingMessageCenter.swift b/yobble/Services/IncomingMessageCenter.swift index bbff503..3451cc8 100644 --- a/yobble/Services/IncomingMessageCenter.swift +++ b/yobble/Services/IncomingMessageCenter.swift @@ -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 diff --git a/yobble/Views/Tab/ChatsTab.swift b/yobble/Views/Tab/ChatsTab.swift index 76a8439..b71710d 100644 --- a/yobble/Views/Tab/ChatsTab.swift +++ b/yobble/Views/Tab/ChatsTab.swift @@ -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, searchRevealProgress: Binding, searchText: Binding ) { 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 ) diff --git a/yobble/Views/Tab/MainView.swift b/yobble/Views/Tab/MainView.swift index fda2be4..e35a3cd 100644 --- a/yobble/Views/Tab/MainView.swift +++ b/yobble/Views/Tab/MainView.swift @@ -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()) } } diff --git a/yobble/yobbleApp.swift b/yobble/yobbleApp.swift index cb6d308..6b253b5 100644 --- a/yobble/yobbleApp.swift +++ b/yobble/yobbleApp.swift @@ -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 + } } } }