diff --git a/submodules/Postbox/Postbox/ChatListIndexTable.swift b/submodules/Postbox/Postbox/ChatListIndexTable.swift index 421e16091e..2d0c86e700 100644 --- a/submodules/Postbox/Postbox/ChatListIndexTable.swift +++ b/submodules/Postbox/Postbox/ChatListIndexTable.swift @@ -636,4 +636,36 @@ final class ChatListIndexTable: Table { return (rootState, summaries) } + + func reindexPeerGroupUnreadCounts(postbox: Postbox, groupId: PeerGroupId) -> PeerGroupUnreadCountersCombinedSummary { + var summary = PeerGroupUnreadCountersCombinedSummary(namespaces: [:]) + + postbox.chatListTable.forEachPeer(groupId: groupId, { peerId in + if peerId.namespace == Int32.max { + return + } + /*guard let peer = postbox.peerTable.get(peerId) else { + return + }*/ + guard let combinedState = postbox.readStateTable.getCombinedState(peerId) else { + return + } + /*let notificationPeerId: PeerId = peer.associatedPeerId ?? peerId + let notificationSettings = postbox.peerNotificationSettingsTable.getEffective(notificationPeerId)*/ + let inclusion = self.get(peerId: peerId) + if let (inclusionGroupId, _) = inclusion.includedIndex(peerId: peerId), inclusionGroupId == groupId { + for (namespace, state) in combinedState.states { + if summary.namespaces[namespace] == nil { + summary.namespaces[namespace] = PeerGroupUnreadCountersSummary(all: PeerGroupUnreadCounters(messageCount: 0, chatCount: 0)) + } + if state.count > 0 { + summary.namespaces[namespace]!.all.chatCount += 1 + summary.namespaces[namespace]!.all.messageCount += state.count + } + } + } + }) + + return summary + } } diff --git a/submodules/Postbox/Postbox/ChatListTable.swift b/submodules/Postbox/Postbox/ChatListTable.swift index a511e90f73..5cdd988d21 100644 --- a/submodules/Postbox/Postbox/ChatListTable.swift +++ b/submodules/Postbox/Postbox/ChatListTable.swift @@ -780,4 +780,27 @@ final class ChatListTable: Table { return lhs.index > rhs.index }) } + + func doesGroupContainHoles(groupId: PeerGroupId) -> Bool { + var result = false + self.valueBox.range(self.table, start: self.lowerBound(groupId: groupId), end: self.upperBound(groupId: groupId), keys: { key in + if extractKey(key).type == ChatListEntryType.hole.rawValue { + result = true + return false + } else { + return true + } + }, limit: 0) + return result + } + + func forEachPeer(groupId: PeerGroupId, _ f: (PeerId) -> Void) { + self.valueBox.range(self.table, start: self.lowerBound(groupId: groupId), end: self.upperBound(groupId: groupId), keys: { key in + let extracted = extractKey(key) + if extracted.type == ChatListEntryType.message.rawValue { + f(extracted.index.id.peerId) + } + return true + }, limit: 0) + } } diff --git a/submodules/Postbox/Postbox/Postbox.swift b/submodules/Postbox/Postbox/Postbox.swift index d08006c7e2..662dae3b26 100644 --- a/submodules/Postbox/Postbox/Postbox.swift +++ b/submodules/Postbox/Postbox/Postbox.swift @@ -57,6 +57,16 @@ public final class Transaction { return self.postbox?.messageHistoryHoleIndexTable.containing(id: id) ?? [:] } + public func doesChatListGroupContainHoles(groupId: PeerGroupId) -> Bool { + assert(!self.disposed) + return self.postbox?.chatListTable.doesGroupContainHoles(groupId: groupId) ?? false + } + + public func recalculateChatListGroupStats(groupId: PeerGroupId) { + assert(!self.disposed) + self.postbox?.recalculateChatListGroupStats(groupId: groupId) + } + public func replaceChatListHole(groupId: PeerGroupId, index: MessageIndex, hole: ChatListHole?) { assert(!self.disposed) self.postbox?.replaceChatListHole(groupId: groupId, index: index, hole: hole) @@ -1474,68 +1484,12 @@ public final class Postbox { self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: space, range: range, operations: &self.currentPeerHoleOperations) } - /*fileprivate func fillMultipleGroupFeedHoles(groupId: PeerGroupId, mainHoleMaxIndex: MessageIndex, fillType: HoleFill, messages: [StoreMessage]) { - let initialGroupFeedOperationsCount = self.currentGroupFeedOperations[groupId]?.count ?? 0 - self.groupFeedIndexTable.fillMultipleHoles(insertMessage: { message in - self.insertMessageInternal(message: message) - }, groupId: groupId, mainHoleMaxIndex: mainHoleMaxIndex, fillType: fillType, messages: self.messageHistoryTable.internalStoreMessages(messages), addOperation: { groupId, operation in - if self.currentGroupFeedOperations[groupId] == nil { - self.currentGroupFeedOperations[groupId] = [] - } - self.currentGroupFeedOperations[groupId]!.append(operation) - }) - - var filledMessageIndices: [MessageIndex: HoleFillDirection] = [:] - if let operations = self.currentGroupFeedOperations[groupId] { - for i in initialGroupFeedOperationsCount ..< operations.count { - switch operations[i] { - case let .insertHole(hole, _): - filledMessageIndices[hole.maxIndex] = fillType.direction - case let .insertMessage(message): - filledMessageIndices[MessageIndex(message)] = fillType.direction - default: - break - } - } - } - - if !filledMessageIndices.isEmpty { - if self.currentGroupFeedIdsWithFilledHoles[groupId] == nil { - self.currentGroupFeedIdsWithFilledHoles[groupId] = [:] - } - for (messageIndex, direction) in filledMessageIndices { - self.currentGroupFeedIdsWithFilledHoles[groupId]![messageIndex] = direction - } - } - - if self.currentRemovedHolesByPeerGroupId[groupId] == nil { - self.currentRemovedHolesByPeerGroupId[groupId] = [:] - } - self.currentRemovedHolesByPeerGroupId[groupId]![mainHoleMaxIndex] = fillType.direction + fileprivate func recalculateChatListGroupStats(groupId: PeerGroupId) { + let summary = self.chatListIndexTable.reindexPeerGroupUnreadCounts(postbox: self, groupId: groupId) + self.groupMessageStatsTable.set(groupId: groupId, summary: summary) + self.currentUpdatedGroupTotalUnreadSummaries[groupId] = summary } - fileprivate func addFeedHoleFromLatestEntries(groupId: PeerGroupId) { - self.groupFeedIndexTable.addHoleFromLatestEntries(groupId: groupId, messageHistoryTable: self.messageHistoryTable, operations: &self.currentGroupFeedOperations) - } - - fileprivate func addMessagesToGroupFeedIndex(groupId: PeerGroupId, ids: [MessageId]) { - for id in ids { - if let entry = self.messageHistoryIndexTable.getMaybeUninitialized(id), case let .Message(index) = entry { - if let message = self.messageHistoryTable.getMessage(index) { - self.groupFeedIndexTable.add(groupId: groupId, message: message, operations: &self.currentGroupFeedOperations) - } - } - } - } - - fileprivate func removeMessagesFromGroupFeedIndex(groupId: PeerGroupId, ids: [MessageId]) { - for id in ids { - if let entry = self.messageHistoryIndexTable.getMaybeUninitialized(id), case let .Message(index) = entry { - self.groupFeedIndexTable.remove(groupId: groupId, messageIndex: index, operations: &self.currentGroupFeedOperations) - } - } - }*/ - fileprivate func replaceChatListHole(groupId: PeerGroupId, index: MessageIndex, hole: ChatListHole?) { self.chatListTable.replaceHole(groupId: groupId, index: index, hole: hole, operations: &self.currentChatListOperations) } diff --git a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift index ea8f584d71..70e2b2ba2e 100644 --- a/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift +++ b/submodules/TelegramCore/TelegramCore/ManagedSynchronizeGroupMessageStats.swift @@ -72,21 +72,26 @@ func managedSynchronizeGroupMessageStats(network: Network, postbox: Postbox, sta } private func synchronizeGroupMessageStats(postbox: Postbox, network: Network, groupId: PeerGroupId, namespace: MessageId.Namespace) -> Signal { - if namespace != Namespaces.Message.Cloud || groupId == .root { - return postbox.transaction { transaction in + return postbox.transaction { transaction -> Signal in + if namespace != Namespaces.Message.Cloud || groupId == .root { transaction.confirmSynchronizedPeerGroupMessageStats(groupId: groupId, namespace: namespace) + return .complete() + } + + if !transaction.doesChatListGroupContainHoles(groupId: groupId) { + transaction.recalculateChatListGroupStats(groupId: groupId) + return .complete() } - } - return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeerFolder(folderId: groupId.rawValue)])) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal in - return postbox.transaction { transaction in - if let result = result { - switch result { + return network.request(Api.functions.messages.getPeerDialogs(peers: [.inputDialogPeerFolder(folderId: groupId.rawValue)])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return postbox.transaction { transaction in + if let result = result { + switch result { case let .peerDialogs(peerDialogs): for dialog in peerDialogs.dialogs { switch dialog { @@ -97,9 +102,11 @@ private func synchronizeGroupMessageStats(postbox: Postbox, network: Network, gr break } } + } } + transaction.confirmSynchronizedPeerGroupMessageStats(groupId: groupId, namespace: namespace) } - transaction.confirmSynchronizedPeerGroupMessageStats(groupId: groupId, namespace: namespace) } } + |> switchToLatest }