TM-SGNL-iOS/Signal/ConversationView/Reactions/InteractionReactionState.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

85 lines
3.1 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Copyright 2019 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
public import SignalServiceKit
public class InteractionReactionState: NSObject {
var hasReactions: Bool { return !emojiCounts.isEmpty }
struct EmojiCount {
let emoji: String
let count: Int
let highestSortOrder: UInt64
}
let reactionsByEmoji: [Emoji: [OWSReaction]]
let emojiCounts: [EmojiCount]
let localUserEmoji: String?
init?(interaction: TSInteraction, transaction: SDSAnyReadTransaction) {
// No reactions on non-message interactions
guard let message = interaction as? TSMessage else { return nil }
guard let localAddress = DependenciesBridge.shared.tsAccountManager.localIdentifiers(tx: transaction.asV2Read)?.aciAddress else {
owsFailDebug("missing local address")
return nil
}
let finder = ReactionFinder(uniqueMessageId: message.uniqueId)
let allReactions = finder.allReactions(transaction: transaction.unwrapGrdbRead)
let localUserReaction = allReactions.first(where: { $0.reactor == localAddress })
reactionsByEmoji = allReactions.reduce(
into: [Emoji: [OWSReaction]]()
) { result, reaction in
guard let emoji = Emoji(reaction.emoji) else {
return owsFailDebug("Skipping reaction with [unknown emoji]")
}
var reactions = result[emoji] ?? []
reactions.append(reaction)
result[emoji] = reactions
}
emojiCounts = reactionsByEmoji.values.compactMap { reactions in
guard let mostRecentReaction = reactions.first else {
owsFailDebug("unexpectedly missing reactions")
return nil
}
let mostRecentEmoji = mostRecentReaction.emoji
// We show your own skintone (if youve reacted), or the most
// recent skintone (if you havent reacted).
let emojiToRender: String
if let localUserReaction = localUserReaction, reactions.contains(localUserReaction) {
emojiToRender = localUserReaction.emoji
} else {
emojiToRender = mostRecentEmoji
}
let highestSortOrder =
(reactions.map { $0.sortOrder }.max() ?? mostRecentReaction.sortOrder)
return EmojiCount(
emoji: emojiToRender,
count: reactions.count,
highestSortOrder: highestSortOrder
)
}.sorted { (lhs: EmojiCount, rhs: EmojiCount) in
if lhs.count != rhs.count {
// Sort more common reactions (higher counter) first.
return lhs.count > rhs.count
} else if lhs.highestSortOrder != rhs.highestSortOrder {
// Sort reactions received in descending order of when we received them.
return lhs.highestSortOrder > rhs.highestSortOrder
} else {
// Ensure stability of sort by comparing emoji.
return lhs.emoji > rhs.emoji
}
}
localUserEmoji = localUserReaction?.emoji
}
}