no message

This commit is contained in:
Peter 2017-10-10 18:42:50 +03:00
parent dfdc87bf95
commit 00c3e87b11
36 changed files with 1461 additions and 245 deletions

View File

@ -129,6 +129,8 @@
D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */; }; D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */; };
D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */; }; D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */; };
D0223A9C1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */; }; D0223A9C1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */; };
D02395D61F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */; };
D02395D71F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */; };
D02ABC7B1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */; }; D02ABC7B1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */; };
D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */; }; D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */; };
D02ABC7E1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */; }; D02ABC7E1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */; };
@ -206,6 +208,10 @@
D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */; }; D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843841DA6EDC4005F29E1 /* CachedChannelData.swift */; };
D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B844521DAC0773005F29E1 /* TelegramUserPresence.swift */; }; D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B844521DAC0773005F29E1 /* TelegramUserPresence.swift */; };
D03C53771DAFF20F004C17B3 /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */; }; D03C53771DAFF20F004C17B3 /* MultipartUpload.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */; };
D03DC9101F82E344001D584C /* AccountStateReset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC90F1F82E344001D584C /* AccountStateReset.swift */; };
D03DC9111F82E344001D584C /* AccountStateReset.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC90F1F82E344001D584C /* AccountStateReset.swift */; };
D03DC9131F82F89D001D584C /* RegularChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC9121F82F89D001D584C /* RegularChatState.swift */; };
D03DC9141F82F89D001D584C /* RegularChatState.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03DC9121F82F89D001D584C /* RegularChatState.swift */; };
D03E5E0C1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */; }; D03E5E0C1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */; };
D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */; }; D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */; };
D041E3F51E535464008C24B4 /* AddPeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F41E535464008C24B4 /* AddPeerMember.swift */; }; D041E3F51E535464008C24B4 /* AddPeerMember.swift in Sources */ = {isa = PBXBuildFile; fileRef = D041E3F41E535464008C24B4 /* AddPeerMember.swift */; };
@ -648,6 +654,7 @@
D021E0E11DB5401A00C6B04F /* StickerManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerManagement.swift; sourceTree = "<group>"; }; D021E0E11DB5401A00C6B04F /* StickerManagement.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerManagement.swift; sourceTree = "<group>"; };
D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaResourceNetworkStatsTag.swift; sourceTree = "<group>"; }; D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaResourceNetworkStatsTag.swift; sourceTree = "<group>"; };
D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaResource.swift; sourceTree = "<group>"; }; D0223A9A1EA5654D00211D94 /* TelegramMediaResource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TelegramMediaResource.swift; sourceTree = "<group>"; };
D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelHistoryAvailabilitySettings.swift; sourceTree = "<group>"; };
D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteMessagesInteractively.swift; sourceTree = "<group>"; }; D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeleteMessagesInteractively.swift; sourceTree = "<group>"; };
D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudChatRemoveMessagesOperation.swift; sourceTree = "<group>"; }; D02ABC7D1E3109F000CAE539 /* CloudChatRemoveMessagesOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CloudChatRemoveMessagesOperation.swift; sourceTree = "<group>"; };
D02ABC801E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedCloudChatRemoveMessagesOperations.swift; sourceTree = "<group>"; }; D02ABC801E310E5D00CAE539 /* ManagedCloudChatRemoveMessagesOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedCloudChatRemoveMessagesOperations.swift; sourceTree = "<group>"; };
@ -713,6 +720,8 @@
D03B0E691D63283000955575 /* libwebp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebp.a; path = "third-party/libwebp/lib/libwebp.a"; sourceTree = "<group>"; }; D03B0E691D63283000955575 /* libwebp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libwebp.a; path = "third-party/libwebp/lib/libwebp.a"; sourceTree = "<group>"; };
D03B0E6B1D63283C00955575 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; }; D03B0E6B1D63283C00955575 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipartUpload.swift; sourceTree = "<group>"; }; D03C53761DAFF20F004C17B3 /* MultipartUpload.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MultipartUpload.swift; sourceTree = "<group>"; };
D03DC90F1F82E344001D584C /* AccountStateReset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountStateReset.swift; sourceTree = "<group>"; };
D03DC9121F82F89D001D584C /* RegularChatState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RegularChatState.swift; sourceTree = "<group>"; };
D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutAccountAttribute.swift; sourceTree = "<group>"; }; D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoggedOutAccountAttribute.swift; sourceTree = "<group>"; };
D041E3F41E535464008C24B4 /* AddPeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPeerMember.swift; sourceTree = "<group>"; }; D041E3F41E535464008C24B4 /* AddPeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddPeerMember.swift; sourceTree = "<group>"; };
D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemovePeerMember.swift; sourceTree = "<group>"; }; D041E3F71E535A88008C24B4 /* RemovePeerMember.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemovePeerMember.swift; sourceTree = "<group>"; };
@ -1153,12 +1162,14 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
D03B0CFF1D62255C00955575 /* ChannelState.swift */, D03B0CFF1D62255C00955575 /* ChannelState.swift */,
D03DC9121F82F89D001D584C /* RegularChatState.swift */,
D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */, D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */,
D03B0D001D62255C00955575 /* EnqueueMessage.swift */, D03B0D001D62255C00955575 /* EnqueueMessage.swift */,
D03B0D011D62255C00955575 /* Holes.swift */, D03B0D011D62255C00955575 /* Holes.swift */,
D017495D1E118F790057C89A /* AccountStateManager.swift */, D017495D1E118F790057C89A /* AccountStateManager.swift */,
D017495F1E118FC30057C89A /* AccountIntermediateState.swift */, D017495F1E118FC30057C89A /* AccountIntermediateState.swift */,
D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */, D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */,
D03DC90F1F82E344001D584C /* AccountStateReset.swift */,
D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */, D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */,
D03B0D051D62255C00955575 /* UpdateGroup.swift */, D03B0D051D62255C00955575 /* UpdateGroup.swift */,
D03B0D061D62255C00955575 /* UpdateMessageService.swift */, D03B0D061D62255C00955575 /* UpdateMessageService.swift */,
@ -1492,6 +1503,7 @@
C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */, C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */,
D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */, D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */,
D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */, D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */,
D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */,
); );
name = Peers; name = Peers;
sourceTree = "<group>"; sourceTree = "<group>";
@ -1814,6 +1826,7 @@
D0E23DDA1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */, D0E23DDA1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */,
D049EAD81E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */, D049EAD81E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */,
D0448C991E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */, D0448C991E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */,
D03DC9131F82F89D001D584C /* RegularChatState.swift in Sources */,
D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */, D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */,
C2366C891E4F40480097CCFF /* SupportPeerId.swift in Sources */, C2366C891E4F40480097CCFF /* SupportPeerId.swift in Sources */,
D05A32E11E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */, D05A32E11E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */,
@ -1837,6 +1850,7 @@
C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */, C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */,
D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */, D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */,
D03B0CD61D62245300955575 /* TelegramUser.swift in Sources */, D03B0CD61D62245300955575 /* TelegramUser.swift in Sources */,
D02395D61F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */,
D019B1CC1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */, D019B1CC1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */,
D03B0CD91D62245B00955575 /* PeerUtils.swift in Sources */, D03B0CD91D62245B00955575 /* PeerUtils.swift in Sources */,
D053B41B1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */, D053B41B1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */,
@ -1905,6 +1919,7 @@
D03B0D5C1D631A6900955575 /* Download.swift in Sources */, D03B0D5C1D631A6900955575 /* Download.swift in Sources */,
D0C27B421F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */, D0C27B421F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */,
D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */, D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */,
D03DC9101F82E344001D584C /* AccountStateReset.swift in Sources */,
D01B27A21E394D8B0022A4C0 /* PrivacySettings.swift in Sources */, D01B27A21E394D8B0022A4C0 /* PrivacySettings.swift in Sources */,
D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */, D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */,
D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */, D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */,
@ -2011,6 +2026,7 @@
D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */, D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */,
D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */, D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */,
D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */, D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */,
D03DC9111F82E344001D584C /* AccountStateReset.swift in Sources */,
D050F2111E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */, D050F2111E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */,
D050F2631E4A5AEB00988324 /* SynchronizePinnedChatsOperation.swift in Sources */, D050F2631E4A5AEB00988324 /* SynchronizePinnedChatsOperation.swift in Sources */,
D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */, D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */,
@ -2075,6 +2091,7 @@
D0BEAF611E54ACF900BD963D /* AccountManager.swift in Sources */, D0BEAF611E54ACF900BD963D /* AccountManager.swift in Sources */,
D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */, D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */,
D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */, D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */,
D03DC9141F82F89D001D584C /* RegularChatState.swift in Sources */,
D00C7CD01E3628180080C3D5 /* UpdateCachedChannelParticipants.swift in Sources */, D00C7CD01E3628180080C3D5 /* UpdateCachedChannelParticipants.swift in Sources */,
D0F3A8A61E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */, D0F3A8A61E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */,
D00BDA1A1EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */, D00BDA1A1EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */,
@ -2193,6 +2210,7 @@
D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */, D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */,
D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */, D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */,
D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */, D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */,
D02395D71F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */,
D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */, D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */,
D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */, D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */,
D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */, D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */,

View File

@ -173,6 +173,7 @@ private var declaredEncodables: Void = {
declareEncodable(TelegramMediaFileAttribute.self, f: { TelegramMediaFileAttribute(decoder: $0) }) declareEncodable(TelegramMediaFileAttribute.self, f: { TelegramMediaFileAttribute(decoder: $0) })
declareEncodable(CloudFileMediaResource.self, f: { CloudFileMediaResource(decoder: $0) }) declareEncodable(CloudFileMediaResource.self, f: { CloudFileMediaResource(decoder: $0) })
declareEncodable(ChannelState.self, f: { ChannelState(decoder: $0) }) declareEncodable(ChannelState.self, f: { ChannelState(decoder: $0) })
declareEncodable(RegularChatState.self, f: { RegularChatState(decoder: $0) })
declareEncodable(InlineBotMessageAttribute.self, f: { InlineBotMessageAttribute(decoder: $0) }) declareEncodable(InlineBotMessageAttribute.self, f: { InlineBotMessageAttribute(decoder: $0) })
declareEncodable(TextEntitiesMessageAttribute.self, f: { TextEntitiesMessageAttribute(decoder: $0) }) declareEncodable(TextEntitiesMessageAttribute.self, f: { TextEntitiesMessageAttribute(decoder: $0) })
declareEncodable(ReplyMessageAttribute.self, f: { ReplyMessageAttribute(decoder: $0) }) declareEncodable(ReplyMessageAttribute.self, f: { ReplyMessageAttribute(decoder: $0) })
@ -748,7 +749,7 @@ public func setupAccount(_ account: Account, fetchCachedResourceRepresentation:
account.transformOutgoingMessageMedia = transformOutgoingMessageMedia account.transformOutgoingMessageMedia = transformOutgoingMessageMedia
account.pendingMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia account.pendingMessageManager.transformOutgoingMessageMedia = transformOutgoingMessageMedia
account.managedContactsDisposable.set(manageContacts(network: account.network, postbox: account.postbox).start()) account.managedContactsDisposable.set(manageContacts(network: account.network, postbox: account.postbox, accountPeerId: account.peerId).start())
account.managedStickerPacksDisposable.set(manageStickerPacks(network: account.network, postbox: account.postbox).start()) account.managedStickerPacksDisposable.set(manageStickerPacks(network: account.network, postbox: account.postbox).start())
/*account.network.request(Api.functions.help.getScheme(version: 0)).start(next: { result in /*account.network.request(Api.functions.help.getScheme(version: 0)).start(next: { result in

View File

@ -84,6 +84,7 @@ enum AccountStateMutationOperation {
case UpdateChatInputState(PeerId, SynchronizeableChatInputState?) case UpdateChatInputState(PeerId, SynchronizeableChatInputState?)
case UpdateCall(Api.PhoneCall) case UpdateCall(Api.PhoneCall)
case UpdateLangPack(Api.LangPackDifference?) case UpdateLangPack(Api.LangPackDifference?)
case UpdateMinAvailableMessage(MessageId)
} }
struct AccountMutableState { struct AccountMutableState {
@ -220,6 +221,10 @@ struct AccountMutableState {
self.addOperation(.UpdateLangPack(difference)) self.addOperation(.UpdateLangPack(difference))
} }
mutating func updateMinAvailableMessage(_ id: MessageId) {
self.addOperation(.UpdateMinAvailableMessage(id))
}
mutating func mergeUsers(_ users: [Api.User]) { mutating func mergeUsers(_ users: [Api.User]) {
self.addOperation(.MergeApiUsers(users)) self.addOperation(.MergeApiUsers(users))
@ -286,7 +291,7 @@ struct AccountMutableState {
mutating func addOperation(_ operation: AccountStateMutationOperation) { mutating func addOperation(_ operation: AccountStateMutationOperation) {
switch operation { switch operation {
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedPeerIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateChatInputState, .UpdateCall, .UpdateLangPack: case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedPeerIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage:
break break
case let .AddMessages(messages, _): case let .AddMessages(messages, _):
for message in messages { for message in messages {

View File

@ -443,7 +443,7 @@ func finalStateWithUpdateGroups(_ account: Account, state: AccountMutableState,
} }
} }
return finalStateWithUpdates(account: account, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty) return finalStateWithUpdates(account: account, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty, shouldResetChannels: true)
} }
func finalStateWithDifference(account: Account, state: AccountMutableState, difference: Api.updates.Difference) -> Signal<AccountFinalState, NoError> { func finalStateWithDifference(account: Account, state: AccountMutableState, difference: Api.updates.Difference) -> Signal<AccountFinalState, NoError> {
@ -501,7 +501,7 @@ func finalStateWithDifference(account: Account, state: AccountMutableState, diff
updatedState.addSecretMessages(encryptedMessages) updatedState.addSecretMessages(encryptedMessages)
} }
return finalStateWithUpdates(account: account, state: updatedState, updates: updates, shouldPoll: false, missingUpdates: false) return finalStateWithUpdates(account: account, state: updatedState, updates: updates, shouldPoll: false, missingUpdates: false, shouldResetChannels: true)
} }
private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] { private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
@ -552,6 +552,13 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
} else { } else {
updatesByChannel[peerId]!.append(update) updatesByChannel[peerId]!.append(update)
} }
case let .updateChannelAvailableMessages(channelId, _):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
if updatesByChannel[peerId] == nil {
updatesByChannel[peerId] = [update]
} else {
updatesByChannel[peerId]!.append(update)
}
default: default:
result.append(update) result.append(update)
} }
@ -602,7 +609,7 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
return result return result
} }
private func finalStateWithUpdates(account: Account, state: AccountMutableState, updates: [Api.Update], shouldPoll: Bool, missingUpdates: Bool) -> Signal<AccountFinalState, NoError> { private func finalStateWithUpdates(account: Account, state: AccountMutableState, updates: [Api.Update], shouldPoll: Bool, missingUpdates: Bool, shouldResetChannels: Bool) -> Signal<AccountFinalState, NoError> {
var updatedState = state var updatedState = state
var channelsToPoll = Set<PeerId>() var channelsToPoll = Set<PeerId>()
@ -694,6 +701,9 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
channelsToPoll.insert(peerId) channelsToPoll.insert(peerId)
} }
} }
case let .updateChannelAvailableMessages(channelId, minId):
let peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
updatedState.updateMinAvailableMessage(MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minId))
case let .updateDeleteMessages(messages, _, _): case let .updateDeleteMessages(messages, _, _):
updatedState.deleteMessagesWithGlobalIds(messages) updatedState.deleteMessagesWithGlobalIds(messages)
case let .updateEditMessage(apiMessage, _, _): case let .updateEditMessage(apiMessage, _, _):
@ -1023,6 +1033,27 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
} }
var pollChannelSignals: [Signal<(AccountMutableState, Bool, Int32?), NoError>] = [] var pollChannelSignals: [Signal<(AccountMutableState, Bool, Int32?), NoError>] = []
if channelsToPoll.isEmpty {
pollChannelSignals = []
} else if shouldResetChannels {
var channelPeers: [Peer] = []
for peerId in channelsToPoll {
if let peer = updatedState.peers[peerId] {
channelPeers.append(peer)
} else {
Logger.shared.log("State", "can't reset channel \(peerId): no peer found")
}
}
if !channelPeers.isEmpty {
let resetSignal = resetChannels(account, peers: channelPeers, state: updatedState)
|> map { resultState -> (AccountMutableState, Bool, Int32?) in
return (resultState, true, nil)
}
pollChannelSignals = [resetSignal]
} else {
pollChannelSignals = []
}
} else {
for peerId in channelsToPoll { for peerId in channelsToPoll {
if let peer = updatedState.peers[peerId] { if let peer = updatedState.peers[peerId] {
pollChannelSignals.append(pollChannel(account, peer: peer, state: updatedState.branch())) pollChannelSignals.append(pollChannel(account, peer: peer, state: updatedState.branch()))
@ -1030,16 +1061,23 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
Logger.shared.log("State", "can't poll channel \(peerId): no peer found") Logger.shared.log("State", "can't poll channel \(peerId): no peer found")
} }
} }
}
return combineLatest(pollChannelSignals) |> mapToSignal { states -> Signal<AccountFinalState, NoError> in return combineLatest(pollChannelSignals) |> mapToSignal { states -> Signal<AccountFinalState, NoError> in
var finalState = updatedState var finalState: AccountMutableState = updatedState
var hadError = false var hadError = false
if shouldResetChannels && states.count != 0 {
assert(states.count == 1)
finalState = states[0].0
} else {
for (state, success, _) in states { for (state, success, _) in states {
finalState.merge(state) finalState.merge(state)
if !success { if !success {
hadError = true hadError = true
} }
} }
}
return resolveAssociatedMessages(account: account, state: finalState) return resolveAssociatedMessages(account: account, state: finalState)
|> mapToSignal { resultingState -> Signal<AccountFinalState, NoError> in |> mapToSignal { resultingState -> Signal<AccountFinalState, NoError> in
return resolveMissingPeerNotificationSettings(account: account, state: resultingState) return resolveMissingPeerNotificationSettings(account: account, state: resultingState)
@ -1237,6 +1275,127 @@ func keepPollingChannel(account: Account, peerId: PeerId, stateManager: AccountS
} |> switchToLatest |> restart } |> switchToLatest |> restart
} }
private func resetChannels(_ account: Account, peers: [Peer], state: AccountMutableState) -> Signal<AccountMutableState, NoError> {
var inputPeers: [Api.InputPeer] = []
for peer in peers {
if let inputPeer = apiInputPeer(peer) {
inputPeers.append(inputPeer)
}
}
return account.network.request(Api.functions.messages.getPeerDialogs(peers: inputPeers))
|> retryRequest
|> map { result -> AccountMutableState in
var updatedState = state
var dialogsChats: [Api.Chat] = []
var dialogsUsers: [Api.User] = []
var storeMessages: [StoreMessage] = []
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
var channelStates: [PeerId: ChannelState] = [:]
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
switch result {
case let .peerDialogs(dialogs, messages, chats, users, _):
dialogsChats.append(contentsOf: chats)
dialogsUsers.append(contentsOf: users)
for dialog in dialogs {
let apiPeer: Api.Peer
let apiReadInboxMaxId: Int32
let apiReadOutboxMaxId: Int32
let apiTopMessage: Int32
let apiUnreadCount: Int32
let apiUnreadMentionsCount: Int32
var apiChannelPts: Int32?
let apiNotificationSettings: Api.PeerNotifySettings
switch dialog {
case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _):
apiPeer = peer
apiTopMessage = topMessage
apiReadInboxMaxId = readInboxMaxId
apiReadOutboxMaxId = readOutboxMaxId
apiUnreadCount = unreadCount
apiUnreadMentionsCount = unreadMentionsCount
apiNotificationSettings = peerNotificationSettings
apiChannelPts = pts
}
let peerId: PeerId
switch apiPeer {
case let .peerUser(userId):
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
case let .peerChat(chatId):
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
case let .peerChannel(channelId):
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
}
if readStates[peerId] == nil {
readStates[peerId] = [:]
}
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount)
if apiTopMessage != 0 {
mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage))
}
if let apiChannelPts = apiChannelPts {
channelStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts)
}
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
}
for message in messages {
if let storeMessage = StoreMessage(apiMessage: message) {
storeMessages.append(storeMessage)
}
}
}
updatedState.mergeChats(dialogsChats)
updatedState.mergeUsers(dialogsUsers)
for message in storeMessages {
if case let .Id(id) = message.id {
updatedState.addHole(MessageId(peerId: id.peerId, namespace: Namespaces.Message.Cloud, id: Int32.max))
}
}
updatedState.addMessages(storeMessages, location: .UpperHistoryBlock)
for (peerId, peerReadStates) in readStates {
for (namespace, state) in peerReadStates {
switch state {
case let .idBased(maxIncomingReadId, maxOutgoingReadId, maxKnownId, count):
updatedState.resetReadState(peerId, namespace: namespace, maxIncomingReadId: maxIncomingReadId, maxOutgoingReadId: maxOutgoingReadId, maxKnownId: maxKnownId, count: count)
default:
assertionFailure()
break
}
}
}
for (peerId, tagSummary) in mentionTagSummaries {
updatedState.resetMessageTagSummary(peerId, namespace: Namespaces.Message.Cloud, count: tagSummary.count, range: tagSummary.range)
}
for (peerId, channelState) in channelStates {
updatedState.updateChannelState(peerId, state: channelState)
}
for (peerId, settings) in notificationSettings {
updatedState.updateNotificationSettings(.peer(peerId), notificationSettings: settings)
}
// TODO: delete messages later than top
return updatedState
}
}
private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableState) -> Signal<(AccountMutableState, Bool, Int32?), NoError> { private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableState) -> Signal<(AccountMutableState, Bool, Int32?), NoError> {
if let inputChannel = apiInputChannel(peer) { if let inputChannel = apiInputChannel(peer) {
var limit: Int32 = 20 var limit: Int32 = 20
@ -1322,6 +1481,18 @@ private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableSt
updatedState.updateMedia(webpage.webpageId, media: webpage) updatedState.updateMedia(webpage.webpageId, media: webpage)
} }
} }
case let .updateChannelAvailableMessages(_, minId):
let messageId = MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: minId)
updatedState.updateMinAvailableMessage(messageId)
updatedState.updateCachedPeerData(peer.id, { current in
let previous: CachedChannelData
if let current = current as? CachedChannelData {
previous = current
} else {
previous = CachedChannelData()
}
return previous.withUpdatedMinAvailableMessageId(messageId)
})
default: default:
break break
} }
@ -1472,7 +1643,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
var currentAddMessages: OptimizeAddMessagesState? var currentAddMessages: OptimizeAddMessagesState?
for operation in operations { for operation in operations {
switch operation { switch operation {
case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ResetReadState, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedPeerIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateChatInputState, .UpdateCall, .UpdateLangPack: case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ResetReadState, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedPeerIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage:
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
} }
@ -1545,6 +1716,8 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, modifier: Modif
modifier.deleteMessagesWithGlobalIds(ids) modifier.deleteMessagesWithGlobalIds(ids)
case let .DeleteMessages(ids): case let .DeleteMessages(ids):
modifier.deleteMessages(ids) modifier.deleteMessages(ids)
case let .UpdateMinAvailableMessage(id):
modifier.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id)
case let .EditMessage(id, message): case let .EditMessage(id, message):
modifier.updateMessage(id, update: { _ in .update(message) }) modifier.updateMessage(id, update: { _ in .update(message) })
case let .UpdateMedia(id, media): case let .UpdateMedia(id, media):

View File

@ -247,9 +247,15 @@ public final class AccountStateManager {
|> take(1) |> take(1)
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in |> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
if let authorizedState = state.state { if let authorizedState = state.state {
let request = account.network.request(Api.functions.updates.getDifference(flags: 0, pts: authorizedState.pts, ptsTotalLimit: nil, date: authorizedState.date, qts: authorizedState.qts)) let request = account.network.request(Api.functions.updates.getDifference(flags: 0 << 0, pts: authorizedState.pts, ptsTotalLimit: 1000, date: authorizedState.date, qts: authorizedState.qts))
|> retryRequest |> retryRequest
return request |> mapToSignal { difference -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in return request |> mapToSignal { difference -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
switch difference {
case .differenceTooLong:
return accountStateReset(postbox: account.postbox, network: account.network) |> mapToSignal { _ -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
return .complete()
} |> then(.single((nil, nil)))
default:
return initialStateWithDifference(account, difference: difference) return initialStateWithDifference(account, difference: difference)
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in |> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
if state.initialState.state != authorizedState { if state.initialState.state != authorizedState {
@ -274,6 +280,7 @@ public final class AccountStateManager {
} }
} }
} }
}
} else { } else {
let appliedState = account.network.request(Api.functions.updates.getState()) let appliedState = account.network.request(Api.functions.updates.getState())
|> retryRequest |> retryRequest
@ -688,8 +695,17 @@ public func messageForNotification(modifier: Modifier, id: MessageId, alwaysRetu
var notify = true var notify = true
var sound: PeerMessageSound = .bundledModern(id: 0) var sound: PeerMessageSound = .bundledModern(id: 0)
var muted = false
var displayContents = true var displayContents = true
for attribute in message.attributes {
if let attribute = attribute as? NotificationInfoMessageAttribute {
if attribute.flags.contains(.muted) {
muted = true
}
}
}
let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970)
var notificationPeerId = id.peerId var notificationPeerId = id.peerId
@ -731,13 +747,17 @@ public func messageForNotification(modifier: Modifier, id: MessageId, alwaysRetu
} else { } else {
sound = notificationSettings.messageSound sound = notificationSettings.messageSound
} }
if !defaultNotify { /*if !defaultNotify {
notify = false notify = false
} }*/
} else { } else {
Logger.shared.log("AccountStateManager", "notification settings for \(notificationPeerId) are undefined") Logger.shared.log("AccountStateManager", "notification settings for \(notificationPeerId) are undefined")
} }
if muted {
sound = .none
}
if let channel = message.peers[message.id.peerId] as? TelegramChannel { if let channel = message.peers[message.id.peerId] as? TelegramChannel {
switch channel.participationStatus { switch channel.participationStatus {
case .kicked, .left: case .kicked, .left:

View File

@ -0,0 +1,237 @@
import Foundation
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
import MtProtoKitMac
#else
import Postbox
import SwiftSignalKit
import MtProtoKitDynamic
#endif
func accountStateReset(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let pinnedChats: Signal<Api.messages.PeerDialogs, NoError> = network.request(Api.functions.messages.getPinnedDialogs())
|> retryRequest
let state: Signal<Api.updates.State, NoError> =
network.request(Api.functions.updates.getState())
|> retryRequest
return combineLatest(network.request(Api.functions.messages.getDialogs(flags: 0, offsetDate: 0, offsetId: 0, offsetPeer: .inputPeerEmpty, limit: 100))
|> retryRequest, pinnedChats, state)
|> mapToSignal { result, pinnedChats, state -> Signal<Void, NoError> in
var dialogsDialogs: [Api.Dialog] = []
var dialogsMessages: [Api.Message] = []
var dialogsChats: [Api.Chat] = []
var dialogsUsers: [Api.User] = []
var holeExists = false
switch result {
case let .dialogs(dialogs, messages, chats, users):
dialogsDialogs = dialogs
dialogsMessages = messages
dialogsChats = chats
dialogsUsers = users
case let .dialogsSlice(_, dialogs, messages, chats, users):
dialogsDialogs = dialogs
dialogsMessages = messages
dialogsChats = chats
dialogsUsers = users
holeExists = true
}
let replacePinnedPeerIds: [PeerId]
switch pinnedChats {
case let .peerDialogs(apiDialogs, apiMessages, apiChats, apiUsers, _):
dialogsDialogs.append(contentsOf: apiDialogs)
dialogsMessages.append(contentsOf: apiMessages)
dialogsChats.append(contentsOf: apiChats)
dialogsUsers.append(contentsOf: apiUsers)
var peerIds: [PeerId] = []
for dialog in apiDialogs {
let apiPeer: Api.Peer
switch dialog {
case let .dialog(_, peer, _, _, _, _, _, _, _, _):
apiPeer = peer
}
let peerId = apiPeer.peerId
peerIds.append(peerId)
}
replacePinnedPeerIds = peerIds
}
var replacementHole: ChatListHole?
var storeMessages: [StoreMessage] = []
var readStates: [PeerId: [MessageId.Namespace: PeerReadState]] = [:]
var mentionTagSummaries: [PeerId: MessageHistoryTagNamespaceSummary] = [:]
var chatStates: [PeerId: PeerChatState] = [:]
var notificationSettings: [PeerId: PeerNotificationSettings] = [:]
var topMesageIds: [PeerId: MessageId] = [:]
for dialog in dialogsDialogs {
let apiPeer: Api.Peer
let apiReadInboxMaxId: Int32
let apiReadOutboxMaxId: Int32
let apiTopMessage: Int32
let apiUnreadCount: Int32
let apiUnreadMentionsCount: Int32
var apiChannelPts: Int32?
let apiNotificationSettings: Api.PeerNotifySettings
switch dialog {
case let .dialog(_, peer, topMessage, readInboxMaxId, readOutboxMaxId, unreadCount, unreadMentionsCount, peerNotificationSettings, pts, _):
apiPeer = peer
apiTopMessage = topMessage
apiReadInboxMaxId = readInboxMaxId
apiReadOutboxMaxId = readOutboxMaxId
apiUnreadCount = unreadCount
apiUnreadMentionsCount = unreadMentionsCount
apiNotificationSettings = peerNotificationSettings
apiChannelPts = pts
}
let peerId: PeerId
switch apiPeer {
case let .peerUser(userId):
peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
case let .peerChat(chatId):
peerId = PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)
case let .peerChannel(channelId):
peerId = PeerId(namespace: Namespaces.Peer.CloudChannel, id: channelId)
}
if readStates[peerId] == nil {
readStates[peerId] = [:]
}
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount)
if apiTopMessage != 0 {
mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage))
topMesageIds[peerId] = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: apiTopMessage)
}
if let apiChannelPts = apiChannelPts {
chatStates[peerId] = ChannelState(pts: apiChannelPts, invalidatedPts: apiChannelPts)
} else {
switch state {
case let .state(pts, _, _, _, _):
chatStates[peerId] = RegularChatState(invalidatedPts: pts)
}
}
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)
}
for message in dialogsMessages {
if let storeMessage = StoreMessage(apiMessage: message) {
storeMessages.append(storeMessage)
}
}
if holeExists {
for dialog in dialogsDialogs {
switch dialog {
case let .dialog(flags, peer, topMessage, _, _, _, _, _, _, _):
let isPinned = (flags & (1 << 2)) != 0
if !isPinned {
var timestamp: Int32?
for message in storeMessages {
if case let .Id(id) = message.id, id.id == topMessage {
timestamp = message.timestamp
}
}
if let timestamp = timestamp {
let index = MessageIndex(id: MessageId(peerId: peer.peerId, namespace: Namespaces.Message.Cloud, id: topMessage - 1), timestamp: timestamp)
if (replacementHole == nil || replacementHole!.index > index) {
replacementHole = ChatListHole(index: index)
}
}
}
}
}
}
var peers: [Peer] = []
var peerPresences: [PeerId: PeerPresence] = [:]
for chat in dialogsChats {
if let groupOrChannel = parseTelegramGroupOrChannel(chat: chat) {
peers.append(groupOrChannel)
}
}
for user in dialogsUsers {
let telegramUser = TelegramUser(user: user)
peers.append(telegramUser)
if let presence = TelegramUserPresence(apiUser: user) {
peerPresences[telegramUser.id] = presence
}
}
return postbox.modify { modifier -> Void in
modifier.resetChatList(replacementHole: replacementHole)
updatePeers(modifier: modifier, peers: peers, update: { _, updated -> Peer in
return updated
})
modifier.updatePeerPresences(peerPresences)
modifier.updateCurrentPeerNotificationSettings(notificationSettings)
var allPeersWithMessages = Set<PeerId>()
for message in storeMessages {
if !allPeersWithMessages.contains(message.id.peerId) {
allPeersWithMessages.insert(message.id.peerId)
}
}
for (_, messageId) in topMesageIds {
if messageId.id > 1 {
var skipHole = false
if let localTopId = modifier.getTopMesssageIndex(peerId: messageId.peerId, namespace: messageId.namespace)?.id {
if localTopId >= messageId {
skipHole = true
}
}
if !skipHole {
modifier.addHole(MessageId(peerId: messageId.peerId, namespace: messageId.namespace, id: messageId.id - 1))
}
}
}
let _ = modifier.addMessages(storeMessages, location: .UpperHistoryBlock)
modifier.resetIncomingReadStates(readStates)
for (peerId, chatState) in chatStates {
if let chatState = chatState as? ChannelState {
if let current = modifier.getPeerChatState(peerId) as? ChannelState {
modifier.setPeerChatState(peerId, state: current.withUpdatedPts(chatState.pts))
} else {
modifier.setPeerChatState(peerId, state: chatState)
}
} else {
modifier.setPeerChatState(peerId, state: chatState)
}
}
modifier.setPinnedPeerIds(replacePinnedPeerIds)
for (peerId, summary) in mentionTagSummaries {
modifier.replaceMessageTagSummary(peerId: peerId, tagMask: .unseenPersonalMessage, namespace: Namespaces.Message.Cloud, count: summary.count, maxId: summary.range.maxId)
}
if let currentState = modifier.getState() as? AuthorizedAccountState, let embeddedState = currentState.state {
switch state {
case let .state(pts, _, _, seq, _):
modifier.setState(currentState.changedState(AuthorizedAccountState.State(pts: pts, qts: embeddedState.qts, date: embeddedState.date, seq: seq)))
}
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@ public struct CachedChannelFlags: OptionSet {
public static let canDisplayParticipants = CachedChannelFlags(rawValue: 1 << 0) public static let canDisplayParticipants = CachedChannelFlags(rawValue: 1 << 0)
public static let canChangeUsername = CachedChannelFlags(rawValue: 1 << 1) public static let canChangeUsername = CachedChannelFlags(rawValue: 1 << 1)
public static let canSetStickerSet = CachedChannelFlags(rawValue: 1 << 2) public static let canSetStickerSet = CachedChannelFlags(rawValue: 1 << 2)
public static let preHistoryEnabled = CachedChannelFlags(rawValue: 1 << 3)
} }
public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable { public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable {
@ -111,6 +112,7 @@ public final class CachedChannelData: CachedPeerData {
public let reportStatus: PeerReportStatus public let reportStatus: PeerReportStatus
public let pinnedMessageId: MessageId? public let pinnedMessageId: MessageId?
public let stickerPack: StickerPackCollectionInfo? public let stickerPack: StickerPackCollectionInfo?
public let minAvailableMessageId: MessageId?
public let peerIds: Set<PeerId> public let peerIds: Set<PeerId>
public let messageIds: Set<MessageId> public let messageIds: Set<MessageId>
@ -127,9 +129,10 @@ public final class CachedChannelData: CachedPeerData {
self.peerIds = Set() self.peerIds = Set()
self.messageIds = Set() self.messageIds = Set()
self.stickerPack = nil self.stickerPack = nil
self.minAvailableMessageId = nil
} }
init(flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], topParticipants: CachedChannelParticipants?, reportStatus: PeerReportStatus, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?) { init(flags: CachedChannelFlags, about: String?, participantsSummary: CachedChannelParticipantsSummary, exportedInvitation: ExportedInvitation?, botInfos: [CachedPeerBotInfo], topParticipants: CachedChannelParticipants?, reportStatus: PeerReportStatus, pinnedMessageId: MessageId?, stickerPack: StickerPackCollectionInfo?, minAvailableMessageId: MessageId?) {
self.flags = flags self.flags = flags
self.about = about self.about = about
self.participantsSummary = participantsSummary self.participantsSummary = participantsSummary
@ -139,6 +142,7 @@ public final class CachedChannelData: CachedPeerData {
self.reportStatus = reportStatus self.reportStatus = reportStatus
self.pinnedMessageId = pinnedMessageId self.pinnedMessageId = pinnedMessageId
self.stickerPack = stickerPack self.stickerPack = stickerPack
self.minAvailableMessageId = minAvailableMessageId
var peerIds = Set<PeerId>() var peerIds = Set<PeerId>()
if let topParticipants = topParticipants { if let topParticipants = topParticipants {
@ -159,39 +163,43 @@ public final class CachedChannelData: CachedPeerData {
} }
func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData { func withUpdatedFlags(_ flags: CachedChannelFlags) -> CachedChannelData {
return CachedChannelData(flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedAbout(_ about: String?) -> CachedChannelData { func withUpdatedAbout(_ about: String?) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData { func withUpdatedParticipantsSummary(_ participantsSummary: CachedChannelParticipantsSummary) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData { func withUpdatedExportedInvitation(_ exportedInvitation: ExportedInvitation?) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData { func withUpdatedBotInfos(_ botInfos: [CachedPeerBotInfo]) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedTopParticipants(_ topParticipants: CachedChannelParticipants?) -> CachedChannelData { func withUpdatedTopParticipants(_ topParticipants: CachedChannelParticipants?) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedReportStatus(_ reportStatus: PeerReportStatus) -> CachedChannelData { func withUpdatedReportStatus(_ reportStatus: PeerReportStatus) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData { func withUpdatedPinnedMessageId(_ pinnedMessageId: MessageId?) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: self.minAvailableMessageId)
} }
func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData { func withUpdatedStickerPack(_ stickerPack: StickerPackCollectionInfo?) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack) return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: stickerPack, minAvailableMessageId: self.minAvailableMessageId)
}
func withUpdatedMinAvailableMessageId(_ minAvailableMessageId: MessageId?) -> CachedChannelData {
return CachedChannelData(flags: self.flags, about: self.about, participantsSummary: self.participantsSummary, exportedInvitation: self.exportedInvitation, botInfos: self.botInfos, topParticipants: self.topParticipants, reportStatus: self.reportStatus, pinnedMessageId: self.pinnedMessageId, stickerPack: self.stickerPack, minAvailableMessageId: minAvailableMessageId)
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -215,6 +223,12 @@ public final class CachedChannelData: CachedPeerData {
self.stickerPack = nil self.stickerPack = nil
} }
if let minAvailableMessagePeerId = decoder.decodeOptionalInt64ForKey("ma.p"), let minAvailableMessageNamespace = decoder.decodeOptionalInt32ForKey("ma.n"), let minAvailableMessageId = decoder.decodeOptionalInt32ForKey("ma.i") {
self.minAvailableMessageId = MessageId(peerId: PeerId(minAvailableMessagePeerId), namespace: minAvailableMessageNamespace, id: minAvailableMessageId)
} else {
self.minAvailableMessageId = nil
}
if let topParticipants = self.topParticipants { if let topParticipants = self.topParticipants {
for participant in topParticipants.participants { for participant in topParticipants.participants {
peerIds.insert(participant.peerId) peerIds.insert(participant.peerId)
@ -267,6 +281,15 @@ public final class CachedChannelData: CachedPeerData {
} else { } else {
encoder.encodeNil(forKey: "sp") encoder.encodeNil(forKey: "sp")
} }
if let minAvailableMessageId = self.minAvailableMessageId {
encoder.encodeInt64(minAvailableMessageId.peerId.toInt64(), forKey: "ma.p")
encoder.encodeInt32(minAvailableMessageId.namespace, forKey: "ma.n")
encoder.encodeInt32(minAvailableMessageId.id, forKey: "ma.i")
} else {
encoder.encodeNil(forKey: "ma.p")
encoder.encodeNil(forKey: "ma.n")
encoder.encodeNil(forKey: "ma.i")
}
} }
public func isEqual(to: CachedPeerData) -> Bool { public func isEqual(to: CachedPeerData) -> Bool {
@ -310,6 +333,10 @@ public final class CachedChannelData: CachedPeerData {
return false return false
} }
if other.minAvailableMessageId != self.minAvailableMessageId {
return false
}
return true return true
} }
} }

View File

@ -37,6 +37,7 @@ public enum AdminLogEventAction {
case participantToggleBan(prev: RenderedChannelParticipant, new: RenderedChannelParticipant) case participantToggleBan(prev: RenderedChannelParticipant, new: RenderedChannelParticipant)
case participantToggleAdmin(prev: RenderedChannelParticipant, new: RenderedChannelParticipant) case participantToggleAdmin(prev: RenderedChannelParticipant, new: RenderedChannelParticipant)
case changeStickerPack(prev: StickerPackReference?, new: StickerPackReference?) case changeStickerPack(prev: StickerPackReference?, new: StickerPackReference?)
case togglePreHistoryHidden(Bool)
} }
public enum ChannelAdminLogEventError { public enum ChannelAdminLogEventError {
@ -176,6 +177,8 @@ public func channelAdminLogEvents(_ account:Account, peerId:PeerId, maxId:AdminL
} }
case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset): case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset):
action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset)) action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset))
case let .channelAdminLogEventActionTogglePreHistoryHidden(value):
action = .togglePreHistoryHidden(value == .boolTrue)
} }
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId)
if let action = action { if let action = action {

View File

@ -12,7 +12,7 @@ import Foundation
public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedChannelParticipant], NoError> { public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedChannelParticipant], NoError> {
return account.postbox.modify { modifier -> Signal<[RenderedChannelParticipant], NoError> in return account.postbox.modify { modifier -> Signal<[RenderedChannelParticipant], NoError> in
if let peer = modifier.getPeer(peerId), let inputChannel = apiInputChannel(peer) { if let peer = modifier.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100)) return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 100, hash: 0))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<[RenderedChannelParticipant], NoError> in |> mapToSignal { result -> Signal<[RenderedChannelParticipant], NoError> in
switch result { switch result {
@ -46,6 +46,8 @@ public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedC
}) })
return items return items
} }
case .channelParticipantsNotModified:
return .single([])
} }
} }
} else { } else {

View File

@ -24,7 +24,7 @@ private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: Cha
case .banned: case .banned:
apiFilter = .channelParticipantsKicked(q: "") apiFilter = .channelParticipantsKicked(q: "")
} }
return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: 0, limit: 100)) return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: 0, limit: 100, hash: 0))
|> retryRequest |> retryRequest
|> map { result -> [RenderedChannelParticipant] in |> map { result -> [RenderedChannelParticipant] in
var items: [RenderedChannelParticipant] = [] var items: [RenderedChannelParticipant] = []
@ -46,6 +46,9 @@ private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: Cha
} }
} }
case .channelParticipantsNotModified:
assertionFailure()
break
} }
return items return items
} }

View File

@ -0,0 +1,35 @@
#if os(macOS)
import PostboxMac
import SwiftSignalKitMac
#else
import Postbox
import SwiftSignalKit
#endif
public func updateChannelHistoryAvailabilitySettingsInteractively(postbox: Postbox, network: Network, peerId: PeerId, historyAvailableForNewMembers: Bool) -> Signal<Void, NoError> {
return postbox.modify { modifier -> Signal<Void, NoError> in
if let peer = modifier.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
return network.request(Api.functions.channels.togglePreHistoryHidden(channel: inputChannel, enabled: historyAvailableForNewMembers ? .boolTrue : .boolFalse))
|> retryRequest
|> mapToSignal { _ -> Signal<Void, NoError> in
return postbox.modify { modifier -> Void in
modifier.updatePeerCachedData(peerIds: [peerId], update: { peerId, currentData in
if let currentData = currentData as? CachedChannelData {
var flags = currentData.flags
if historyAvailableForNewMembers {
flags.insert(.preHistoryEnabled)
} else {
flags.remove(.preHistoryEnabled)
}
return currentData.withUpdatedFlags(flags)
} else {
return currentData
}
})
}
}
} else {
return .complete()
}
} |> switchToLatest
}

View File

@ -24,7 +24,7 @@ public func channelMembers(account: Account, peerId: PeerId, filter: ChannelMemb
case let .search(query): case let .search(query):
apiFilter = .channelParticipantsSearch(q: query) apiFilter = .channelParticipantsSearch(q: query)
} }
return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: 0, limit: 100)) return account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: apiFilter, offset: 0, limit: 100, hash: 0))
|> retryRequest |> retryRequest
|> map { result -> [RenderedChannelParticipant] in |> map { result -> [RenderedChannelParticipant] in
var items: [RenderedChannelParticipant] = [] var items: [RenderedChannelParticipant] = []
@ -46,6 +46,8 @@ public func channelMembers(account: Account, peerId: PeerId, filter: ChannelMemb
} }
} }
case .channelParticipantsNotModified:
break
} }
return items return items
} }

View File

@ -29,10 +29,10 @@ public struct RenderedChannelParticipant: Equatable {
func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signal<Void, NoError> { func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
return account.postbox.modify { modifier -> Signal<Void, NoError> in return account.postbox.modify { modifier -> Signal<Void, NoError> in
if let peer = modifier.getPeer(peerId), let inputChannel = apiInputChannel(peer) { if let peer = modifier.getPeer(peerId), let inputChannel = apiInputChannel(peer) {
let admins = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 0)) let admins = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsAdmins, offset: 0, limit: 0, hash: 0))
let members = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsRecent, offset: 0, limit: 0)) let members = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsRecent, offset: 0, limit: 0, hash: 0))
let banned = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsBanned(q: ""), offset: 0, limit: 0)) let banned = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsBanned(q: ""), offset: 0, limit: 0, hash: 0))
let kicked = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsKicked(q: ""), offset: 0, limit: 0)) let kicked = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsKicked(q: ""), offset: 0, limit: 0, hash: 0))
return combineLatest(admins, members, banned, kicked) return combineLatest(admins, members, banned, kicked)
|> mapToSignal { admins, members, banned, kicked -> Signal<Void, MTRpcError> in |> mapToSignal { admins, members, banned, kicked -> Signal<Void, MTRpcError> in
return account.postbox.modify { modifier -> Void in return account.postbox.modify { modifier -> Void in
@ -42,21 +42,33 @@ func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signa
switch admins { switch admins {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _):
adminCount = count adminCount = count
case .channelParticipantsNotModified:
assertionFailure()
adminCount = 0
} }
let memberCount: Int32 let memberCount: Int32
switch members { switch members {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _):
memberCount = count memberCount = count
case .channelParticipantsNotModified:
assertionFailure()
memberCount = 0
} }
let bannedCount: Int32 let bannedCount: Int32
switch banned { switch banned {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _):
bannedCount = count bannedCount = count
case .channelParticipantsNotModified:
assertionFailure()
bannedCount = 0
} }
let kickedCount: Int32 let kickedCount: Int32
switch kicked { switch kicked {
case let .channelParticipants(count, _, _): case let .channelParticipants(count, _, _):
kickedCount = count kickedCount = count
case .channelParticipantsNotModified:
assertionFailure()
kickedCount = 0
} }
return current.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: memberCount, adminCount: adminCount, bannedCount: bannedCount, kickedCount: kickedCount)) return current.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: memberCount, adminCount: adminCount, bannedCount: bannedCount, kickedCount: kickedCount))
} }

View File

@ -341,14 +341,14 @@ extension ChatContextResultMessage {
} }
self = .text(text: message, entities: parsedEntities, disableUrlPreview: (flags & (1 << 0)) != 0, replyMarkup: parsedReplyMarkup) self = .text(text: message, entities: parsedEntities, disableUrlPreview: (flags & (1 << 0)) != 0, replyMarkup: parsedReplyMarkup)
case let .botInlineMessageMediaGeo(_, geo, replyMarkup): case let .botInlineMessageMediaGeo(_, geo, replyMarkup):
let media = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil) let media = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil)
var parsedReplyMarkup: ReplyMarkupMessageAttribute? var parsedReplyMarkup: ReplyMarkupMessageAttribute?
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
} }
self = .mapLocation(media: media, replyMarkup: parsedReplyMarkup) self = .mapLocation(media: media, replyMarkup: parsedReplyMarkup)
case let .botInlineMessageMediaVenue(_, geo, title, address, provider, venueId, replyMarkup): case let .botInlineMessageMediaVenue(_, geo, title, address, provider, venueId, replyMarkup):
let media = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId) let media = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId, venueType: nil, liveBroadcastingTimeout: nil)
var parsedReplyMarkup: ReplyMarkupMessageAttribute? var parsedReplyMarkup: ReplyMarkupMessageAttribute?
if let replyMarkup = replyMarkup { if let replyMarkup = replyMarkup {
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup) parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
@ -400,7 +400,7 @@ extension ChatContextResultSwitchPeer {
extension ChatContextResultCollection { extension ChatContextResultCollection {
convenience init(apiResults: Api.messages.BotResults, botId: PeerId) { convenience init(apiResults: Api.messages.BotResults, botId: PeerId) {
switch apiResults { switch apiResults {
case let .botResults(flags, queryId, nextOffset, switchPm, results, cacheTime): case let .botResults(flags, queryId, nextOffset, switchPm, results, cacheTime, users):
var switchPeer: ChatContextResultSwitchPeer? var switchPeer: ChatContextResultSwitchPeer?
if let switchPm = switchPm { if let switchPm = switchPm {
switchPeer = ChatContextResultSwitchPeer(apiSwitchPeer: switchPm) switchPeer = ChatContextResultSwitchPeer(apiSwitchPeer: switchPm)

View File

@ -50,17 +50,18 @@ private func hashForCountAndIds(count: Int32, ids: [Int32]) -> Int32 {
let low = UInt32(bitPattern: id) let low = UInt32(bitPattern: id)
acc = (acc &* 20261) &+ low acc = (acc &* 20261) &+ low
} }
return Int32(bitPattern: acc % UInt32(0x7FFFFFFF)) return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))
} }
func manageContacts(network: Network, postbox: Postbox) -> Signal<Void, NoError> { func manageContacts(network: Network, postbox: Postbox, accountPeerId: PeerId) -> Signal<Void, NoError> {
#if DEBUG #if DEBUG
return .never() return .never()
#endif #endif
let initialContactPeerIdsHash = postbox.contactPeerIdsView() let initialContactPeerIdsHash = postbox.contactPeerIdsView()
|> take(1) |> take(1)
|> map { view -> Int32 in |> map { view -> Int32 in
let sortedUserIds = Set(view.peerIds.filter({ $0.namespace == Namespaces.Peer.CloudUser }).map({ $0.id })).sorted() let peerIds = Set(view.peerIds.filter({ $0.namespace == Namespaces.Peer.CloudUser }))
let sortedUserIds = peerIds.map({ $0.id }).sorted()
return hashForCountAndIds(count: view.remoteTotalCount, ids: sortedUserIds) return hashForCountAndIds(count: view.remoteTotalCount, ids: sortedUserIds)
} }
@ -87,9 +88,9 @@ func manageContacts(network: Network, postbox: Postbox) -> Signal<Void, NoError>
return appliedUpdatedPeers return appliedUpdatedPeers
} }
public func addContactPeerInteractively(account: Account, peerId: PeerId) -> Signal<Void, NoError> { public func addContactPeerInteractively(account: Account, peerId: PeerId, phone: String?) -> Signal<Void, NoError> {
return account.postbox.modify { modifier -> Signal<Void, NoError> in return account.postbox.modify { modifier -> Signal<Void, NoError> in
if let peer = modifier.getPeer(peerId) as? TelegramUser, let phone = peer.phone, !phone.isEmpty { if let peer = modifier.getPeer(peerId) as? TelegramUser, let phone = phone ?? peer.phone, !phone.isEmpty {
return account.network.request(Api.functions.contacts.importContacts(contacts: [Api.InputContact.inputPhoneContact(clientId: 1, phone: phone, firstName: peer.firstName ?? "", lastName: peer.lastName ?? "")])) return account.network.request(Api.functions.contacts.importContacts(contacts: [Api.InputContact.inputPhoneContact(clientId: 1, phone: phone, firstName: peer.firstName ?? "", lastName: peer.lastName ?? "")]))
|> map { Optional($0) } |> map { Optional($0) }
|> `catch` { _ -> Signal<Api.contacts.ImportedContacts?, NoError> in |> `catch` { _ -> Signal<Api.contacts.ImportedContacts?, NoError> in

View File

@ -59,9 +59,16 @@ public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId
public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signal<Void, NoError> { public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signal<Void, NoError> {
return postbox.modify { modifier -> Void in return postbox.modify { modifier -> Void in
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup { if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
var topTimestamp: Int32?
if let topIndex = modifier.getTopMesssageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) {
topTimestamp = topIndex.timestamp
}
cloudChatAddClearHistoryOperation(modifier: modifier, peerId: peerId) cloudChatAddClearHistoryOperation(modifier: modifier, peerId: peerId)
modifier.clearHistory(peerId) modifier.clearHistory(peerId)
if let topTimestamp = topTimestamp {
updatePeerChatInclusionWithMinTimestamp(modifier: modifier, id: peerId, minTimestamp: topTimestamp)
}
} else if peerId.namespace == Namespaces.Peer.SecretChat { } else if peerId.namespace == Namespaces.Peer.SecretChat {
modifier.clearHistory(peerId) modifier.clearHistory(peerId)
@ -87,9 +94,8 @@ public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signa
} }
} }
public func clearAuthorHistory(account: Account, peerId: PeerId, memberId:PeerId) -> Signal<Void, NoError> { public func clearAuthorHistory(account: Account, peerId: PeerId, memberId: PeerId) -> Signal<Void, NoError> {
return account.postbox.modify { modifier -> Signal<Void, Void> in return account.postbox.modify { modifier -> Signal<Void, Void> in
if let peer = modifier.getPeer(peerId), let memberPeer = modifier.getPeer(memberId), let inputChannel = apiInputChannel(peer), let inputUser = apiInputUser(memberPeer) { if let peer = modifier.getPeer(peerId), let memberPeer = modifier.getPeer(memberId), let inputChannel = apiInputChannel(peer), let inputUser = apiInputUser(memberPeer) {
let signal = account.network.request(Api.functions.channels.deleteUserHistory(channel: inputChannel, userId: inputUser)) let signal = account.network.request(Api.functions.channels.deleteUserHistory(channel: inputChannel, userId: inputUser))

View File

@ -335,7 +335,7 @@ func fetchChatListHole(network: Network, postbox: Postbox, hole: ChatListHole) -
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount) readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount)
if apiTopMessage != 0 { if apiTopMessage != 0 {
mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: 0, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage)) mentionTagSummaries[peerId] = MessageHistoryTagNamespaceSummary(version: 1, count: apiUnreadMentionsCount, range: MessageHistoryTagNamespaceCountValidityRange(maxId: apiTopMessage))
} }
notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings) notificationSettings[peerId] = TelegramPeerNotificationSettings(apiSettings: apiNotificationSettings)

View File

@ -12,8 +12,8 @@ public func currentlySuggestedLocalization(network: Network, extractKeys: [Strin
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<SuggestedLocalizationInfo?, NoError> in |> mapToSignal { result -> Signal<SuggestedLocalizationInfo?, NoError> in
switch result { switch result {
//config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int phonecalls_enabled:flags.1?true call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector<DisabledFeature> = Config; //config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int phonecalls_enabled:flags.1?true call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector<DisabledFeature> = Config;
case let .config(flags, _, _, _, _, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, onlineUpdatePeriodMs, offlineBlurTimeoutMs, offlineIdleTimeoutMs, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, stickersFavedLimit, _, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, suggestedLangCode, _, disabledFeatures): case let .config(flags, _, _, _, _, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, onlineUpdatePeriodMs, offlineBlurTimeoutMs, offlineIdleTimeoutMs, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, stickersFavedLimit, channelsReadMediaPeriod, _, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, suggestedLangCode, _, disabledFeatures):
if let suggestedLangCode = suggestedLangCode { if let suggestedLangCode = suggestedLangCode {
return suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map { Optional($0) } return suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map { Optional($0) }
} else { } else {
@ -92,7 +92,7 @@ public func downloadLocalization(network: Network, languageCode: String) -> Sign
public func downoadAndApplyLocalization(postbox: Postbox, network: Network, languageCode: String) -> Signal<Void, NoError> { public func downoadAndApplyLocalization(postbox: Postbox, network: Network, languageCode: String) -> Signal<Void, NoError> {
return downloadLocalization(network: network, languageCode: languageCode) return downloadLocalization(network: network, languageCode: languageCode)
|> mapToSignal { language -> Signal<Void, NoError> in |> mapToSignal { language -> Signal<Void, NoError> in
return postbox.modify { modifier -> Void in return postbox.modify { modifier -> Signal<Void, NoError> in
modifier.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in modifier.updatePreferencesEntry(key: PreferencesKeys.localizationSettings, { _ in
return LocalizationSettings(languageCode: languageCode, localization: language) return LocalizationSettings(languageCode: languageCode, localization: language)
}) })
@ -100,6 +100,14 @@ public func downoadAndApplyLocalization(postbox: Postbox, network: Network, lang
network.context.updateApiEnvironment { current in network.context.updateApiEnvironment { current in
return current?.withUpdatedLangPackCode(languageCode) return current?.withUpdatedLangPackCode(languageCode)
} }
return network.request(Api.functions.help.test())
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .complete()
} }
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
} |> switchToLatest
} }
} }

View File

@ -82,6 +82,7 @@ public final class Logger {
public init(basePath: String) { public init(basePath: String) {
self.basePath = basePath self.basePath = basePath
//self.logToConsole = false
} }
public func collectLogs() -> Signal<[(String, String)], NoError> { public func collectLogs() -> Signal<[(String, String)], NoError> {

View File

@ -309,6 +309,14 @@ private func clearHistory(modifier: Modifier, postbox: Postbox, network: Network
} else { } else {
return .complete() return .complete()
} }
} else if peer.id.namespace == Namespaces.Peer.CloudChannel, let inputChannel = apiInputChannel(peer) {
return network.request(Api.functions.channels.deleteHistory(channel: inputChannel, maxId: operation.topMessageId.id))
|> `catch` { _ -> Signal<Api.Bool, NoError> in
return .single(.boolFalse)
}
|> mapToSignal { _ -> Signal<Void, NoError> in
return .complete()
}
} else { } else {
assertionFailure() assertionFailure()
return .complete() return .complete()

View File

@ -9,12 +9,14 @@ import Foundation
import MtProtoKitDynamic import MtProtoKitDynamic
#endif #endif
//config flags:# date:int expires:int test_mode:Bool this_dc:int dc_options:Vector<DcOption> chat_size_max:int megagroup_size_max:int forwarded_count_max:int online_update_period_ms:int offline_blur_timeout_ms:int offline_idle_timeout_ms:int online_cloud_timeout_ms:int notify_cloud_delay_ms:int notify_default_delay_ms:int chat_big_size:int push_chat_period_ms:int push_chat_limit:int saved_gifs_limit:int edit_time_limit:int rating_e_decay:int stickers_recent_limit:int stickers_faved_limit:int channels_read_media_period:int tmp_sessions:flags.0?int pinned_dialogs_count_max:int phonecalls_enabled:flags.1?true call_receive_timeout_ms:int call_ring_timeout_ms:int call_connect_timeout_ms:int call_packet_timeout_ms:int me_url_prefix:string suggested_lang_code:flags.2?string lang_pack_version:flags.2?int disabled_features:Vector<DisabledFeature> = Config;
func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> { func managedConfigurationUpdates(postbox: Postbox, network: Network) -> Signal<Void, NoError> {
let poll = Signal<Void, NoError> { subscriber in let poll = Signal<Void, NoError> { subscriber in
return (network.request(Api.functions.help.getConfig()) |> retryRequest |> mapToSignal { result -> Signal<Void, NoError> in return (network.request(Api.functions.help.getConfig()) |> retryRequest |> mapToSignal { result -> Signal<Void, NoError> in
return postbox.modify { modifier -> Void in return postbox.modify { modifier -> Void in
switch result { switch result {
case let .config(_, _, _, _, _, dcOptions, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, stickersFavedLimit, tmpSessions, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, suggestedLangCode, langPackVersion, disabledFeatures): case let .config(_, _, _, _, _, dcOptions, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, onlineCloudTimeoutMs, notifyCloudDelayMs, notifyDefaultDelayMs, chatBigSize, pushChatPeriodMs, pushChatLimit, savedGifsLimit, editTimeLimit, ratingEDecay, stickersRecentLimit, stickersFavedLimit, channelsReadMediaPeriod, tmpSessions, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, suggestedLangCode, langPackVersion, disabledFeatures):
var addressList: [Int: [MTDatacenterAddress]] = [:] var addressList: [Int: [MTDatacenterAddress]] = [:]
for option in dcOptions { for option in dcOptions {
switch option { switch option {

View File

@ -17,7 +17,7 @@ private func hashForIds(_ ids: [Int64]) -> Int32 {
acc = (acc &* 20261) &+ high acc = (acc &* 20261) &+ high
acc = (acc &* 20261) &+ low acc = (acc &* 20261) &+ low
} }
return Int32(bitPattern: acc % UInt32(0x7FFFFFFF)) return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))
} }
private func managedRecentMedia(postbox: Postbox, network: Network, collectionId: Int32, reverseHashOrder: Bool, fetch: @escaping (Int32) -> Signal<[OrderedItemListEntry]?, NoError>) -> Signal<Void, NoError> { private func managedRecentMedia(postbox: Postbox, network: Network, collectionId: Int32, reverseHashOrder: Bool, fetch: @escaping (Int32) -> Signal<[OrderedItemListEntry]?, NoError>) -> Signal<Void, NoError> {

View File

@ -128,7 +128,7 @@ private func hashForStickerPackInfos(_ infos: [StickerPackCollectionInfo]) -> In
acc = UInt32(bitPattern: Int32(bitPattern: acc &* UInt32(20261)) &+ info.hash) acc = UInt32(bitPattern: Int32(bitPattern: acc &* UInt32(20261)) &+ info.hash)
} }
return Int32(bitPattern: acc % 0x7FFFFFFF) return Int32(bitPattern: acc & 0x7FFFFFFF)
} }
private enum SynchronizeInstalledStickerPacksError { private enum SynchronizeInstalledStickerPacksError {

View File

@ -5,9 +5,7 @@ import Foundation
import Postbox import Postbox
#endif #endif
public struct NotificationInfoMessageAttributeFlags: OptionSet {
public struct NotificationInfoMessageAttributeFlags : OptionSet {
public var rawValue: Int32 public var rawValue: Int32
public init(rawValue: Int32) { public init(rawValue: Int32) {
@ -24,8 +22,8 @@ public struct NotificationInfoMessageAttributeFlags : OptionSet {
} }
public class NotificationInfoMessageAttribute: MessageAttribute { public class NotificationInfoMessageAttribute: MessageAttribute {
public let flags: NotificationInfoMessageAttributeFlags
public let flags:NotificationInfoMessageAttributeFlags
public init(flags: NotificationInfoMessageAttributeFlags) { public init(flags: NotificationInfoMessageAttributeFlags) {
self.flags = flags self.flags = flags
} }

View File

@ -42,7 +42,7 @@ public extension Peer {
switch self { switch self {
case let user as TelegramUser: case let user as TelegramUser:
return user.username return user.username
case let _ as TelegramGroup: case _ as TelegramGroup:
return nil return nil
case let channel as TelegramChannel: case let channel as TelegramChannel:
return channel.username return channel.username

View File

@ -74,7 +74,7 @@ func messageContentToUpload(network: Network, postbox: Postbox, transformOutgoin
} else if let map = media as? TelegramMediaMap { } else if let map = media as? TelegramMediaMap {
let input: Api.InputMedia let input: Api.InputMedia
if let venue = map.venue { if let venue = map.venue {
input = .inputMediaVenue(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude), title: venue.title, address: venue.address ?? "", provider: venue.provider ?? "", venueId: venue.id ?? "") input = .inputMediaVenue(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude), title: venue.title, address: venue.address ?? "", provider: venue.provider ?? "", venueId: venue.id ?? "", venueType: venue.type ?? "")
} else { } else {
input = .inputMediaGeoPoint(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude)) input = .inputMediaGeoPoint(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude))
} }

View File

@ -0,0 +1,41 @@
import Foundation
#if os(macOS)
import PostboxMac
#else
import Postbox
#endif
final class RegularChatState: PeerChatState, Equatable {
let invalidatedPts: Int32?
init(invalidatedPts: Int32?) {
self.invalidatedPts = invalidatedPts
}
init(decoder: PostboxDecoder) {
self.invalidatedPts = decoder.decodeOptionalInt32ForKey("ipts")
}
func encode(_ encoder: PostboxEncoder) {
if let invalidatedPts = self.invalidatedPts {
encoder.encodeInt32(invalidatedPts, forKey: "ipts")
} else {
encoder.encodeNil(forKey: "ipts")
}
}
func withUpdatedInvalidatedPts(_ invalidatedPts: Int32?) -> RegularChatState {
return RegularChatState(invalidatedPts: invalidatedPts)
}
func equals(_ other: PeerChatState) -> Bool {
if let other = other as? RegularChatState, other == self {
return true
}
return false
}
static func ==(lhs: RegularChatState, rhs: RegularChatState) -> Bool {
return lhs.invalidatedPts == rhs.invalidatedPts
}
}

View File

@ -20,7 +20,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization { public class Serialization: NSObject, MTSerialization {
public func currentLayer() -> UInt { public func currentLayer() -> UInt {
return 71 return 72
} }
public func parseMessage(_ data: Data!) -> Any! { public func parseMessage(_ data: Data!) -> Any! {
@ -56,7 +56,7 @@ public class Serialization: NSObject, MTSerialization {
return { response -> MTDatacenterAddressListData! in return { response -> MTDatacenterAddressListData! in
if let config = parse(Buffer(data: response)) { if let config = parse(Buffer(data: response)) {
switch config { switch config {
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _): case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
var addressDict: [NSNumber: [Any]] = [:] var addressDict: [NSNumber: [Any]] = [:]
for option in dcOptions { for option in dcOptions {
switch option { switch option {

View File

@ -18,7 +18,7 @@ private func hashForIdsReverse(_ ids: [Int64]) -> Int32 {
acc = (acc &* 20261) &+ high acc = (acc &* 20261) &+ high
acc = (acc &* 20261) &+ low acc = (acc &* 20261) &+ low
} }
return Int32(bitPattern: acc % UInt32(0x7FFFFFFF)) return Int32(bitPattern: acc & UInt32(0x7FFFFFFF))
} }
func manageStickerPacks(network: Network, postbox: Postbox) -> Signal<Void, NoError> { func manageStickerPacks(network: Network, postbox: Postbox) -> Signal<Void, NoError> {

View File

@ -201,7 +201,7 @@ extension Api.Message {
} }
switch action { switch action {
case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken: case .messageActionChannelCreate, .messageActionChatDeletePhoto, .messageActionChatEditPhoto, .messageActionChatEditTitle, .messageActionEmpty, .messageActionPinMessage, .messageActionHistoryClear, .messageActionGameScore, .messageActionPaymentSent, .messageActionPaymentSentMe, .messageActionPhoneCall, .messageActionScreenshotTaken, .messageActionCustomAction:
break break
case let .messageActionChannelMigrateFrom(_, chatId): case let .messageActionChannelMigrateFrom(_, chatId):
result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId)) result.append(PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))
@ -278,10 +278,13 @@ func textMediaAndExpirationTimerFromApiMedia(_ media: Api.MessageMedia?, _ peerI
let mediaContact = TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: contactPeerId) let mediaContact = TelegramMediaContact(firstName: firstName, lastName: lastName, phoneNumber: phoneNumber, peerId: contactPeerId)
return (nil, mediaContact, nil) return (nil, mediaContact, nil)
case let .messageMediaGeo(geo): case let .messageMediaGeo(geo):
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil) let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil)
return (nil, mediaMap, nil) return (nil, mediaMap, nil)
case let .messageMediaVenue(geo, title, address, provider, venueId): case let .messageMediaVenue(geo, title, address, provider, venueId, venueType):
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId) let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId, venueType: venueType, liveBroadcastingTimeout: nil)
return (nil, mediaMap, nil)
case let .messageMediaGeoLive(geo, period):
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period)
return (nil, mediaMap, nil) return (nil, mediaMap, nil)
case let .messageMediaDocument(_, document, caption, ttlSeconds): case let .messageMediaDocument(_, document, caption, ttlSeconds):
if let document = document { if let document = document {
@ -505,6 +508,9 @@ extension StoreMessage {
case .messageEmpty: case .messageEmpty:
return nil return nil
case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action): case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action):
if case .messageActionHistoryClear = action {
return nil
}
let peerId: PeerId let peerId: PeerId
var authorId: PeerId? var authorId: PeerId?
switch toId { switch toId {

View File

@ -29,6 +29,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case gameScore(gameId: Int64, score: Int32) case gameScore(gameId: Int64, score: Int32)
case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?) case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?)
case paymentSent(currency: String, totalAmount: Int64) case paymentSent(currency: String, totalAmount: Int64)
case customText(text: String)
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
switch rawValue { switch rawValue {
@ -66,7 +68,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0)) self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0))
case 15: case 15:
self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0)) self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0))
case 16:
self = .customText(text: decoder.decodeStringForKey("text", orElse: ""))
default: default:
self = .unknown self = .unknown
} }
@ -137,6 +140,9 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
} else { } else {
encoder.encodeNil(forKey: "d") encoder.encodeNil(forKey: "d")
} }
case let .customText(text):
encoder.encodeInt32(16, forKey: "_rawValue")
encoder.encodeString(text, forKey: "text")
} }
} }
@ -256,6 +262,12 @@ public func ==(lhs: TelegramMediaActionType, rhs: TelegramMediaActionType) -> Bo
} else { } else {
return false return false
} }
case let .customText(text):
if case .customText(text) = rhs {
return true
} else {
return false
}
} }
return false return false
} }
@ -330,6 +342,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return nil return nil
case .messageActionScreenshotTaken: case .messageActionScreenshotTaken:
return TelegramMediaAction(action: .historyScreenshot) return TelegramMediaAction(action: .historyScreenshot)
case let .messageActionCustomAction(message):
return TelegramMediaAction(action: .customText(text: message))
} }
} }

View File

@ -5,7 +5,7 @@ import Foundation
import Postbox import Postbox
#endif #endif
public final class NamedGeoPlace: PostboxCoding { public final class NamedGeoPlace: PostboxCoding, Equatable {
public let country: String? public let country: String?
public let state: String? public let state: String?
public let city: String? public let city: String?
@ -49,19 +49,40 @@ public final class NamedGeoPlace: PostboxCoding {
encoder.encodeString(street, forKey: "gp_str") encoder.encodeString(street, forKey: "gp_str")
} }
} }
public static func ==(lhs: NamedGeoPlace, rhs: NamedGeoPlace) -> Bool {
if lhs.country != rhs.country {
return false
}
if lhs.state != rhs.state {
return false
}
if lhs.city != rhs.city {
return false
}
if lhs.district != rhs.district {
return false
}
if lhs.street != rhs.street {
return false
}
return true
}
} }
public final class MapVenue: PostboxCoding { public final class MapVenue: PostboxCoding, Equatable {
public let title: String public let title: String
public let address: String? public let address: String?
public let provider: String? public let provider: String?
public let id: String? public let id: String?
public let type: String?
public init(title: String, address: String?, provider: String?, id: String?) { public init(title: String, address: String?, provider: String?, id: String?, type: String?) {
self.title = title self.title = title
self.address = address self.address = address
self.provider = provider self.provider = provider
self.id = id self.id = id
self.type = type
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -69,6 +90,7 @@ public final class MapVenue: PostboxCoding {
self.address = decoder.decodeOptionalStringForKey("ad") self.address = decoder.decodeOptionalStringForKey("ad")
self.provider = decoder.decodeOptionalStringForKey("pr") self.provider = decoder.decodeOptionalStringForKey("pr")
self.id = decoder.decodeOptionalStringForKey("id") self.id = decoder.decodeOptionalStringForKey("id")
self.type = decoder.decodeOptionalStringForKey("ty")
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -76,13 +98,40 @@ public final class MapVenue: PostboxCoding {
if let address = self.address { if let address = self.address {
encoder.encodeString(address, forKey: "ad") encoder.encodeString(address, forKey: "ad")
} else {
encoder.encodeNil(forKey: "ad")
} }
if let provider = self.provider { if let provider = self.provider {
encoder.encodeString(provider, forKey: "pr") encoder.encodeString(provider, forKey: "pr")
} else {
encoder.encodeNil(forKey: "pr")
} }
if let id = self.id { if let id = self.id {
encoder.encodeString(id, forKey: "id") encoder.encodeString(id, forKey: "id")
} else {
encoder.encodeNil(forKey: "id")
} }
if let type = self.type {
encoder.encodeString(type, forKey: "ty")
} else {
encoder.encodeNil(forKey: "ty")
}
}
public static func ==(lhs: MapVenue, rhs: MapVenue) -> Bool {
if lhs.address != rhs.address {
return false
}
if lhs.provider != rhs.provider {
return false
}
if lhs.id != rhs.id {
return false
}
if lhs.type != rhs.type {
return false
}
return true
} }
} }
@ -91,15 +140,17 @@ public final class TelegramMediaMap: Media {
public let longitude: Double public let longitude: Double
public let geoPlace: NamedGeoPlace? public let geoPlace: NamedGeoPlace?
public let venue: MapVenue? public let venue: MapVenue?
public let liveBroadcastingTimeout: Int32?
public let id: MediaId? = nil public let id: MediaId? = nil
public let peerIds: [PeerId] = [] public let peerIds: [PeerId] = []
public init(latitude: Double, longitude: Double, geoPlace: NamedGeoPlace?, venue: MapVenue?) { public init(latitude: Double, longitude: Double, geoPlace: NamedGeoPlace?, venue: MapVenue?, liveBroadcastingTimeout: Int32?) {
self.latitude = latitude self.latitude = latitude
self.longitude = longitude self.longitude = longitude
self.geoPlace = geoPlace self.geoPlace = geoPlace
self.venue = venue self.venue = venue
self.liveBroadcastingTimeout = liveBroadcastingTimeout
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -107,6 +158,7 @@ public final class TelegramMediaMap: Media {
self.longitude = decoder.decodeDoubleForKey("lo", orElse: 0.0) self.longitude = decoder.decodeDoubleForKey("lo", orElse: 0.0)
self.geoPlace = decoder.decodeObjectForKey("gp", decoder: { NamedGeoPlace(decoder: $0) }) as? NamedGeoPlace self.geoPlace = decoder.decodeObjectForKey("gp", decoder: { NamedGeoPlace(decoder: $0) }) as? NamedGeoPlace
self.venue = decoder.decodeObjectForKey("ve", decoder: { MapVenue(decoder: $0) }) as? MapVenue self.venue = decoder.decodeObjectForKey("ve", decoder: { MapVenue(decoder: $0) }) as? MapVenue
self.liveBroadcastingTimeout = decoder.decodeOptionalInt32ForKey("bt")
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -114,31 +166,50 @@ public final class TelegramMediaMap: Media {
encoder.encodeDouble(self.longitude, forKey: "lo") encoder.encodeDouble(self.longitude, forKey: "lo")
if let geoPlace = self.geoPlace { if let geoPlace = self.geoPlace {
encoder.encodeObject(geoPlace, forKey: "gp") encoder.encodeObject(geoPlace, forKey: "gp")
} else {
encoder.encodeNil(forKey: "gp")
} }
if let venue = self.venue { if let venue = self.venue {
encoder.encodeObject(venue, forKey: "ve") encoder.encodeObject(venue, forKey: "ve")
} else {
encoder.encodeNil(forKey: "ve")
}
if let liveBroadcastingTimeout = self.liveBroadcastingTimeout {
encoder.encodeInt32(liveBroadcastingTimeout, forKey: "bt")
} else {
encoder.encodeNil(forKey: "bt")
} }
} }
public func isEqual(_ other: Media) -> Bool { public func isEqual(_ other: Media) -> Bool {
if let other = other as? TelegramMediaMap { if let other = other as? TelegramMediaMap {
if self.latitude == other.latitude && self.longitude == other.longitude { if self.latitude != other.latitude || self.longitude != other.longitude {
return true return false
} }
if self.geoPlace != other.geoPlace {
return false
}
if self.venue != other.venue {
return false
}
if self.liveBroadcastingTimeout != other.liveBroadcastingTimeout {
return false
}
return true
} }
return false return false
} }
} }
public func telegramMediaMapFromApiGeoPoint(_ geo: Api.GeoPoint, title: String?, address: String?, provider: String?, venueId: String?) -> TelegramMediaMap { public func telegramMediaMapFromApiGeoPoint(_ geo: Api.GeoPoint, title: String?, address: String?, provider: String?, venueId: String?, venueType: String?, liveBroadcastingTimeout: Int32?) -> TelegramMediaMap {
var venue: MapVenue? var venue: MapVenue?
if let title = title { if let title = title {
venue = MapVenue(title: title, address: address, provider: provider, id: venueId) venue = MapVenue(title: title, address: address, provider: provider, id: venueId, type: venueType)
} }
switch geo { switch geo {
case let .geoPoint(long, lat): case let .geoPoint(long, lat):
return TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: venue) return TelegramMediaMap(latitude: lat, longitude: long, geoPlace: nil, venue: venue, liveBroadcastingTimeout: liveBroadcastingTimeout)
case .geoPointEmpty: case .geoPointEmpty:
return TelegramMediaMap(latitude: 0.0, longitude: 0.0, geoPlace: nil, venue: venue) return TelegramMediaMap(latitude: 0.0, longitude: 0.0, geoPlace: nil, venue: venue, liveBroadcastingTimeout: liveBroadcastingTimeout)
} }
} }

View File

@ -11,7 +11,7 @@ func fetchAndUpdateCachedParticipants(peerId: PeerId, network: Network, postbox:
return postbox.loadedPeerWithId(peerId) return postbox.loadedPeerWithId(peerId)
|> mapToSignal { peer -> Signal<Void, NoError> in |> mapToSignal { peer -> Signal<Void, NoError> in
if let inputChannel = apiInputChannel(peer) { if let inputChannel = apiInputChannel(peer) {
return network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsRecent, offset: 0, limit: 200)) return network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsRecent, offset: 0, limit: 200, hash: 0))
|> retryRequest |> retryRequest
|> mapToSignal { result -> Signal<Void, NoError> in |> mapToSignal { result -> Signal<Void, NoError> in
return postbox.modify { modifier -> Void in return postbox.modify { modifier -> Void in
@ -42,6 +42,8 @@ func fetchAndUpdateCachedParticipants(peerId: PeerId, network: Network, postbox:
return currentData return currentData
} }
}) })
case .channelParticipantsNotModified:
break
} }
} }
} }

View File

@ -213,14 +213,14 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
switch result { switch result {
case let .chatFull(fullChat, chats, users): case let .chatFull(fullChat, chats, users):
switch fullChat { switch fullChat {
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _): case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _):
modifier.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)]) modifier.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
case .chatFull: case .chatFull:
break break
} }
switch fullChat { switch fullChat {
case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet): case let .channelFull(flags, _, about, participantsCount, adminsCount, kickedCount, bannedCount, _, _, _, _, _, apiExportedInvite, apiBotInfos, migratedFromChatId, migratedFromMaxId, pinnedMsgId, stickerSet, minAvailableMsgId):
var channelFlags = CachedChannelFlags() var channelFlags = CachedChannelFlags()
if (flags & (1 << 3)) != 0 { if (flags & (1 << 3)) != 0 {
channelFlags.insert(.canDisplayParticipants) channelFlags.insert(.canDisplayParticipants)
@ -246,6 +246,15 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
pinnedMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: pinnedMsgId) pinnedMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: pinnedMsgId)
} }
var minAvailableMessageId: MessageId?
if let minAvailableMsgId = minAvailableMsgId {
minAvailableMessageId = MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: minAvailableMsgId)
if let pinnedMsgId = pinnedMsgId, pinnedMsgId < minAvailableMsgId {
pinnedMessageId = nil
}
}
var peers: [Peer] = [] var peers: [Peer] = []
var peerPresences: [PeerId: PeerPresence] = [:] var peerPresences: [PeerId: PeerPresence] = [:]
for chat in chats { for chat in chats {
@ -281,6 +290,7 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
return StickerPackCollectionInfo(apiSet: apiSet, namespace: namespace) return StickerPackCollectionInfo(apiSet: apiSet, namespace: namespace)
} }
var minAvailableMessageIdUpdated = false
modifier.updatePeerCachedData(peerIds: [peerId], update: { _, current in modifier.updatePeerCachedData(peerIds: [peerId], update: { _, current in
let previous: CachedChannelData let previous: CachedChannelData
if let current = current as? CachedChannelData { if let current = current as? CachedChannelData {
@ -289,6 +299,8 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
previous = CachedChannelData() previous = CachedChannelData()
} }
minAvailableMessageIdUpdated = previous.minAvailableMessageId != minAvailableMessageId
return previous.withUpdatedFlags(channelFlags) return previous.withUpdatedFlags(channelFlags)
.withUpdatedAbout(about) .withUpdatedAbout(about)
.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: participantsCount, adminCount: adminsCount, bannedCount: bannedCount, kickedCount: kickedCount)) .withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: participantsCount, adminCount: adminsCount, bannedCount: bannedCount, kickedCount: kickedCount))
@ -296,7 +308,12 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
.withUpdatedBotInfos(botInfos) .withUpdatedBotInfos(botInfos)
.withUpdatedPinnedMessageId(pinnedMessageId) .withUpdatedPinnedMessageId(pinnedMessageId)
.withUpdatedStickerPack(stickerPack) .withUpdatedStickerPack(stickerPack)
.withUpdatedMinAvailableMessageId(minAvailableMessageId)
}) })
if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated {
modifier.deleteMessagesInRange(peerId: peerId, namespace: minAvailableMessageId.namespace, minId: 1, maxId: minAvailableMessageId.id)
}
case .chatFull: case .chatFull:
break break
} }

View File

@ -5,6 +5,20 @@ import Foundation
import Postbox import Postbox
#endif #endif
func updatePeerChatInclusionWithMinTimestamp(modifier: Modifier, id: PeerId, minTimestamp: Int32) {
let currentInclusion = modifier.getPeerChatListInclusion(id)
var updatedInclusion: PeerChatListInclusion?
switch currentInclusion {
case .ifHasMessages, .ifHasMessagesOrOneOf:
updatedInclusion = currentInclusion.withSetIfHasMessagesOrMaxMinTimestamp(minTimestamp)
default:
break
}
if let updatedInclusion = updatedInclusion {
modifier.updatePeerChatListInclusion(id, inclusion: updatedInclusion)
}
}
public func updatePeers(modifier: Modifier, peers: [Peer], update: (Peer?, Peer) -> Peer?) { public func updatePeers(modifier: Modifier, peers: [Peer], update: (Peer?, Peer) -> Peer?) {
modifier.updatePeersInternal(peers, update: { previous, updated in modifier.updatePeersInternal(peers, update: { previous, updated in
let peerId = updated.id let peerId = updated.id