mirror of
https://github.com/block/buzz.git
synced 2026-11-13 21:01:53 +00:00
## Context A reaction slot should never show an emoji shortcode as text. Today it does in two cases: - An agent's reaction is a kind 7 event with content `:shortcode:` and no NIP-30 `emoji` tag, so the pill printed `:approve:` in tiny text instead of the community emoji. - A custom emoji whose image fails to load fell back to the shortcode text. ## Behavior - A tagless `:shortcode:` reaction resolves against the community custom-emoji palette and renders that image. An `emoji` tag on the event still wins. - A shortcode with no palette entry, or whose image fails to load, shows a neutral placeholder glyph (the muted sparkles icon) instead of text. The shortcode survives only as the semantics label. - This applies to every reaction slot: the timeline pills, the combined reaction tray, the Flutter reaction detail sheet, and the native iOS reactions sheet (which is told which shortcodes have no image, so `NativeMessageGlyph` draws the placeholder). System-message rows reuse the same reaction row. - Unicode emoji are unchanged. The icon is the existing `BuzzIcons.sparkles`. Pareto note: the palette lookup is the shared `reactionEmojiUrl` helper, so there is no new resolver, and the pill only watches the palette when the reaction has no tag. ### Validation - `just mobile-check mobile-test`: format and analyze clean; full suite passes (4773 passed, 74 skipped). - New widget tests (journeys, in `reaction_row_test/shortcode_tests.dart`): a tagless known shortcode renders its image; an unknown shortcode and a failed image render the placeholder and never the text; unicode is unchanged; the native sheet payload marks image-less shortcodes. Reverting the fix makes both new journeys fail. - iOS: added a Swift unit test for the native glyph placeholder (`NativeMessageImageLoaderTests`); not run locally, the app run below exercises the same code. - Automated app run on a cloned iOS simulator with a fixture entry point (mocked media, synthetic palette): confirmed the pills before and after, and opened the reaction sheet from a long-press to confirm the placeholder renders there too. The clone was deleted afterwards. ## Before / after Captures use synthetic shortcodes and a synthetic palette. <img width="300" alt="reaction-pills-before" src="https://raw.githubusercontent.com/block/buzz/75b22a00d92df2db389ef90d35d476b285b60374/pr-9411--reaction-pills-before.png"> <img width="300" alt="reaction-pills-after" src="https://raw.githubusercontent.com/block/buzz/75b22a00d92df2db389ef90d35d476b285b60374/pr-9411--reaction-pills-after.png"> Reaction sheet after: <img width="300" alt="reaction-sheet-after" src="https://raw.githubusercontent.com/block/buzz/75b22a00d92df2db389ef90d35d476b285b60374/pr-9411--reaction-sheet-after.png"> 🤖 Generated with [Claude Code](https://claude.com/claude-code) Signed-off-by: Tom Brow <tomb@squareup.com> Co-authored-by: Tom Brow <tomb@squareup.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: studio <dc2fc481343672df31a689840c09299972e704dac592e0da6f18486646a7ee3e@buzz.block.builderlab.xyz>