From 1371ba5d7777be0e575575e05bfef9ba1ccc3275 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 19 Jun 2026 21:06:20 +0000 Subject: [PATCH] fix: dedup emoji shortcodes in EmojiPackScreen to prevent LazyGrid crash An emoji pack can carry duplicate shortcodes: NIP-30 puts no uniqueness constraint on emoji tags, so foreign packs may repeat them and our own addEmoji appends without a duplicate guard. The grid keyed items on "${code}-${priv|pub}", so two same-code entries in the same visibility bucket produced identical keys (e.g. "kohakucho-pub") and crashed the LazyVerticalGrid with IllegalArgumentException. Collapse to one cell per (shortcode, visibility) with distinctBy when building the list. Beyond fixing the crash this is the correct UX: two cells with the same shortcode are indistinguishable and share one delete path (removeEmoji deletes by shortcode, dropping both). Dedup on code + visibility so a legit public/private pair of the same shortcode survives. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01346aiAXBbdg5hMTAGydTqp --- .../loggedIn/emojipacks/display/EmojiPackScreen.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt index 77aaacf039..19a8eec9d6 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/emojipacks/display/EmojiPackScreen.kt @@ -224,9 +224,19 @@ private fun EmojiGrid( pack: OwnedEmojiPack, onLongPress: (EmojiUrlTag, Boolean) -> Unit, ) { + // Collapse to one cell per (shortcode, visibility). A pack can carry + // duplicate shortcodes: NIP-30 puts no uniqueness constraint on emoji + // tags, so foreign packs may repeat them, and our own addEmoji appends + // without a duplicate guard. Two same-code cells in the same visibility + // bucket are indistinguishable to the user and share one delete path + // (removeEmoji deletes by shortcode, so it would drop both), and their + // identical keys would crash the LazyGrid. distinctBy keeps the first. + // Dedup on code + visibility so a legit public/private pair of the same + // shortcode (told apart by the lock badge, deleted separately) survives. val allEmojis = remember(pack) { - pack.publicEmojis.map { it to false } + pack.privateEmojis.map { it to true } + (pack.publicEmojis.map { it to false } + pack.privateEmojis.map { it to true }) + .distinctBy { (emoji, isPrivate) -> emoji.code to isPrivate } } LazyVerticalGrid(