Skip to content

Add gallery slideshow and smart albums - #205

Open
IAmJSD wants to merge 5 commits into
mainfrom
feat/gallery-slideshow-smart-albums
Open

IAmJSD wants to merge 5 commits into
mainfrom
feat/gallery-slideshow-smart-albums

Conversation

@IAmJSD

@IAmJSD IAmJSD commented Oct 4, 2026

Copy link
Copy Markdown
Member

What and why

Two gallery features:

  1. Smart albums. Saved searches that stay live. Rules cover rating (at least, at most or exactly), flag, colour label, XMP keyword, capture date range, camera, lens, file type, has location, place, People name, folder, edited and has earlier versions. A group can match all, any or none of its rules, and groups nest one level in the editor (the model allows any depth). Albums get their own SMART ALBUMS section in the sidebar. You can edit, rename and delete them, and they keep updating as the library changes.
  2. Slideshow. Plays the grid's current view fullscreen: a folder, date or place group, bucket or album, person, or search result, with the culling and map filters applied, starting from the selected photo. If several photos are selected, it plays only those. Each photo shows for 2–60 s. Transitions are cut, crossfade, or a Ken Burns pan and zoom that moves towards the faces People found (area-weighted), or towards the centre when there are none. It also has shuffle, loop, a caption overlay (title, caption, date, place, rating, flag, label), silent video playback or skipping, and keyboard control: Space pauses, ←/→ step, I toggles the caption, Esc ends. The 0–5, P/X/U and 6–9/M/L keys save through the normal culling path, so a slideshow works as a culling pass. Entry points: the tray button, Gallery ▸ Slideshow…, the photo menu's "Slideshow from here" and a bucket's "Play slideshow".

Design

  • A smart album is a bucket with a filter: RuleGroup. It is persisted as an optional filter key on BucketFile::Rich. Older files read unchanged, and a bucket without rules writes no key. There is no parallel engine: refresh_smart_buckets (the pass that already fills query and area buckets) also checks each album's rules against PhotoFacts gathered from the in-memory index. Query, area and rules are ANDed when more than one is set. The pass key gains people_rev while an album exists, so ratings, flags, labels and People tags re-run it just as index changes do. No decoding is involved. Only albums that use "has earlier versions" list each folder's .schist/versions, once per pass.
  • Rules and slideshow arithmetic live in schist-gallery (smart.rs, slideshow.rs). They are pure and unit-tested, and the headless MCP server can read them.
  • Camera and lens come from the existing EXIF pass and are cached in a separate .cam file beside the thumbnail, so the .meta format and its caches stay as they are. Keywords come through the existing XMP overlay. On upgrade, each photo's EXIF is read once more on the next metadata refresh to fill .cam.
  • Relation to Add exclusion queries to smart buckets #171 (exclusion queries on smart buckets): compatible and not duplicated. Add exclusion queries to smart buckets #171 adds a negative search query (exclude_query), while this PR adds metadata rules (filter). Both are additive optional fields on the same bucket and narrow the same match set. I deliberately did not change configure_bucket's signature or the BucketName modal that Add exclusion queries to smart buckets #171 edits; albums use set_bucket_filter and their own Modal::SmartAlbum. Expect small mechanical conflicts where both touch the field list in BucketFile::Rich, the bucket load/save mapping and the candidate-set branch in refresh_smart_buckets (Add exclusion queries to smart buckets #171 changes the area-only branch to use all indexed paths, and this PR adds a filter-only branch beside it). Resolve them by keeping both sides.
  • Slideshow preloading: only the current slide, the next two and the previous one are decoded, at the screen's own size in device pixels (640–4096 px), and everything else is released. A slide's time starts when it is on screen. When the show starts, the window enters fullscreen, and it comes back out at the end if the show put it there. The in-window menu bar is hidden while the slideshow runs.
  • Mobile and web: the slideshow is part of the local gallery view, so it runs on iOS and Android too, with touch-sized controls that stay visible (video_mobile.rs was not needed). The browser build has no local gallery, and the Cloud gallery does not offer a slideshow. Both are documented.
  • Cloud sync: albums are local only and documented as such. The saved-library sync (brushes, actions, recipes) needs a provider-side kind, and album rules refer to local folders and People, so it isn't straightforward.

Verification done

  • cargo test -p schist-gallery: 78 pass. New tests cover every predicate, all/any/none, nesting, blank and empty albums, JSON round-trip and defaults, file kinds, kept-version detection, persistence and migration of filter and slideshow options, playlist order/shuffle/loop and reshuffle seams, the preload window, display edge, and Ken Burns framing (start = fit, end covers the view, edge faces never pull in background, a fitting axis stays centred) plus the face-weighted subject point.
  • cargo test -p schist-editor --lib: 426 pass, 1 fails: clipboard::tests::image_url_follows_redirects_and_checks_http_errors. That test needs network access and is unrelated to this change. New editor tests cover album facts following the library as it changes (decisions, the metadata pass, People tags, rescans, rule edits invalidating matches), the editor's row and field routing for nested rules, version marking, and caption decision text.
  • cargo clippy -p schist-gallery -p schist-gallery-ui -p schist-app-actions -p schist-editor --all-targets -- -D warnings: clean before the final rebase. cargo fmt --check: clean.
  • i18n: cargo test -p schist-i18n passes, tools/check-i18n.py --strict-audit passes, tools/test-check-i18n.py passes, sync-i18n.py --check passes, and node --test web/i18n.test.mjs passes. New strings are in slideshow.lang and smart_album.lang, translated for all 150 locales; no and sh were generated.
  • After rebasing onto main (Add OpenRaster (.ora) read/write and Krita (.kra) import #202): cargo check -p schist-editor succeeds and the i18n audit and sync checks pass again.

Not verified

  • No headless GUI run (Xvfb recipe): disk was too tight for a release build. Dialog layout, fullscreen toggling, crossfade and Ken Burns smoothness, and the controls overlay have not been seen running.
  • Video slides were not exercised end to end. They reuse the video viewer's decoder loop.
  • The wasm32 build was not checked. The new modules are native-only, and wasm arms were added to the shared code.
  • iOS and Android were not built or run.
  • The full cargo test --workspace was not run.

Limits

  • An album holds at most 16 rules (dialog widgets are keyed by static ids). The editor offers one level of groups.
  • Text rules match case-insensitively on part of a value. Canon CR3 files have no camera or lens here, because the existing EXIF reader doesn't parse them.
  • There is no live match count in the editor; the album fills after you save.
  • No swipe gestures on touch; use the buttons.
  • The headless schist-mcp server reports which buckets are albums but, as with smart buckets, lists only their hand-added photos. The in-app gallery_state includes each album's rules.

🤖 Generated with Claude Code

IAmJSD and others added 5 commits October 4, 2026 17:49
Rule groups (all/any/none, nested) over culling, keywords, capture date,
camera, lens, file type, location, place, People, folder, edits and kept
versions; persisted on buckets as `filter`. Camera and lens join the EXIF
pass via a separate .cam cache. Playlist order/shuffle/loop, preload window
and Ken Burns framing maths, with tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Smart albums are buckets with rules, evaluated by the existing smart-bucket
pass and re-run when the index, decisions or People tags change; they get a
sidebar section and an editor. The slideshow plays the grid's view or
selection fullscreen with cut/crossfade/face-aware Ken Burns, shuffle, loop,
captions, silent video, display-size preloading and culling keys.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@IAmJSD
IAmJSD force-pushed the feat/gallery-slideshow-smart-albums branch from 3f30791 to c4c9252 Compare October 4, 2026 18:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant