feat(tui): wire Gallery screen to GalleryStorage #107

Merged
claude-desktop merged 2 commits from tui/gallery-wire-88 into main 2026-04-12 15:46:16 +00:00
Collaborator

Summary

  • Connect Gallery screen to GalleryStorage via AppCtx for loading, searching, sorting, favorite toggling, and deletion
  • Items load from SQLite on screen entry and on refresh (r); search (/) and sort (S) trigger reloads with proper filtering/ordering
  • Favorite toggle (*) persists immediately via toggle_favorite_batch; delete (dd chord / Delete key) removes items via delete_batch
  • Detail view renders images through AppCtx.render_image when a renderer is available
  • Grid/list views show favorite indicators and multi-select highlights; title bar shows item count, search query, and sort mode

Test plan

  • cargo clippy -p loom-tui -- -D warnings passes
  • cargo test -p loom-tui passes (120 tests, 7 new)
  • Manual: launch TUI with a populated gallery DB, verify items appear on Gallery screen
  • Manual: press /, type a query, press Enter — verify filtered results
  • Manual: press S multiple times — verify sort order cycles and items reorder
  • Manual: press * on an item — verify favorite indicator toggles
  • Manual: press dd on an item — verify deletion and reload
  • Manual: press r — verify items refresh from storage

Closes charles/loom#88

🤖 Generated with Claude Code

## Summary - Connect Gallery screen to `GalleryStorage` via `AppCtx` for loading, searching, sorting, favorite toggling, and deletion - Items load from SQLite on screen entry and on refresh (`r`); search (`/`) and sort (`S`) trigger reloads with proper filtering/ordering - Favorite toggle (`*`) persists immediately via `toggle_favorite_batch`; delete (`dd` chord / `Delete` key) removes items via `delete_batch` - Detail view renders images through `AppCtx.render_image` when a renderer is available - Grid/list views show favorite indicators and multi-select highlights; title bar shows item count, search query, and sort mode ## Test plan - [x] `cargo clippy -p loom-tui -- -D warnings` passes - [x] `cargo test -p loom-tui` passes (120 tests, 7 new) - [ ] Manual: launch TUI with a populated gallery DB, verify items appear on Gallery screen - [ ] Manual: press `/`, type a query, press Enter — verify filtered results - [ ] Manual: press `S` multiple times — verify sort order cycles and items reorder - [ ] Manual: press `*` on an item — verify favorite indicator toggles - [ ] Manual: press `dd` on an item — verify deletion and reload - [ ] Manual: press `r` — verify items refresh from storage Closes charles/loom#88 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Connect the Gallery screen to loom-core's GalleryStorage via AppCtx:
- Load items from SQLite on screen entry and on refresh (r key)
- Search (/) commits filter.search and reloads from storage
- Sort (S) cycles sort order and reloads with proper ORDER BY
- Favorite (*) toggles in-memory and persists via toggle_favorite_batch
- Delete (dd / Delete) removes items from storage with dd chord confirm
- Detail view renders images via AppCtx.render_image when available
- Grid/list views show favorite indicators and multi-select highlights
- Title bar shows item count, active search query, and sort mode

Closes charles/loom#88

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Author
Collaborator

Good integration. Lazy loading, search, sort, delete, favorite toggle, detail view with image rendering — all wired up.

Concern: dd delete has no undo

The dd chord deletes immediately from SQLite with no confirmation dialog and no undo. For a gallery app where images are the primary asset, this is risky. Consider either:

  • Using the confirm overlay from #42 (ctx.app.send(AppAction::PushOverlay(OverlayKind::Confirm(...))))
  • Or at minimum, moving deleted items to a trash/hidden state rather than hard-deleting

Concern: toggle_favorite holds mutex during DB write

if let Some(storage) = ctx.storage()
    && let Ok(guard) = storage.lock()
    && let Err(e) = guard.toggle_favorite_batch(&[id], new_val)

This is fine for a single toggle, but the lock is std::sync::Mutex shared across screens. If another screen is doing a long DB operation (e.g. gallery list with many items), this could contend. Low risk in practice.

Minor

  • render_detail calls ctx.render_image(...) which acquires the renderer mutex during the render pass. If the image decode is slow (first render of a large file), the frame will lag. Consider caching the decoded image or rendering asynchronously.
  • Title bar shows self.items.len() — this is the filtered count after search, not total. Consider showing "N of M items" when a search filter is active.
  • Multi-select Space toggle + dd delete interaction: if items are multi-selected, dd deletes all selected items. This is the right behavior but not discoverable. The hint row should mention it.

Good test coverage, including the pending_d reset logic.

## Review — PR #107: Gallery screen wired to GalleryStorage **Good integration.** Lazy loading, search, sort, delete, favorite toggle, detail view with image rendering — all wired up. ### Concern: `dd` delete has no undo The `dd` chord deletes immediately from SQLite with no confirmation dialog and no undo. For a gallery app where images are the primary asset, this is risky. Consider either: - Using the confirm overlay from #42 (`ctx.app.send(AppAction::PushOverlay(OverlayKind::Confirm(...)))`) - Or at minimum, moving deleted items to a trash/hidden state rather than hard-deleting ### Concern: `toggle_favorite` holds mutex during DB write ```rust if let Some(storage) = ctx.storage() && let Ok(guard) = storage.lock() && let Err(e) = guard.toggle_favorite_batch(&[id], new_val) ``` This is fine for a single toggle, but the lock is `std::sync::Mutex` shared across screens. If another screen is doing a long DB operation (e.g. gallery list with many items), this could contend. Low risk in practice. ### Minor - `render_detail` calls `ctx.render_image(...)` which acquires the renderer mutex during the render pass. If the image decode is slow (first render of a large file), the frame will lag. Consider caching the decoded image or rendering asynchronously. - Title bar shows `self.items.len()` — this is the filtered count after search, not total. Consider showing "N of M items" when a search filter is active. - Multi-select `Space` toggle + `dd` delete interaction: if items are multi-selected, `dd` deletes all selected items. This is the right behavior but not discoverable. The hint row should mention it. Good test coverage, including the `pending_d` reset logic.
charles force-pushed tui/gallery-wire-88 from 15bb8ef0d7 to bd2cb9315d 2026-04-12 14:47:53 +00:00 Compare
claude-desktop changed target branch from tui/image-ctx-85 to main 2026-04-12 15:36:28 +00:00
charles force-pushed tui/gallery-wire-88 from bd2cb9315d to d920790594
Some checks failed
QA / qa (pull_request) Has been cancelled
2026-04-12 15:46:12 +00:00
Compare
claude-desktop deleted branch tui/gallery-wire-88 2026-04-12 15:46:16 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/loom!107
No description provided.