Signal-iOS/Signal/src/ViewControllers/ConversationView/InteractionReactionState.swift
2021-04-29 10:25:11 -03:00

86 lines
3.2 KiB
Swift
Raw 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 (c) 2021 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc
public class InteractionReactionState: NSObject {
@objc
var hasReactions: Bool { return !emojiCounts.isEmpty }
struct EmojiCount {
let emoji: String
let count: Int
let lastReceivedAtTimestamp: UInt64
}
let reactionsByEmoji: [Emoji: [OWSReaction]]
let emojiCounts: [EmojiCount]
let localUserEmoji: String?
@objc
init?(interaction: TSInteraction, transaction: SDSAnyReadTransaction) {
// No reactions on non-message interactions
guard let message = interaction as? TSMessage else { return nil }
guard let localAddress = TSAccountManager.shared.localAddress else {
owsFailDebug("missing local address")
return nil
}
let finder = ReactionFinder(uniqueMessageId: message.uniqueId)
let allReactions = finder.allReactions(transaction: transaction.unwrapGrdbRead)
let localUserReaction = finder.reaction(for: localAddress, transaction: transaction.unwrapGrdbRead)
reactionsByEmoji = allReactions.reduce(
into: [Emoji: [OWSReaction]]()
) { result, reaction in
guard let emoji = Emoji(reaction.emoji) else {
return owsFailDebug("Skipping reaction with unknown emoji \(reaction.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 lastReceivedAtTimestamp = (reactions.map { $0.receivedAtTimestamp }.max()
?? mostRecentReaction.receivedAtTimestamp)
return EmojiCount(emoji: emojiToRender,
count: reactions.count,
lastReceivedAtTimestamp: lastReceivedAtTimestamp)
}.sorted { (left: EmojiCount, right: EmojiCount) in
if left.count != right.count {
// Sort more common reactions (higher counter) first.
return left.count > right.count
} else if left.lastReceivedAtTimestamp != right.lastReceivedAtTimestamp {
// Sort reactions received in descending order of when we received them.
return left.lastReceivedAtTimestamp > right.lastReceivedAtTimestamp
} else {
// Ensure stability of sort by comparing emoji.
return left.emoji > right.emoji
}
}
localUserEmoji = localUserReaction?.emoji
}
}