diff --git a/TelegramCore/AccountIntermediateState.swift b/TelegramCore/AccountIntermediateState.swift index 4292d1fa87..83f7f1e907 100644 --- a/TelegramCore/AccountIntermediateState.swift +++ b/TelegramCore/AccountIntermediateState.swift @@ -90,6 +90,7 @@ enum AccountStateMutationOperation { case UpdateCall(Api.PhoneCall) case UpdateLangPack(String, Api.LangPackDifference?) case UpdateMinAvailableMessage(MessageId) + case UpdatePeerInclusionMinTimestamp(PeerId, Int32) } struct AccountMutableState { @@ -277,6 +278,10 @@ struct AccountMutableState { self.addOperation(.UpdateMinAvailableMessage(id)) } + mutating func updatePeerInclusionMinTimestamp(peerId: PeerId, timestamp: Int32) { + self.addOperation(.UpdatePeerInclusionMinTimestamp(peerId, timestamp)) + } + mutating func mergeUsers(_ users: [Api.User]) { self.addOperation(.MergeApiUsers(users)) @@ -347,7 +352,7 @@ struct AccountMutableState { mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerInclusionMinTimestamp, .UpdatePeerChatUnreadMark, .UpdateIsContact: break case let .AddMessages(messages, location): for message in messages { diff --git a/TelegramCore/AccountStateManagementUtils.swift b/TelegramCore/AccountStateManagementUtils.swift index 771bb85e5c..f0ac5444f4 100644 --- a/TelegramCore/AccountStateManagementUtils.swift +++ b/TelegramCore/AccountStateManagementUtils.swift @@ -829,6 +829,13 @@ private func finalStateWithUpdatesAndServerTime(postbox: Postbox, network: Netwo } } updatedState.editMessage(messageId, message: message) + for media in message.media { + if let media = media as? TelegramMediaAction { + if case .historyCleared = media.action { + updatedState.readInbox(messageId) + } + } + } } case let .updateNewChannelMessage(apiMessage, pts, ptsCount): if let message = StoreMessage(apiMessage: apiMessage) { @@ -1885,7 +1892,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerInclusionMinTimestamp, .UpdateIsContact: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -2104,6 +2111,14 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP deleteMessages(transaction: transaction, mediaBox: mediaBox, ids: ids) case let .UpdateMinAvailableMessage(id): transaction.deleteMessagesInRange(peerId: id.peerId, namespace: id.namespace, minId: 1, maxId: id.id) + case let .UpdatePeerInclusionMinTimestamp(peerId, timestamp): + let inclusion = transaction.getPeerChatListInclusion(peerId) + switch inclusion { + case .ifHasMessages, .ifHasMessagesOrOneOf: + transaction.updatePeerChatListInclusion(peerId, inclusion: inclusion.withSetIfHasMessagesOrMaxMinTimestamp(timestamp)) + default: + break + } case let .EditMessage(id, message): transaction.updateMessage(id, update: { previousMessage in var updatedFlags = message.flags diff --git a/TelegramCore/CloudChatRemoveMessagesOperation.swift b/TelegramCore/CloudChatRemoveMessagesOperation.swift index 14e9af4a99..c04b940624 100644 --- a/TelegramCore/CloudChatRemoveMessagesOperation.swift +++ b/TelegramCore/CloudChatRemoveMessagesOperation.swift @@ -86,15 +86,18 @@ final class CloudChatRemoveChatOperation: PostboxCoding { final class CloudChatClearHistoryOperation: PostboxCoding { let peerId: PeerId let topMessageId: MessageId + let type: InteractiveMessagesDeletionType - init(peerId: PeerId, topMessageId: MessageId) { + init(peerId: PeerId, topMessageId: MessageId, type: InteractiveMessagesDeletionType) { self.peerId = peerId self.topMessageId = topMessageId + self.type = type } init(decoder: PostboxDecoder) { self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0)) self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0)) + self.type = InteractiveMessagesDeletionType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer } func encode(_ encoder: PostboxEncoder) { @@ -102,6 +105,7 @@ final class CloudChatClearHistoryOperation: PostboxCoding { encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p") encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n") encoder.encodeInt32(self.topMessageId.id, forKey: "m.i") + encoder.encodeInt32(self.type.rawValue, forKey: "type") } } @@ -113,7 +117,7 @@ func cloudChatAddRemoveChatOperation(transaction: Transaction, peerId: PeerId, r transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud))) } -func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?) { +func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, type: InteractiveMessagesDeletionType) { let topMessageId: MessageId? if let explicitTopMessageId = explicitTopMessageId { topMessageId = explicitTopMessageId @@ -121,6 +125,6 @@ func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud) } if let topMessageId = topMessageId { - transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId)) + transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, type: type)) } } diff --git a/TelegramCore/DeleteMessagesInteractively.swift b/TelegramCore/DeleteMessagesInteractively.swift index d66a3a346d..829724fd0d 100644 --- a/TelegramCore/DeleteMessagesInteractively.swift +++ b/TelegramCore/DeleteMessagesInteractively.swift @@ -9,9 +9,9 @@ import Foundation import MtProtoKitDynamic #endif -public enum InteractiveMessagesDeletionType { - case forLocalPeer - case forEveryone +public enum InteractiveMessagesDeletionType: Int32 { + case forLocalPeer = 0 + case forEveryone = 1 } public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId], type: InteractiveMessagesDeletionType) -> Signal { @@ -57,21 +57,25 @@ public func deleteMessagesInteractively(postbox: Postbox, messageIds: [MessageId } } -public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId) -> Signal { +public func clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveMessagesDeletionType) -> Signal { return postbox.transaction { transaction -> Void in if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel { - var topTimestamp: Int32? - if let topIndex = transaction.getTopPeerMessageIndex(peerId: peerId, namespace: Namespaces.Message.Cloud) { - topTimestamp = topIndex.timestamp + cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, type: type) + var topIndex: MessageIndex? + if let topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud), let topMessage = transaction.getMessage(topMessageId) { + topIndex = MessageIndex(topMessage) } - cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil) clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId) if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference { - cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1)) + cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), type: type) clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId) } - if let topTimestamp = topTimestamp { - updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topTimestamp) + if let topIndex = topIndex { + if peerId.namespace == Namespaces.Peer.CloudUser { + let _ = transaction.addMessages([StoreMessage(id: topIndex.id, globallyUniqueId: nil, groupingKey: nil, timestamp: topIndex.timestamp, flags: StoreMessageFlags(), tags: [], globalTags: [], localTags: [], forwardInfo: nil, authorId: nil, text: "", attributes: [], media: [TelegramMediaAction(action: .historyCleared)])], location: .Random) + } else { + updatePeerChatInclusionWithMinTimestamp(transaction: transaction, id: peerId, minTimestamp: topIndex.timestamp) + } } } else if peerId.namespace == Namespaces.Peer.SecretChat { clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId) diff --git a/TelegramCore/LimitsConfiguration.swift b/TelegramCore/LimitsConfiguration.swift index 1b137a5e81..fb8efa1019 100644 --- a/TelegramCore/LimitsConfiguration.swift +++ b/TelegramCore/LimitsConfiguration.swift @@ -6,6 +6,8 @@ import Foundation #endif public struct LimitsConfiguration: Equatable, PreferencesEntry { + public static let timeIntervalForever: Int32 = 0x7fffffff + public var maxGroupMemberCount: Int32 public var maxSupergroupMemberCount: Int32 public var maxMessageForwardBatchSize: Int32 diff --git a/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift b/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift index f50f266335..a6780f8bb5 100644 --- a/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift +++ b/TelegramCore/ManagedCloudChatRemoveMessagesOperations.swift @@ -261,7 +261,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net } let deleteMessages: Signal if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) { - deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false) + deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer) } else { deleteMessages = .complete() } @@ -285,7 +285,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net } else { reportSignal = .complete() } - return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false) + return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer) |> then(reportSignal) |> then(postbox.transaction { transaction -> Void in clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id) @@ -298,8 +298,15 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net } } -private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool) -> Signal { - let signal = network.request(Api.functions.messages.deleteHistory(flags: justClear ? 1 : 0, peer: inputPeer, maxId: maxId)) +private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, type: InteractiveMessagesDeletionType) -> Signal { + var flags: Int32 = 0 + if justClear { + flags |= 1 << 0 + } + if case .forEveryone = type { + flags |= 1 << 1 + } + let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: maxId)) |> map { result -> Api.messages.AffectedHistory? in return result } @@ -330,7 +337,7 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage private func clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal { if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser { if let inputPeer = apiInputPeer(peer) { - return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true) + return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, type: operation.type) } else { return .complete() } diff --git a/TelegramCore/StoreMessage_Telegram.swift b/TelegramCore/StoreMessage_Telegram.swift index a87081219f..af00d69b22 100644 --- a/TelegramCore/StoreMessage_Telegram.swift +++ b/TelegramCore/StoreMessage_Telegram.swift @@ -559,9 +559,6 @@ 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 { diff --git a/TelegramCore/TelegramMediaAction.swift b/TelegramCore/TelegramMediaAction.swift index c27e6b5093..39f4f19173 100644 --- a/TelegramCore/TelegramMediaAction.swift +++ b/TelegramCore/TelegramMediaAction.swift @@ -240,7 +240,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe return TelegramMediaAction(action: .channelMigratedFromGroup(title: title, groupId: PeerId(namespace: Namespaces.Peer.CloudGroup, id: chatId))) case let .messageActionChatAddUser(users): return TelegramMediaAction(action: .addedMembers(peerIds: users.map({ PeerId(namespace: Namespaces.Peer.CloudUser, id: $0) }))) - case let .messageActionChatCreate(title, userIds): + case let .messageActionChatCreate(title, _): return TelegramMediaAction(action: .groupCreated(title: title)) case .messageActionChatDeletePhoto: return TelegramMediaAction(action: .photoUpdated(image: nil))