diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index 51c9f102b7..d973ada34e 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -336,15 +336,7 @@ final class ChatModel: ObservableObject { chats[i].chatStats.unreadCount = chats[i].chatStats.unreadCount + 1 increaseUnreadCounter(user: currentUser!) } - if i > 0 { - if chatId == nil { - withAnimation { popChat_(i) } - } else if chatId == cInfo.id { - chatToTop = cInfo.id - } else { - popChat_(i) - } - } + popChatCollector.addChat(cInfo.id) } else { addChat(Chat(chatInfo: cInfo, chatItems: [cItem])) } @@ -572,14 +564,13 @@ final class ChatModel: ObservableObject { func markChatItemRead(_ cInfo: ChatInfo, _ cItem: ChatItem) async { if chatId == cInfo.id, let itemIndex = getChatItemIndex(cItem), - let chatIndex = getChatIndex(cInfo.id), im.reversedChatItems[itemIndex].isRcvNew { await MainActor.run { withTransaction(Transaction()) { // update current chat markChatItemRead_(itemIndex) // update preview - unreadCollector.decreaseUnreadCounter(chatIndex) + unreadCollector.decreaseUnreadCounter(cInfo.id) } } } @@ -588,26 +579,59 @@ final class ChatModel: ObservableObject { private let unreadCollector = UnreadCollector() class UnreadCollector { - private let subject = PassthroughSubject() + private let subject = PassthroughSubject() private var bag = Set() - private var dictionary = Dictionary() + private var unreadCounts: [ChatId: Int] = [:] init() { subject .debounce(for: 1, scheduler: DispatchQueue.main) - .sink { _ in - self.dictionary.forEach { key, value in - ChatModel.shared.decreaseUnreadCounter(key, by: value) + .sink { + let m = ChatModel.shared + for (chatId, count) in self.unreadCounts { + if let i = m.getChatIndex(chatId) { + m.decreaseUnreadCounter(i, by: count) + } } - self.dictionary = Dictionary() + self.unreadCounts = [:] } .store(in: &bag) } // Only call from main thread - func decreaseUnreadCounter(_ chatIndex: Int) { - dictionary[chatIndex] = (dictionary[chatIndex] ?? 0) + 1 - subject.send(chatIndex) + func decreaseUnreadCounter(_ chatId: ChatId) { + unreadCounts[chatId] = (unreadCounts[chatId] ?? 0) + 1 + subject.send() + } + } + + let popChatCollector = PopChatCollector() + + class PopChatCollector { + private let subject = PassthroughSubject() + private var bag = Set() + + init() { + subject + .throttle(for: 2, scheduler: DispatchQueue.main, latest: true) + .sink { + let m = ChatModel.shared + if m.chatId == nil { + withAnimation { + m.chats = m.chats.sorted(using: KeyPathComparator(\.popTs, order: .reverse)) + } + } else { + m.chats = m.chats.sorted(using: KeyPathComparator(\.popTs, order: .reverse)) + } + } + .store(in: &bag) + } + + func addChat(_ chatId: ChatId) { + if let index = ChatModel.shared.getChatIndex(chatId) { + ChatModel.shared.chats[index].popTs = CFAbsoluteTimeGetCurrent() + subject.send() + } } } @@ -825,6 +849,7 @@ final class Chat: ObservableObject, Identifiable, ChatLike { @Published var chatItems: [ChatItem] @Published var chatStats: ChatStats var created = Date.now + var popTs: CFAbsoluteTime? init(_ cData: ChatData) { self.chatInfo = cData.chatInfo diff --git a/apps/ios/Shared/Views/ChatList/ChatListView.swift b/apps/ios/Shared/Views/ChatList/ChatListView.swift index 82d322d6fd..dfaaf1f192 100644 --- a/apps/ios/Shared/Views/ChatList/ChatListView.swift +++ b/apps/ios/Shared/Views/ChatList/ChatListView.swift @@ -158,8 +158,8 @@ struct ChatListView: View { .offset(x: -8) } } - .onChange(of: chatModel.chatId) { _ in - if chatModel.chatId == nil, let chatId = chatModel.chatToTop { + .onChange(of: chatModel.chatId) { chId in + if chId == nil, let chatId = chatModel.chatToTop { chatModel.chatToTop = nil chatModel.popChat(chatId) }