Files
amethyst/desktopApp/plans/2026-08-18-chat-composer-enrichment-manual-testing.md
nrobi144andClaude Opus 4.8 84a031b931 feat(desktop): enrich the DM chat composer + message UX
Brings the desktop DM experience up to par with a modern chat client,
reusing existing commons/quartz infrastructure throughout.

Composer:
- Emoji picker (org.kodein.emoji, MIT) with search; unicode + NIP-30
  custom-emoji ":shortcode:" autocomplete in one strip
- @mention autocomplete (avatar + display name) inserting nostr:npub
- Reply-quoting: composer bar + a quoted chip on reply bubbles that taps
  to scroll-and-highlight the original (bounce + flash)
- Per-message image quality selector; send-in-progress spinner

Rendering:
- DM bubbles render rich text (mentions resolve to names; image/GIF/
  custom-emoji inline) instead of raw text

GIF search (Nostr-native, no third-party API):
- Query NIP-94 kind-1063 GIF metadata from a configurable relay list
  (nos.lol + relay.damus.io), dedup + client-side filter, animated preview

Uploads / privacy:
- Encrypted DM files upload as opaque application/octet-stream by default
  so the media server can't learn the media type; optional "Reveal media
  type" toggle for strict servers. Only reencode jpg/png/webp; GIF/video/
  AVIF/HEIC pass through. Actionable errors for servers that reject
  private uploads
- Reply/glyph: add a real Reply icon to the Material Symbols subset

Robustness:
- Preserve Messages state (selected room, draft, attachments) across the
  device lock by hoisting it above the lock gate
- Thread the send so the composer always clears and errors surface

Adds unit tests for the GIF merge/filter and caret insertion.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-19 10:59:21 +03:00

3.4 KiB

Desktop Chat Composer Enrichment — Manual Testing Sheet

Branch: feat/desktop-chat-composer-enrichment Run: ./gradlew :desktopApp:run, log in with an account that has NIP-17 DMs, open Messages, select a conversation.

Legend: ☐ untested · ✅ pass · ❌ fail (note issue)

P0 — TextFieldValue composer (foundation)

  • ☐ Type text; move the caret with arrow keys/click mid-word — cursor position holds.
  • ☐ Cmd/Ctrl+Enter sends; Enter alone inserts a newline.

P1 — Reply-quoting

  • ☐ Hover a message → quote (❝) icon appears; click it → a reply bar shows the quoted author + snippet above the input.
  • ☐ Send → recipient sees a threaded reply (reply marker present).
  • ☐ Click the ✕ on the reply bar → reply target cleared; next send is a normal message.
  • ☐ Reply, then send → reply bar auto-clears after send.

P2 — Emoji picker

  • ☐ Click the 🙂 (EmojiEmotions) button → grid opens.
  • ☐ Search "fire" → grid filters; click 🔥 → inserted at the caret (not appended blindly).
  • ☐ Insert an emoji mid-word → lands at the cursor, text splits correctly.
  • ☐ Works offline (disable network) — emojis still render via system font.

P3 — NIP-30 custom emoji

  • ☐ (Requires an emoji pack selected on the account.) Type : + a prefix → suggestion strip shows matching pack emojis with images.
  • ☐ Click one → :shortcode: inserted at the caret.
  • ☐ Send → recipient renders the custom emoji (event carries emoji tags).
  • ☐ No pack selected → no strip appears, no errors.

P4 — @mention

  • ☐ Type @ + a name prefix → dropdown of matching cached users.
  • ☐ Click one → nostr:npub… inserted (with trailing space); dropdown closes.
  • ☐ Recipient/link resolves to the mentioned profile.
  • ☐ #hashtag — typing #tag still tags the note on send (no dropdown; deferred — no hashtag index).

P5 — Per-message image quality

  • ☐ Attach a JPEG/PNG → a "Quality:" chip appears above the input.
  • ☐ Send at Low vs Uncompressed → recipient's received file is visibly smaller at Low (check dimensions/size).
  • ☐ Attach an animated GIF → sends animated (byte-identical pass-through), quality chip hidden for GIF-only.
  • ☐ Quality override resets to the default after each send.
  • ☐ EXIF: a photo with GPS EXIF sent at pass-through has EXIF stripped (desktop opts in).
  • ☐ Click GIF → panel opens, loads recent GIFs from relay.gifbuddy.lol.
  • ☐ Search "cat" → grid updates (debounced ~350ms).
  • ☐ Click a GIF → its URL inserted into the message; send → renders inline/animated for the recipient.
  • ☐ Add a second relay via DesktopPreferences.gifRelays → results merge, deduped by URL.
  • ☐ Point at an unreachable relay → panel degrades to empty/"No GIFs found", no crash, composer still usable.

Cross-feature integration

  1. ☐ One message mixing a unicode emoji + :customshortcode: + @mention + #tag → sends; recipient renders all; event carries emoji, p, t tags.
  2. ☐ Reply to a message and send → reply preserved; clear() resets the whole composer.
  3. ☐ Switch rooms mid-typing (with an open suggestion) → no stale dropdown / no cross-room leakage.
  4. ☐ Compact (narrow) and split (wide) layouts both wire the composer correctly.

Regression

  • ☐ Plain-text send still works.
  • ☐ File attach + drag-and-drop still work.
  • ☐ Quick-reaction bar on messages still works.