diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift index a5ac5daeae..68b01c664c 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeLocation.swift @@ -36,18 +36,23 @@ func chatListFilterPredicate(filter: ChatListFilterData) -> ChatListFilterPredic if !filter.excludeArchived { includeAdditionalPeerGroupIds.append(Namespaces.PeerGroup.archive) } - return ChatListFilterPredicate(includePeerIds: includePeers, excludePeerIds: excludePeers, includeAdditionalPeerGroupIds: includeAdditionalPeerGroupIds, include: { peer, notificationSettings, isUnread, isContact in + + var messageTagSummary: ChatListMessageTagSummaryResultCalculation? + if filter.excludeRead { + messageTagSummary = ChatListMessageTagSummaryResultCalculation(addCount: ChatListMessageTagSummaryResultComponent(tag: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud), subtractCount: ChatListMessageTagActionsSummaryResultComponent(type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud)) + } + return ChatListFilterPredicate(includePeerIds: includePeers, excludePeerIds: excludePeers, messageTagSummary: messageTagSummary, includeAdditionalPeerGroupIds: includeAdditionalPeerGroupIds, include: { peer, isMuted, isUnread, isContact, messageTagSummaryResult in if filter.excludeRead { - if !isUnread { + var effectiveUnread = isUnread + if let messageTagSummaryResult = messageTagSummaryResult, messageTagSummaryResult { + effectiveUnread = true + } + if !effectiveUnread { return false } } if filter.excludeMuted { - if let notificationSettings = notificationSettings as? TelegramPeerNotificationSettings { - if case .muted = notificationSettings.muteState { - return false - } - } else { + if isMuted { return false } } diff --git a/submodules/Postbox/Sources/ChatListTable.swift b/submodules/Postbox/Sources/ChatListTable.swift index 0b9620ad32..6996f19a9b 100644 --- a/submodules/Postbox/Sources/ChatListTable.swift +++ b/submodules/Postbox/Sources/ChatListTable.swift @@ -260,7 +260,9 @@ final class ChatListTable: Table { let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(messageIndex.id.peerId)) - if filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact) { + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: filterPredicate.messageTagSummary) + + if filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) { passFilter = true } else { passFilter = false diff --git a/submodules/Postbox/Sources/ChatListView.swift b/submodules/Postbox/Sources/ChatListView.swift index f83745e42d..6d7880a4cc 100644 --- a/submodules/Postbox/Sources/ChatListView.swift +++ b/submodules/Postbox/Sources/ChatListView.swift @@ -253,17 +253,19 @@ private enum ChatListEntryType { public struct ChatListFilterPredicate { public var includePeerIds: Set public var excludePeerIds: Set + public var messageTagSummary: ChatListMessageTagSummaryResultCalculation? public var includeAdditionalPeerGroupIds: [PeerGroupId] - public var include: (Peer, Bool, Bool, Bool) -> Bool + public var include: (Peer, Bool, Bool, Bool, Bool?) -> Bool - public init(includePeerIds: Set, excludePeerIds: Set, includeAdditionalPeerGroupIds: [PeerGroupId], include: @escaping (Peer, Bool, Bool, Bool) -> Bool) { + public init(includePeerIds: Set, excludePeerIds: Set, messageTagSummary: ChatListMessageTagSummaryResultCalculation?, includeAdditionalPeerGroupIds: [PeerGroupId], include: @escaping (Peer, Bool, Bool, Bool, Bool?) -> Bool) { self.includePeerIds = includePeerIds self.excludePeerIds = excludePeerIds + self.messageTagSummary = messageTagSummary self.includeAdditionalPeerGroupIds = includeAdditionalPeerGroupIds self.include = include } - func includes(peer: Peer, groupId: PeerGroupId, isRemovedFromTotalUnreadCount: Bool, isUnread: Bool, isContact: Bool) -> Bool { + func includes(peer: Peer, groupId: PeerGroupId, isRemovedFromTotalUnreadCount: Bool, isUnread: Bool, isContact: Bool, messageTagSummaryResult: Bool?) -> Bool { let includePeerId = peer.associatedPeerId ?? peer.id if self.excludePeerIds.contains(includePeerId) { return false @@ -276,7 +278,7 @@ public struct ChatListFilterPredicate { return false } } - return self.include(peer, isRemovedFromTotalUnreadCount, isUnread, isContact) + return self.include(peer, isRemovedFromTotalUnreadCount, isUnread, isContact, messageTagSummaryResult) } } @@ -420,7 +422,7 @@ final class MutableChatListView { func replay(postbox: Postbox, operations: [PeerGroupId: [ChatListOperation]], updatedPeerNotificationSettings: [PeerId: (PeerNotificationSettings?, PeerNotificationSettings)], updatedPeers: [PeerId: Peer], updatedPeerPresences: [PeerId: PeerPresence], transaction: PostboxTransaction, context: MutableChatListViewReplayContext) -> Bool { var hasChanges = false - if transaction.updatedGlobalNotificationSettings { + if transaction.updatedGlobalNotificationSettings && self.filterPredicate != nil { self.state = ChatListViewState(postbox: postbox, spaces: self.spaces, anchorIndex: .absoluteUpperBound, filterPredicate: self.filterPredicate, summaryComponents: self.summaryComponents, halfLimit: self.count) self.sampledState = self.state.sample(postbox: postbox) hasChanges = true @@ -630,53 +632,7 @@ public final class ChatListView { assertionFailure() } } - /*if !mutableView.additionalMixedItemEntries.isEmpty || !mutableView.additionalMixedPinnedEntries.isEmpty { - var existingIds = Set() - for entry in entries { - if case let .MessageEntry(messageEntry) = entry { - existingIds.insert(messageEntry.0.messageIndex.id.peerId) - } - } - for entry in mutableView.additionalMixedItemEntries { - if case let .MessageEntry(messageEntry) = entry { - if !existingIds.contains(messageEntry.0.messageIndex.id.peerId) { - switch entry { - case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact): - if let filterPredicate = mutableView.filterPredicate, let peerValue = peer.peer { - if filterPredicate.includes(peer: peerValue, notificationSettings: notificationSettings, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, isArchived: true) { - existingIds.insert(messageEntry.0.messageIndex.id.peerId) - entries.append(.MessageEntry(ChatListIndex(pinningIndex: nil, messageIndex: index.messageIndex), message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact)) - } - } - case let .HoleEntry(hole): - entries.append(.HoleEntry(hole)) - case .IntermediateMessageEntry: - assertionFailure() - } - } - } - } - for entry in mutableView.additionalMixedPinnedEntries { - if case let .MessageEntry(messageEntry) = entry { - if !existingIds.contains(messageEntry.0.messageIndex.id.peerId) { - switch entry { - case let .MessageEntry(index, message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact): - if let filterPredicate = mutableView.filterPredicate, let peerValue = peer.peer { - if filterPredicate.includes(peer: peerValue, notificationSettings: notificationSettings, isUnread: combinedReadState?.isUnread ?? false, isContact: isContact, isArchived: false) { - existingIds.insert(messageEntry.0.messageIndex.id.peerId) - entries.append(.MessageEntry(ChatListIndex(pinningIndex: nil, messageIndex: index.messageIndex), message, combinedReadState, notificationSettings, embeddedState, peer, peerPresence, summaryInfo, hasFailed, isContact)) - } - } - case let .HoleEntry(hole): - entries.append(.HoleEntry(hole)) - case .IntermediateMessageEntry: - assertionFailure() - } - } - } - } - entries.sort() - }*/ + self.entries = entries self.earlierIndex = mutableView.sampledState.lower?.index self.laterIndex = mutableView.sampledState.upper?.index diff --git a/submodules/Postbox/Sources/ChatListViewState.swift b/submodules/Postbox/Sources/ChatListViewState.swift index 0e2502063e..c280881455 100644 --- a/submodules/Postbox/Sources/ChatListViewState.swift +++ b/submodules/Postbox/Sources/ChatListViewState.swift @@ -28,8 +28,9 @@ private func mappedChatListFilterPredicate(postbox: Postbox, groupId: PeerGroupI let notificationsPeerId = peer.notificationSettingsPeerId ?? peer.id let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId) let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId)) + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: predicate.messageTagSummary) - if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact) { + if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) { return true } else { return false @@ -244,7 +245,9 @@ private final class ChatListViewSpaceState { let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId)) - if !filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: postbox.readStateTable.getCombinedState(peer.id)?.isUnread ?? false, isContact: postbox.contactsTable.isContact(peerId: notificationsPeerId)) { + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: filterPredicate.messageTagSummary) + + if !filterPredicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: postbox.readStateTable.getCombinedState(peer.id)?.isUnread ?? false, isContact: postbox.contactsTable.isContact(peerId: notificationsPeerId), messageTagSummaryResult: messageTagSummaryResult) { continue inner } } else { @@ -323,15 +326,13 @@ private final class ChatListViewSpaceState { globalNotificationSettings = globalNotificationSettingsValue } - let wasRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: settingsChange.0) let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: settingsChange.1) - let wasIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: wasRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId)) - let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId)) - if wasIncluded != isIncluded { - if !isIncluded { - removeEntryIndices.append(entry.entryIndex) - } + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, calculation: filterPredicate.messageTagSummary) + + let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult) + if !isIncluded { + removeEntryIndices.append(entry.entryIndex) } } return nil @@ -363,26 +364,24 @@ private final class ChatListViewSpaceState { globalNotificationSettings = globalNotificationSettingsValue } - let wasRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: settingsChange.0) let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: settingsChange.1) - let wasIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: wasRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId)) - let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId)) - if wasIncluded != isIncluded { - if isIncluded { - for peer in peers { - let tableEntry = postbox.chatListTable.getEntry(groupId: groupId, peerId: peer.id, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) - if let entry = tableEntry { - if pinned.include == (entry.index.pinningIndex != nil) { - if self.orderedEntries.indicesForPeerId(peer.id) == nil { - switch entry { - case let .message(index, messageIndex): - if self.add(entry: .IntermediateMessageEntry(index: index, messageIndex: messageIndex)) { - hasUpdates = true - } - default: - break + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, calculation: filterPredicate.messageTagSummary) + + let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId), messageTagSummaryResult: messageTagSummaryResult) + if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil { + for peer in peers { + let tableEntry = postbox.chatListTable.getEntry(groupId: groupId, peerId: peer.id, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) + if let entry = tableEntry { + if pinned.include == (entry.index.pinningIndex != nil) { + if self.orderedEntries.indicesForPeerId(peer.id) == nil { + switch entry { + case let .message(index, messageIndex): + if self.add(entry: .IntermediateMessageEntry(index: index, messageIndex: messageIndex)) { + hasUpdates = true } + default: + break } } } @@ -480,6 +479,117 @@ private final class ChatListViewSpaceState { } } + if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty, let filterPredicate = self.filterPredicate, let filterMessageTagSummary = filterPredicate.messageTagSummary, case let .group(groupId, pinned) = self.space { + var removeEntryIndices: [MutableChatListEntryIndex] = [] + let _ = self.orderedEntries.mutableScan { entry in + let entryPeer: Peer + let entryNotificationsPeerId: PeerId + switch entry { + case let .MessageEntry(messageEntry): + if let peer = messageEntry.renderedPeer.peer { + entryPeer = peer + entryNotificationsPeerId = peer.notificationSettingsPeerId ?? peer.id + } else { + return nil + } + case let .IntermediateMessageEntry(intermediateMessageEntry): + if let peer = postbox.peerTable.get(intermediateMessageEntry.index.messageIndex.id.peerId) { + entryPeer = peer + entryNotificationsPeerId = peer.notificationSettingsPeerId ?? peer.id + } else { + return nil + } + case .HoleEntry: + return nil + } + + let updatedMessageSummary = transaction.currentUpdatedMessageTagSummaries[MessageHistoryTagsSummaryKey(tag: filterMessageTagSummary.addCount.tag, peerId: entryPeer.id, namespace: filterMessageTagSummary.addCount.namespace)] + let updatedActionsSummary = transaction.currentUpdatedMessageActionsSummaries[PendingMessageActionsSummaryKey(type: filterMessageTagSummary.subtractCount.type, peerId: entryPeer.id, namespace: filterMessageTagSummary.subtractCount.namespace)] + + if updatedMessageSummary != nil || updatedActionsSummary != nil { + let isUnread = postbox.readStateTable.getCombinedState(entryPeer.id)?.isUnread ?? false + + let globalNotificationSettingsValue: PostboxGlobalNotificationSettings + if let current = globalNotificationSettings { + globalNotificationSettingsValue = current + } else { + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettings = globalNotificationSettingsValue + } + + let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: entryPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(entryPeer.id)) + + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: entryPeer.id, calculation: filterPredicate.messageTagSummary) + + let isIncluded = filterPredicate.includes(peer: entryPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: entryNotificationsPeerId), messageTagSummaryResult: messageTagSummaryResult) + if !isIncluded { + removeEntryIndices.append(entry.entryIndex) + } + } + return nil + } + if !removeEntryIndices.isEmpty { + hasUpdates = true + hadRemovals = true + for index in removeEntryIndices { + let _ = self.orderedEntries.remove(index: index) + } + } + var changedPeerIds = Set() + for key in transaction.currentUpdatedMessageTagSummaries.keys { + changedPeerIds.insert(key.peerId) + } + for key in transaction.currentUpdatedMessageTagSummaries.keys { + changedPeerIds.insert(key.peerId) + } + for peerId in changedPeerIds { + if let mainPeer = postbox.peerTable.get(peerId) { + var peers: [Peer] = [mainPeer] + for associatedId in postbox.reverseAssociatedPeerTable.get(peerId: mainPeer.id) { + if let associatedPeer = postbox.peerTable.get(associatedId) { + peers.append(associatedPeer) + } + } + assert(Set(peers.map { $0.id }).count == peers.count) + + let isUnread = postbox.readStateTable.getCombinedState(peerId)?.isUnread ?? false + + let globalNotificationSettingsValue: PostboxGlobalNotificationSettings + if let current = globalNotificationSettings { + globalNotificationSettingsValue = current + } else { + globalNotificationSettingsValue = postbox.getGlobalNotificationSettings() + globalNotificationSettings = globalNotificationSettingsValue + } + + let nowRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettingsValue, peer: mainPeer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(mainPeer.id)) + + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peerId, calculation: filterPredicate.messageTagSummary) + + let isIncluded = filterPredicate.includes(peer: mainPeer, groupId: groupId, isRemovedFromTotalUnreadCount: nowRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: postbox.contactsTable.isContact(peerId: peerId), messageTagSummaryResult: messageTagSummaryResult) + if isIncluded && self.orderedEntries.indicesForPeerId(mainPeer.id) == nil { + for peer in peers { + let tableEntry = postbox.chatListTable.getEntry(groupId: groupId, peerId: peer.id, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable) + if let entry = tableEntry { + if pinned.include == (entry.index.pinningIndex != nil) { + if self.orderedEntries.indicesForPeerId(peer.id) == nil { + switch entry { + case let .message(index, messageIndex): + if self.add(entry: .IntermediateMessageEntry(index: index, messageIndex: messageIndex)) { + hasUpdates = true + } + default: + break + } + } + } + } + } + } + } + } + } + if !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageActionsSummaries.isEmpty { if self.orderedEntries.mutableScan({ entry in switch entry { diff --git a/submodules/Postbox/Sources/Postbox.swift b/submodules/Postbox/Sources/Postbox.swift index 2d5d06ff88..16d2f01690 100644 --- a/submodules/Postbox/Sources/Postbox.swift +++ b/submodules/Postbox/Sources/Postbox.swift @@ -795,8 +795,9 @@ public final class Transaction { let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId let isContact = postbox.contactsTable.isContact(peerId: notificationsPeerId) let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: postbox.peerNotificationSettingsTable.getEffective(notificationsPeerId)) + let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: postbox, peerId: peer.id, calculation: predicate.messageTagSummary) - if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact) { + if predicate.includes(peer: peer, groupId: groupId, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) { includedPeerIds[peer.id] = true return true } else { @@ -921,6 +922,11 @@ public final class Transaction { self.postbox?.replaceMessageTagSummary(peerId: peerId, tagMask: tagMask, namespace: namespace, count: count, maxId: maxId) } + public func getPendingMessageActionsSummary(peerId: PeerId, type: PendingMessageActionType, namespace: MessageId.Namespace) -> Int32? { + assert(!self.disposed) + return self.postbox?.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, namespace, type)) + } + public func getMessageIndicesWithTag(peerId: PeerId, namespace: MessageId.Namespace, tag: MessageTags) -> [MessageIndex] { assert(!self.disposed) guard let postbox = self.postbox else { diff --git a/submodules/Postbox/Sources/SeedConfiguration.swift b/submodules/Postbox/Sources/SeedConfiguration.swift index a0eb801070..751c4d858b 100644 --- a/submodules/Postbox/Sources/SeedConfiguration.swift +++ b/submodules/Postbox/Sources/SeedConfiguration.swift @@ -10,6 +10,51 @@ public struct GlobalMessageIdsNamespace: Hashable { } } +public struct ChatListMessageTagSummaryResultComponent { + public let tag: MessageTags + public let namespace: MessageId.Namespace + + public init(tag: MessageTags, namespace: MessageId.Namespace) { + self.tag = tag + self.namespace = namespace + } +} + +public struct ChatListMessageTagActionsSummaryResultComponent { + public let type: PendingMessageActionType + public let namespace: MessageId.Namespace + + public init(type: PendingMessageActionType, namespace: MessageId.Namespace) { + self.type = type + self.namespace = namespace + } +} + +public struct ChatListMessageTagSummaryResultCalculation { + public let addCount: ChatListMessageTagSummaryResultComponent + public let subtractCount: ChatListMessageTagActionsSummaryResultComponent + + public init(addCount: ChatListMessageTagSummaryResultComponent, subtractCount: ChatListMessageTagActionsSummaryResultComponent) { + self.addCount = addCount + self.subtractCount = subtractCount + } +} + +func resolveChatListMessageTagSummaryResultCalculation(addSummary: MessageHistoryTagNamespaceSummary?, subtractSummary: Int32?) -> Bool? { + let count = (addSummary?.count ?? 0) - (subtractSummary ?? 0) + return count > 0 +} + +func resolveChatListMessageTagSummaryResultCalculation(postbox: Postbox, peerId: PeerId, calculation: ChatListMessageTagSummaryResultCalculation?) -> Bool? { + guard let calculation = calculation else { + return nil + } + let addSummary = postbox.messageHistoryTagsSummaryTable.get(MessageHistoryTagsSummaryKey(tag: calculation.addCount.tag, peerId: peerId, namespace: calculation.addCount.namespace)) + let subtractSummary = postbox.pendingMessageActionsMetadataTable.getCount(.peerNamespaceAction(peerId, calculation.subtractCount.namespace, calculation.subtractCount.type)) + let count = (addSummary?.count ?? 0) - subtractSummary + return count > 0 +} + public final class SeedConfiguration { public let globalMessageIdsPeerIdNamespaces: Set public let initializeChatListWithHole: (topLevel: ChatListHole?, groups: ChatListHole?) diff --git a/submodules/Postbox/Sources/ViewTracker.swift b/submodules/Postbox/Sources/ViewTracker.swift index 1b92f90044..14483b6760 100644 --- a/submodules/Postbox/Sources/ViewTracker.swift +++ b/submodules/Postbox/Sources/ViewTracker.swift @@ -351,22 +351,19 @@ final class ViewTracker { } } - if !transaction.chatListOperations.isEmpty || !transaction.currentUpdatedPeerNotificationSettings.isEmpty || !transaction.currentUpdatedPeers.isEmpty || !transaction.currentInvalidateMessageTagSummaries.isEmpty || !transaction.currentUpdatedMessageTagSummaries.isEmpty || !transaction.currentOperationsByPeerId.isEmpty || transaction.replacedAdditionalChatListItems != nil || !transaction.currentUpdatedPeerPresences.isEmpty || - !transaction.updatedFailedMessagePeerIds.isEmpty { - for (mutableView, pipe) in self.chatListViews.copyItems() { - let context = MutableChatListViewReplayContext() - if mutableView.replay(postbox: postbox, operations: transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, updatedPeerPresences: transaction.currentUpdatedPeerPresences, transaction: transaction, context: context) { - mutableView.complete(postbox: postbox, context: context) - mutableView.render(postbox: postbox, renderMessage: self.renderMessage, getPeer: { id in - return self.getPeer(id) - }, getPeerNotificationSettings: self.getPeerNotificationSettings, getPeerPresence: self.getPeerPresence) - pipe.putNext((ChatListView(mutableView), .Generic)) - } + for (mutableView, pipe) in self.chatListViews.copyItems() { + let context = MutableChatListViewReplayContext() + if mutableView.replay(postbox: postbox, operations: transaction.chatListOperations, updatedPeerNotificationSettings: transaction.currentUpdatedPeerNotificationSettings, updatedPeers: transaction.currentUpdatedPeers, updatedPeerPresences: transaction.currentUpdatedPeerPresences, transaction: transaction, context: context) { + mutableView.complete(postbox: postbox, context: context) + mutableView.render(postbox: postbox, renderMessage: self.renderMessage, getPeer: { id in + return self.getPeer(id) + }, getPeerNotificationSettings: self.getPeerNotificationSettings, getPeerPresence: self.getPeerPresence) + pipe.putNext((ChatListView(mutableView), .Generic)) } - - self.updateTrackedChatListHoles() } + self.updateTrackedChatListHoles() + if updateTrackedHoles { self.updateTrackedHoles() } diff --git a/submodules/TelegramCore/Sources/ApplyMaxReadIndexInteractively.swift b/submodules/TelegramCore/Sources/ApplyMaxReadIndexInteractively.swift index a322c58cc6..8c15c1719d 100644 --- a/submodules/TelegramCore/Sources/ApplyMaxReadIndexInteractively.swift +++ b/submodules/TelegramCore/Sources/ApplyMaxReadIndexInteractively.swift @@ -135,6 +135,14 @@ public func togglePeerUnreadMarkInteractively(transaction: Transaction, viewTrac } } + if !hasUnread && peerId.namespace == Namespaces.Peer.SecretChat { + let unseenSummary = transaction.getMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud) + let actionSummary = transaction.getPendingMessageActionsSummary(peerId: peerId, type: PendingMessageActionType.consumeUnseenPersonalMessage, namespace: Namespaces.Message.Cloud) + if (unseenSummary?.count ?? 0) - (actionSummary ?? 0) > 0 { + hasUnread = true + } + } + if hasUnread { if setToValue == nil || !(setToValue!) { if let index = transaction.getTopPeerMessageIndex(peerId: peerId) {