From 06a0031bdd250ffbacabecc89fec5c17e7d31b85 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Wed, 29 Apr 2026 18:22:42 +0200 Subject: [PATCH] Various improvements --- .../Messages/DeleteMessages.swift | 88 ++++++++++++++++++- .../Messages/TelegramEngineMessages.swift | 4 +- .../Sources/ChatControllerAdminBanUsers.swift | 3 +- 3 files changed, 90 insertions(+), 5 deletions(-) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift index 5c3f072d76..84878e8508 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/DeleteMessages.swift @@ -76,9 +76,93 @@ func _internal_deleteAllMessagesWithForwardAuthor(transaction: Transaction, medi } } -func _internal_deleteAllReactionsWithAuthor(account: Account, peerId: PeerId, authorId: PeerId) -> Signal { +func _internal_deleteAllReactionsWithAuthor(account: Account, peerId: PeerId, authorId: PeerId, aroundMessageId: MessageId?) -> Signal { return account.postbox.transaction { transaction -> (Peer?, Peer?) in - return (transaction.getPeer(peerId), transaction.getPeer(authorId)) + let peer = transaction.getPeer(peerId) + let author = transaction.getPeer(authorId) + + if peer.flatMap(apiInputPeer) != nil && author.flatMap(apiInputPeer) != nil { + let anchor: HistoryViewInputAnchor + if let aroundMessageId, aroundMessageId.peerId == peerId { + anchor = .message(aroundMessageId) + } else { + anchor = .upperBound + } + let historyView = transaction.getMessagesHistoryViewState(input: .single(peerId: peerId, threadId: nil), ignoreMessagesInTimestampRange: nil, ignoreMessageIds: Set(), count: 50, clipHoles: true, anchor: anchor, namespaces: .just(Set([Namespaces.Message.Cloud]))) + for entry in historyView.entries { + transaction.updateMessage(entry.message.id, update: { currentMessage in + var attributes = currentMessage.attributes + var updated = false + + for i in 0 ..< attributes.count { + guard let attribute = attributes[i] as? ReactionsMessageAttribute else { + continue + } + + let removedRecentPeers = attribute.recentPeers.filter { $0.peerId == authorId } + var updatedTopPeers = attribute.topPeers + var removedStarsTopPeerCount: Int32 = 0 + for j in (0 ..< updatedTopPeers.count).reversed() { + if updatedTopPeers[j].peerId == authorId { + removedStarsTopPeerCount += updatedTopPeers[j].count + updatedTopPeers.remove(at: j) + } + } + + if removedRecentPeers.isEmpty && removedStarsTopPeerCount == 0 { + continue + } + + var updatedReactions = attribute.reactions + for removedRecentPeer in removedRecentPeers { + if let index = updatedReactions.firstIndex(where: { $0.value == removedRecentPeer.value }) { + if removedRecentPeer.value != .stars || removedStarsTopPeerCount == 0 { + updatedReactions[index].count -= 1 + } + if removedRecentPeer.isMy { + updatedReactions[index].chosenOrder = nil + } + } + } + if removedStarsTopPeerCount != 0, let index = updatedReactions.firstIndex(where: { $0.value == .stars }) { + updatedReactions[index].count -= removedStarsTopPeerCount + } + for j in (0 ..< updatedReactions.count).reversed() { + if updatedReactions[j].count <= 0 { + updatedReactions.remove(at: j) + } + } + + let updatedRecentPeers = attribute.recentPeers.filter { $0.peerId != authorId } + let updatedAttribute = ReactionsMessageAttribute(canViewList: attribute.canViewList, isTags: attribute.isTags, reactions: updatedReactions, recentPeers: updatedRecentPeers, topPeers: updatedTopPeers) + if updatedAttribute != attribute { + attributes[i] = updatedAttribute + updated = true + } + } + + if !updated { + return .skip + } + + var storeForwardInfo: StoreMessageForwardInfo? + if let forwardInfo = currentMessage.forwardInfo { + storeForwardInfo = StoreMessageForwardInfo(authorId: forwardInfo.author?.id, sourceId: forwardInfo.source?.id, sourceMessageId: forwardInfo.sourceMessageId, date: forwardInfo.date, authorSignature: forwardInfo.authorSignature, psaType: forwardInfo.psaType, flags: forwardInfo.flags) + } + + var tags = currentMessage.tags + if attributes.contains(where: { ($0 as? ReactionsMessageAttribute)?.hasUnseen == true }) { + tags.insert(.unseenReaction) + } else { + tags.remove(.unseenReaction) + } + + return .update(StoreMessage(id: currentMessage.id, customStableId: nil, globallyUniqueId: currentMessage.globallyUniqueId, groupingKey: currentMessage.groupingKey, threadId: currentMessage.threadId, timestamp: currentMessage.timestamp, flags: StoreMessageFlags(currentMessage.flags), tags: tags, globalTags: currentMessage.globalTags, localTags: currentMessage.localTags, forwardInfo: storeForwardInfo, authorId: currentMessage.author?.id, text: currentMessage.text, attributes: attributes, media: currentMessage.media)) + }) + } + } + + return (peer, author) } |> mapToSignal { peer, author in guard let inputPeer = peer.flatMap(apiInputPeer), let inputAuthor = author.flatMap(apiInputPeer) else { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index 81d51ae255..553cf4a3b9 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -170,8 +170,8 @@ public extension TelegramEngine { |> ignoreValues } - public func deleteAllReactionsWithAuthor(peerId: EnginePeer.Id, authorId: EnginePeer.Id) -> Signal { - return _internal_deleteAllReactionsWithAuthor(account: self.account, peerId: peerId, authorId: authorId) + public func deleteAllReactionsWithAuthor(peerId: EnginePeer.Id, authorId: EnginePeer.Id, aroundMessageId: EngineMessage.Id? = nil) -> Signal { + return _internal_deleteAllReactionsWithAuthor(account: self.account, peerId: peerId, authorId: authorId, aroundMessageId: aroundMessageId) } public func deleteReaction(messageId: EngineMessage.Id, authorId: EnginePeer.Id) -> Signal { diff --git a/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift b/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift index 8042d75db9..28e3fc0de9 100644 --- a/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift +++ b/submodules/TelegramUI/Sources/ChatControllerAdminBanUsers.swift @@ -85,8 +85,9 @@ extension ChatControllerImpl { let _ = self.context.engine.messages.clearAuthorHistory(peerId: messagesPeerId, memberId: authorId).startStandalone() } + let aroundMessageId = messageIds.count == 1 ? messageIds.first : nil for authorId in result.deleteAllReactionsFromPeers { - let _ = self.context.engine.messages.deleteAllReactionsWithAuthor(peerId: messagesPeerId, authorId: authorId).startStandalone() + let _ = self.context.engine.messages.deleteAllReactionsWithAuthor(peerId: messagesPeerId, authorId: authorId, aroundMessageId: aroundMessageId).startStandalone() } for authorId in result.reportSpamPeers {