implemented dynamic quick reactions by surfacing emojis from message content in the chat options dialog

This commit is contained in:
2026-07-12 16:42:30 +02:00
parent 59501d3b45
commit 3f44e9302f
3 changed files with 133 additions and 12 deletions
+31 -1
View File
@@ -10,6 +10,8 @@ const int _zwj = 0x200D;
const int _vs15 = 0xFE0E;
const int _vs16 = 0xFE0F;
const int _keycap = 0x20E3;
const int _skinToneStart = 0x1F3FB;
const int _skinToneEnd = 0x1F3FF;
/// Codepoints that only ever glue an emoji sequence together and never stand
/// on their own — they don't disqualify a cluster from counting as emoji.
@@ -18,7 +20,7 @@ bool _isModifier(int r) =>
r == _vs15 ||
r == _vs16 ||
r == _keycap ||
(r >= 0x1F3FB && r <= 0x1F3FF) || // skin-tone modifiers
(r >= _skinToneStart && r <= _skinToneEnd) || // skin-tone modifiers
(r >= 0xE0020 && r <= 0xE007F); // tag characters (flag sequences)
/// The digits, `#` and `*` that become emoji only when combined with the
@@ -84,3 +86,31 @@ double? standaloneEmojiFontSize(String text) {
if (count == 0) return null;
return 34;
}
/// [emoji] with any Fitzpatrick skin-tone modifier stripped, so tone variants
/// of the same emoji compare equal (👍🏻 → 👍). Used to dedupe reactions that
/// only differ in skin tone.
String emojiSkinToneNeutral(String emoji) => String.fromCharCodes(
emoji.runes.where((r) => r < _skinToneStart || r > _skinToneEnd),
);
/// Distinct emojis contained in [text], most-frequent first with ties broken
/// by first appearance. Used to offer a message's own emojis as quick
/// reactions.
List<String> extractEmojis(String text) {
final counts = <String, int>{};
final firstSeen = <String, int>{};
var order = 0;
for (final cluster in text.characters) {
if (!_isEmojiCluster(cluster)) continue;
counts.update(cluster, (value) => value + 1, ifAbsent: () => 1);
firstSeen.putIfAbsent(cluster, () => order++);
}
final emojis = counts.keys.toList();
emojis.sort((a, b) {
final byCount = counts[b]!.compareTo(counts[a]!);
return byCount != 0 ? byCount : firstSeen[a]!.compareTo(firstSeen[b]!);
});
return emojis;
}