no message

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

View File

@ -129,6 +129,8 @@
D0223A991EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0223A971EA564BD00211D94 /* MediaResourceNetworkStatsTag.swift */; };
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 */,

View File

@ -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

View File

@ -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 {

View File

@ -443,7 +443,7 @@ func finalStateWithUpdateGroups(_ account: Account, state: AccountMutableState,
}
}
return finalStateWithUpdates(account: account, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty)
return finalStateWithUpdates(account: account, state: updatedState, updates: collectedUpdates, shouldPoll: hadReset, missingUpdates: !ptsUpdatesAfterHole.isEmpty || !qtsUpdatesAfterHole.isEmpty || !seqGroupsAfterHole.isEmpty, shouldResetChannels: true)
}
func finalStateWithDifference(account: Account, state: AccountMutableState, difference: Api.updates.Difference) -> Signal<AccountFinalState, NoError> {
@ -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):

View File

@ -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:

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -19,6 +19,7 @@ public struct CachedChannelFlags: OptionSet {
public static let canDisplayParticipants = CachedChannelFlags(rawValue: 1 << 0)
public static let 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
}
}

View File

@ -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 {

View File

@ -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 {

View File

@ -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
}

View File

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

View File

@ -24,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
}

View File

@ -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))
}

View File

@ -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)

View File

@ -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

View File

@ -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))

View File

@ -335,7 +335,7 @@ func fetchChatListHole(network: Network, postbox: Postbox, hole: ChatListHole) -
readStates[peerId]![Namespaces.Message.Cloud] = .idBased(maxIncomingReadId: apiReadInboxMaxId, maxOutgoingReadId: apiReadOutboxMaxId, maxKnownId: apiTopMessage, count: apiUnreadCount)
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)

View File

@ -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
}
}

View File

@ -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> {

View File

@ -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()

View File

@ -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 {

View File

@ -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> {

View File

@ -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 {

View File

@ -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
}

View File

@ -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

View File

@ -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))
}

View File

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

View File

@ -20,7 +20,7 @@ public class BoxedMessage: NSObject {
public class Serialization: NSObject, MTSerialization {
public 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 {

View File

@ -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> {

View File

@ -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 {

View File

@ -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))
}
}

View File

@ -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)
}
}

View File

@ -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
}
}
}

View File

@ -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
}

View File

@ -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