Root cause of padlock: all images in E2EE rooms have content.file so the
gallery skipped thumbnails for all of them. Fix:
- useDecryptedMediaUrl hook: downloads + decrypts encrypted media using
downloadEncryptedMedia/decryptFile, creates a blob URL, revokes on
unmount. For unencrypted media returns the HTTP URL directly.
- GalleryTile: prefers content.info.thumbnail_file (smaller encrypted
thumb) over content.file; falls back gracefully. Shows spinner while
decrypting, broken-image icon on error. Hover overlay shows sender
name + relative date with a gradient.
- Lightbox: full-screen overlay with ← → keyboard/button navigation,
filename/sender/date header, image counter. Full-res decryption done
in LightboxImage (separate component per item so keys reset the hook).
- File list: shows sender name + file size (formatted KB/MB).
- Empty states: distinct messages for "nothing in recent events" vs
"nothing found after loading more". "Beginning of history" shown when
pagination exhausts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Suppress Ctrl+P browser print dialog via SuppressPrintShortcut in
ClientNonUIFeatures (no UI opened, just preventDefault)
- mxcUrlToHttp: build URL manually instead of delegating to SDK.
The SDK forces allow_redirect=true when useAuthentication=true;
Synapse's /_matrix/client/v1/media/thumbnail rejects that with 400.
Manual construction omits allow_redirect entirely.
- Gallery: redesign using folds color tokens (color.Surface.*) instead
of non-existent CSS custom properties; add ThumbState so broken
images show an icon placeholder; use useAuthentication for thumbnails
now that the URL builder is fixed; "Load More" always visible.
- PollCreator: replace raw <button> with folds Button components so the
Single/Multiple choice toggle renders with actual visual difference.
- PollContent: support multiple-choice polls end-to-end —
myVote:string → myVotes:Set<string>; computeVotes collects all
m.selections (not just [0]); toggle-select for multi, radio for
single; checkbox/radio indicator icons next to each option;
"◉ Poll · Multiple choice" / "Single choice" label in header;
sends full selections array on every vote event.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Use useAuthentication=false for thumbnail requests: the v1 authenticated
URL adds allow_redirect=true which Synapse rejects with 400
- Encrypted events (content.file set) show a lock+filename placeholder
since server can't thumbnail encrypted blobs
- Unencrypted thumbnails add onError handler to hide broken images gracefully
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MediaGallery: switch from createMessagesRequest (returns raw encrypted
events) to room.getLiveTimeline().getEvents() which gives already-
decrypted MatrixEvent objects. Load More uses paginateEventTimeline().
- QuickSwitcher: change hotkey from Ctrl+K to Ctrl+P to avoid conflict
with the existing SearchModalRenderer mod+k handler
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>