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
@@ -687,4 +687,15 @@
<string name="analytics_tool_uses">%1$d회 호출 • 전체의 %2$d%%</string>
<string name="processes_kill_confirm">종료</string>
<string name="processes_kill_cd">프로세스 종료</string>
<!-- Image viewer (issue #723) -->
<string name="image_viewer_content_desc">채팅 이미지</string>
<string name="image_viewer_close">닫기</string>
<string name="image_viewer_save">기기에 저장</string>
<string name="image_viewer_share">공유</string>
<string name="image_viewer_share_title">이미지 공유</string>
<string name="image_viewer_saved">다운로드에 이미지 저장됨</string>
<string name="image_viewer_save_failed">이미지를 저장할 수 없음</string>
<string name="image_viewer_load_failed">이미지를 불러올 수 없음: %1$s</string>
<string name="image_viewer_share_failed">이미지를 공유할 수 없음</string>
</resources>