feat(tui): mid-size batch — model detail, tagging, filter, entity AI/LoRA, keybinds view #148

Merged
charles merged 6 commits from tui/mid-size-batch into main 2026-04-15 13:48:59 +00:00
Collaborator

Six mid-size features from the GTK↔TUI parity audit.

Commits

Commit Issue Title
aa47fd7 #134 model browser detail overlay (carousel + metadata)
a08018b #135 gallery tagging via TagEditor overlay
9ea00a7 #137 gallery filter overlay (tags / model / lora / nsfw / favorites)
8da16bb #133 entities — Ctrl+D describe, Ctrl+F face detect
6f4e4cc #139 per-entity LoRA association
0ad3dac #146 settings — KeyBindings section shows live key map

Highlights

Model browser

  • Enter opens a centered overlay with carousel of preview_urls, description, base model, author, ratings, downloads, file size, NSFW + installed badges
  • i now installs (was Enter)
  • Async per-image download with per-URL hashed cache
  • t opens a tag editor — list/add/remove with ↑↓ x Enter Ctrl+S
  • F opens a unified filter overlay covering NSFW / favorites / tags (csv) / model name / LoRA name
  • Active filters render as chips in the gallery title

Entities

  • Ctrl+D dispatches bridge.describe_entity_from_image; result replaces prompt_natural
  • Ctrl+F dispatches bridge.detect_face_region; rect persisted on screen
  • l opens the LoRA picker scoped to the focused entity (reuses LoraPickerOverlay with target_entity_id)
  • Entity Detail shows attached LoRAs in a dedicated section with strength

Settings

  • KeyBindings section now renders the actual live KeyMap (was a placeholder pointing to tui.toml)
  • New AppCtx::key_map: Arc<KeyMap> exposes the map to screens

Test plan

  • Model browser Enter shows the detail overlay; ←/→ cycles previews
  • Gallery t adds a tag; gallery refreshes after save
  • Gallery F toggles NSFW/favorites and applies tag/model filters
  • Entities Ctrl+D triggers describe; Ctrl+F triggers face detect
  • Entities l opens picker; selecting a LoRA persists on the entity
  • Settings → Key Bindings shows all global bindings
  • All cargo test pass

Closes charles/loom#134
Closes charles/loom#135 (manual editor; AI auto-tag follow-up)
Closes charles/loom#137 (single-screen filter)
Closes charles/loom#133 (Confirm-on-overwrite + face overlay rendering follow-up)
Closes charles/loom#139 (strength adjust/remove keys follow-up)
Closes charles/loom#146 (read-only view; interactive rebind follow-up)

🤖 Generated with Claude Code

Six mid-size features from the GTK↔TUI parity audit. ## Commits | Commit | Issue | Title | |---|---|---| | `aa47fd7` | #134 | model browser detail overlay (carousel + metadata) | | `a08018b` | #135 | gallery tagging via TagEditor overlay | | `9ea00a7` | #137 | gallery filter overlay (tags / model / lora / nsfw / favorites) | | `8da16bb` | #133 | entities — Ctrl+D describe, Ctrl+F face detect | | `6f4e4cc` | #139 | per-entity LoRA association | | `0ad3dac` | #146 | settings — KeyBindings section shows live key map | ## Highlights ### Model browser - **Enter** opens a centered overlay with carousel of `preview_urls`, description, base model, author, ratings, downloads, file size, NSFW + installed badges - **i** now installs (was Enter) - Async per-image download with per-URL hashed cache ### Gallery - **t** opens a tag editor — list/add/remove with `↑↓ x Enter Ctrl+S` - **F** opens a unified filter overlay covering NSFW / favorites / tags (csv) / model name / LoRA name - Active filters render as chips in the gallery title ### Entities - **Ctrl+D** dispatches `bridge.describe_entity_from_image`; result replaces `prompt_natural` - **Ctrl+F** dispatches `bridge.detect_face_region`; rect persisted on screen - **l** opens the LoRA picker scoped to the focused entity (reuses `LoraPickerOverlay` with `target_entity_id`) - Entity Detail shows attached LoRAs in a dedicated section with strength ### Settings - **KeyBindings** section now renders the actual live `KeyMap` (was a placeholder pointing to tui.toml) - New `AppCtx::key_map: Arc<KeyMap>` exposes the map to screens ## Test plan - [ ] Model browser Enter shows the detail overlay; ←/→ cycles previews - [ ] Gallery `t` adds a tag; gallery refreshes after save - [ ] Gallery `F` toggles NSFW/favorites and applies tag/model filters - [ ] Entities Ctrl+D triggers describe; Ctrl+F triggers face detect - [ ] Entities `l` opens picker; selecting a LoRA persists on the entity - [ ] Settings → Key Bindings shows all global bindings - [ ] All `cargo test` pass Closes charles/loom#134 Closes charles/loom#135 (manual editor; AI auto-tag follow-up) Closes charles/loom#137 (single-screen filter) Closes charles/loom#133 (Confirm-on-overwrite + face overlay rendering follow-up) Closes charles/loom#139 (strength adjust/remove keys follow-up) Closes charles/loom#146 (read-only view; interactive rebind follow-up) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
``Enter`` on a search result now opens a centered overlay with the
model's full metadata; ``i`` on the result list installs (was Enter).

ResultCard gains the fields needed to render the detail view —
``preview_urls`` (carousel), ``description``, ``base_model``,
``trigger_words``, ``author``, ``file_size_kb``, ``nsfw``, ``tags``
— populated from ``LuaModelInfo`` / ``LuaLoraInfo``.

New ``OverlayKind::ModelDetail(Box<ResultCard>)`` and
``ModelDetailOverlay`` render:

- Header line: kind · base_model · author · ★ rating · ⬇ downloads ·
  file size · NSFW / installed badges
- Carousel (50% height) with ``←/→`` cycling preview_urls; per-image
  async download to ``~/.cache/loom/thumbs/`` (URL-hashed filename)
- Lower panel: trigger words, tags, description (first 20 lines)
- Hint row: `←/→ carousel · Esc close`

Closes charles/loom#134

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
``t`` on a gallery item opens a modal overlay with the item's existing
tags and an input row for adding new ones.

- ``↑/↓`` navigates between tags + the input row
- ``Enter`` on input adds the typed tag (case-insensitive dedup)
- ``Enter`` on a tag saves and closes
- ``x`` / ``Delete`` on a focused tag removes it
- ``Ctrl+S`` saves at any time; ``Esc`` cancels

New ``OverlayKind::TagEditor`` and ``AppAction::SetItemTags`` —
storage write happens on a blocking task, then publishes
``LoomEvent::GalleryChanged`` so the gallery view auto-refreshes.

AI auto-tag (``T``) is out of scope for this commit (requires a Lua
``tag_image`` capability that isn't implemented yet).

Closes charles/loom#135 (manual editor; AI auto-tag is follow-up)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
``F`` opens a modal that lets the user toggle ``hide_nsfw`` and
``favorites_only``, plus type into text buffers for tag list (csv),
model name, and LoRA name. ``Enter`` applies; ``Esc`` cancels;
``Shift+R`` resets all filters to defaults.

The gallery title line now lists active filters as chips:
``[search: x · tags: a,b · model: sd-xl · ★ favorites · hide NSFW]``
so it's always obvious what the current view is filtered by.

New machinery:
- ``OverlayKind::GalleryFilter(Box<GalleryFilter>)``
- ``AppAction::SetGalleryFilter`` routes the new filter to
  ``GalleryScreen::apply_filter`` which sets ``needs_load = true``
- The storage `list(&filter)` already honours all dimensions

Closes charles/loom#137 (single-screen filter; tabbed UI with
multi-select tag picker is a follow-up)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
From the entity Detail focus, two new keybinds dispatch async AI
plugin calls against the entity's reference image:

- ``Ctrl+D`` — calls ``bridge.describe_entity_from_image`` with the
  image base64 + entity kind + `prompt_style: "natural"`. Result
  replaces ``entity.prompt_natural``.
- ``Ctrl+F`` — calls ``bridge.detect_face_region``. Returned
  normalised rect stored on the screen's ``face_rect``.

New ``AppAction::EntityDescribeResult`` and ``EntityFaceResult``
land back in the dispatch loop, route to ``EntitiesScreen::
apply_describe_result`` / ``apply_face_result`` which persist via
``storage.save_entity``.

Notifications surface progress (`describing…`, `detecting face…`)
and error states. Missing reference image is surfaced as a warning
without dispatching the call.

Closes charles/loom#133 (Confirm-on-overwrite for non-empty
prompt_natural is a follow-up; face rect overlay rendering is also
follow-up since Entity model currently has no face_rect field —
state is screen-local for now).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Entity Detail panel gains a "loras" section showing each attached
``EntityLora`` with name + strength. Header line shows attached count
and the ``l`` hint.

- ``l`` from entity Detail opens the LoRA picker overlay
  (``OverlayKind::EntityLoraPicker``) — same UI as the Generate-side
  picker but routed through ``AppAction::AddLoraToEntity`` instead
  of ``AddLora``.
- ``LoraPickerOverlay`` gains an optional ``target_entity_id``;
  when set, Enter writes to the entity instead of Generate.
- ``EntitiesScreen::add_lora_to_entity`` and ``remove_focused_lora``
  mutate the entity's ``loras`` field and persist via
  ``storage.save_entity``.
- Hint row in entity Detail updated with ``l add lora ·
  Ctrl+D describe · Ctrl+F face``.

A small ``kick_lora_list_load`` helper extracted from the LoraPicker
constructor so both variants share the async list-loading.

Closes charles/loom#139 (strength adjust + remove keys are noted as
follow-ups; the picker handles initial add and storage persistence)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat(tui): settings — KeyBindings section shows live key map
All checks were successful
qa / qa (pull_request) Successful in 28m26s
0ad3dacc0e
Previously a placeholder row pointed to ``tui.toml``. Now the
KeyBindings section renders the full list of global bindings sorted
by action id with their current key combos:

```
  [g g       ]  app.help
  [Ctrl+P    ]  app.palette
  …
```

New ``AppCtx::key_map: Arc<KeyMap>`` carries the active map (cheap
clone wrap on each ``ctx()`` call). ``KeyMap`` gains ``derive(Clone)``.

Interactive rebinding (Enter on a row → key capture overlay → write
back + persist to ``tui.toml``) is still the follow-up. This commit
is the read-only display foundation.

Closes charles/loom#146 (foundation; full editor is follow-up)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
charles deleted branch tui/mid-size-batch 2026-04-15 13:49:00 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
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!148
No description provided.