feat(chat): full-screen image viewer (issue #723) (#729)

* feat(chat): full-screen image viewer (issue #723)

Tap any chat image (markdown ![alt](url), inline attachment thumbnail,
or bubble image) to open a full-screen viewer:
- pinch-zoom + pan via native detectTransformGestures
- downswipe-to-dismiss at min zoom
- Save -> device Downloads (MediaStore), Share -> Android share sheet
  (both fully device-local; never sent back to the Hermes server)

Plumbing: onImageClick(ImageViewerModel) flows MarkdownText ->
ChatBubble/InlineAttachment -> ChatMessageList -> ChatScreen (state +
ImageViewerDialog). ImageBytesResolver reuses the existing authed
OkHttpProvider path for gateway http(s) sources; data:/content://
handled locally. No new dependencies.

Closes #723

* fix(chat): resolve strings at composable scope to satisfy LocalContextGetResourceValueCall lint

Lint forbids reading resource *values* from LocalContext.current inside
coroutine lambdas. Hoist all viewer strings via stringResource() at
composable scope and reuse them in onSave/onShare.

---------

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-07-27 15:21:19 +03:00
1 parent a1155e8015
commit f45a68b0db
11 files changed
+651 -4

No files matched your search

+11
View File
@@ -863,4 +863,15 @@
<string name="analytics_tool_uses">%1$d calls \u2022 %2$d%% of total</string>
<string name="processes_kill_confirm">Kill</string>
<string name="processes_kill_cd">Kill process</string>
<!-- Image viewer (issue #723) -->
<string name="image_viewer_content_desc">Chat image</string>
<string name="image_viewer_close">Close</string>
<string name="image_viewer_save">Save to device</string>
<string name="image_viewer_share">Share</string>
<string name="image_viewer_share_title">Share image</string>
<string name="image_viewer_saved">Image saved to Downloads</string>
<string name="image_viewer_save_failed">Could not save image</string>
<string name="image_viewer_load_failed">Could not load image: %1$s</string>
<string name="image_viewer_share_failed">Could not share image</string>
</resources>