mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-16 03:09:56 +00:00
no message
This commit is contained in:
parent
dfdc87bf95
commit
00c3e87b11
@ -129,6 +129,8 @@
|
||||
D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */; };
|
||||
D0223A9B1EA5654D00211D94 /* 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 */; };
|
||||
D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */ = {isa = PBXBuildFile; fileRef = D02ABC7A1E30058F00CAE539 /* DeleteMessagesInteractively.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 */; };
|
||||
D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B844521DAC0773005F29E1 /* TelegramUserPresence.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 */; };
|
||||
D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03E5E0B1E55E02D0029569A /* LoggedOutAccountAttribute.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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -713,6 +720,8 @@
|
||||
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; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
@ -1153,12 +1162,14 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D03B0CFF1D62255C00955575 /* ChannelState.swift */,
|
||||
D03DC9121F82F89D001D584C /* RegularChatState.swift */,
|
||||
D03121011DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift */,
|
||||
D03B0D001D62255C00955575 /* EnqueueMessage.swift */,
|
||||
D03B0D011D62255C00955575 /* Holes.swift */,
|
||||
D017495D1E118F790057C89A /* AccountStateManager.swift */,
|
||||
D017495F1E118FC30057C89A /* AccountIntermediateState.swift */,
|
||||
D03B0D031D62255C00955575 /* AccountStateManagementUtils.swift */,
|
||||
D03DC90F1F82E344001D584C /* AccountStateReset.swift */,
|
||||
D03B0D041D62255C00955575 /* SynchronizePeerReadState.swift */,
|
||||
D03B0D051D62255C00955575 /* UpdateGroup.swift */,
|
||||
D03B0D061D62255C00955575 /* UpdateMessageService.swift */,
|
||||
@ -1492,6 +1503,7 @@
|
||||
C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */,
|
||||
D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */,
|
||||
D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */,
|
||||
D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */,
|
||||
);
|
||||
name = Peers;
|
||||
sourceTree = "<group>";
|
||||
@ -1814,6 +1826,7 @@
|
||||
D0E23DDA1E806F7700B9B6D2 /* ManagedSynchronizeMarkFeaturedStickerPacksAsSeenOperations.swift in Sources */,
|
||||
D049EAD81E43DAD200A2CD3A /* ManagedRecentStickers.swift in Sources */,
|
||||
D0448C991E268F9A005A61A7 /* SecretApiLayer46.swift in Sources */,
|
||||
D03DC9131F82F89D001D584C /* RegularChatState.swift in Sources */,
|
||||
D0613FCF1E60520700202CDB /* ChannelMembers.swift in Sources */,
|
||||
C2366C891E4F40480097CCFF /* SupportPeerId.swift in Sources */,
|
||||
D05A32E11E6F0982002760B4 /* UpdatedAccountPrivacySettings.swift in Sources */,
|
||||
@ -1837,6 +1850,7 @@
|
||||
C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */,
|
||||
D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */,
|
||||
D03B0CD61D62245300955575 /* TelegramUser.swift in Sources */,
|
||||
D02395D61F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */,
|
||||
D019B1CC1E2E3B6A00F80DB3 /* SecretChatRekeySession.swift in Sources */,
|
||||
D03B0CD91D62245B00955575 /* PeerUtils.swift in Sources */,
|
||||
D053B41B1F18DEF500E2D58A /* TelegramMediaExpiredContent.swift in Sources */,
|
||||
@ -1905,6 +1919,7 @@
|
||||
D03B0D5C1D631A6900955575 /* Download.swift in Sources */,
|
||||
D0C27B421F4B58C000A4E170 /* PeerSpecificStickerPack.swift in Sources */,
|
||||
D01749591E1092BC0057C89A /* RequestStartBot.swift in Sources */,
|
||||
D03DC9101F82E344001D584C /* AccountStateReset.swift in Sources */,
|
||||
D01B27A21E394D8B0022A4C0 /* PrivacySettings.swift in Sources */,
|
||||
D0223A9B1EA5654D00211D94 /* TelegramMediaResource.swift in Sources */,
|
||||
D017495E1E118F790057C89A /* AccountStateManager.swift in Sources */,
|
||||
@ -2011,6 +2026,7 @@
|
||||
D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */,
|
||||
D0B418A71D7E0592004562A4 /* Fetch.swift in Sources */,
|
||||
D02ABC7C1E30058F00CAE539 /* DeleteMessagesInteractively.swift in Sources */,
|
||||
D03DC9111F82E344001D584C /* AccountStateReset.swift in Sources */,
|
||||
D050F2111E48AB0600988324 /* InteractivePhoneFormatter.swift in Sources */,
|
||||
D050F2631E4A5AEB00988324 /* SynchronizePinnedChatsOperation.swift in Sources */,
|
||||
D0B418B81D7E05A6004562A4 /* ContactManagement.swift in Sources */,
|
||||
@ -2075,6 +2091,7 @@
|
||||
D0BEAF611E54ACF900BD963D /* AccountManager.swift in Sources */,
|
||||
D0F3CC791DDE2859008148FA /* SearchMessages.swift in Sources */,
|
||||
D0B8442B1DAB91E0005F29E1 /* NBMetadataCore.m in Sources */,
|
||||
D03DC9141F82F89D001D584C /* RegularChatState.swift in Sources */,
|
||||
D00C7CD01E3628180080C3D5 /* UpdateCachedChannelParticipants.swift in Sources */,
|
||||
D0F3A8A61E82C94C00B4C64C /* SynchronizeableChatInputState.swift in Sources */,
|
||||
D00BDA1A1EE593D600C64C5E /* TelegramChannelAdminRights.swift in Sources */,
|
||||
@ -2193,6 +2210,7 @@
|
||||
D03C53741DAD5CA9004C17B3 /* CachedChannelData.swift in Sources */,
|
||||
D0B418861D7E056D004562A4 /* Namespaces.swift in Sources */,
|
||||
D05A32E51E6F0B2E002760B4 /* RecentAccountSessions.swift in Sources */,
|
||||
D02395D71F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift in Sources */,
|
||||
D0F7B1E41E045C7B007EB8A5 /* InstantPage.swift in Sources */,
|
||||
D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */,
|
||||
D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */,
|
||||
|
||||
@ -173,6 +173,7 @@ private var declaredEncodables: Void = {
|
||||
declareEncodable(TelegramMediaFileAttribute.self, f: { TelegramMediaFileAttribute(decoder: $0) })
|
||||
declareEncodable(CloudFileMediaResource.self, f: { CloudFileMediaResource(decoder: $0) })
|
||||
declareEncodable(ChannelState.self, f: { ChannelState(decoder: $0) })
|
||||
declareEncodable(RegularChatState.self, f: { RegularChatState(decoder: $0) })
|
||||
declareEncodable(InlineBotMessageAttribute.self, f: { InlineBotMessageAttribute(decoder: $0) })
|
||||
declareEncodable(TextEntitiesMessageAttribute.self, f: { TextEntitiesMessageAttribute(decoder: $0) })
|
||||
declareEncodable(ReplyMessageAttribute.self, f: { ReplyMessageAttribute(decoder: $0) })
|
||||
@ -748,7 +749,7 @@ public func setupAccount(_ account: Account, fetchCachedResourceRepresentation:
|
||||
account.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.network.request(Api.functions.help.getScheme(version: 0)).start(next: { result in
|
||||
|
||||
@ -84,6 +84,7 @@ enum AccountStateMutationOperation {
|
||||
case UpdateChatInputState(PeerId, SynchronizeableChatInputState?)
|
||||
case UpdateCall(Api.PhoneCall)
|
||||
case UpdateLangPack(Api.LangPackDifference?)
|
||||
case UpdateMinAvailableMessage(MessageId)
|
||||
}
|
||||
|
||||
struct AccountMutableState {
|
||||
@ -220,6 +221,10 @@ struct AccountMutableState {
|
||||
self.addOperation(.UpdateLangPack(difference))
|
||||
}
|
||||
|
||||
mutating func updateMinAvailableMessage(_ id: MessageId) {
|
||||
self.addOperation(.UpdateMinAvailableMessage(id))
|
||||
}
|
||||
|
||||
mutating func mergeUsers(_ users: [Api.User]) {
|
||||
self.addOperation(.MergeApiUsers(users))
|
||||
|
||||
@ -286,7 +291,7 @@ struct AccountMutableState {
|
||||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
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
|
||||
case let .AddMessages(messages, _):
|
||||
for message in messages {
|
||||
|
||||
@ -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> {
|
||||
@ -501,7 +501,7 @@ func finalStateWithDifference(account: Account, state: AccountMutableState, diff
|
||||
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] {
|
||||
@ -552,6 +552,13 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
|
||||
} else {
|
||||
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:
|
||||
result.append(update)
|
||||
}
|
||||
@ -602,7 +609,7 @@ private func sortedUpdates(_ updates: [Api.Update]) -> [Api.Update] {
|
||||
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 channelsToPoll = Set<PeerId>()
|
||||
@ -694,6 +701,9 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
|
||||
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, _, _):
|
||||
updatedState.deleteMessagesWithGlobalIds(messages)
|
||||
case let .updateEditMessage(apiMessage, _, _):
|
||||
@ -1023,21 +1033,49 @@ private func finalStateWithUpdates(account: Account, state: AccountMutableState,
|
||||
}
|
||||
|
||||
var pollChannelSignals: [Signal<(AccountMutableState, Bool, Int32?), NoError>] = []
|
||||
for peerId in channelsToPoll {
|
||||
if let peer = updatedState.peers[peerId] {
|
||||
pollChannelSignals.append(pollChannel(account, peer: peer, state: updatedState.branch()))
|
||||
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 {
|
||||
Logger.shared.log("State", "can't poll channel \(peerId): no peer found")
|
||||
pollChannelSignals = []
|
||||
}
|
||||
} else {
|
||||
for peerId in channelsToPoll {
|
||||
if let peer = updatedState.peers[peerId] {
|
||||
pollChannelSignals.append(pollChannel(account, peer: peer, state: updatedState.branch()))
|
||||
} else {
|
||||
Logger.shared.log("State", "can't poll channel \(peerId): no peer found")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return combineLatest(pollChannelSignals) |> mapToSignal { states -> Signal<AccountFinalState, NoError> in
|
||||
var finalState = updatedState
|
||||
var finalState: AccountMutableState = updatedState
|
||||
var hadError = false
|
||||
for (state, success, _) in states {
|
||||
finalState.merge(state)
|
||||
if !success {
|
||||
hadError = true
|
||||
|
||||
if shouldResetChannels && states.count != 0 {
|
||||
assert(states.count == 1)
|
||||
finalState = states[0].0
|
||||
} else {
|
||||
for (state, success, _) in states {
|
||||
finalState.merge(state)
|
||||
if !success {
|
||||
hadError = true
|
||||
}
|
||||
}
|
||||
}
|
||||
return resolveAssociatedMessages(account: account, state: finalState)
|
||||
@ -1237,6 +1275,127 @@ func keepPollingChannel(account: Account, peerId: PeerId, stateManager: AccountS
|
||||
} |> 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> {
|
||||
if let inputChannel = apiInputChannel(peer) {
|
||||
var limit: Int32 = 20
|
||||
@ -1322,6 +1481,18 @@ private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableSt
|
||||
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:
|
||||
break
|
||||
}
|
||||
@ -1472,7 +1643,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
||||
var currentAddMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
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 {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@ -1545,6 +1716,8 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, modifier: Modif
|
||||
modifier.deleteMessagesWithGlobalIds(ids)
|
||||
case let .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):
|
||||
modifier.updateMessage(id, update: { _ in .update(message) })
|
||||
case let .UpdateMedia(id, media):
|
||||
|
||||
@ -247,30 +247,37 @@ public final class AccountStateManager {
|
||||
|> take(1)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
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
|
||||
return request |> mapToSignal { difference -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
return initialStateWithDifference(account, difference: difference)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if state.initialState.state != authorizedState {
|
||||
Logger.shared.log("State", "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)")
|
||||
return .single((nil, nil))
|
||||
} else {
|
||||
return finalStateWithDifference(account: account, state: state, difference: difference)
|
||||
|> mapToSignal { finalState -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if !finalState.state.preCachedResources.isEmpty {
|
||||
for (resource, data) in finalState.state.preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
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)
|
||||
|> mapToSignal { state -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if state.initialState.state != authorizedState {
|
||||
Logger.shared.log("State", "pollDifference initial state \(authorizedState) != current state \(state.initialState.state)")
|
||||
return .single((nil, nil))
|
||||
} else {
|
||||
return finalStateWithDifference(account: account, state: state, difference: difference)
|
||||
|> mapToSignal { finalState -> Signal<(Api.updates.Difference?, AccountReplayedFinalState?), NoError> in
|
||||
if !finalState.state.preCachedResources.isEmpty {
|
||||
for (resource, data) in finalState.state.preCachedResources {
|
||||
account.postbox.mediaBox.storeResourceData(resource.id, data: data)
|
||||
}
|
||||
}
|
||||
return account.postbox.modify { modifier -> (Api.updates.Difference?, AccountReplayedFinalState?) in
|
||||
if let replayedState = replayFinalState(accountPeerId: accountPeerId, mediaBox: mediaBox, modifier: modifier, auxiliaryMethods: auxiliaryMethods, finalState: finalState) {
|
||||
return (difference, replayedState)
|
||||
} else {
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
return account.postbox.modify { modifier -> (Api.updates.Difference?, AccountReplayedFinalState?) in
|
||||
if let replayedState = replayFinalState(accountPeerId: accountPeerId, mediaBox: mediaBox, modifier: modifier, auxiliaryMethods: auxiliaryMethods, finalState: finalState) {
|
||||
return (difference, replayedState)
|
||||
} else {
|
||||
return (nil, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -685,11 +692,20 @@ public func messageForNotification(modifier: Modifier, id: MessageId, alwaysRetu
|
||||
Logger.shared.log("AccountStateManager", "notification message doesn't exist")
|
||||
return (nil, false, .bundledModern(id: 0), false)
|
||||
}
|
||||
|
||||
|
||||
var notify = true
|
||||
var sound: PeerMessageSound = .bundledModern(id: 0)
|
||||
var muted = false
|
||||
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)
|
||||
|
||||
var notificationPeerId = id.peerId
|
||||
@ -731,13 +747,17 @@ public func messageForNotification(modifier: Modifier, id: MessageId, alwaysRetu
|
||||
} else {
|
||||
sound = notificationSettings.messageSound
|
||||
}
|
||||
if !defaultNotify {
|
||||
/*if !defaultNotify {
|
||||
notify = false
|
||||
}
|
||||
}*/
|
||||
} else {
|
||||
Logger.shared.log("AccountStateManager", "notification settings for \(notificationPeerId) are undefined")
|
||||
}
|
||||
|
||||
if muted {
|
||||
sound = .none
|
||||
}
|
||||
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel {
|
||||
switch channel.participationStatus {
|
||||
case .kicked, .left:
|
||||
|
||||
237
TelegramCore/AccountStateReset.swift
Normal file
237
TelegramCore/AccountStateReset.swift
Normal 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
@ -19,6 +19,7 @@ public struct CachedChannelFlags: OptionSet {
|
||||
public static let canDisplayParticipants = CachedChannelFlags(rawValue: 1 << 0)
|
||||
public static let canChangeUsername = CachedChannelFlags(rawValue: 1 << 1)
|
||||
public static let canSetStickerSet = CachedChannelFlags(rawValue: 1 << 2)
|
||||
public static let preHistoryEnabled = CachedChannelFlags(rawValue: 1 << 3)
|
||||
}
|
||||
|
||||
public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable {
|
||||
@ -111,6 +112,7 @@ public final class CachedChannelData: CachedPeerData {
|
||||
public let reportStatus: PeerReportStatus
|
||||
public let pinnedMessageId: MessageId?
|
||||
public let stickerPack: StickerPackCollectionInfo?
|
||||
public let minAvailableMessageId: MessageId?
|
||||
|
||||
public let peerIds: Set<PeerId>
|
||||
public let messageIds: Set<MessageId>
|
||||
@ -127,9 +129,10 @@ public final class CachedChannelData: CachedPeerData {
|
||||
self.peerIds = Set()
|
||||
self.messageIds = Set()
|
||||
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.about = about
|
||||
self.participantsSummary = participantsSummary
|
||||
@ -139,6 +142,7 @@ public final class CachedChannelData: CachedPeerData {
|
||||
self.reportStatus = reportStatus
|
||||
self.pinnedMessageId = pinnedMessageId
|
||||
self.stickerPack = stickerPack
|
||||
self.minAvailableMessageId = minAvailableMessageId
|
||||
|
||||
var peerIds = Set<PeerId>()
|
||||
if let topParticipants = topParticipants {
|
||||
@ -159,39 +163,43 @@ public final class CachedChannelData: CachedPeerData {
|
||||
}
|
||||
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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) {
|
||||
@ -215,6 +223,12 @@ public final class CachedChannelData: CachedPeerData {
|
||||
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 {
|
||||
for participant in topParticipants.participants {
|
||||
peerIds.insert(participant.peerId)
|
||||
@ -267,6 +281,15 @@ public final class CachedChannelData: CachedPeerData {
|
||||
} else {
|
||||
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 {
|
||||
@ -310,6 +333,10 @@ public final class CachedChannelData: CachedPeerData {
|
||||
return false
|
||||
}
|
||||
|
||||
if other.minAvailableMessageId != self.minAvailableMessageId {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@ public enum AdminLogEventAction {
|
||||
case participantToggleBan(prev: RenderedChannelParticipant, new: RenderedChannelParticipant)
|
||||
case participantToggleAdmin(prev: RenderedChannelParticipant, new: RenderedChannelParticipant)
|
||||
case changeStickerPack(prev: StickerPackReference?, new: StickerPackReference?)
|
||||
case togglePreHistoryHidden(Bool)
|
||||
}
|
||||
|
||||
public enum ChannelAdminLogEventError {
|
||||
@ -176,6 +177,8 @@ public func channelAdminLogEvents(_ account:Account, peerId:PeerId, maxId:AdminL
|
||||
}
|
||||
case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, 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)
|
||||
if let action = action {
|
||||
|
||||
@ -12,7 +12,7 @@ import Foundation
|
||||
public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedChannelParticipant], NoError> {
|
||||
return account.postbox.modify { modifier -> Signal<[RenderedChannelParticipant], NoError> in
|
||||
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
|
||||
|> mapToSignal { result -> Signal<[RenderedChannelParticipant], NoError> in
|
||||
switch result {
|
||||
@ -46,6 +46,8 @@ public func channelAdmins(account: Account, peerId: PeerId) -> Signal<[RenderedC
|
||||
})
|
||||
return items
|
||||
}
|
||||
case .channelParticipantsNotModified:
|
||||
return .single([])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -24,7 +24,7 @@ private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: Cha
|
||||
case .banned:
|
||||
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
|
||||
|> map { result -> [RenderedChannelParticipant] in
|
||||
var items: [RenderedChannelParticipant] = []
|
||||
@ -40,12 +40,15 @@ private func fetchChannelBlacklist(account: Account, peerId: PeerId, filter: Cha
|
||||
}
|
||||
}
|
||||
|
||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||
if let peer = peers[participant.peerId] {
|
||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences))
|
||||
}
|
||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||
if let peer = peers[participant.peerId] {
|
||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
case .channelParticipantsNotModified:
|
||||
assertionFailure()
|
||||
break
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
35
TelegramCore/ChannelHistoryAvailabilitySettings.swift
Normal file
35
TelegramCore/ChannelHistoryAvailabilitySettings.swift
Normal 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
|
||||
}
|
||||
@ -24,28 +24,30 @@ public func channelMembers(account: Account, peerId: PeerId, filter: ChannelMemb
|
||||
case let .search(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
|
||||
|> map { result -> [RenderedChannelParticipant] in
|
||||
var items: [RenderedChannelParticipant] = []
|
||||
switch result {
|
||||
case let .channelParticipants(_, participants, users):
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
var presences:[PeerId: PeerPresence] = [:]
|
||||
for user in users {
|
||||
let peer = TelegramUser(user: user)
|
||||
peers[peer.id] = peer
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
presences[peer.id] = presence
|
||||
}
|
||||
}
|
||||
|
||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||
if let peer = peers[participant.peerId] {
|
||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences))
|
||||
case let .channelParticipants(_, participants, users):
|
||||
var peers: [PeerId: Peer] = [:]
|
||||
var presences:[PeerId: PeerPresence] = [:]
|
||||
for user in users {
|
||||
let peer = TelegramUser(user: user)
|
||||
peers[peer.id] = peer
|
||||
if let presence = TelegramUserPresence(apiUser: user) {
|
||||
presences[peer.id] = presence
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
for participant in CachedChannelParticipants(apiParticipants: participants).participants {
|
||||
if let peer = peers[participant.peerId] {
|
||||
items.append(RenderedChannelParticipant(participant: participant, peer: peer, peers: peers, presences: presences))
|
||||
}
|
||||
|
||||
}
|
||||
case .channelParticipantsNotModified:
|
||||
break
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
@ -29,10 +29,10 @@ public struct RenderedChannelParticipant: Equatable {
|
||||
func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signal<Void, NoError> {
|
||||
return account.postbox.modify { modifier -> Signal<Void, NoError> in
|
||||
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 members = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsRecent, offset: 0, limit: 0))
|
||||
let banned = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsBanned(q: ""), offset: 0, limit: 0))
|
||||
let kicked = account.network.request(Api.functions.channels.getParticipants(channel: inputChannel, filter: .channelParticipantsKicked(q: ""), 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, hash: 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, hash: 0))
|
||||
return combineLatest(admins, members, banned, kicked)
|
||||
|> mapToSignal { admins, members, banned, kicked -> Signal<Void, MTRpcError> in
|
||||
return account.postbox.modify { modifier -> Void in
|
||||
@ -42,21 +42,33 @@ func updateChannelParticipantsSummary(account: Account, peerId: PeerId) -> Signa
|
||||
switch admins {
|
||||
case let .channelParticipants(count, _, _):
|
||||
adminCount = count
|
||||
case .channelParticipantsNotModified:
|
||||
assertionFailure()
|
||||
adminCount = 0
|
||||
}
|
||||
let memberCount: Int32
|
||||
switch members {
|
||||
case let .channelParticipants(count, _, _):
|
||||
memberCount = count
|
||||
case .channelParticipantsNotModified:
|
||||
assertionFailure()
|
||||
memberCount = 0
|
||||
}
|
||||
let bannedCount: Int32
|
||||
switch banned {
|
||||
case let .channelParticipants(count, _, _):
|
||||
bannedCount = count
|
||||
case .channelParticipantsNotModified:
|
||||
assertionFailure()
|
||||
bannedCount = 0
|
||||
}
|
||||
let kickedCount: Int32
|
||||
switch kicked {
|
||||
case let .channelParticipants(count, _, _):
|
||||
kickedCount = count
|
||||
case .channelParticipantsNotModified:
|
||||
assertionFailure()
|
||||
kickedCount = 0
|
||||
}
|
||||
return current.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: memberCount, adminCount: adminCount, bannedCount: bannedCount, kickedCount: kickedCount))
|
||||
}
|
||||
|
||||
@ -341,14 +341,14 @@ extension ChatContextResultMessage {
|
||||
}
|
||||
self = .text(text: message, entities: parsedEntities, disableUrlPreview: (flags & (1 << 0)) != 0, replyMarkup: parsedReplyMarkup)
|
||||
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?
|
||||
if let replyMarkup = replyMarkup {
|
||||
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
|
||||
}
|
||||
self = .mapLocation(media: media, replyMarkup: parsedReplyMarkup)
|
||||
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?
|
||||
if let replyMarkup = replyMarkup {
|
||||
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
|
||||
@ -400,7 +400,7 @@ extension ChatContextResultSwitchPeer {
|
||||
extension ChatContextResultCollection {
|
||||
convenience init(apiResults: Api.messages.BotResults, botId: PeerId) {
|
||||
switch apiResults {
|
||||
case let .botResults(flags, queryId, nextOffset, switchPm, results, cacheTime):
|
||||
case let .botResults(flags, queryId, nextOffset, switchPm, results, cacheTime, users):
|
||||
var switchPeer: ChatContextResultSwitchPeer?
|
||||
if let switchPm = switchPm {
|
||||
switchPeer = ChatContextResultSwitchPeer(apiSwitchPeer: switchPm)
|
||||
|
||||
@ -50,17 +50,18 @@ private func hashForCountAndIds(count: Int32, ids: [Int32]) -> Int32 {
|
||||
let low = UInt32(bitPattern: id)
|
||||
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
|
||||
return .never()
|
||||
#endif
|
||||
let initialContactPeerIdsHash = postbox.contactPeerIdsView()
|
||||
|> take(1)
|
||||
|> 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)
|
||||
}
|
||||
@ -87,9 +88,9 @@ func manageContacts(network: Network, postbox: Postbox) -> Signal<Void, NoError>
|
||||
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
|
||||
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 ?? "")]))
|
||||
|> map { Optional($0) }
|
||||
|> `catch` { _ -> Signal<Api.contacts.ImportedContacts?, NoError> in
|
||||
|
||||
@ -59,9 +59,16 @@ public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId
|
||||
|
||||
public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signal<Void, NoError> {
|
||||
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)
|
||||
modifier.clearHistory(peerId)
|
||||
if let topTimestamp = topTimestamp {
|
||||
updatePeerChatInclusionWithMinTimestamp(modifier: modifier, id: peerId, minTimestamp: topTimestamp)
|
||||
}
|
||||
} else if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||
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
|
||||
|
||||
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))
|
||||
|
||||
@ -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)
|
||||
|
||||
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)
|
||||
|
||||
@ -12,8 +12,8 @@ public func currentlySuggestedLocalization(network: Network, extractKeys: [Strin
|
||||
|> retryRequest
|
||||
|> mapToSignal { result -> Signal<SuggestedLocalizationInfo?, NoError> in
|
||||
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;
|
||||
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):
|
||||
//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, channelsReadMediaPeriod, _, pinnedDialogsCountMax, callReceiveTimeoutMs, callRingTimeoutMs, callConnectTimeoutMs, callPacketTimeoutMs, meUrlPrefix, suggestedLangCode, _, disabledFeatures):
|
||||
if let suggestedLangCode = suggestedLangCode {
|
||||
return suggestedLocalizationInfo(network: network, languageCode: suggestedLangCode, extractKeys: extractKeys) |> map { Optional($0) }
|
||||
} 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> {
|
||||
return downloadLocalization(network: network, languageCode: languageCode)
|
||||
|> 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
|
||||
return LocalizationSettings(languageCode: languageCode, localization: language)
|
||||
})
|
||||
@ -100,6 +100,14 @@ public func downoadAndApplyLocalization(postbox: Postbox, network: Network, lang
|
||||
network.context.updateApiEnvironment { current in
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,6 +82,7 @@ public final class Logger {
|
||||
|
||||
public init(basePath: String) {
|
||||
self.basePath = basePath
|
||||
//self.logToConsole = false
|
||||
}
|
||||
|
||||
public func collectLogs() -> Signal<[(String, String)], NoError> {
|
||||
|
||||
@ -309,6 +309,14 @@ private func clearHistory(modifier: Modifier, postbox: Postbox, network: Network
|
||||
} else {
|
||||
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 {
|
||||
assertionFailure()
|
||||
return .complete()
|
||||
|
||||
@ -9,12 +9,14 @@ import Foundation
|
||||
import MtProtoKitDynamic
|
||||
#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> {
|
||||
let poll = Signal<Void, NoError> { subscriber in
|
||||
return (network.request(Api.functions.help.getConfig()) |> retryRequest |> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.modify { modifier -> Void in
|
||||
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]] = [:]
|
||||
for option in dcOptions {
|
||||
switch option {
|
||||
|
||||
@ -17,7 +17,7 @@ private func hashForIds(_ ids: [Int64]) -> Int32 {
|
||||
acc = (acc &* 20261) &+ high
|
||||
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> {
|
||||
|
||||
@ -128,7 +128,7 @@ private func hashForStickerPackInfos(_ infos: [StickerPackCollectionInfo]) -> In
|
||||
acc = UInt32(bitPattern: Int32(bitPattern: acc &* UInt32(20261)) &+ info.hash)
|
||||
}
|
||||
|
||||
return Int32(bitPattern: acc % 0x7FFFFFFF)
|
||||
return Int32(bitPattern: acc & 0x7FFFFFFF)
|
||||
}
|
||||
|
||||
private enum SynchronizeInstalledStickerPacksError {
|
||||
|
||||
@ -5,9 +5,7 @@ import Foundation
|
||||
import Postbox
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
public struct NotificationInfoMessageAttributeFlags : OptionSet {
|
||||
public struct NotificationInfoMessageAttributeFlags: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
||||
public init(rawValue: Int32) {
|
||||
@ -24,8 +22,8 @@ public struct NotificationInfoMessageAttributeFlags : OptionSet {
|
||||
}
|
||||
|
||||
public class NotificationInfoMessageAttribute: MessageAttribute {
|
||||
|
||||
public let flags:NotificationInfoMessageAttributeFlags
|
||||
public let flags: NotificationInfoMessageAttributeFlags
|
||||
|
||||
public init(flags: NotificationInfoMessageAttributeFlags) {
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
@ -42,7 +42,7 @@ public extension Peer {
|
||||
switch self {
|
||||
case let user as TelegramUser:
|
||||
return user.username
|
||||
case let _ as TelegramGroup:
|
||||
case _ as TelegramGroup:
|
||||
return nil
|
||||
case let channel as TelegramChannel:
|
||||
return channel.username
|
||||
|
||||
@ -74,7 +74,7 @@ func messageContentToUpload(network: Network, postbox: Postbox, transformOutgoin
|
||||
} else if let map = media as? TelegramMediaMap {
|
||||
let input: Api.InputMedia
|
||||
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 {
|
||||
input = .inputMediaGeoPoint(geoPoint: Api.InputGeoPoint.inputGeoPoint(lat: map.latitude, long: map.longitude))
|
||||
}
|
||||
|
||||
41
TelegramCore/RegularChatState.swift
Normal file
41
TelegramCore/RegularChatState.swift
Normal 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
|
||||
}
|
||||
}
|
||||
@ -20,7 +20,7 @@ public class BoxedMessage: NSObject {
|
||||
|
||||
public class Serialization: NSObject, MTSerialization {
|
||||
public func currentLayer() -> UInt {
|
||||
return 71
|
||||
return 72
|
||||
}
|
||||
|
||||
public func parseMessage(_ data: Data!) -> Any! {
|
||||
@ -56,7 +56,7 @@ public class Serialization: NSObject, MTSerialization {
|
||||
return { response -> MTDatacenterAddressListData! in
|
||||
if let config = parse(Buffer(data: response)) {
|
||||
switch config {
|
||||
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
case let .config(_, _, _, _, _, dcOptions, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
var addressDict: [NSNumber: [Any]] = [:]
|
||||
for option in dcOptions {
|
||||
switch option {
|
||||
|
||||
@ -18,7 +18,7 @@ private func hashForIdsReverse(_ ids: [Int64]) -> Int32 {
|
||||
acc = (acc &* 20261) &+ high
|
||||
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> {
|
||||
|
||||
@ -201,7 +201,7 @@ extension Api.Message {
|
||||
}
|
||||
|
||||
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
|
||||
case let .messageActionChannelMigrateFrom(_, 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)
|
||||
return (nil, mediaContact, nil)
|
||||
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)
|
||||
case let .messageMediaVenue(geo, title, address, provider, venueId):
|
||||
let mediaMap = telegramMediaMapFromApiGeoPoint(geo, title: title, address: address, provider: provider, venueId: venueId)
|
||||
case let .messageMediaVenue(geo, title, address, provider, venueId, venueType):
|
||||
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)
|
||||
case let .messageMediaDocument(_, document, caption, ttlSeconds):
|
||||
if let document = document {
|
||||
@ -505,6 +508,9 @@ extension StoreMessage {
|
||||
case .messageEmpty:
|
||||
return nil
|
||||
case let .messageService(flags, id, fromId, toId, replyToMsgId, date, action):
|
||||
if case .messageActionHistoryClear = action {
|
||||
return nil
|
||||
}
|
||||
let peerId: PeerId
|
||||
var authorId: PeerId?
|
||||
switch toId {
|
||||
|
||||
@ -29,6 +29,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case gameScore(gameId: Int64, score: Int32)
|
||||
case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?)
|
||||
case paymentSent(currency: String, totalAmount: Int64)
|
||||
case customText(text: String)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
||||
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))
|
||||
case 15:
|
||||
self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0))
|
||||
|
||||
case 16:
|
||||
self = .customText(text: decoder.decodeStringForKey("text", orElse: ""))
|
||||
default:
|
||||
self = .unknown
|
||||
}
|
||||
@ -137,6 +140,9 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
} else {
|
||||
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 {
|
||||
return false
|
||||
}
|
||||
case let .customText(text):
|
||||
if case .customText(text) = rhs {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -330,6 +342,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return nil
|
||||
case .messageActionScreenshotTaken:
|
||||
return TelegramMediaAction(action: .historyScreenshot)
|
||||
case let .messageActionCustomAction(message):
|
||||
return TelegramMediaAction(action: .customText(text: message))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ import Foundation
|
||||
import Postbox
|
||||
#endif
|
||||
|
||||
public final class NamedGeoPlace: PostboxCoding {
|
||||
public final class NamedGeoPlace: PostboxCoding, Equatable {
|
||||
public let country: String?
|
||||
public let state: String?
|
||||
public let city: String?
|
||||
@ -49,19 +49,40 @@ public final class NamedGeoPlace: PostboxCoding {
|
||||
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 address: String?
|
||||
public let provider: 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.address = address
|
||||
self.provider = provider
|
||||
self.id = id
|
||||
self.type = type
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
@ -69,6 +90,7 @@ public final class MapVenue: PostboxCoding {
|
||||
self.address = decoder.decodeOptionalStringForKey("ad")
|
||||
self.provider = decoder.decodeOptionalStringForKey("pr")
|
||||
self.id = decoder.decodeOptionalStringForKey("id")
|
||||
self.type = decoder.decodeOptionalStringForKey("ty")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
@ -76,13 +98,40 @@ public final class MapVenue: PostboxCoding {
|
||||
|
||||
if let address = self.address {
|
||||
encoder.encodeString(address, forKey: "ad")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "ad")
|
||||
}
|
||||
if let provider = self.provider {
|
||||
encoder.encodeString(provider, forKey: "pr")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "pr")
|
||||
}
|
||||
if let id = self.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 geoPlace: NamedGeoPlace?
|
||||
public let venue: MapVenue?
|
||||
public let liveBroadcastingTimeout: Int32?
|
||||
|
||||
public let id: MediaId? = nil
|
||||
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.longitude = longitude
|
||||
self.geoPlace = geoPlace
|
||||
self.venue = venue
|
||||
self.liveBroadcastingTimeout = liveBroadcastingTimeout
|
||||
}
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
@ -107,6 +158,7 @@ public final class TelegramMediaMap: Media {
|
||||
self.longitude = decoder.decodeDoubleForKey("lo", orElse: 0.0)
|
||||
self.geoPlace = decoder.decodeObjectForKey("gp", decoder: { NamedGeoPlace(decoder: $0) }) as? NamedGeoPlace
|
||||
self.venue = decoder.decodeObjectForKey("ve", decoder: { MapVenue(decoder: $0) }) as? MapVenue
|
||||
self.liveBroadcastingTimeout = decoder.decodeOptionalInt32ForKey("bt")
|
||||
}
|
||||
|
||||
public func encode(_ encoder: PostboxEncoder) {
|
||||
@ -114,31 +166,50 @@ public final class TelegramMediaMap: Media {
|
||||
encoder.encodeDouble(self.longitude, forKey: "lo")
|
||||
if let geoPlace = self.geoPlace {
|
||||
encoder.encodeObject(geoPlace, forKey: "gp")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "gp")
|
||||
}
|
||||
if let venue = self.venue {
|
||||
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 {
|
||||
if let other = other as? TelegramMediaMap {
|
||||
if self.latitude == other.latitude && self.longitude == other.longitude {
|
||||
return true
|
||||
if self.latitude != other.latitude || self.longitude != other.longitude {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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?
|
||||
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 {
|
||||
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:
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ func fetchAndUpdateCachedParticipants(peerId: PeerId, network: Network, postbox:
|
||||
return postbox.loadedPeerWithId(peerId)
|
||||
|> mapToSignal { peer -> Signal<Void, NoError> in
|
||||
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
|
||||
|> mapToSignal { result -> Signal<Void, NoError> in
|
||||
return postbox.modify { modifier -> Void in
|
||||
@ -42,6 +42,8 @@ func fetchAndUpdateCachedParticipants(peerId: PeerId, network: Network, postbox:
|
||||
return currentData
|
||||
}
|
||||
})
|
||||
case .channelParticipantsNotModified:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,14 +213,14 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
|
||||
switch result {
|
||||
case let .chatFull(fullChat, chats, users):
|
||||
switch fullChat {
|
||||
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _):
|
||||
case let .channelFull(_, _, _, _, _, _, _, _, _, _, _, notifySettings, _, _, _, _, _, _, _):
|
||||
modifier.updateCurrentPeerNotificationSettings([peerId: TelegramPeerNotificationSettings(apiSettings: notifySettings)])
|
||||
case .chatFull:
|
||||
break
|
||||
}
|
||||
|
||||
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()
|
||||
if (flags & (1 << 3)) != 0 {
|
||||
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)
|
||||
}
|
||||
|
||||
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 peerPresences: [PeerId: PeerPresence] = [:]
|
||||
for chat in chats {
|
||||
@ -281,6 +290,7 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
|
||||
return StickerPackCollectionInfo(apiSet: apiSet, namespace: namespace)
|
||||
}
|
||||
|
||||
var minAvailableMessageIdUpdated = false
|
||||
modifier.updatePeerCachedData(peerIds: [peerId], update: { _, current in
|
||||
let previous: CachedChannelData
|
||||
if let current = current as? CachedChannelData {
|
||||
@ -289,6 +299,8 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
|
||||
previous = CachedChannelData()
|
||||
}
|
||||
|
||||
minAvailableMessageIdUpdated = previous.minAvailableMessageId != minAvailableMessageId
|
||||
|
||||
return previous.withUpdatedFlags(channelFlags)
|
||||
.withUpdatedAbout(about)
|
||||
.withUpdatedParticipantsSummary(CachedChannelParticipantsSummary(memberCount: participantsCount, adminCount: adminsCount, bannedCount: bannedCount, kickedCount: kickedCount))
|
||||
@ -296,7 +308,12 @@ func fetchAndUpdateCachedPeerData(peerId: PeerId, network: Network, postbox: Pos
|
||||
.withUpdatedBotInfos(botInfos)
|
||||
.withUpdatedPinnedMessageId(pinnedMessageId)
|
||||
.withUpdatedStickerPack(stickerPack)
|
||||
.withUpdatedMinAvailableMessageId(minAvailableMessageId)
|
||||
})
|
||||
|
||||
if let minAvailableMessageId = minAvailableMessageId, minAvailableMessageIdUpdated {
|
||||
modifier.deleteMessagesInRange(peerId: peerId, namespace: minAvailableMessageId.namespace, minId: 1, maxId: minAvailableMessageId.id)
|
||||
}
|
||||
case .chatFull:
|
||||
break
|
||||
}
|
||||
|
||||
@ -5,6 +5,20 @@ import Foundation
|
||||
import Postbox
|
||||
#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?) {
|
||||
modifier.updatePeersInternal(peers, update: { previous, updated in
|
||||
let peerId = updated.id
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user