diff --git a/Postbox/ChatListTable.swift b/Postbox/ChatListTable.swift index 9e81c1509b..59d2f95e5a 100644 --- a/Postbox/ChatListTable.swift +++ b/Postbox/ChatListTable.swift @@ -10,7 +10,6 @@ enum ChatListOperation { enum ChatListEntryInfo { case message(ChatListIndex, MessageIndex?) case hole(ChatListHole) - case groupReference(PeerGroupId, ChatListIndex) var index: ChatListIndex { switch self { @@ -18,8 +17,6 @@ enum ChatListEntryInfo { return index case let .hole(hole): return ChatListIndex(pinningIndex: nil, messageIndex: hole.index) - case let .groupReference(_, index): - return index } } } @@ -27,7 +24,6 @@ enum ChatListEntryInfo { enum ChatListIntermediateEntry { case message(ChatListIndex, IntermediateMessage?, PeerChatListEmbeddedInterfaceState?) case hole(ChatListHole) - //case groupReference(PeerGroupId, ChatListIndex) var index: ChatListIndex { switch self { @@ -35,8 +31,6 @@ enum ChatListIntermediateEntry { return index case let .hole(hole): return ChatListIndex(pinningIndex: nil, messageIndex: hole.index) - /*case let .groupReference(_, index): - return index*/ } } } @@ -538,6 +532,42 @@ final class ChatListTable: Table { return entries } + func earlierEntryInfos(groupId: PeerGroupId, index: (ChatListIndex, Bool)?, messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable, count: Int) -> [ChatListEntryInfo] { + self.ensureInitialized(groupId: groupId) + + var entries: [ChatListEntryInfo] = [] + let key: ValueBoxKey + if let (index, message) = index { + key = self.key(groupId: groupId, index: index, type: message ? .message : .hole) + } else { + key = self.upperBound(groupId: groupId) + } + + self.valueBox.range(self.table, start: key, end: self.lowerBound(groupId: groupId), values: { key, value in + let (keyGroupId, pinningIndex, messageIndex, type) = extractKey(key) + assert(groupId == keyGroupId) + + let index = ChatListIndex(pinningIndex: pinningIndex, messageIndex: messageIndex) + if type == ChatListEntryType.message.rawValue { + var messageIndex: MessageIndex? + if value.length != 0 { + var idNamespace: Int32 = 0 + value.read(&idNamespace, offset: 0, length: 4) + var idId: Int32 = 0 + value.read(&idId, offset: 0, length: 4) + var indexTimestamp: Int32 = 0 + value.read(&indexTimestamp, offset: 0, length: 4) + messageIndex = MessageIndex(id: MessageId(peerId: index.messageIndex.id.peerId, namespace: idNamespace, id: idId), timestamp: indexTimestamp) + } + entries.append(.message(index, messageIndex)) + } else if type == ChatListEntryType.hole.rawValue { + entries.append(.hole(ChatListHole(index: index.messageIndex))) + } + return true + }, limit: count) + return entries + } + func laterEntries(groupId: PeerGroupId, index: (ChatListIndex, Bool)?, messageHistoryTable: MessageHistoryTable, peerChatInterfaceStateTable: PeerChatInterfaceStateTable, count: Int) -> [ChatListIntermediateEntry] { self.ensureInitialized(groupId: groupId) diff --git a/Postbox/ChatListView.swift b/Postbox/ChatListView.swift index 454a34654c..35671b0eba 100644 --- a/Postbox/ChatListView.swift +++ b/Postbox/ChatListView.swift @@ -44,9 +44,30 @@ public struct ChatListMessageTagSummaryInfo: Equatable { } } +public final class ChatListGroupReferencePeer: Equatable { + public let peer: RenderedPeer + public let isUnread: Bool + + init(peer: RenderedPeer, isUnread: Bool) { + self.peer = peer + self.isUnread = isUnread + } + + public static func ==(lhs: ChatListGroupReferencePeer, rhs: ChatListGroupReferencePeer) -> Bool { + if lhs.peer != rhs.peer { + return false + } + if lhs.isUnread != rhs.isUnread { + return false + } + return true + } +} + public struct ChatListGroupReferenceEntry: Equatable { public let groupId: PeerGroupId - public let renderedPeers: [RenderedPeer] + public let message: Message? + public let renderedPeers: [ChatListGroupReferencePeer] public let unreadState: PeerGroupUnreadCountersCombinedSummary public static func ==(lhs: ChatListGroupReferenceEntry, rhs: ChatListGroupReferenceEntry) -> Bool { @@ -56,6 +77,9 @@ public struct ChatListGroupReferenceEntry: Equatable { if lhs.unreadState != rhs.unreadState { return false } + if lhs.message?.stableVersion != rhs.message?.stableVersion { + return false + } if lhs.renderedPeers != rhs.renderedPeers { return false } @@ -63,7 +87,7 @@ public struct ChatListGroupReferenceEntry: Equatable { } } -public indirect enum ChatListEntry: Comparable { +public enum ChatListEntry: Comparable { case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer, PeerPresence?, ChatListMessageTagSummaryInfo) case HoleEntry(ChatListHole) @@ -152,7 +176,7 @@ private func processedChatListEntry(_ entry: MutableChatListEntry, cachedDataTab } } -indirect enum MutableChatListEntry: Equatable { +enum MutableChatListEntry: Equatable { case IntermediateMessageEntry(ChatListIndex, IntermediateMessage?, CombinedPeerReadState?, PeerChatListEmbeddedInterfaceState?) case MessageEntry(ChatListIndex, Message?, CombinedPeerReadState?, PeerNotificationSettings?, PeerChatListEmbeddedInterfaceState?, RenderedPeer, PeerPresence?, ChatListMessageTagSummaryInfo) case HoleEntry(ChatListHole) @@ -307,43 +331,45 @@ final class MutableChatListView { self.groupEntries.removeAll() if case .root = self.groupId { for groupId in postbox.chatListTable.existingGroups() { - var foundIndices: [ChatListIndex] = [] + var foundIndices: [(ChatListIndex, MessageIndex)] = [] var unpinnedCount = 0 let maxCount = 8 var upperBound: (ChatListIndex, Bool)? inner: while true { - if let entry = postbox.chatListTable.earlierEntries(groupId: groupId, index: upperBound, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: 1).first { - if case let .message(index, maybeMessage, _) = entry { - foundIndices.append(index) - if index.pinningIndex == nil { - unpinnedCount += 1 - } - - if unpinnedCount >= maxCount { - break inner - } - - if let _ = maybeMessage { - upperBound = (entry.index, true) - } else { - upperBound = (entry.index.predecessor, true) - } - } else { - upperBound = (entry.index, false) + if let entry = postbox.chatListTable.earlierEntryInfos(groupId: groupId, index: upperBound, messageHistoryTable: postbox.messageHistoryTable, peerChatInterfaceStateTable: postbox.peerChatInterfaceStateTable, count: 1).first { + switch entry { + case let .message(index, messageIndex): + if let messageIndex = messageIndex { + foundIndices.append((index, messageIndex)) + if index.pinningIndex == nil { + unpinnedCount += 1 + } + + if unpinnedCount >= maxCount { + break inner + } + + upperBound = (entry.index, true) + } else { + upperBound = (entry.index.predecessor, true) + } + case .hole: + upperBound = (entry.index, false) } } else { break inner } } - foundIndices.sort(by: { $0.messageIndex > $1.messageIndex }) + foundIndices.sort(by: { $0.1 > $1.1 }) if foundIndices.count > maxCount { foundIndices.removeSubrange(maxCount...) } - var renderedPeers: [RenderedPeer] = [] - for index in foundIndices { + var message: Message? + var renderedPeers: [ChatListGroupReferencePeer] = [] + for (index, messageIndex) in foundIndices { if let peer = postbox.peerTable.get(index.messageIndex.id.peerId) { var peers = SimpleDictionary() peers[peer.id] = peer @@ -354,11 +380,16 @@ final class MutableChatListView { } let renderedPeer = RenderedPeer(peerId: peer.id, peers: peers) - renderedPeers.append(renderedPeer) + let isUnread = postbox.readStateTable.getCombinedState(peer.id)?.isUnread ?? false + renderedPeers.append(ChatListGroupReferencePeer(peer: renderedPeer, isUnread: isUnread)) + + if foundIndices.count == 1 && message == nil { + message = postbox.messageHistoryTable.getMessage(messageIndex).flatMap({ postbox.messageHistoryTable.renderMessage($0, peerTable: postbox.peerTable) }) + } } } - self.groupEntries.append(ChatListGroupReferenceEntry(groupId: groupId, renderedPeers: renderedPeers, unreadState: postbox.groupMessageStatsTable.get(groupId: groupId))) + self.groupEntries.append(ChatListGroupReferenceEntry(groupId: groupId, message: message, renderedPeers: renderedPeers, unreadState: postbox.groupMessageStatsTable.get(groupId: groupId))) } } } @@ -423,16 +454,32 @@ final class MutableChatListView { invalidatedGroups = true } } + if invalidatedGroups { self.reloadGroups(postbox: postbox) hasChanges = true } else { for i in 0 ..< self.groupEntries.count { if let updatedState = transaction.currentUpdatedTotalUnreadSummaries[self.groupEntries[i].groupId] { - self.groupEntries[i] = ChatListGroupReferenceEntry(groupId: self.groupEntries[i].groupId, renderedPeers: self.groupEntries[i].renderedPeers, unreadState: updatedState) + self.groupEntries[i] = ChatListGroupReferenceEntry(groupId: self.groupEntries[i].groupId, message: self.groupEntries[i].message, renderedPeers: self.groupEntries[i].renderedPeers, unreadState: updatedState) hasChanges = true } } + + if !transaction.alteredInitialPeerCombinedReadStates.isEmpty { + for i in 0 ..< self.groupEntries.count { + for j in 0 ..< groupEntries[i].renderedPeers.count { + if transaction.alteredInitialPeerCombinedReadStates[groupEntries[i].renderedPeers[j].peer.peerId] != nil { + let isUnread = postbox.readStateTable.getCombinedState(groupEntries[i].renderedPeers[j].peer.peerId)?.isUnread ?? false + if isUnread != groupEntries[i].renderedPeers[j].isUnread { + var renderedPeers = self.groupEntries[i].renderedPeers + renderedPeers[j] = ChatListGroupReferencePeer(peer: groupEntries[i].renderedPeers[j].peer, isUnread: isUnread) + self.groupEntries[i] = ChatListGroupReferenceEntry(groupId: self.groupEntries[i].groupId, message: self.groupEntries[i].message, renderedPeers: renderedPeers, unreadState: self.groupEntries[i].unreadState) + } + } + } + } + } } } diff --git a/Postbox/ItemCollection.swift b/Postbox/ItemCollection.swift index 2e0a78c397..947f2d53ec 100644 --- a/Postbox/ItemCollection.swift +++ b/Postbox/ItemCollection.swift @@ -100,7 +100,7 @@ public protocol ItemCollectionItem: PostboxCoding { var indexKeys: [MemoryBuffer] { get } } -public indirect enum ItemCollectionSearchQuery { +public enum ItemCollectionSearchQuery { case exact(ValueBoxKey) case matching([ValueBoxKey]) } diff --git a/Postbox/PeerNameIndexRepresentation.swift b/Postbox/PeerNameIndexRepresentation.swift index 615aaeaea3..e94beda690 100644 --- a/Postbox/PeerNameIndexRepresentation.swift +++ b/Postbox/PeerNameIndexRepresentation.swift @@ -1,6 +1,6 @@ import Foundation -public indirect enum PeerIndexNameRepresentation: Equatable { +public enum PeerIndexNameRepresentation: Equatable { case title(title: String, addressName: String?) case personName(first: String, last: String, addressName: String?, phoneNumber: String?) diff --git a/Postbox/PeerNotificationSettings.swift b/Postbox/PeerNotificationSettings.swift index 6401f6f0f4..f5ef31781d 100644 --- a/Postbox/PeerNotificationSettings.swift +++ b/Postbox/PeerNotificationSettings.swift @@ -1,5 +1,5 @@ -public indirect enum PeerNotificationSettingsBehavior: PostboxCoding { +public enum PeerNotificationSettingsBehavior: PostboxCoding { case none case reset(atTimestamp: Int32, toValue: PeerNotificationSettings) diff --git a/Postbox/UnreadMessageCountsView.swift b/Postbox/UnreadMessageCountsView.swift index 942a9ad5b5..2f229445fc 100644 --- a/Postbox/UnreadMessageCountsView.swift +++ b/Postbox/UnreadMessageCountsView.swift @@ -10,7 +10,7 @@ private enum MutableUnreadMessageCountsItemEntry { case peer(PeerId, CombinedPeerReadState?) } -public indirect enum UnreadMessageCountsItemEntry { +public enum UnreadMessageCountsItemEntry { case total(PreferencesEntry?, ChatListTotalUnreadState) case peer(PeerId, CombinedPeerReadState?) } diff --git a/Postbox/Upgrades.swift b/Postbox/Upgrades.swift index f6ebcb3eb4..4cce537b00 100644 --- a/Postbox/Upgrades.swift +++ b/Postbox/Upgrades.swift @@ -5,7 +5,7 @@ import SwiftSignalKitMac import SwiftSignalKit #endif -indirect enum PostboxUpgradeOperation { +enum PostboxUpgradeOperation { case inplace((MetadataTable, ValueBox, (Float) -> Void) -> Void) case standalone((Queue, String, ValueBox, ValueBoxEncryptionParameters, (Float) -> Void) -> String?) }