diff --git a/Postbox.xcodeproj/project.pbxproj b/Postbox.xcodeproj/project.pbxproj index c6ca2d338b..ff8555489c 100644 --- a/Postbox.xcodeproj/project.pbxproj +++ b/Postbox.xcodeproj/project.pbxproj @@ -141,6 +141,7 @@ D0AB0B901D65D4AB002C78E7 /* UnsentMessageIndicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AB0B8F1D65D4AB002C78E7 /* UnsentMessageIndicesView.swift */; }; D0AD23271E194D1C00A7089A /* PeerOperationLogTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AD23261E194D1C00A7089A /* PeerOperationLogTable.swift */; }; D0AD23291E196B6400A7089A /* PeerOperationLogMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AD23281E196B6400A7089A /* PeerOperationLogMetadataTable.swift */; }; + D0AE3EBC1F68261B0069BC90 /* PeerNotificationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0AE3EBB1F68261B0069BC90 /* PeerNotificationSettingsView.swift */; }; D0B418171D7DFAF3004562A4 /* PostboxMac.h in Headers */ = {isa = PBXBuildFile; fileRef = D0B418151D7DFAF3004562A4 /* PostboxMac.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0B4181C1D7DFDF1004562A4 /* SQLite-Bridging.m in Sources */ = {isa = PBXBuildFile; fileRef = D07516761B2EC90400AE42E0 /* SQLite-Bridging.m */; }; D0B4181D1D7DFDF4004562A4 /* sqlite3.c in Sources */ = {isa = PBXBuildFile; fileRef = D07516401B2D9CEF00AE42E0 /* sqlite3.c */; settings = {COMPILER_FLAGS = "-Wno-conversion -Wno-ambiguous-macro -Wno-conditional-uninitialized -Wno-unused-const-variable -Wno-unused-function -Wno-unreachable-code"; }; }; @@ -198,8 +199,6 @@ D0C07F6A1B67DB4800966E43 /* SwiftSignalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D0C07F691B67DB4800966E43 /* SwiftSignalKit.framework */; }; D0C0B5AB1EE1AB08000F4D2C /* ReverseAssociatedPeerTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B5AA1EE1AB08000F4D2C /* ReverseAssociatedPeerTable.swift */; }; D0C0B5AC1EE1AB08000F4D2C /* ReverseAssociatedPeerTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B5AA1EE1AB08000F4D2C /* ReverseAssociatedPeerTable.swift */; }; - D0C0B5AE1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B5AD1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift */; }; - D0C0B5AF1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C0B5AD1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift */; }; D0C27B451F4B598200A4E170 /* CachedPeerDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C27B441F4B598200A4E170 /* CachedPeerDataView.swift */; }; D0C27B461F4B598200A4E170 /* CachedPeerDataView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C27B441F4B598200A4E170 /* CachedPeerDataView.swift */; }; D0C674C81CBB11C600183765 /* MessageHistoryReadStateTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C674C71CBB11C600183765 /* MessageHistoryReadStateTable.swift */; }; @@ -208,6 +207,10 @@ D0C8FCB71C5C2D200028C27F /* MessageHistoryViewTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C8FCB61C5C2D200028C27F /* MessageHistoryViewTests.swift */; }; D0C9DA391C65782500855278 /* SimpleSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0C9DA381C65782500855278 /* SimpleSet.swift */; }; D0CE63F61CA1CCB2002BC462 /* MediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CE63F51CA1CCB2002BC462 /* MediaResource.swift */; }; + D0CE8CF31F70249400AA2DB0 /* PostboxUpgrade_13to14.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CE8CF21F70249400AA2DB0 /* PostboxUpgrade_13to14.swift */; }; + D0CE8CF41F70249400AA2DB0 /* PostboxUpgrade_13to14.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CE8CF21F70249400AA2DB0 /* PostboxUpgrade_13to14.swift */; }; + D0CE8CF61F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CE8CF51F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift */; }; + D0CE8CF71F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0CE8CF51F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift */; }; D0D510F41D63BA8400A97B8A /* PostboxTransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D510F31D63BA8400A97B8A /* PostboxTransaction.swift */; }; D0D510F61D63BBE100A97B8A /* MessageHistoryOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D510F51D63BBE100A97B8A /* MessageHistoryOperation.swift */; }; D0D510F91D63BCC200A97B8A /* IntermediateMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D510F81D63BCC200A97B8A /* IntermediateMessage.swift */; }; @@ -216,6 +219,8 @@ D0D511041D64D91C00A97B8A /* IpcNotifier.h in Headers */ = {isa = PBXBuildFile; fileRef = D0D511031D64D75200A97B8A /* IpcNotifier.h */; settings = {ATTRIBUTES = (Public, ); }; }; D0D949F31D35302600740E02 /* RandomAccessResourceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D949F21D35302600740E02 /* RandomAccessResourceTests.swift */; }; D0D949F51D35353900740E02 /* MappedFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0D949F41D35353900740E02 /* MappedFile.swift */; }; + D0DA1D2F1F70419D0034E892 /* PendingPeerNotificationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA1D2E1F70419D0034E892 /* PendingPeerNotificationSettingsView.swift */; }; + D0DA1D301F70419D0034E892 /* PendingPeerNotificationSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA1D2E1F70419D0034E892 /* PendingPeerNotificationSettingsView.swift */; }; D0DA44481E4C7D1E005FDCA7 /* PostboxAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA44471E4C7D1E005FDCA7 /* PostboxAccess.swift */; }; D0DA44491E4C7D1E005FDCA7 /* PostboxAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DA44471E4C7D1E005FDCA7 /* PostboxAccess.swift */; }; D0DF0C8F1D81A350008AEB01 /* PeerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C8E1D81A350008AEB01 /* PeerView.swift */; }; @@ -401,6 +406,7 @@ D0AB0B8F1D65D4AB002C78E7 /* UnsentMessageIndicesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnsentMessageIndicesView.swift; sourceTree = ""; }; D0AD23261E194D1C00A7089A /* PeerOperationLogTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerOperationLogTable.swift; sourceTree = ""; }; D0AD23281E196B6400A7089A /* PeerOperationLogMetadataTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerOperationLogMetadataTable.swift; sourceTree = ""; }; + D0AE3EBB1F68261B0069BC90 /* PeerNotificationSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PeerNotificationSettingsView.swift; sourceTree = ""; }; D0B418131D7DFAF2004562A4 /* PostboxMac.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PostboxMac.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D0B418151D7DFAF3004562A4 /* PostboxMac.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PostboxMac.h; sourceTree = ""; }; D0B418161D7DFAF3004562A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -416,7 +422,6 @@ D0BEAF6F1E54BC1E00BD963D /* AccountRecordsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountRecordsView.swift; sourceTree = ""; }; D0C07F691B67DB4800966E43 /* SwiftSignalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = SwiftSignalKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; D0C0B5AA1EE1AB08000F4D2C /* ReverseAssociatedPeerTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseAssociatedPeerTable.swift; sourceTree = ""; }; - D0C0B5AD1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostboxUpgrade_13to14.swift; sourceTree = ""; }; D0C27B441F4B598200A4E170 /* CachedPeerDataView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CachedPeerDataView.swift; sourceTree = ""; }; D0C674C71CBB11C600183765 /* MessageHistoryReadStateTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryReadStateTable.swift; sourceTree = ""; }; D0C674CB1CBB14A700183765 /* PeerReadState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerReadState.swift; sourceTree = ""; }; @@ -424,6 +429,8 @@ D0C8FCB61C5C2D200028C27F /* MessageHistoryViewTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryViewTests.swift; sourceTree = ""; }; D0C9DA381C65782500855278 /* SimpleSet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleSet.swift; sourceTree = ""; }; D0CE63F51CA1CCB2002BC462 /* MediaResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaResource.swift; sourceTree = ""; }; + D0CE8CF21F70249400AA2DB0 /* PostboxUpgrade_13to14.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostboxUpgrade_13to14.swift; sourceTree = ""; }; + D0CE8CF51F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingPeerNotificationSettingsIndexTable.swift; sourceTree = ""; }; D0D510F31D63BA8400A97B8A /* PostboxTransaction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostboxTransaction.swift; sourceTree = ""; }; D0D510F51D63BBE100A97B8A /* MessageHistoryOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageHistoryOperation.swift; sourceTree = ""; }; D0D510F81D63BCC200A97B8A /* IntermediateMessage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntermediateMessage.swift; sourceTree = ""; }; @@ -432,6 +439,7 @@ D0D511031D64D75200A97B8A /* IpcNotifier.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IpcNotifier.h; sourceTree = ""; }; D0D949F21D35302600740E02 /* RandomAccessResourceTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RandomAccessResourceTests.swift; sourceTree = ""; }; D0D949F41D35353900740E02 /* MappedFile.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MappedFile.swift; sourceTree = ""; }; + D0DA1D2E1F70419D0034E892 /* PendingPeerNotificationSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PendingPeerNotificationSettingsView.swift; sourceTree = ""; }; D0DA44471E4C7D1E005FDCA7 /* PostboxAccess.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostboxAccess.swift; sourceTree = ""; }; D0DF0C8E1D81A350008AEB01 /* PeerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerView.swift; sourceTree = ""; }; D0E1D30B1ECA1F5500FCEEF1 /* GlobalMessageHistoryTagsTable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalMessageHistoryTagsTable.swift; sourceTree = ""; }; @@ -578,7 +586,7 @@ children = ( D0F02CDE1E99223D0065DEE2 /* Upgrades.swift */, D0F02CE11E9922F50065DEE2 /* PostboxUpgrade_12to13.swift */, - D0C0B5AD1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift */, + D0CE8CF21F70249400AA2DB0 /* PostboxUpgrade_13to14.swift */, ); name = Upgrade; sourceTree = ""; @@ -609,6 +617,7 @@ D0F9E86E1C5A0E7600037222 /* KeychainTable.swift */, D0F9E8701C5A0E9B00037222 /* PeerTable.swift */, D03120FF1DA579A0006A2A60 /* PeerNotificationSettingsTable.swift */, + D0CE8CF51F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift */, D03120FD1DA562E9006A2A60 /* CachedPeerDataTable.swift */, D03120F71DA53FF4006A2A60 /* PeerPresenceTable.swift */, D0C735271C864DF300BB3149 /* PeerChatStateTable.swift */, @@ -726,6 +735,8 @@ D0A352F71F549D95001423DC /* InvalidatedMessageHistoryTagSummariesView.swift */, D07047B01F3DE40400F6A8D4 /* PendingMessageActionsSummaryView.swift */, D0C27B441F4B598200A4E170 /* CachedPeerDataView.swift */, + D0AE3EBB1F68261B0069BC90 /* PeerNotificationSettingsView.swift */, + D0DA1D2E1F70419D0034E892 /* PendingPeerNotificationSettingsView.swift */, ); name = Views; sourceTree = ""; @@ -1029,6 +1040,7 @@ D0F82CFE1E4345D7007E499C /* OrderedItemListTable.swift in Sources */, D0F7B1C51E045C6A007EB8A5 /* MessageHistoryMetadataTable.swift in Sources */, D073CE781DCBF3B4007511FD /* MessageHistoryHole.swift in Sources */, + D0CE8CF71F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift in Sources */, D0E1D3101ECA53F900FCEEF1 /* GlobalMessageTagsView.swift in Sources */, D08775071E3E3F2100A97350 /* PreferencesView.swift in Sources */, D049EAF11E44D9B900A2CD3A /* PostboxStateView.swift in Sources */, @@ -1042,7 +1054,6 @@ D073CE7F1DCBF3B4007511FD /* ItemCollection.swift in Sources */, D07047B21F3DE40400F6A8D4 /* PendingMessageActionsSummaryView.swift in Sources */, D0F7B1D91E045C6A007EB8A5 /* OrderStatisticTable.swift in Sources */, - D0C0B5AF1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift in Sources */, D073CEA01DCBF3C1007511FD /* ItemCollectionsView.swift in Sources */, D0BE383A1E7C1FD4000079AF /* ItemCollectionInfoView.swift in Sources */, D0B418491D7DFE20004562A4 /* ChatListView.swift in Sources */, @@ -1070,12 +1081,14 @@ D0B4185C1D7DFE2F004562A4 /* MurMurHash32.m in Sources */, D0F7B1E01E045C6A007EB8A5 /* ItemCacheTable.swift in Sources */, D07047A91F3DA8D700F6A8D4 /* PendingMessageActionsMetadataTable.swift in Sources */, + D0DA1D301F70419D0034E892 /* PendingPeerNotificationSettingsView.swift in Sources */, D0F7B1E11E045C6A007EB8A5 /* ReverseIndexReferenceTable.swift in Sources */, D0B418241D7DFE0C004562A4 /* SimpleSet.swift in Sources */, D073CE7B1DCBF3B4007511FD /* PeerNameIndexRepresentation.swift in Sources */, D073CE7D1DCBF3B4007511FD /* PeerPresence.swift in Sources */, D0B4184C1D7DFE20004562A4 /* ContactPeerIdsView.swift in Sources */, D0DA44491E4C7D1E005FDCA7 /* PostboxAccess.swift in Sources */, + D0CE8CF41F70249400AA2DB0 /* PostboxUpgrade_13to14.swift in Sources */, D073CE751DCBF3B4007511FD /* Message.swift in Sources */, D087C20D1E43C11C00D686F8 /* OrderedItemListView.swift in Sources */, D00C7CD51E365C4E0080C3D5 /* PeerChatListInclusion.swift in Sources */, @@ -1117,15 +1130,18 @@ buildActionMask = 2147483647; files = ( D08775061E3E3F2100A97350 /* PreferencesView.swift in Sources */, + D0CE8CF61F703B1E00AA2DB0 /* PendingPeerNotificationSettingsIndexTable.swift in Sources */, D03229EE1E6B33FD0000AF9C /* SqliteInterface.swift in Sources */, D01C7F071EFC1ED3008305F1 /* UnorderedItemListTable.swift in Sources */, D0F9E8631C579F0200037222 /* MediaCleanupTable.swift in Sources */, D0F3CC741DDE1EB9008148FA /* ItemCacheMetaTable.swift in Sources */, D08D451F1D5D2CA700A7428A /* RatingTable.swift in Sources */, D07CFF831DCA909100761F81 /* PeerChatInterfaceStateTable.swift in Sources */, + D0DA1D2F1F70419D0034E892 /* PendingPeerNotificationSettingsView.swift in Sources */, D0F9E86F1C5A0E7600037222 /* KeychainTable.swift in Sources */, D0E3A7821B28ADD000A402D9 /* Postbox.swift in Sources */, D0575AE31E9ECBB2006F2541 /* AccessChallengeDataView.swift in Sources */, + D0CE8CF31F70249400AA2DB0 /* PostboxUpgrade_13to14.swift in Sources */, D0E3A79E1B28B50400A402D9 /* Message.swift in Sources */, D0C674C81CBB11C600183765 /* MessageHistoryReadStateTable.swift in Sources */, D0DF0C8F1D81A350008AEB01 /* PeerView.swift in Sources */, @@ -1181,7 +1197,6 @@ D0BEAF631E54B2FA00BD963D /* AccountManager.swift in Sources */, D0AD23271E194D1C00A7089A /* PeerOperationLogTable.swift in Sources */, D021E0D41DB4FAE100C6B04F /* ItemCollection.swift in Sources */, - D0C0B5AE1EE1B3F4000F4D2C /* PostboxUpgrade_13to14.swift in Sources */, D0D510F91D63BCC200A97B8A /* IntermediateMessage.swift in Sources */, D0BE38391E7C1FD4000079AF /* ItemCollectionInfoView.swift in Sources */, D0F9E86B1C59719800037222 /* ChatListView.swift in Sources */, @@ -1230,6 +1245,7 @@ D0BEAF6D1E54B77900BD963D /* AccountManagerRecordTable.swift in Sources */, D03120F81DA53FF4006A2A60 /* PeerPresenceTable.swift in Sources */, D0F9E8731C5A1EE500037222 /* GlobalMessageIdsTable.swift in Sources */, + D0AE3EBC1F68261B0069BC90 /* PeerNotificationSettingsView.swift in Sources */, D00EED1E1C81F28D00341DFF /* MessageHistoryTagsTable.swift in Sources */, D044CA2C1C617E2D002160FF /* MessageHistoryMetadataTable.swift in Sources */, D03120FC1DA55427006A2A60 /* PeerNotificationSettings.swift in Sources */, diff --git a/Postbox/ChatListIndexTable.swift b/Postbox/ChatListIndexTable.swift index 57ce1ea40e..055200f302 100644 --- a/Postbox/ChatListIndexTable.swift +++ b/Postbox/ChatListIndexTable.swift @@ -265,9 +265,9 @@ final class ChatListIndexTable: Table { var notificationSettings: PeerNotificationSettings? if let peer = getPeer(peerId) { if let notificationSettingsPeerId = peer.notificationSettingsPeerId { - notificationSettings = self.notificationSettingsTable.get(notificationSettingsPeerId) + notificationSettings = self.notificationSettingsTable.getEffective(notificationSettingsPeerId) } else { - notificationSettings = self.notificationSettingsTable.get(peerId) + notificationSettings = self.notificationSettingsTable.getEffective(peerId) } } if let _ = self.get(peerId).includedIndex(peerId: peerId), let notificationSettings = notificationSettings, !notificationSettings.isRemovedFromTotalUnreadCount { @@ -292,9 +292,9 @@ final class ChatListIndexTable: Table { var notificationSettings: PeerNotificationSettings? if let peer = getPeer(peerId) { if let notificationSettingsPeerId = peer.notificationSettingsPeerId { - notificationSettings = self.notificationSettingsTable.get(notificationSettingsPeerId) + notificationSettings = self.notificationSettingsTable.getEffective(notificationSettingsPeerId) } else { - notificationSettings = self.notificationSettingsTable.get(peerId) + notificationSettings = self.notificationSettingsTable.getEffective(peerId) } } if let notificationSettings = notificationSettings, !notificationSettings.isRemovedFromTotalUnreadCount { @@ -335,9 +335,9 @@ final class ChatListIndexTable: Table { var notificationSettings: PeerNotificationSettings? if let peer = getPeer(peerId) { if let notificationSettingsPeerId = peer.notificationSettingsPeerId { - notificationSettings = self.notificationSettingsTable.get(notificationSettingsPeerId) + notificationSettings = self.notificationSettingsTable.getEffective(notificationSettingsPeerId) } else { - notificationSettings = self.notificationSettingsTable.get(peerId) + notificationSettings = self.notificationSettingsTable.getEffective(peerId) } } if let notificationSettings = notificationSettings, !notificationSettings.isRemovedFromTotalUnreadCount { diff --git a/Postbox/ChatListTable.swift b/Postbox/ChatListTable.swift index 7ad2267924..b5a7ced351 100644 --- a/Postbox/ChatListTable.swift +++ b/Postbox/ChatListTable.swift @@ -159,6 +159,9 @@ final class ChatListTable: Table { updatedTimestamp = max(updatedTimestamp, embeddedChatState.timestamp) } topMessageIndex = MessageIndex(id: topMessage.id, timestamp: updatedTimestamp) + } else if let embeddedChatState = embeddedChatState, embeddedChatState.timestamp != 0 { + topMessageIndex = MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 1), timestamp: embeddedChatState.timestamp) + rawTopMessageIndex = nil } else { topMessageIndex = nil rawTopMessageIndex = nil diff --git a/Postbox/MessageHistoryView.swift b/Postbox/MessageHistoryView.swift index 89be871834..6ca1314c88 100644 --- a/Postbox/MessageHistoryView.swift +++ b/Postbox/MessageHistoryView.swift @@ -4,12 +4,14 @@ public enum AdditionalMessageHistoryViewData { case cachedPeerData(PeerId) case peerChatState(PeerId) case totalUnreadCount + case peerNotificationSettings(PeerId) } public enum AdditionalMessageHistoryViewDataEntry { case cachedPeerData(PeerId, CachedPeerData?) case peerChatState(PeerId, PeerChatState?) case totalUnreadCount(Int32) + case peerNotificationSettings(PeerNotificationSettings?) } public struct MessageHistoryViewId: Equatable { @@ -373,11 +375,12 @@ final class MutableMessageHistoryView { fileprivate var later: MutableMessageHistoryEntry? fileprivate var entries: [MutableMessageHistoryEntry] fileprivate let fillCount: Int + fileprivate let clipHoles: Bool fileprivate var topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?] fileprivate var additionalDatas: [AdditionalMessageHistoryViewDataEntry] - init(id: MessageHistoryViewId, postbox: Postbox, orderStatistics: MessageHistoryViewOrderStatistics, peerId: PeerId, anchorIndex: MessageHistoryAnchorIndex, combinedReadState: CombinedPeerReadState?, earlier: MutableMessageHistoryEntry?, entries: [MutableMessageHistoryEntry], later: MutableMessageHistoryEntry?, tagMask: MessageTags?, count: Int, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?], additionalDatas: [AdditionalMessageHistoryViewDataEntry], getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32) { + init(id: MessageHistoryViewId, postbox: Postbox, orderStatistics: MessageHistoryViewOrderStatistics, peerId: PeerId, anchorIndex: MessageHistoryAnchorIndex, combinedReadState: CombinedPeerReadState?, earlier: MutableMessageHistoryEntry?, entries: [MutableMessageHistoryEntry], later: MutableMessageHistoryEntry?, tagMask: MessageTags?, count: Int, clipHoles: Bool, topTaggedMessages: [MessageId.Namespace: MessageHistoryTopTaggedMessage?], additionalDatas: [AdditionalMessageHistoryViewDataEntry], getMessageCountInRange: (MessageIndex, MessageIndex) -> Int32) { self.id = id self.orderStatistics = orderStatistics self.anchorIndex = anchorIndex @@ -388,6 +391,7 @@ final class MutableMessageHistoryView { self.later = later self.tagMask = tagMask self.fillCount = count + self.clipHoles = clipHoles self.topTaggedMessages = topTaggedMessages self.additionalDatas = additionalDatas @@ -692,6 +696,8 @@ final class MutableMessageHistoryView { } case .totalUnreadCount: break + case .peerNotificationSettings: + break } } @@ -1057,7 +1063,7 @@ public final class MessageHistoryView { } } } - if !entries.isEmpty { + if !entries.isEmpty && mutableView.clipHoles { var referenceIndex = entries.count - 1 for i in 0 ..< entries.count { if entries[i].index > self.anchorIndex { diff --git a/Postbox/PeerNotificationSettingsTable.swift b/Postbox/PeerNotificationSettingsTable.swift index b53b23745f..435823d700 100644 --- a/Postbox/PeerNotificationSettingsTable.swift +++ b/Postbox/PeerNotificationSettingsTable.swift @@ -1,42 +1,163 @@ import Foundation +private struct PeerNotificationSettingsTableEntry: Equatable { + let current: PeerNotificationSettings? + let pending: PeerNotificationSettings? + + static func ==(lhs: PeerNotificationSettingsTableEntry, rhs: PeerNotificationSettingsTableEntry) -> Bool { + if let lhsCurrent = lhs.current, let rhsCurrent = rhs.current { + if !lhsCurrent.isEqual(to: rhsCurrent) { + return false + } + } else if (lhs.current != nil) != (rhs.current != nil) { + return false + } + if let lhsPending = lhs.pending, let rhsPending = rhs.pending { + if !lhsPending.isEqual(to: rhsPending) { + return false + } + } else if (lhs.pending != nil) != (rhs.pending != nil) { + return false + } + return true + } + + var effective: PeerNotificationSettings? { + if let pending = self.pending { + return pending + } + return self.current + } + + func withUpdatedCurrent(_ current: PeerNotificationSettings?) -> PeerNotificationSettingsTableEntry { + return PeerNotificationSettingsTableEntry(current: current, pending: self.pending) + } + + func withUpdatedPending(_ pending: PeerNotificationSettings?) -> PeerNotificationSettingsTableEntry { + return PeerNotificationSettingsTableEntry(current: self.current, pending: pending) + } +} + +private struct PeerNotificationSettingsTableEntryFlags: OptionSet { + var rawValue: Int32 + + init(rawValue: Int32) { + self.rawValue = rawValue + } + + static let hasCurrent = PeerNotificationSettingsTableEntryFlags(rawValue: 1 << 0) + static let hasPending = PeerNotificationSettingsTableEntryFlags(rawValue: 1 << 1) +} + final class PeerNotificationSettingsTable: Table { static func tableSpec(_ id: Int32) -> ValueBoxTable { return ValueBoxTable(id: id, keyType: .int64) } + private let pendingIndexTable: PendingPeerNotificationSettingsIndexTable + private let sharedEncoder = PostboxEncoder() private let sharedKey = ValueBoxKey(length: 8) - private var cachedSettings: [PeerId: PeerNotificationSettings] = [:] - private var updatedInitialSettings: [PeerId: PeerNotificationSettings?] = [:] + private var cachedSettings: [PeerId: PeerNotificationSettingsTableEntry] = [:] + private var updatedInitialSettings: [PeerId: PeerNotificationSettingsTableEntry] = [:] + + init(valueBox: ValueBox, table: ValueBoxTable, pendingIndexTable: PendingPeerNotificationSettingsIndexTable) { + self.pendingIndexTable = pendingIndexTable + + super.init(valueBox: valueBox, table: table) + } private func key(_ id: PeerId) -> ValueBoxKey { self.sharedKey.setInt64(0, value: id.toInt64()) return self.sharedKey } - func set(id: PeerId, settings: PeerNotificationSettings) { - let current = self.get(id) - if current == nil || !current!.isEqual(to: settings) { - if self.updatedInitialSettings[id] == nil { - self.updatedInitialSettings[id] = current + private func getEntry(_ id: PeerId) -> PeerNotificationSettingsTableEntry { + if let entry = self.cachedSettings[id] { + return entry + } else if let value = self.valueBox.get(self.table, key: self.key(id)) { + var flagsValue: Int32 = 0 + value.read(&flagsValue, offset: 0, length: 4) + let flags = PeerNotificationSettingsTableEntryFlags(rawValue: flagsValue) + + var current: PeerNotificationSettings? + if flags.contains(.hasCurrent) { + var length: Int32 = 0 + value.read(&length, offset: 0, length: 4) + let object = PostboxDecoder(buffer: MemoryBuffer(memory: value.memory.advanced(by: value.offset), capacity: Int(length), length: Int(length), freeWhenDone: false)).decodeRootObject() as? PeerNotificationSettings + assert(object != nil) + current = object + value.skip(Int(length)) } - self.cachedSettings[id] = settings + + var pending: PeerNotificationSettings? + if flags.contains(.hasPending) { + var length: Int32 = 0 + value.read(&length, offset: 0, length: 4) + let object = PostboxDecoder(buffer: MemoryBuffer(memory: value.memory.advanced(by: value.offset), capacity: Int(length), length: Int(length), freeWhenDone: false)).decodeRootObject() as? PeerNotificationSettings + assert(object != nil) + pending = object + value.skip(Int(length)) + } + let entry = PeerNotificationSettingsTableEntry(current: current, pending: pending) + self.cachedSettings[id] = entry + return entry + } else { + let entry = PeerNotificationSettingsTableEntry(current: nil, pending: nil) + self.cachedSettings[id] = entry + return entry } } - func get(_ id: PeerId) -> PeerNotificationSettings? { - if let settings = self.cachedSettings[id] { - return settings + func setCurrent(id: PeerId, settings: PeerNotificationSettings?) -> PeerNotificationSettings? { + let currentEntry = self.getEntry(id) + var updated = false + if let current = currentEntry.current, let settings = settings { + updated = !current.isEqual(to: settings) + } else if (currentEntry.current != nil) != (settings != nil) { + updated = true } - if let value = self.valueBox.get(self.table, key: self.key(id)) { - if let settings = PostboxDecoder(buffer: value).decodeRootObject() as? PeerNotificationSettings { - self.cachedSettings[id] = settings - return settings + if updated { + if self.updatedInitialSettings[id] == nil { + self.updatedInitialSettings[id] = currentEntry } + let updatedEntry = currentEntry.withUpdatedCurrent(settings) + self.cachedSettings[id] = updatedEntry + return updatedEntry.effective + } else { + return nil } - return nil + } + + func setPending(id: PeerId, settings: PeerNotificationSettings?, updatedSettings: inout Set) -> PeerNotificationSettings? { + let currentEntry = self.getEntry(id) + var updated = false + if let pending = currentEntry.pending, let settings = settings { + updated = !pending.isEqual(to: settings) + } else if (currentEntry.pending != nil) != (settings != nil) { + updated = true + } + if updated { + if self.updatedInitialSettings[id] == nil { + self.updatedInitialSettings[id] = currentEntry + } + updatedSettings.insert(id) + let updatedEntry = currentEntry.withUpdatedPending(settings) + self.cachedSettings[id] = updatedEntry + self.pendingIndexTable.set(peerId: id, pending: updatedEntry.pending != nil) + return updatedEntry.effective + } else { + return nil + } + } + + func getEffective(_ id: PeerId) -> PeerNotificationSettings? { + return self.getEntry(id).effective + } + + func getPending(_ id: PeerId) -> PeerNotificationSettings? { + return self.getEntry(id).pending } override func clearMemoryCache() { @@ -50,10 +171,13 @@ final class PeerNotificationSettingsTable: Table { for (peerId, initialSettings) in self.updatedInitialSettings { var wasParticipating = false - if let initialSettings = initialSettings { - wasParticipating = !initialSettings.isRemovedFromTotalUnreadCount + if let initialEffective = initialSettings.effective { + wasParticipating = !initialEffective.isRemovedFromTotalUnreadCount + } + var isParticipating = false + if let resultEffective = self.cachedSettings[peerId]?.effective { + isParticipating = !resultEffective.isRemovedFromTotalUnreadCount } - let isParticipating = !self.cachedSettings[peerId]!.isRemovedFromTotalUnreadCount if wasParticipating != isParticipating { if isParticipating { added.insert(peerId) @@ -66,7 +190,7 @@ final class PeerNotificationSettingsTable: Table { return (added, removed) } - func resetAll(to settings: PeerNotificationSettings) -> [PeerId] { + func resetAll(to settings: PeerNotificationSettings, updatedSettings: inout Set) -> [PeerId] { let lowerBound = ValueBoxKey(length: 8) lowerBound.setInt64(0, value: 0) let upperBound = ValueBoxKey(length: 8) @@ -79,9 +203,11 @@ final class PeerNotificationSettingsTable: Table { var updatedPeerIds: [PeerId] = [] for peerId in peerIds { - if let current = self.get(peerId), !current.isEqual(to: settings) { + let entry = self.getEntry(peerId) + if let current = entry.current, !current.isEqual(to: settings) || entry.pending != nil { + let _ = self.setCurrent(id: peerId, settings: settings) + let _ = self.setPending(id: peerId, settings: nil, updatedSettings: &updatedSettings) updatedPeerIds.append(peerId) - self.set(id: peerId, settings: settings) } } @@ -90,12 +216,48 @@ final class PeerNotificationSettingsTable: Table { override func beforeCommit() { if !self.updatedInitialSettings.isEmpty { + let buffer = WriteBuffer() + let encoder = PostboxEncoder() for (peerId, _) in self.updatedInitialSettings { - if let settings = self.cachedSettings[peerId] { - self.sharedEncoder.reset() - self.sharedEncoder.encodeRootObject(settings) + if let entry = self.cachedSettings[peerId] { + buffer.reset() - self.valueBox.set(self.table, key: self.key(peerId), value: self.sharedEncoder.readBufferNoCopy()) + var flags = PeerNotificationSettingsTableEntryFlags() + if entry.current != nil { + flags.insert(.hasCurrent) + } + if entry.pending != nil { + flags.insert(.hasPending) + } + + var flagsValue: Int32 = flags.rawValue + buffer.write(&flagsValue, offset: 0, length: 4) + + if let current = entry.current { + encoder.reset() + encoder.encodeRootObject(current) + let object = encoder.readBufferNoCopy() + withExtendedLifetime(object, { + var length: Int32 = Int32(object.length) + buffer.write(&length, offset: 0, length: 4) + buffer.write(object.memory, offset: 0, length: object.length) + }) + } + + if let pending = entry.pending { + encoder.reset() + encoder.encodeRootObject(pending) + let object = encoder.readBufferNoCopy() + withExtendedLifetime(object, { + var length: Int32 = Int32(object.length) + buffer.write(&length, offset: 0, length: 4) + buffer.write(object.memory, offset: 0, length: object.length) + }) + } + + self.valueBox.set(self.table, key: self.key(peerId), value: buffer.readBufferNoCopy()) + } else { + assertionFailure() } } diff --git a/Postbox/PeerNotificationSettingsView.swift b/Postbox/PeerNotificationSettingsView.swift new file mode 100644 index 0000000000..1fbfa9e09c --- /dev/null +++ b/Postbox/PeerNotificationSettingsView.swift @@ -0,0 +1,35 @@ +import Foundation + +final class MutablePeerNotificationSettingsView: MutablePostboxView { + let peerId: PeerId + var notificationSettings: PeerNotificationSettings? + + init(postbox: Postbox, peerId: PeerId) { + self.peerId = peerId + self.notificationSettings = postbox.peerNotificationSettingsTable.getEffective(peerId) + } + + func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { + if let notificationSettings = transaction.currentUpdatedPeerNotificationSettings[self.peerId] { + self.notificationSettings = notificationSettings + return true + } else { + return false + } + } + + func immutableView() -> PostboxView { + return PeerNotificationSettingsView(self) + } +} + +public final class PeerNotificationSettingsView: PostboxView { + public let peerId: PeerId + public let notificationSettings: PeerNotificationSettings? + + init(_ view: MutablePeerNotificationSettingsView) { + self.peerId = view.peerId + self.notificationSettings = view.notificationSettings + } +} + diff --git a/Postbox/PeerView.swift b/Postbox/PeerView.swift index fb8656d4f4..e0911aed7d 100644 --- a/Postbox/PeerView.swift +++ b/Postbox/PeerView.swift @@ -9,7 +9,7 @@ final class MutablePeerView: MutablePostboxView { var peerIsContact: Bool init(postbox: Postbox, peerId: PeerId) { - let notificationSettings = postbox.peerNotificationSettingsTable.get(peerId) + let notificationSettings = postbox.peerNotificationSettingsTable.getEffective(peerId) let cachedData = postbox.cachedPeerDataTable.get(peerId) let peerIsContact = postbox.contactsTable.isContact(peerId: peerId) diff --git a/Postbox/PendingPeerNotificationSettingsIndexTable.swift b/Postbox/PendingPeerNotificationSettingsIndexTable.swift new file mode 100644 index 0000000000..4a40121b00 --- /dev/null +++ b/Postbox/PendingPeerNotificationSettingsIndexTable.swift @@ -0,0 +1,40 @@ +import Foundation + +final class PendingPeerNotificationSettingsIndexTable: Table { + static func tableSpec(_ id: Int32) -> ValueBoxTable { + return ValueBoxTable(id: id, keyType: .int64) + } + + private let sharedKey = ValueBoxKey(length: 8) + private var updatedPeerIds: [PeerId: Bool] = [:] + + private func key(_ id: PeerId) -> ValueBoxKey { + self.sharedKey.setInt64(0, value: id.toInt64()) + return self.sharedKey + } + + private func get(peerId: PeerId) -> Bool { + if let _ = self.valueBox.get(self.table, key: self.key(peerId)) { + return true + } else { + return false + } + } + + func getAll() -> [PeerId] { + var peerIds: [PeerId] = [] + self.valueBox.scanInt64(self.table, values: { key, _ in + peerIds.append(PeerId(key)) + return true + }) + return peerIds + } + + func set(peerId: PeerId, pending: Bool) { + if pending { + self.valueBox.set(self.table, key: self.key(peerId), value: MemoryBuffer()) + } else { + self.valueBox.remove(self.table, key: self.key(peerId)) + } + } +} diff --git a/Postbox/PendingPeerNotificationSettingsView.swift b/Postbox/PendingPeerNotificationSettingsView.swift new file mode 100644 index 0000000000..cf794b2c8d --- /dev/null +++ b/Postbox/PendingPeerNotificationSettingsView.swift @@ -0,0 +1,41 @@ + +final class MutablePendingPeerNotificationSettingsView: MutablePostboxView { + var entries: [PeerId: PeerNotificationSettings] = [:] + + init(postbox: Postbox) { + for peerId in postbox.pendingPeerNotificationSettingsIndexTable.getAll() { + if let value = postbox.peerNotificationSettingsTable.getPending(peerId) { + self.entries[peerId] = value + } else { + assertionFailure() + } + } + } + + func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { + var updated = false + for peerId in transaction.currentUpdatedPendingPeerNotificationSettings { + if let value = postbox.peerNotificationSettingsTable.getPending(peerId) { + self.entries[peerId] = value + updated = true + } else if self.entries[peerId] != nil { + self.entries.removeValue(forKey: peerId) + updated = true + } + } + return updated + } + + func immutableView() -> PostboxView { + return PendingPeerNotificationSettingsView(self) + } +} + +public final class PendingPeerNotificationSettingsView: PostboxView { + public let entries: [PeerId: PeerNotificationSettings] + + init(_ view: MutablePendingPeerNotificationSettingsView) { + self.entries = view.entries + } +} + diff --git a/Postbox/Postbox.swift b/Postbox/Postbox.swift index e0a3696bdd..c041fc6026 100644 --- a/Postbox/Postbox.swift +++ b/Postbox/Postbox.swift @@ -179,7 +179,12 @@ public final class Modifier { public func getPeerNotificationSettings(_ id: PeerId) -> PeerNotificationSettings? { assert(!self.disposed) - return self.postbox?.peerNotificationSettingsTable.get(id) + return self.postbox?.peerNotificationSettingsTable.getEffective(id) + } + + public func getPendingPeerNotificationSettings(_ id: PeerId) -> PeerNotificationSettings? { + assert(!self.disposed) + return self.postbox?.peerNotificationSettingsTable.getPending(id) } public func updatePeersInternal(_ peers: [Peer], update: (Peer?, Peer) -> Peer?) { @@ -209,9 +214,14 @@ public final class Modifier { self.postbox?.updatePeerChatListInclusion(id, inclusion: inclusion) } - public func updatePeerNotificationSettings(_ notificationSettings: [PeerId: PeerNotificationSettings]) { + public func updateCurrentPeerNotificationSettings(_ notificationSettings: [PeerId: PeerNotificationSettings]) { assert(!self.disposed) - self.postbox?.updatePeerNotificationSettings(notificationSettings) + self.postbox?.updateCurrentPeerNotificationSettings(notificationSettings) + } + + public func updatePendingPeerNotificationSettings(peerId: PeerId, settings: PeerNotificationSettings?) { + assert(!self.disposed) + self.postbox?.updatePendingPeerNotificationSettings(peerId: peerId, settings: settings) } public func resetAllPeerNotificationSettings(_ notificationSettings: PeerNotificationSettings) { @@ -738,7 +748,7 @@ public func openPostbox(basePath: String, globalMessageIdsNamespace: MessageId.N let metadataTable = MetadataTable(valueBox: valueBox, table: MetadataTable.tableSpec(0)) let userVersion: Int32? = metadataTable.userVersion() - let currentUserVersion: Int32 = 13 + let currentUserVersion: Int32 = 14 if let userVersion = userVersion { if userVersion != currentUserVersion { @@ -812,6 +822,7 @@ public final class Postbox { private var currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] = [:] private var currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey : MessageHistoryTagNamespaceSummary] = [:] private var currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] = [] + private var currentUpdatedPendingPeerNotificationSettings = Set() private var currentReplaceChatListHoles: [(MessageIndex, ChatListHole?)] = [] private var currentReplaceRemoteContactCount: Int32? @@ -835,6 +846,7 @@ public final class Postbox { let keychainTable: KeychainTable let peerTable: PeerTable let peerNotificationSettingsTable: PeerNotificationSettingsTable + let pendingPeerNotificationSettingsIndexTable: PendingPeerNotificationSettingsIndexTable let cachedPeerDataTable: CachedPeerDataTable let peerPresenceTable: PeerPresenceTable let globalMessageIdsTable: GlobalMessageIdsTable @@ -938,7 +950,8 @@ public final class Postbox { self.contactsTable = ContactTable(valueBox: self.valueBox, table: ContactTable.tableSpec(16), peerNameIndexTable: self.peerNameIndexTable) self.peerRatingTable = RatingTable(valueBox: self.valueBox, table: RatingTable.tableSpec(17)) self.cachedPeerDataTable = CachedPeerDataTable(valueBox: self.valueBox, table: CachedPeerDataTable.tableSpec(18)) - self.peerNotificationSettingsTable = PeerNotificationSettingsTable(valueBox: self.valueBox, table: PeerNotificationSettingsTable.tableSpec(19)) + self.pendingPeerNotificationSettingsIndexTable = PendingPeerNotificationSettingsIndexTable(valueBox: self.valueBox, table: PendingPeerNotificationSettingsIndexTable.tableSpec(48)) + self.peerNotificationSettingsTable = PeerNotificationSettingsTable(valueBox: self.valueBox, table: PeerNotificationSettingsTable.tableSpec(19), pendingIndexTable: self.pendingPeerNotificationSettingsIndexTable) self.peerPresenceTable = PeerPresenceTable(valueBox: self.valueBox, table: PeerPresenceTable.tableSpec(20)) self.itemCollectionInfoTable = ItemCollectionInfoTable(valueBox: self.valueBox, table: ItemCollectionInfoTable.tableSpec(21)) self.itemCollectionReverseIndexTable = ReverseIndexReferenceTable(valueBox: self.valueBox, table: ReverseIndexReferenceTable.tableSpec(36)) @@ -1013,7 +1026,7 @@ public final class Postbox { self.viewTracker = ViewTracker(queue: self.queue, fetchEarlierHistoryEntries: self.fetchEarlierHistoryEntries, fetchLaterHistoryEntries: self.fetchLaterHistoryEntries, fetchEarlierChatEntries: self.fetchEarlierChatEntries, fetchLaterChatEntries: self.fetchLaterChatEntries, fetchAnchorIndex: self.fetchAnchorIndex, renderMessage: self.renderIntermediateMessage, getPeer: { peerId in return self.peerTable.get(peerId) }, getPeerNotificationSettings: { peerId in - return self.peerNotificationSettingsTable.get(peerId) + return self.peerNotificationSettingsTable.getEffective(peerId) }, getCachedPeerData: { peerId in return self.cachedPeerDataTable.get(peerId) }, getPeerPresence: { peerId in @@ -1425,7 +1438,7 @@ public final class Postbox { private func beforeCommit() -> (updatedTransactionStateVersion: Int64?, updatedMasterClientId: Int64?) { var chatListOperations: [ChatListOperation] = [] - self.chatListTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId, updatedPeerChatListEmbeddedStates: currentUpdatedPeerChatListEmbeddedStates, updatedChatListInclusions: self.currentUpdatedChatListInclusions, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, operations: &chatListOperations) + self.chatListTable.replay(historyOperationsByPeerId: self.currentOperationsByPeerId, updatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, updatedChatListInclusions: self.currentUpdatedChatListInclusions, messageHistoryTable: self.messageHistoryTable, peerChatInterfaceStateTable: self.peerChatInterfaceStateTable, operations: &chatListOperations) for (index, hole) in self.currentReplaceChatListHoles { self.chatListTable.replaceHole(index, hole: hole, operations: &chatListOperations) } @@ -1438,7 +1451,7 @@ public final class Postbox { return self.peerTable.get(peerId) }, updatedTotalUnreadCount: &self.currentUpdatedTotalUnreadCount) - let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentOperationsByPeerId: self.currentOperationsByPeerId, peerIdsWithFilledHoles: self.currentFilledHolesByPeerId, removedHolesByPeerId: self.currentRemovedHolesByPeerId, chatListOperations: chatListOperations, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadCount: self.currentUpdatedTotalUnreadCount, peerIdsWithUpdatedUnreadCounts: Set(transactionUnreadCountDeltas.keys), currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, updatedAccessChallengeData: self.currentUpdatedAccessChallengeData, currentGlobalTagsOperations: self.currentGlobalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedMasterClientId: currentUpdatedMasterClientId) + let transaction = PostboxTransaction(currentUpdatedState: self.currentUpdatedState, currentOperationsByPeerId: self.currentOperationsByPeerId, peerIdsWithFilledHoles: self.currentFilledHolesByPeerId, removedHolesByPeerId: self.currentRemovedHolesByPeerId, chatListOperations: chatListOperations, currentUpdatedPeers: self.currentUpdatedPeers, currentUpdatedPeerNotificationSettings: self.currentUpdatedPeerNotificationSettings, currentUpdatedCachedPeerData: self.currentUpdatedCachedPeerData, currentUpdatedPeerPresences: currentUpdatedPeerPresences, currentUpdatedPeerChatListEmbeddedStates: self.currentUpdatedPeerChatListEmbeddedStates, currentUpdatedTotalUnreadCount: self.currentUpdatedTotalUnreadCount, peerIdsWithUpdatedUnreadCounts: Set(transactionUnreadCountDeltas.keys), currentPeerMergedOperationLogOperations: self.currentPeerMergedOperationLogOperations, currentTimestampBasedMessageAttributesOperations: self.currentTimestampBasedMessageAttributesOperations, unsentMessageOperations: self.currentUnsentOperations, updatedSynchronizePeerReadStateOperations: self.currentUpdatedSynchronizeReadStateOperations, currentPreferencesOperations: self.currentPreferencesOperations, currentOrderedItemListOperations: self.currentOrderedItemListOperations, currentItemCollectionItemsOperations: self.currentItemCollectionItemsOperations, currentItemCollectionInfosOperations: self.currentItemCollectionInfosOperations, currentUpdatedPeerChatStates: self.currentUpdatedPeerChatStates, updatedAccessChallengeData: self.currentUpdatedAccessChallengeData, currentGlobalTagsOperations: self.currentGlobalTagsOperations, updatedMedia: self.currentUpdatedMedia, replaceRemoteContactCount: self.currentReplaceRemoteContactCount, replaceContactPeerIds: self.currentReplacedContactPeerIds, currentPendingMessageActionsOperations: self.currentPendingMessageActionsOperations, currentUpdatedMessageActionsSummaries: self.currentUpdatedMessageActionsSummaries, currentUpdatedMessageTagSummaries: self.currentUpdatedMessageTagSummaries, currentInvalidateMessageTagSummaries: self.currentInvalidateMessageTagSummaries, currentUpdatedPendingPeerNotificationSettings: self.currentUpdatedPendingPeerNotificationSettings, currentUpdatedMasterClientId: currentUpdatedMasterClientId) var updatedTransactionState: Int64? var updatedMasterClientId: Int64? if !transaction.isEmpty { @@ -1483,6 +1496,7 @@ public final class Postbox { self.currentUpdatedMessageActionsSummaries.removeAll() self.currentUpdatedMessageTagSummaries.removeAll() self.currentInvalidateMessageTagSummaries.removeAll() + self.currentUpdatedPendingPeerNotificationSettings.removeAll() for table in self.tables { table.beforeCommit() @@ -1551,18 +1565,22 @@ public final class Postbox { self.chatListTable.setPinnedPeerIds(peerIds: peerIds, updatedChatListInclusions: &self.currentUpdatedChatListInclusions) } - fileprivate func updatePeerNotificationSettings(_ notificationSettings: [PeerId: PeerNotificationSettings]) { + fileprivate func updateCurrentPeerNotificationSettings(_ notificationSettings: [PeerId: PeerNotificationSettings]) { for (peerId, settings) in notificationSettings { - let currentSettings = self.peerNotificationSettingsTable.get(peerId) - if currentSettings == nil || !(currentSettings!.isEqual(to: settings)) { - self.peerNotificationSettingsTable.set(id: peerId, settings: settings) - self.currentUpdatedPeerNotificationSettings[peerId] = settings + if let updated = self.peerNotificationSettingsTable.setCurrent(id: peerId, settings: settings) { + self.currentUpdatedPeerNotificationSettings[peerId] = updated } } } + fileprivate func updatePendingPeerNotificationSettings(peerId: PeerId, settings: PeerNotificationSettings?) { + if let updated = self.peerNotificationSettingsTable.setPending(id: peerId, settings: settings, updatedSettings: &self.currentUpdatedPendingPeerNotificationSettings) { + self.currentUpdatedPeerNotificationSettings[peerId] = updated + } + } + fileprivate func resetAllPeerNotificationSettings(_ notificationSettings: PeerNotificationSettings) { - for peerId in self.peerNotificationSettingsTable.resetAll(to: notificationSettings) { + for peerId in self.peerNotificationSettingsTable.resetAll(to: notificationSettings, updatedSettings: &self.currentUpdatedPendingPeerNotificationSettings) { self.currentUpdatedPeerNotificationSettings[peerId] = notificationSettings } } @@ -1782,7 +1800,7 @@ public final class Postbox { } } - public func aroundMessageOfInterestHistoryViewForPeerId(_ peerId: PeerId, count: Int, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundMessageOfInterestHistoryViewForPeerId(_ peerId: PeerId, count: Int, clipHoles: Bool, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { return self.modify(userInteractive: true, { modifier -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in var index = MessageHistoryAnchorIndex(index: MessageIndex.upperBound(peerId: peerId), exact: true) if let maxReadIndex = self.messageHistoryTable.maxReadIndex(peerId) { @@ -1790,27 +1808,27 @@ public final class Postbox { } else if let scrollIndex = self.peerChatInterfaceStateTable.get(peerId)?.historyScrollMessageIndex { index = MessageHistoryAnchorIndex(index: scrollIndex, exact: true) } - return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) + return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, clipHoles: clipHoles, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) }) |> switchToLatest } - public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, messageId: MessageId, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundIdMessageHistoryViewForPeerId(_ peerId: PeerId, count: Int, clipHoles: Bool, messageId: MessageId, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { return self.modify { modifier -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in var index = MessageHistoryAnchorIndex(index: MessageIndex.upperBound(peerId: peerId), exact: true) if let anchorIndex = self.messageHistoryTable.anchorIndex(messageId) { index = anchorIndex } - return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) + return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index.index, count: count, clipHoles: clipHoles, anchorIndex: index, unreadIndex: index.index, fixedCombinedReadState: nil, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) } |> switchToLatest } - public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + public func aroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, clipHoles: Bool, anchorIndex: MessageIndex, fixedCombinedReadState: CombinedPeerReadState?, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData] = []) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { return self.modify { modifier -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> in - return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index, count: count, anchorIndex: MessageHistoryAnchorIndex(index: anchorIndex, exact: true), unreadIndex: nil, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) + return self.syncAroundMessageHistoryViewForPeerId(peerId, index: index, count: count, clipHoles: clipHoles, anchorIndex: MessageHistoryAnchorIndex(index: anchorIndex, exact: true), unreadIndex: nil, fixedCombinedReadState: fixedCombinedReadState, topTaggedMessageIdNamespaces: topTaggedMessageIdNamespaces, tagMask: tagMask, orderStatistics: orderStatistics, additionalData: additionalData) } |> switchToLatest } - private func syncAroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, anchorIndex: MessageHistoryAnchorIndex, unreadIndex: MessageIndex?, fixedCombinedReadState: CombinedPeerReadState?, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { + private func syncAroundMessageHistoryViewForPeerId(_ peerId: PeerId, index: MessageIndex, count: Int, clipHoles: Bool, anchorIndex: MessageHistoryAnchorIndex, unreadIndex: MessageIndex?, fixedCombinedReadState: CombinedPeerReadState?, topTaggedMessageIdNamespaces: Set, tagMask: MessageTags?, orderStatistics: MessageHistoryViewOrderStatistics, additionalData: [AdditionalMessageHistoryViewData]) -> Signal<(MessageHistoryView, ViewUpdateType, InitialMessageHistoryData?), NoError> { let startTime = CFAbsoluteTimeGetCurrent() let (entries, earlier, later) = self.fetchAroundHistoryEntries(index, count: count, tagMask: tagMask) print("aroundMessageHistoryViewForPeerId fetchAroundHistoryEntries \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms") @@ -1842,10 +1860,12 @@ public final class Postbox { additionalDataEntries.append(.peerChatState(peerId, self.peerChatStateTable.get(peerId) as? PeerChatState)) case .totalUnreadCount: additionalDataEntries.append(.totalUnreadCount(self.messageHistoryMetadataTable.getChatListTotalUnreadCount())) + case let .peerNotificationSettings(peerId): + additionalDataEntries.append(.peerNotificationSettings(self.peerNotificationSettingsTable.getEffective(peerId))) } } - let mutableView = MutableMessageHistoryView(id: MessageHistoryViewId(peerId: peerId, id: self.takeNextViewId()), postbox: self, orderStatistics: orderStatistics, peerId: peerId, anchorIndex: anchorIndex, combinedReadState: fixedCombinedReadState ?? self.readStateTable.getCombinedState(peerId), earlier: earlier, entries: entries, later: later, tagMask: tagMask, count: count, topTaggedMessages: topTaggedMessages, additionalDatas: additionalDataEntries, getMessageCountInRange: { lowerBound, upperBound in + let mutableView = MutableMessageHistoryView(id: MessageHistoryViewId(peerId: peerId, id: self.takeNextViewId()), postbox: self, orderStatistics: orderStatistics, peerId: peerId, anchorIndex: anchorIndex, combinedReadState: fixedCombinedReadState ?? self.readStateTable.getCombinedState(peerId), earlier: earlier, entries: entries, later: later, tagMask: tagMask, count: count, clipHoles: clipHoles, topTaggedMessages: topTaggedMessages, additionalDatas: additionalDataEntries, getMessageCountInRange: { lowerBound, upperBound in if let tagMask = tagMask { return self.messageHistoryTable.getMessageCountInRange(peerId: peerId, tagMask: tagMask, lowerBound: lowerBound, upperBound: upperBound) } else { @@ -1933,7 +1953,7 @@ public final class Postbox { let mutableView = MutableChatListView(earlier: earlier, entries: entries, later: later, count: count, summaryComponents: summaryComponents) mutableView.render(postbox: self, renderMessage: self.renderIntermediateMessage, getPeer: { id in return self.peerTable.get(id) - }, getPeerNotificationSettings: { self.peerNotificationSettingsTable.get($0) }) + }, getPeerNotificationSettings: { self.peerNotificationSettingsTable.getEffective($0) }) let (index, signal) = self.viewTracker.addChatListView(mutableView) @@ -2097,19 +2117,7 @@ public final class Postbox { public func unreadMessageCountsView(items: [UnreadMessageCountsItem]) -> Signal { return self.modify { modifier -> Signal in - let entries: [UnreadMessageCountsItemEntry] = items.map { item in - switch item { - case .total: - return .total(self.messageHistoryMetadataTable.getChatListTotalUnreadCount()) - case let .peer(peerId): - var count: Int32 = 0 - if let combinedState = self.readStateTable.getCombinedState(peerId) { - count = combinedState.count - } - return .peer(peerId, count) - } - } - let view = MutableUnreadMessageCountsView(entries: entries) + let view = MutableUnreadMessageCountsView(postbox: self, items: items) let (index, signal) = self.viewTracker.addUnreadMessageCountsView(view) return (.single(UnreadMessageCountsView(view)) diff --git a/Postbox/PostboxPrivate/sqlcipher/sqlite3.c b/Postbox/PostboxPrivate/sqlcipher/sqlite3.c index 59d03f428e..3aa3174e06 100644 --- a/Postbox/PostboxPrivate/sqlcipher/sqlite3.c +++ b/Postbox/PostboxPrivate/sqlcipher/sqlite3.c @@ -11824,6 +11824,11 @@ typedef INT16_TYPE LogEst; # define SQLITE_MAX_MMAP_SIZE_xc 1 /* exclude from ctime.c */ #endif +#ifdef SQLITE_MAX_MMAP_SIZE +#undef SQLITE_MAX_MMAP_SIZE +#endif +#define SQLITE_MAX_MMAP_SIZE 0 + /* ** The default MMAP_SIZE is zero on all platforms. Or, even if a larger ** default MMAP_SIZE is specified at compile-time, make sure that it does diff --git a/Postbox/PostboxTransaction.swift b/Postbox/PostboxTransaction.swift index f6d1a635ff..e6b16fabd7 100644 --- a/Postbox/PostboxTransaction.swift +++ b/Postbox/PostboxTransaction.swift @@ -26,6 +26,7 @@ final class PostboxTransaction { let currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32] let currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary] let currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation] + let currentUpdatedPendingPeerNotificationSettings: Set let unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation] let updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?] @@ -128,10 +129,13 @@ final class PostboxTransaction { if !self.currentInvalidateMessageTagSummaries.isEmpty { return false } + if !self.currentUpdatedPendingPeerNotificationSettings.isEmpty { + return false + } return true } - init(currentUpdatedState: PostboxCoding?, currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], peerIdsWithFilledHoles: [PeerId: [MessageIndex: HoleFillDirection]], removedHolesByPeerId: [PeerId: [MessageIndex: HoleFillDirection]], chatListOperations: [ChatListOperation], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?], currentUpdatedTotalUnreadCount: Int32?, peerIdsWithUpdatedUnreadCounts: Set, currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set, updatedAccessChallengeData: PostboxAccessChallengeData?, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedMasterClientId: Int64?) { + init(currentUpdatedState: PostboxCoding?, currentOperationsByPeerId: [PeerId: [MessageHistoryOperation]], peerIdsWithFilledHoles: [PeerId: [MessageIndex: HoleFillDirection]], removedHolesByPeerId: [PeerId: [MessageIndex: HoleFillDirection]], chatListOperations: [ChatListOperation], currentUpdatedPeers: [PeerId: Peer], currentUpdatedPeerNotificationSettings: [PeerId: PeerNotificationSettings], currentUpdatedCachedPeerData: [PeerId: CachedPeerData], currentUpdatedPeerPresences: [PeerId: PeerPresence], currentUpdatedPeerChatListEmbeddedStates: [PeerId: PeerChatListEmbeddedInterfaceState?], currentUpdatedTotalUnreadCount: Int32?, peerIdsWithUpdatedUnreadCounts: Set, currentPeerMergedOperationLogOperations: [PeerMergedOperationLogOperation], currentTimestampBasedMessageAttributesOperations: [TimestampBasedMessageAttributesOperation], unsentMessageOperations: [IntermediateMessageHistoryUnsentOperation], updatedSynchronizePeerReadStateOperations: [PeerId: PeerReadStateSynchronizationOperation?], currentPreferencesOperations: [PreferencesOperation], currentOrderedItemListOperations: [Int32: [OrderedItemListOperation]], currentItemCollectionItemsOperations: [ItemCollectionId: [ItemCollectionItemsOperation]], currentItemCollectionInfosOperations: [ItemCollectionInfosOperation], currentUpdatedPeerChatStates: Set, updatedAccessChallengeData: PostboxAccessChallengeData?, currentGlobalTagsOperations: [GlobalMessageHistoryTagsOperation], updatedMedia: [MediaId: Media?], replaceRemoteContactCount: Int32?, replaceContactPeerIds: Set?, currentPendingMessageActionsOperations: [PendingMessageActionsOperation], currentUpdatedMessageActionsSummaries: [PendingMessageActionsSummaryKey: Int32], currentUpdatedMessageTagSummaries: [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], currentInvalidateMessageTagSummaries: [InvalidatedMessageHistoryTagsSummaryEntryOperation], currentUpdatedPendingPeerNotificationSettings: Set, currentUpdatedMasterClientId: Int64?) { self.currentUpdatedState = currentUpdatedState self.currentOperationsByPeerId = currentOperationsByPeerId self.peerIdsWithFilledHoles = peerIdsWithFilledHoles @@ -162,6 +166,7 @@ final class PostboxTransaction { self.currentUpdatedMessageActionsSummaries = currentUpdatedMessageActionsSummaries self.currentUpdatedMessageTagSummaries = currentUpdatedMessageTagSummaries self.currentInvalidateMessageTagSummaries = currentInvalidateMessageTagSummaries + self.currentUpdatedPendingPeerNotificationSettings = currentUpdatedPendingPeerNotificationSettings self.currentUpdatedMasterClientId = currentUpdatedMasterClientId } } diff --git a/Postbox/PostboxUpgrade_13to14.swift b/Postbox/PostboxUpgrade_13to14.swift index d84659cef5..5420cffc8b 100644 --- a/Postbox/PostboxUpgrade_13to14.swift +++ b/Postbox/PostboxUpgrade_13to14.swift @@ -1,40 +1,28 @@ import Foundation -private func writePeerIds(_ buffer: WriteBuffer, _ peerIds: Set) { - for id in peerIds { - var value: Int64 = id.toInt64() - buffer.write(&value, offset: 0, length: 8) - } -} - func postboxUpgrade_13to14(metadataTable: MetadataTable, valueBox: ValueBox) { - var reverseAssociations: [PeerId: Set] = [:] + var peerSettings: [PeerId: Data] = [:] - let peerTable = ValueBoxTable(id: 2, keyType: .int64) - valueBox.scan(peerTable, values: { _, value in - if let peer = PostboxDecoder(buffer: value).decodeRootObject() as? Peer { - if let association = peer.associatedPeerId { - if reverseAssociations[association] == nil { - reverseAssociations[association] = Set() - } - reverseAssociations[association]!.insert(peer.id) - } - } else { - assertionFailure() - } + let peerNotificationSettingsTable = ValueBoxTable(id: 19, keyType: .int64) + valueBox.scanInt64(peerNotificationSettingsTable, values: { key, value in + let peerId = PeerId(key) + peerSettings[peerId] = value.makeData() return true }) - let reverseAssociatedPeerTable = ValueBoxTable(id: 40, keyType: .int64) - - let sharedKey = ValueBoxKey(length: 8) - let sharedBuffer = WriteBuffer() - for (peerId, associations) in reverseAssociations { - sharedBuffer.reset() - writePeerIds(sharedBuffer, associations) + valueBox.dropTable(peerNotificationSettingsTable) + let key = ValueBoxKey(length: 8) + let buffer = WriteBuffer() + for (peerId, settings) in peerSettings { + buffer.reset() - sharedKey.setInt64(0, value: peerId.toInt64()) - valueBox.set(reverseAssociatedPeerTable, key: sharedKey, value: sharedBuffer) + key.setInt64(0, value: peerId.toInt64()) + var flagsValue: Int32 = (1 << 0) + buffer.write(&flagsValue, offset: 0, length: 4) + var length: Int32 = Int32(settings.count) + buffer.write(&length, offset: 0, length: 4) + buffer.write(settings) + valueBox.set(peerNotificationSettingsTable, key: key, value: buffer) } metadataTable.setUserVersion(14) diff --git a/Postbox/SqliteValueBox.swift b/Postbox/SqliteValueBox.swift index ccd0a09b11..be0d1b77c5 100644 --- a/Postbox/SqliteValueBox.swift +++ b/Postbox/SqliteValueBox.swift @@ -102,6 +102,10 @@ private struct SqlitePreparedStatement { return key } + func int64KeyValueAt(_ index: Int) -> Int64 { + return sqlite3_column_int64(statement, Int32(index)) + } + func destroy() { sqlite3_finalize(statement) } @@ -177,10 +181,8 @@ final class SqliteValueBox: ValueBox { var resultCode: Bool //database.execute("PRAGMA cache_size=-2097152") + resultCode = database.execute("PRAGMA mmap_size=0") resultCode = database.execute("PRAGMA journal_mode=WAL") - if !resultCode { - resultCode = database.execute("PRAGMA VACUUM") - } assert(resultCode) resultCode = database.execute("PRAGMA synchronous=NORMAL") assert(resultCode) @@ -192,7 +194,7 @@ final class SqliteValueBox: ValueBox { /*var statement: OpaquePointer? = nil sqlite3_prepare_v2(database.handle, "PRAGMA integrity_check", -1, &statement, nil) let preparedStatement = SqlitePreparedStatement(statement: statement) - while preparedStatement.step() { + while preparedStatement.step(handle: database.handle) { let value = preparedStatement.valueAt(0) let text = String(data: Data(bytes: value.memory.assumingMemoryBound(to: UInt8.self), count: value.length), encoding: .utf8) print("integrity_check: \(text ?? "")") @@ -1186,6 +1188,37 @@ final class SqliteValueBox: ValueBox { } } + public func scanInt64(_ table: ValueBoxTable, values: (Int64, ReadBuffer) -> Bool) { + assert(self.queue.isCurrent()) + + if let _ = self.tables[table.id] { + let statement: SqlitePreparedStatement = self.scanStatement(table) + + var startTime = CFAbsoluteTimeGetCurrent() + + var currentTime = CFAbsoluteTimeGetCurrent() + self.readQueryTime += currentTime - startTime + + startTime = currentTime + + while statement.step(handle: self.database.handle) { + startTime = CFAbsoluteTimeGetCurrent() + + let key = statement.int64KeyValueAt(0) + let value = statement.valueAt(1) + + currentTime = CFAbsoluteTimeGetCurrent() + self.readQueryTime += currentTime - startTime + + if !values(key, value) { + break + } + } + + statement.reset() + } + } + public func set(_ table: ValueBoxTable, key: ValueBoxKey, value: MemoryBuffer) { assert(self.queue.isCurrent()) self.checkTable(table) diff --git a/Postbox/UnreadMessageCountsView.swift b/Postbox/UnreadMessageCountsView.swift index 21551728f4..1f61421f65 100644 --- a/Postbox/UnreadMessageCountsView.swift +++ b/Postbox/UnreadMessageCountsView.swift @@ -1,8 +1,25 @@ import Foundation -public enum UnreadMessageCountsItem { +public enum UnreadMessageCountsItem: Equatable { case total case peer(PeerId) + + public static func ==(lhs: UnreadMessageCountsItem, rhs: UnreadMessageCountsItem) -> Bool { + switch lhs { + case .total: + if case .total = rhs { + return true + } else { + return false + } + case let .peer(peerId): + if case .peer(peerId) = rhs { + return true + } else { + return false + } + } + } } enum UnreadMessageCountsItemEntry { @@ -10,41 +27,60 @@ enum UnreadMessageCountsItemEntry { case peer(PeerId, Int32) } -final class MutableUnreadMessageCountsView { +final class MutableUnreadMessageCountsView: MutablePostboxView { fileprivate var entries: [UnreadMessageCountsItemEntry] - init(entries: [UnreadMessageCountsItemEntry]) { - self.entries = entries + init(postbox: Postbox, items: [UnreadMessageCountsItem]) { + self.entries = items.map { item in + switch item { + case .total: + return .total(postbox.messageHistoryMetadataTable.getChatListTotalUnreadCount()) + case let .peer(peerId): + var count: Int32 = 0 + if let combinedState = postbox.readStateTable.getCombinedState(peerId) { + count = combinedState.count + } + return .peer(peerId, count) + } + } } - func replay(peerIdsWithUpdatedUnreadCounts: Set, getTotalUnreadCount: () -> Int32, getPeerReadState: (PeerId) -> CombinedPeerReadState?) -> Bool { + func replay(postbox: Postbox, transaction: PostboxTransaction) -> Bool { var updated = false - for i in 0 ..< self.entries.count { - switch self.entries[i] { - case let .total(count): - let updatedCount = getTotalUnreadCount() - if updatedCount != count { - self.entries[i] = .total(updatedCount) - updated = true - } - case let .peer(peerId, count): - if peerIdsWithUpdatedUnreadCounts.contains(peerId) { - var updatedCount: Int32 = 0 - if let combinedState = getPeerReadState(peerId) { - updatedCount = combinedState.count + if transaction.currentUpdatedTotalUnreadCount != nil || !transaction.peerIdsWithUpdatedUnreadCounts.isEmpty { + for i in 0 ..< self.entries.count { + switch self.entries[i] { + case let .total(count): + if transaction.currentUpdatedTotalUnreadCount != nil { + let updatedCount = postbox.messageHistoryMetadataTable.getChatListTotalUnreadCount() + if updatedCount != count { + self.entries[i] = .total(updatedCount) + updated = true + } } - self.entries[i] = .peer(peerId, updatedCount) - updated = true - } + case let .peer(peerId, count): + if transaction.peerIdsWithUpdatedUnreadCounts.contains(peerId) { + var updatedCount: Int32 = 0 + if let combinedState = postbox.readStateTable.getCombinedState(peerId) { + updatedCount = combinedState.count + } + self.entries[i] = .peer(peerId, updatedCount) + updated = true + } + } } } return updated } + + func immutableView() -> PostboxView { + return UnreadMessageCountsView(self) + } } -public final class UnreadMessageCountsView { +public final class UnreadMessageCountsView: PostboxView { private let entries: [UnreadMessageCountsItemEntry] init(_ view: MutableUnreadMessageCountsView) { diff --git a/Postbox/Upgrades.swift b/Postbox/Upgrades.swift index 21e053a2d6..ac0a6a7885 100644 --- a/Postbox/Upgrades.swift +++ b/Postbox/Upgrades.swift @@ -8,5 +8,6 @@ func registeredUpgrades() -> [Int32: PostboxUpgradeOperation] { var dict: [Int32: PostboxUpgradeOperation] = [:] dict[12] = .inplace(postboxUpgrade_12to13) dict[13] = .inplace(postboxUpgrade_13to14) + //dict[14] = .inplace(postboxUpgrade_14to15) return dict } diff --git a/Postbox/ValueBox.swift b/Postbox/ValueBox.swift index fa5cb36034..7dad255bd2 100644 --- a/Postbox/ValueBox.swift +++ b/Postbox/ValueBox.swift @@ -24,6 +24,7 @@ protocol ValueBox { func range(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey, values: (ValueBoxKey, ReadBuffer) -> Bool, limit: Int) func range(_ table: ValueBoxTable, start: ValueBoxKey, end: ValueBoxKey, keys: (ValueBoxKey) -> Bool, limit: Int) func scan(_ table: ValueBoxTable, values: (ValueBoxKey, ReadBuffer) -> Bool) + func scanInt64(_ table: ValueBoxTable, values: (Int64, ReadBuffer) -> Bool) func get(_ table: ValueBoxTable, key: ValueBoxKey) -> ReadBuffer? func exists(_ table: ValueBoxTable, key: ValueBoxKey) -> Bool func set(_ table: ValueBoxTable, key: ValueBoxKey, value: MemoryBuffer) diff --git a/Postbox/ViewTracker.swift b/Postbox/ViewTracker.swift index b6d1979273..6c030d84ee 100644 --- a/Postbox/ViewTracker.swift +++ b/Postbox/ViewTracker.swift @@ -435,7 +435,7 @@ final class ViewTracker { } for (view, pipe) in self.unreadMessageCountsViews.copyItems() { - if view.replay(peerIdsWithUpdatedUnreadCounts: transaction.peerIdsWithUpdatedUnreadCounts, getTotalUnreadCount: self.getTotalUnreadCount, getPeerReadState: self.getPeerReadState) { + if view.replay(postbox: postbox, transaction: transaction) { pipe.putNext(UnreadMessageCountsView(view)) } } diff --git a/Postbox/Views.swift b/Postbox/Views.swift index a9b122f440..ce0039583d 100644 --- a/Postbox/Views.swift +++ b/Postbox/Views.swift @@ -15,6 +15,9 @@ public enum PostboxViewKey: Hashable { case pendingMessageActionsSummary(type: PendingMessageActionType, peerId: PeerId, namespace: MessageId.Namespace) case historyTagSummaryView(tag: MessageTags, peerId: PeerId, namespace: MessageId.Namespace) case cachedPeerData(peerId: PeerId) + case unreadCounts(items: [UnreadMessageCountsItem]) + case peerNotificationSettings(peerId: PeerId) + case pendingPeerNotificationSettings public var hashValue: Int { switch self { @@ -46,6 +49,12 @@ public enum PostboxViewKey: Hashable { return tag.rawValue.hashValue ^ peerId.hashValue ^ namespace.hashValue case let .cachedPeerData(peerId): return peerId.hashValue + case .unreadCounts: + return 5 + case let .peerNotificationSettings(peerId): + return 6 &+ 31 &* peerId.hashValue + case .pendingPeerNotificationSettings: + return 7 } } @@ -135,6 +144,24 @@ public enum PostboxViewKey: Hashable { } else { return false } + case let .unreadCounts(lhsItems): + if case let .unreadCounts(rhsItems) = rhs, lhsItems == rhsItems { + return true + } else { + return false + } + case let .peerNotificationSettings(peerId): + if case .peerNotificationSettings(peerId) = rhs { + return true + } else { + return false + } + case .pendingPeerNotificationSettings: + if case .pendingPeerNotificationSettings = rhs { + return true + } else { + return false + } } } } @@ -169,5 +196,11 @@ func postboxViewForKey(postbox: Postbox, key: PostboxViewKey) -> MutablePostboxV return MutableMessageHistoryTagSummaryView(postbox: postbox, tag: tag, peerId: peerId, namespace: namespace) case let .cachedPeerData(peerId): return MutableCachedPeerDataView(postbox: postbox, peerId: peerId) + case let .unreadCounts(items): + return MutableUnreadMessageCountsView(postbox: postbox, items: items) + case let .peerNotificationSettings(peerId): + return MutablePeerNotificationSettingsView(postbox: postbox, peerId: peerId) + case .pendingPeerNotificationSettings: + return MutablePendingPeerNotificationSettingsView(postbox: postbox) } }