From 624155ae99b758354c8af12f05fc0bb5525075a5 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 22 Dec 2023 11:41:29 +0400 Subject: [PATCH] Adjust dust effect --- .../Sources/State/AccountStateManager.swift | 93 ++++++++++++++++++- .../Messages/TelegramEngineMessages.swift | 12 +++ .../Sources/ChatHistoryListNode.swift | 27 ++++-- 3 files changed, 120 insertions(+), 12 deletions(-) diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index 3f7469dabe..9948ef3083 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -49,6 +49,41 @@ public enum DeletedMessageId: Hashable { case messageId(MessageId) } +final class MessagesRemovedContext { + private var messagesRemovedInteractively = Set() + private var messagesRemovedInteractivelyLock = NSLock() + + func synchronouslyIsMessageDeletedInteractively(ids: [MessageId]) -> [EngineMessage.Id] { + var result: [EngineMessage.Id] = [] + + self.messagesRemovedInteractivelyLock.lock() + for id in ids { + let mappedId: DeletedMessageId + if id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup { + mappedId = .global(id.id) + } else { + mappedId = .messageId(id) + } + if self.messagesRemovedInteractively.contains(mappedId) { + result.append(id) + } + } + self.messagesRemovedInteractivelyLock.unlock() + + return result + } + + func addIsMessagesDeletedInteractively(ids: [DeletedMessageId]) { + if ids.isEmpty { + return + } + + self.messagesRemovedInteractivelyLock.lock() + self.messagesRemovedInteractively.formUnion(ids) + self.messagesRemovedInteractivelyLock.unlock() + } +} + public final class AccountStateManager { public final class IncomingCallUpdate { public let callId: Int64 @@ -227,6 +262,8 @@ public final class AccountStateManager { return self.deletedMessagesPipe.signal() } + let messagesRemovedContext: MessagesRemovedContext + fileprivate let storyUpdatesPipe = ValuePipe<[InternalStoryUpdate]>() public var storyUpdates: Signal<[InternalStoryUpdate], NoError> { return self.storyUpdatesPipe.signal() @@ -256,7 +293,8 @@ public final class AccountStateManager { peerInputActivityManager: PeerInputActivityManager?, auxiliaryMethods: AccountAuxiliaryMethods, updateConfigRequested: (() -> Void)?, - isPremiumUpdated: (() -> Void)? + isPremiumUpdated: (() -> Void)?, + messagesRemovedContext: MessagesRemovedContext ) { self.queue = queue self.accountPeerId = accountPeerId @@ -270,6 +308,7 @@ public final class AccountStateManager { self.auxiliaryMethods = auxiliaryMethods self.updateConfigRequested = updateConfigRequested self.isPremiumUpdated = isPremiumUpdated + self.messagesRemovedContext = messagesRemovedContext } deinit { @@ -591,13 +630,14 @@ public final class AccountStateManager { let network = self.network let auxiliaryMethods = self.auxiliaryMethods let events = channelOperationsContext.events + let messagesRemovedContext = self.messagesRemovedContext let _ = (self.postbox.transaction { transaction -> AccountReplayedFinalState? in if let state = transaction.getState() as? AuthorizedAccountState { transaction.setState(state.withInvalidatedChannels([])) } - return replayFinalState( + let result = replayFinalState( accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, @@ -616,6 +656,12 @@ public final class AccountStateManager { ignoreDate: false, skipVerification: true ) + + if let result = result, !result.deletedMessageIds.isEmpty { + messagesRemovedContext.addIsMessagesDeletedInteractively(ids: result.deletedMessageIds) + } + + return result } |> deliverOn(self.queue)).start(next: { [weak self] finalState in guard let strongSelf = self else { @@ -663,6 +709,8 @@ public final class AccountStateManager { let mediaBox = postbox.mediaBox let accountPeerId = self.accountPeerId let auxiliaryMethods = self.auxiliaryMethods + let messagesRemovedContext = self.messagesRemovedContext + let signal = postbox.transaction { transaction -> (AuthorizedAccountState?, [(peer: Peer, pts: Int32?)], Bool) in let state = transaction.getState() as? AuthorizedAccountState @@ -749,6 +797,10 @@ public final class AccountStateManager { } if let replayedState = replayedState { + if !replayedState.deletedMessageIds.isEmpty { + messagesRemovedContext.addIsMessagesDeletedInteractively(ids: replayedState.deletedMessageIds) + } + return (difference, replayedState, false, false) } else { return (nil, nil, false, false) @@ -861,6 +913,8 @@ public final class AccountStateManager { let accountPeerId = self.accountPeerId let mediaBox = postbox.mediaBox let queue = self.queue + let messagesRemovedContext = self.messagesRemovedContext + let signal = initialStateWithUpdateGroups(postbox: postbox, groups: groups) |> mapToSignal { [weak self] state -> Signal<(AccountReplayedFinalState?, AccountFinalState), NoError> in return finalStateWithUpdateGroups(accountPeerId: accountPeerId, postbox: postbox, network: network, state: state, groups: groups, asyncResetChannels: nil) @@ -880,6 +934,11 @@ public final class AccountStateManager { } else { let startTime = CFAbsoluteTimeGetCurrent() let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false, skipVerification: false) + + if let result = result, !result.deletedMessageIds.isEmpty { + messagesRemovedContext.addIsMessagesDeletedInteractively(ids: result.deletedMessageIds) + } + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") @@ -1133,6 +1192,7 @@ public final class AccountStateManager { let network = self.network let auxiliaryMethods = self.auxiliaryMethods let removePossiblyDeliveredMessagesUniqueIds = self.removePossiblyDeliveredMessagesUniqueIds + let messagesRemovedContext = self.messagesRemovedContext let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in let startTime = CFAbsoluteTimeGetCurrent() let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false, skipVerification: false) @@ -1140,6 +1200,11 @@ public final class AccountStateManager { if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") } + + if let result = result, !result.deletedMessageIds.isEmpty { + messagesRemovedContext.addIsMessagesDeletedInteractively(ids: result.deletedMessageIds) + } + return result } |> map({ ($0, finalState) }) @@ -1178,9 +1243,16 @@ public final class AccountStateManager { let network = self.network let auxiliaryMethods = self.auxiliaryMethods let removePossiblyDeliveredMessagesUniqueIds = self.removePossiblyDeliveredMessagesUniqueIds + let messagesRemovedContext = self.messagesRemovedContext + let signal = self.postbox.transaction { transaction -> AccountReplayedFinalState? in let startTime = CFAbsoluteTimeGetCurrent() let result = replayFinalState(accountManager: accountManager, postbox: postbox, accountPeerId: accountPeerId, mediaBox: mediaBox, encryptionProvider: network.encryptionProvider, transaction: transaction, auxiliaryMethods: auxiliaryMethods, finalState: finalState, removePossiblyDeliveredMessagesUniqueIds: removePossiblyDeliveredMessagesUniqueIds, ignoreDate: false, skipVerification: false) + + if let result = result, !result.deletedMessageIds.isEmpty { + messagesRemovedContext.addIsMessagesDeletedInteractively(ids: result.deletedMessageIds) + } + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") @@ -1202,6 +1274,7 @@ public final class AccountStateManager { let mediaBox = postbox.mediaBox let accountPeerId = self.accountPeerId let auxiliaryMethods = self.auxiliaryMethods + let messagesRemovedContext = self.messagesRemovedContext let signal = postbox.stateView() |> mapToSignal { view -> Signal in @@ -1267,6 +1340,11 @@ public final class AccountStateManager { ignoreDate: true, skipVerification: false ) + + if let replayedState = replayedState, !replayedState.deletedMessageIds.isEmpty { + messagesRemovedContext.addIsMessagesDeletedInteractively(ids: replayedState.deletedMessageIds) + } + let deltaTime = CFAbsoluteTimeGetCurrent() - startTime if deltaTime > 1.0 { Logger.shared.log("State", "replayFinalState took \(deltaTime)s") @@ -1653,6 +1731,8 @@ public final class AccountStateManager { var updateConfigRequested: (() -> Void)? var isPremiumUpdated: (() -> Void)? + let messagesRemovedContext = MessagesRemovedContext() + init( accountPeerId: PeerId, accountManager: AccountManager, @@ -1671,6 +1751,8 @@ public final class AccountStateManager { self.network = network self.auxiliaryMethods = auxiliaryMethods + let messagesRemovedContext = self.messagesRemovedContext + var updateConfigRequestedImpl: (() -> Void)? var isPremiumUpdatedImpl: (() -> Void)? @@ -1691,7 +1773,8 @@ public final class AccountStateManager { }, isPremiumUpdated: { isPremiumUpdatedImpl?() - } + }, + messagesRemovedContext: messagesRemovedContext ) }) @@ -1848,6 +1931,10 @@ public final class AccountStateManager { return nil } } + + public func synchronouslyIsMessageDeletedInteractively(ids: [EngineMessage.Id]) -> [EngineMessage.Id] { + return self.messagesRemovedContext.synchronouslyIsMessageDeletedInteractively(ids: ids) + } } func resolveNotificationSettings(list: [TelegramPeerNotificationSettings], defaultSettings: MessageNotificationSettings) -> (sound: PeerMessageSound, notify: Bool, displayContents: Bool) { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 4b828008a2..58ef3e29a8 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -110,6 +110,14 @@ public extension TelegramEngine { } public func deleteMessagesInteractively(messageIds: [MessageId], type: InteractiveMessagesDeletionType, deleteAllInGroup: Bool = false) -> Signal { + self.account.stateManager.messagesRemovedContext.addIsMessagesDeletedInteractively(ids: messageIds.map { id -> DeletedMessageId in + if id.namespace == Namespaces.Message.Cloud && (id.peerId.namespace == Namespaces.Peer.CloudUser || id.peerId.namespace == Namespaces.Peer.CloudGroup) { + return .global(id.id) + } else { + return .messageId(id) + } + }) + return _internal_deleteMessagesInteractively(account: self.account, messageIds: messageIds, type: type, deleteAllInGroup: deleteAllInGroup) } @@ -1278,5 +1286,9 @@ public extension TelegramEngine { public func getStory(peerId: EnginePeer.Id, id: Int32) -> Signal { return _internal_getStoryById(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, peerId: peerId, id: id) } + + public func synchronouslyIsMessageDeletedInteractively(ids: [EngineMessage.Id]) -> [EngineMessage.Id] { + return account.stateManager.synchronouslyIsMessageDeletedInteractively(ids: ids) + } } } diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 599fb613ed..cba436a799 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -680,7 +680,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto private var toLang: String? private var allowDustEffect: Bool = true - private var allowDustEffectForAllMessages: Bool = true private var dustEffectLayer: DustEffectLayer? public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal), chatLocation: ChatLocation, chatLocationContextHolder: Atomic, tagMask: MessageTags?, source: ChatHistoryListSource, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal?, NoError>, mode: ChatHistoryListMode = .bubbles, messageTransitionNode: @escaping () -> ChatMessageTransitionNodeImpl?) { @@ -707,8 +706,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } } - self.allowDustEffectForAllMessages = context.sharedContext.immediateExperimentalUISettings.dustEffect - let presentationData = updatedPresentationData.initial self.currentPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: presentationData.theme, wallpaper: presentationData.chatWallpaper), fontSize: presentationData.chatFontSize, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: true, largeEmoji: presentationData.largeEmoji, chatBubbleCorners: presentationData.chatBubbleCorners, animatedEmojiScale: 1.0) @@ -3003,6 +3000,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto } } let currentTimestamp = Int32(CFAbsoluteTimeGetCurrent()) + var maybeRemovedInteractivelyMessageIds: [(UInt32, EngineMessage.Id)] = [] for entry in previousHistoryView.filteredEntries { switch entry { case let .MessageEntry(message, _, _, _, _, _): @@ -3013,9 +3011,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto expiredMessageStableIds.insert(message.stableId) } } else { - if self.allowDustEffectForAllMessages { - expiredMessageStableIds.insert(message.stableId) - } + maybeRemovedInteractivelyMessageIds.append((message.stableId, message.id)) } } case let .MessageGroupEntry(_, messages, _): @@ -3033,15 +3029,28 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto expiredMessageStableIds.insert(message.stableId) } } else { - if self.allowDustEffectForAllMessages { - expiredMessageStableIds.insert(message.stableId) - } + maybeRemovedInteractivelyMessageIds.append((message.stableId, message.id)) } } default: break } } + + var testIds: [MessageId] = [] + if !maybeRemovedInteractivelyMessageIds.isEmpty { + for (_, id) in maybeRemovedInteractivelyMessageIds { + testIds.append(id) + } + } + for id in self.context.engine.messages.synchronouslyIsMessageDeletedInteractively(ids: testIds) { + inner: for (stableId, listId) in maybeRemovedInteractivelyMessageIds { + if listId == id { + expiredMessageStableIds.insert(stableId) + break inner + } + } + } } self.currentDeleteAnimationCorrelationIds.formUnion(expiredMessageStableIds)