Commit Graph
658 Commits
Author SHA1 Message Date
Nathaniel LedfordandClaude Sonnet 5.5 6f33aacd22 Sidebar: scrolls sideways so deep folders keep their nesting
Every level indents one step more than its parent however deep it goes (the
five-level indent cap is gone). The whole sidebar scrolls in both directions:
rows report how wide they need to be, the widest one of the last frame sets
the content width (at least the panel's), and a bar appears only when it
overflows. Folder names are no longer cut in the tree; Create Album stays at
the visible edge.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 09:06:18 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 5d13d59520 Folders: review fixes (smart albums, disk guards, deep chains, long titles)
- engine: a smart album made from a folder view keeps the folder; only a
  folder that shows exactly its own photos can be the source (not the
  startup disk, not a folder above disks, not one with no photos); a
  folder source and a folder filter never coexist; a folder source with no
  folder shows nothing; a saved view whose folder is gone opens on All
  Photos; removing a folder above a disk needs `disk: true` even with one
  disk mounted; library.folders documents volume/selectable
- ui: deep chains stop indenting after five levels, the grid title gives
  way to the photo count (full name on hover), disclosure triangles have
  spoken names, the remove dialog says what is included and has a disk
  title; test temp folders are cleaned up on failure

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 09:06:18 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 0732edc64f Folders: every folder its own node; choosing one loads it like an album
- catalog: a row is exactly one folder (no folding of single-child levels);
  the UI starts a folder that holds nothing and leads to one folder open
- engine: a library folder is a source (LibrarySource::LibraryFolder with
  Session::library_folder, like Local's browse): library.source
  {kind: libraryFolder, path}, kept with the library's view, shown by
  library.state, followed through folder.rename / folder.move and undo,
  dropped back to All Photos when its folder is removed
- ui: clicking a folder replaces whatever the grid showed (Picks, Recently
  Deleted, a Local folder…) instead of narrowing it with a filter chip; the
  grid is titled after the folder

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 09:06:18 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 82e827b9d9 Sidebar: Folders section for the folders the library's photos were imported from
Another way to explore the library next to By Date and Keywords: a tree of
the folders that hold imported photos, with counts (subfolders included),
under the disk or network share each is on. Local stays the way to browse
any folder on disk.

- catalog: Catalog::folder_tree and Filter::library_folder. Each disk is a
  volume row (drive letter, Windows share, /Volumes/<share>, /media, /mnt,
  gvfs, /net…), found from the stored paths alone, so an offline share costs
  nothing. Levels that hold nothing and lead to one folder fold into one row;
  depth is bounded. The tree and the filter read paths through one splitter
  (separators, `.`, `..`, verbatim UNC prefix, repeated separators), and a
  row that would cover other disks' photos is not choosable
- engine: library.folders, library.removeFolder (to Recently Deleted, one
  undo step, no file touched; a whole disk or a folder spanning several
  needs `disk: true`, the startup disk never), libraryFolder in
  library.filter, chip; a chosen folder follows folder.rename / folder.move
  and their undo
- ui: collapsible Folders section; the chosen folder's row is always opened
  into view; right-click (row or triangle) Rename, Move, Show in Finder,
  Remove from Library…; disk rows Remove Disk from Library…; both ask first

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 09:06:18 -04:00
Brandon ThomasandClaude Opus 5.5 b8df5f472c Bump version to 0.3.0 (from 0.2.1) for release
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:12:53 -04:00
Brandon ThomasandClaude Opus 5.5 629e39380e Release CI: macOS job on macos-15-xlarge
Custom macOS larger runners in a runner group do not pick up jobs; the
built-in M2 Pro label does. Only release.yml uses it, and the
actions_macos_xl budget caps the monthly spend.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 22:07:59 -04:00
Brandon ThomasandClaude Opus 5.5 8734e95dc8 Release CI: macOS job on the org macos-release runner
The standard macOS runners are shared with all CI and queue for an hour or
more. The macos-release runner (GitHub-hosted M2 Pro) is in a runner group
usable only by release.yml on the release branch, with a monthly spend cap
on the actions_macos_xl SKU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:54:56 -04:00
Brandon ThomasandClaude Opus 5.5 4159ceb1b0 About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#252)
* About: contributors compiled in from contributors.json (Contributors + Models tabs, grab bag + table, sortable, name toggle)

Adds the craftrules standard (standards/contributors.md) to LightCraft: contributors/contributors.json
is generated by craftrules/scripts/contributors.py and baked into the binary by
crates/ui-egui/build.rs (merged next to the tr_format! generation) as static tables. The About
dialog gets tabs About · Contributors · Models. Each contributor line: @username, opt-in
display/real name, PRs, commits, lines +/−/Δ, binary assets +/−, first/last commit. Sortable by
every column; alphabetical ignores case and the leading @. Tabs and the list view are
control-channel widgets (button:aboutTab-*, button:creditsTable / button:creditsGrabBag).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors docs: craftrules is two levels up (../../craftrules)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section

build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate after rebase onto main

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:22:08 -04:00
Brandon Thomas 2694d7089f Merge pull request #249 from radialmonster/ci-available-ram 2026-10-07 21:06:13 -04:00
Brandon Thomas 88f38c7e2a Merge pull request #248 from andrewyao (web_time in raw preview decode timing) 2026-10-07 21:06:13 -04:00
Brandon Thomas df574a537a Merge PR #213 from Orthic-Labs/orthic/arw-lossless-ycbcr
# Conflicts:
#	crates/ui-egui/src/headless.rs
2026-10-07 20:53:51 -04:00
Brandon Thomas 5bc923b4f9 Merge PR #246 2026-10-07 20:53:29 -04:00
Brandon ThomasandClaude Opus 5.5 71c8382b10 Merge main into #213 (keep main's Windows test fixes from #207; parity row combines RW2 and the downsized ARW)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:53:25 -04:00
Andrew YaoandClaude Opus 5.5 0a952b3536 Web: time raw preview decodes with web_time so wasm doesn't panic
load_bytes_now timed the binned demosaic with std::time::Instant, which
panics on wasm32-unknown-unknown ("time not implemented on this
platform"). Opening a raw in the web build aborted the decode. Use
web_time::Instant, as library.rs already does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-07 17:53:19 -07:00
radialmonsterandClaude Opus 5.5 f9cfe15db6 CI: pick build jobs from available RAM, not installed RAM
Installed RAM overcommits a busy machine: on a 32 GB desktop with browsers,
a VM and editors open, about 7 GB was free and the installed-RAM rule chose
16 jobs. A fresh build then pushed free RAM below 1 GB.

`cargo xtask ci` now uses one build job per 1.5 GB of RAM available when it
starts (Linux MemAvailable, Windows AvailableMBytes, macOS free + inactive +
speculative pages), capped at the CPU count. With line-table debuginfo,
4 jobs measured about 3 GB in use, so this leaves about half the available
RAM spare. If available RAM can't be read, half the installed RAM is
assumed; if neither can, 4 jobs. Test threads follow, capped at 4.
Explicit CARGO_BUILD_JOBS / RUST_TEST_THREADS still win.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:46:10 -04:00
radialmonsterandClaude Opus 5.5 ed0a2a4f07 GPU tests: drop the edge-pixel tolerance; the coverage mask makes edges match
#207 let up to two edge pixels differ because the GPU's f32 framing could
fall on the other side of the lens-warp boundary. 'GPU: decide warped-geometry
edges with a CPU coverage mask' (this PR) makes the GPU use the CPU's f64
decision, so every case is back within the plain MAX_LSB check (embedded
lens + perspective: max 1 LSB, was 91 before the mask).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:40:47 -04:00
Brandon ThomasandClaude Opus 5.5 0801219b17 Merge #243 (with main) into #246
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:38:46 -04:00
Brandon Thomas e716ede8e4 Merge remote-tracking branch 'origin/main' into HEAD 2026-10-07 20:33:23 -04:00
Brandon ThomasandClaude Opus 5.5 2e48f25997 Merge main into #243 (combine with #207's Windows test fixes)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:33:23 -04:00
Brandon ThomasandClaude Opus 5.5 d716d74af5 Merge main into #243 (combine with #207's Windows test fixes: hide_home_above plus local.addRoot, FakeFs path normalising plus case folding)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:32:47 -04:00
Brandon ThomasandClaude Opus 5.5 a1c5e2dad1 Tests: three headless UI tests wait for the textures and dialog they check
settle() returns after a quiet spell, which on a loaded machine can come before the first grid
thumbnails, the profile browser's variant thumbnails or the async import review (and its
thumbnails) land. demo_grid_snapshot_has_ui_pixels, profile_browser_previews_on_hover_and_applies_on_click
and import_review_dialog failed that way when two test runs shared the machine; they (and the
two other import-review tests) now step until what they assert is there. 2 concurrent runs: 138/138 each.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:32:34 -04:00
radialmonsterandClaude Opus 5.5 c816ca8e35 UI tests: wait for sidebar rows with main's step_until
main gained Headless::step_until for the same job as this branch's
test-only wait_for_widget (run frames until a condition holds). Use the one
helper and drop the duplicate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:23:25 -04:00
radialmonsterandClaude Opus 5.5 62325bd45e Thumbnails: retire the replaced preview cache so its old jobs can't write
Reopening a library (or opening another one, or set_disk_cache_bytes
falling back to attaching) replaced MediaCache::rendered with a new
PreviewCache, but render jobs still in flight kept the old object.
Each PreviewCache checked only its own generation, so after a clear on
the new cache the old one's generation was still current: a finishing
thumbnail job wrote its pixels through it into the directory the clear
had just emptied. The UI rejected the result, but the JPEG stayed.

attach_disk_cache now retires the cache it replaces before swapping it:
PreviewCache::retire takes the generation write lock (so it waits for a
write in progress, like clear) and marks the object retired; every
get/put/put_deferred through it is then refused and its clear() is a
no-op, as its directory may now belong to the replacement. Files on
disk are left alone, so a plain reopen still finds its thumbnails, and
resizing the budget in place keeps the same cache object as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:23:17 -04:00
radialmonsterandClaude Opus 5.5 4d5504cf16 Web: watch the thumbnail cache from worker start so an early clear invalidates
The main thread's Workers tracked no rendered-thumbnail cache until the
first render request carried one. If Clear Preview Cache ran before that
(e.g. starting on an empty filtered view), the per-frame observation in
finished() had nothing to compare with, and the first request only
recorded the already-cleared generation as its baseline. The persisted
ThumbIndex was never invalidated, so once the filter was removed the
request touched the old entry and the worker read the pre-clear JPEG
back from browser storage. Replacing the cache (another library) before
the first request had the same gap.

Workers::start now takes the session's cache and records it, with its
current generation, as the baseline the persisted index belongs to. A
normal start with no clear observes the same cache and generation and
keeps the index. The comparison moves into wire::CacheWatch so it is
tested natively (cargo test --workspace) next to ThumbIndex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:23:17 -04:00
Brandon Thomas aec820033b Merge pull request #206 from anarion80/add_nix_build
Packaging: add a Nix flake (nix build / nix develop)
2026-10-07 20:15:50 -04:00
Brandon Thomas b90c06b347 Merge pull request #210 from voshart/pr/fetch-crate
Fetch: the model downloader becomes its own crate (no behaviour change)
2026-10-07 20:15:46 -04:00
Brandon Thomas 52f64ce0b9 Merge pull request #215 from XRTce/rw2-panasonic-lumix
LR-IMP-FORMATS: Panasonic RW2 / Leica RWL / Panasonic RAW in every raw format, with the RW2 camera look
2026-10-07 20:15:41 -04:00
Brandon Thomas 767ed15adc Merge pull request #235 from Gremiger/fix/issue-212-nef-dng-white-balance
Issue #212: Raw: keep vendor white balance when writing DNG
2026-10-07 20:15:37 -04:00
Brandon Thomas 1c025fbb97 Merge pull request #207 from voshart/pr/tests-windows
Tests: pass on Windows (path separators, temp folder inside home, one GPU edge pixel)
2026-10-07 20:15:33 -04:00
Brandon ThomasandClaude Opus 5.5 9b41e33a24 Merge main into #213 (keep main's waits in the two flaky UI tests)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:14:41 -04:00
Brandon ThomasandClaude Opus 5.5 0143704c7d Merge #243 (with main) into #246
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:14:28 -04:00
Brandon ThomasandClaude Opus 5.5 9da8163ae2 Merge main into #243 (keep main's settle and step_until in the two flaky UI tests)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:12:10 -04:00
Brandon ThomasandClaude Opus 5.5 46f5d212e7 Merge main into #207 (keep main's step_until wait for the folder row)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:11:00 -04:00
Brandon Thomas eba0b9723b Merge pull request #223 from Ndsanes/l10n/zh-hans-catalog-gap
LR-BEHAV-LOCALIZE: fill the zh-hans catalog to match zh-hant
2026-10-07 20:09:36 -04:00
Brandon Thomas 5372309ad8 Merge pull request #228 from RicSchonfelder/i18n-pt-br
i18n: add Brazilian Portuguese (pt-br) UI translation
2026-10-07 20:09:32 -04:00
Brandon Thomas b63ea8f5c2 Merge pull request #222 from Ndsanes/fix/craft-fonts-relative-path
Build: resolve a relative CRAFT_FONTS_DIR against the workspace root
2026-10-07 20:09:28 -04:00
Brandon Thomas 2dda7cf842 Merge pull request #241 from agorevski/copilot/issue-cluster-docs-consistency
Docs: fix release, sibling, and command references
2026-10-07 20:09:24 -04:00
Brandon Thomas be87e1b6e7 Merge pull request #238 from DWAA1660/fix/export-missing-folder
Export: clear error when there's no export folder (instead of "Access is denied")
2026-10-07 20:09:19 -04:00
Brandon Thomas 97e34434d0 Merge pull request #217 from nledford/feat/random-sort
Library: Random sort with a stable seed and Reshuffle
2026-10-07 20:09:14 -04:00
Brandon Thomas 30192541ea Merge pull request #242 from nledford/feat/collapsible-sidebar-sections
Sidebar: collapsible Albums, Local, By Date and Keywords sections
2026-10-07 20:09:10 -04:00
Brandon Thomas c4d7c00e74 Merge pull request #225 from nledford/fix/stale-panels-after-library-switch
Library: switching libraries no longer shows the old library's sidebar
2026-10-07 20:09:06 -04:00
Brandon Thomas 3fe0bef364 Merge pull request #239 from nledford/feat/smart-album-file-path
Smart albums: File Path rule field
2026-10-07 20:09:03 -04:00
Brandon Thomas 590b387a53 Merge pull request #221 from MusseJusse/codex/navigation-arrows-pr
M16.1: complete navigation arrowheads
2026-10-07 20:08:59 -04:00
Brandon Thomas 51c878ddd8 Merge pull request #199 from storytold/fix/flaky-profile-hover-test
Tests: fix three FreeBSD-flaky headless UI tests
2026-10-07 20:08:55 -04:00
Brandon ThomasandClaude Opus 5.5 034bb6e324 Rename: drop a redundant from != to (clippy nonminimal_bool)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:08:52 -04:00
Brandon ThomasandClaude Opus 5.5 41f9ae0c2b Loupe: a draft that finishes after a newer request still replaces older pixels, so a long drag keeps updating
#243 dropped every result whose request id wasn't the newest for its slot. The loupe requests a new
draft every frame while a slider moves, so when a draft took longer than a frame nothing landed
until the drag paused. Main, Before and Hover now take a superseded draft that is newer than what
they show (never one from before a library or preview-cache reset, never an error or its source).
Also saturate the xtask RAM rounding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:06:58 -04:00
Brandon ThomasandClaude Opus 5.5 e2a941887e Nix: mark the package community-maintained in the agent guide; craft-fonts holds CJK fonts, not only Japanese
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:03:05 -04:00
Brandon ThomasandClaude Opus 5.5 e574839724 Merge main into #213 (camera_preview: main's proxy edge/size with the sensor_proxy fallback)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:01:23 -04:00
Brandon ThomasandClaude Opus 5.5 f0632e7022 Fetch: crate root forbids unsafe and denies panicking lints, like every other crate
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:56:42 -04:00
Brandon ThomasandClaude Opus 5.5 d3c6dc0aa8 i18n zh-hans: "Add Remove Spot" means adding a spot removal
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 19:56:03 -04:00