Compare commits
No commits in common. "6d8b322688fc33ce7d93ce2ee63fcd749afbdfbb" and "1bc4dda14cdd40a9098886e4a9b57101eb7b56e9" have entirely different histories.
6d8b322688
...
1bc4dda14c
@ -1,11 +1,6 @@
|
||||
import Foundation
|
||||
import Combine
|
||||
|
||||
struct ChatNavigationTarget: Identifiable {
|
||||
let id = UUID()
|
||||
let chat: PrivateChatListItem
|
||||
}
|
||||
|
||||
final class IncomingMessageCenter: ObservableObject {
|
||||
@Published private(set) var banner: IncomingMessageBanner?
|
||||
@Published var presentedChat: PrivateChatListItem?
|
||||
@ -127,4 +122,9 @@ final class IncomingMessageCenter: ObservableObject {
|
||||
dismissWorkItem = workItem
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: workItem)
|
||||
}
|
||||
|
||||
struct ChatNavigationTarget: Identifiable {
|
||||
let id = UUID()
|
||||
let chat: PrivateChatListItem
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import UIKit
|
||||
|
||||
struct ChatsTab: View {
|
||||
@ObservedObject private var loginViewModel: LoginViewModel
|
||||
@Binding private var pendingNavigation: IncomingMessageCenter.ChatNavigationTarget?
|
||||
@Binding var searchRevealProgress: CGFloat
|
||||
@Binding var searchText: String
|
||||
private let searchService = SearchService()
|
||||
@ -40,10 +41,12 @@ struct ChatsTab: View {
|
||||
|
||||
init(
|
||||
loginViewModel: LoginViewModel,
|
||||
pendingNavigation: Binding<IncomingMessageCenter.ChatNavigationTarget?>,
|
||||
searchRevealProgress: Binding<CGFloat>,
|
||||
searchText: Binding<String>
|
||||
) {
|
||||
self._loginViewModel = ObservedObject(wrappedValue: loginViewModel)
|
||||
self._pendingNavigation = pendingNavigation
|
||||
self._searchRevealProgress = searchRevealProgress
|
||||
self._searchText = searchText
|
||||
}
|
||||
@ -97,6 +100,13 @@ struct ChatsTab: View {
|
||||
globalSearchTask?.cancel()
|
||||
globalSearchTask = nil
|
||||
}
|
||||
.onChange(of: pendingNavigation?.id) { _ in
|
||||
guard let target = pendingNavigation else { return }
|
||||
handleNavigationTarget(target.chat)
|
||||
DispatchQueue.main.async {
|
||||
pendingNavigation = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
@ -542,6 +552,30 @@ private extension ChatsTab {
|
||||
#endif
|
||||
}
|
||||
|
||||
func handleNavigationTarget(_ chatItem: PrivateChatListItem) {
|
||||
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 == chatItem.chatId })
|
||||
pendingChatItem = existingChat ?? chatItem
|
||||
selectedChatId = chatItem.chatId
|
||||
isPendingChatActive = true
|
||||
|
||||
if existingChat == nil {
|
||||
if loginViewModel.chatLoadingState != .loading {
|
||||
loginViewModel.chatLoadingState = .loading
|
||||
}
|
||||
viewModel.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
func handleSearchQueryChange(_ query: String) {
|
||||
let trimmed = query.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
@ -1161,10 +1195,12 @@ struct ChatsTab_Previews: PreviewProvider {
|
||||
@State private var progress: CGFloat = 1
|
||||
@State private var searchText: String = ""
|
||||
@StateObject private var loginViewModel = LoginViewModel()
|
||||
@State private var pendingNavigation: IncomingMessageCenter.ChatNavigationTarget?
|
||||
|
||||
var body: some View {
|
||||
ChatsTab(
|
||||
loginViewModel: loginViewModel,
|
||||
pendingNavigation: $pendingNavigation,
|
||||
searchRevealProgress: $progress,
|
||||
searchText: $searchText
|
||||
)
|
||||
|
||||
@ -17,8 +17,6 @@ struct MainView: View {
|
||||
@State private var chatSearchRevealProgress: CGFloat = 0
|
||||
@State private var chatSearchText: String = ""
|
||||
@State private var isSettingsPresented = false
|
||||
@State private var deepLinkChatItem: PrivateChatListItem?
|
||||
@State private var isDeepLinkChatActive = false
|
||||
|
||||
private var tabTitle: String {
|
||||
switch selectedTab {
|
||||
@ -36,6 +34,12 @@ struct MainView: View {
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
let pendingNavigationBinding: Binding<IncomingMessageCenter.ChatNavigationTarget?> = AppConfig.PRESENT_CHAT_AS_SHEET
|
||||
? .constant(nil)
|
||||
: Binding(
|
||||
get: { messageCenter.pendingNavigation },
|
||||
set: { messageCenter.pendingNavigation = $0 }
|
||||
)
|
||||
ZStack(alignment: .top) {
|
||||
ZStack(alignment: .leading) { // Выравниваем ZStack по левому краю
|
||||
// Основной контент
|
||||
@ -60,6 +64,7 @@ struct MainView: View {
|
||||
|
||||
ChatsTab(
|
||||
loginViewModel: viewModel,
|
||||
pendingNavigation: pendingNavigationBinding,
|
||||
searchRevealProgress: $chatSearchRevealProgress,
|
||||
searchText: $chatSearchText
|
||||
)
|
||||
@ -99,8 +104,6 @@ struct MainView: View {
|
||||
.offset(x: -menuWidth + menuOffset) // Новая логика смещения
|
||||
.ignoresSafeArea(edges: .vertical)
|
||||
}
|
||||
|
||||
deepLinkNavigationLink
|
||||
}
|
||||
.gesture(
|
||||
DragGesture()
|
||||
@ -144,25 +147,12 @@ struct MainView: View {
|
||||
}
|
||||
.onChange(of: messageCenter.pendingNavigation?.id) { _ in
|
||||
guard !AppConfig.PRESENT_CHAT_AS_SHEET,
|
||||
let target = messageCenter.pendingNavigation else { return }
|
||||
messageCenter.pendingNavigation != nil else { return }
|
||||
withAnimation(.easeInOut) {
|
||||
selectedTab = 2
|
||||
isSideMenuPresented = false
|
||||
menuOffset = 0
|
||||
}
|
||||
if !chatSearchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
chatSearchText = ""
|
||||
}
|
||||
if chatSearchRevealProgress > 0 {
|
||||
withAnimation(.spring(response: 0.35, dampingFraction: 0.75)) {
|
||||
chatSearchRevealProgress = 0
|
||||
}
|
||||
}
|
||||
deepLinkChatItem = target.chat
|
||||
isDeepLinkChatActive = true
|
||||
NotificationCenter.default.post(name: .chatsShouldRefresh, object: nil)
|
||||
DispatchQueue.main.async {
|
||||
messageCenter.pendingNavigation = nil
|
||||
}
|
||||
}
|
||||
.onChange(of: selectedTab) { newValue in
|
||||
if newValue != 3 {
|
||||
@ -172,39 +162,6 @@ struct MainView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private extension MainView {
|
||||
var deepLinkNavigationLink: some View {
|
||||
NavigationLink(
|
||||
destination: deepLinkChatDestination,
|
||||
isActive: Binding(
|
||||
get: { isDeepLinkChatActive && deepLinkChatItem != nil },
|
||||
set: { newValue in
|
||||
if !newValue {
|
||||
isDeepLinkChatActive = false
|
||||
deepLinkChatItem = nil
|
||||
}
|
||||
}
|
||||
)
|
||||
) {
|
||||
EmptyView()
|
||||
}
|
||||
.hidden()
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
var deepLinkChatDestination: some View {
|
||||
if let chatItem = deepLinkChatItem {
|
||||
PrivateChatView(
|
||||
chat: chatItem,
|
||||
currentUserId: messageCenter.currentUserId
|
||||
)
|
||||
.id(chatItem.chatId)
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct MainView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
let mockViewModel = LoginViewModel()
|
||||
|
||||
@ -14,7 +14,7 @@ struct AppConfig {
|
||||
|
||||
static let DISABLE_DB = false
|
||||
/// Controls whether incoming chat opens as a modal sheet (`true`) or navigates to Chats tab (`false`).
|
||||
static let PRESENT_CHAT_AS_SHEET = false
|
||||
static let PRESENT_CHAT_AS_SHEET = true
|
||||
/// Fallback SQLCipher key used until the user sets an application password.
|
||||
static let DEFAULT_DATABASE_ENCRYPTION_KEY = "yobble_dev_change_me"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user