Commit Graph
574 Commits
Author SHA1 Message Date
Claude cd8d2b96a2 Merge PR #259 2026-10-08 17:50:50 +00:00
Claude a12fabd588 Library: the Photo Grid label footer is translucent; pt-br for "Color label cleared" (#308)
#308 painted an opaque label-coloured bar over the bottom 24 px of every
labelled photo in Photo Grid, hiding part of the photo, while its docs
said the photo pixels stay as they are. The footer is now translucent
over the photo and the docs say so. Also adds the one string pt-br lacked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:39:23 +00:00
Claude 99fa19099b Merge PR #308
# Conflicts:
#	apps/lightcraft/src/native_menu.rs
#	crates/ui-egui/src/panels/detail.rs
#	docs/parity.md
2026-10-08 17:38:20 +00:00
Claude b7f60a1fac i18n: translate the strings #312, #313 and #325 added (ja, pt-br, zh-hans, zh-hant)
Crop Apply / Lock / Locked, Set Image Zoom and Pan, the import review's
Recently Deleted choices and Empty Recently Deleted. The import's undo
labels and its "restored from Recently Deleted" summary used format!, so
they could not be translated; they go through tr_format! now.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:37:06 +00:00
Claude 90fe6d1616 Merge PR #325
# Conflicts:
#	crates/ui-egui/src/panels/detail.rs
#	crates/ui-egui/src/tests_panels.rs
2026-10-08 17:34:31 +00:00
Claude fa630a233a Merge PR #307
# Conflicts:
#	docs/parity.md
2026-10-08 17:34:04 +00:00
Claude 9e9e45b3c7 Merge PR #313
# Conflicts:
#	crates/ui-egui/src/panels/detail.rs
#	docs/parity.md
2026-10-08 17:33:58 +00:00
Claude 259de3d9df Merge PR #312 2026-10-08 17:33:04 +00:00
Claude e4737f68c7 Format: rustfmt the Show in Explorer button (#324)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:29:18 +00:00
Claude 21de86b3df UI: the loupe follows a texture's aspect only when it really differs (#280)
A texture's whole-pixel size is slightly off the frame's exact aspect (a
128 px thumbnail by up to ~1 %), so following it always made the loupe
rect jump a little as the thumbnail, preview and full render arrived, and
moved mask and crop overlays with it. Follow it only when it differs by
more than 2 % (an unsupported raw's embedded JPEG with another crop), and
never in the crop tool, whose overlays need the frame's own geometry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:29:00 +00:00
Claude 0b101be155 Issue #181: saved presets and Export with Previous drop keys this version doesn't know
#287 made app.export refuse unknown params. Stored settings (a user export
preset, prefs.json lastExport) written by another version are not the
caller's typo, and refusing them would break that preset or Export with
Previous for good after an update: their unknown keys (also inside
watermark) are dropped before the strict check. What the caller passes is
still checked strictly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:29:00 +00:00
ClaudeandDWAA1660 7d2bb5e5ec Issue #188: D65 reads as a small positive tint (test from #336)
Daylight sits above the Planckian locus, so with the DNG / Lightroom tint
sign D65 converts to about +10, as Lightroom's Daylight preset has it.
Taken from #336, which made the same sign fix as #258.

Co-Authored-By: DWAA1660 <80738438+DWAA1660@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01912WaK6Rmew3wxZuPyX7E8
2026-10-08 17:26:01 +00:00
Claude 2565f893c4 Merge PR #257
# Conflicts:
#	docs/parity.md
2026-10-08 17:21:02 +00:00
Claude 4e2584e559 Merge PR #277
# Conflicts:
#	docs/parity.md
2026-10-08 17:21:02 +00:00
Claude cb173c22dc Merge PR #311
# Conflicts:
#	docs/parity.md
2026-10-08 17:20:41 +00:00
Claude 98da2a0229 Merge PR #288
# Conflicts:
#	docs/whats-new.md
2026-10-08 17:19:31 +00:00
Claude 1ece9341d6 Merge PR #324 2026-10-08 17:18:59 +00:00
Claude 6d52e0744a Merge PR #280 2026-10-08 17:18:59 +00:00
Claude 81e28f25c9 Merge PR #255 2026-10-08 17:18:59 +00:00
Claude b5b6f8caa8 Merge PR #300 2026-10-08 17:18:58 +00:00
Claude 7e21d185b8 Merge PR #258 2026-10-08 17:18:58 +00:00
Claude 70db2f2320 Merge PR #292 2026-10-08 17:18:58 +00:00
Claude 74b9129a05 Merge PR #287 2026-10-08 17:18:58 +00:00
Claude 36c6920f55 Merge PR #285 2026-10-08 17:18:58 +00:00
Claude 5f9548a7ba Merge PR #269 2026-10-08 17:18:57 +00:00
Claude 0e188f6a40 Merge PR #268 2026-10-08 17:18:57 +00:00
Nathaniel LedfordandClaude Sonnet 5.5 0b5ef3fe11 Import review: choose what happens to files in Recently Deleted (#298)
Files whose photo is in the trash stay unchecked until Restore them or Import as
new is chosen; the toast and undo label say what was restored.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:39:28 -04:00
peiyan0 38d2ff07c9 desktop: fix Windows Explorer reveal path and platform file manager labels (#272) 2026-10-08 23:36:56 +08:00
Nathaniel LedfordandClaude Sonnet 5.5 6c19090fde Grid: selected photos whose thumbnail isn't drawn yet still show as selected (#298)
The grid and filmstrip now both ask Selection::state_of.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:29:05 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 5b80fc6bcf MCP import onDeleted; Empty Recently Deleted in the trash view's Photo menu; parity row
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:29:05 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 0a474cc06e Permanent delete of several photos is one consistent op list; restored photos join album/selection
Review of the onDeleted work found that purging photos one at a time built each
op list against the unchanged catalog, so photos sharing an album or a stack made
Empty Recently Deleted (and Fresh imports) fail with NoStack or leave dangling
album entries. Catalog::delete_photos_permanently_ops builds one list for all of
them; Empty, Delete Permanently and the Fresh purge use it. Photos an import
restores now take part in album/albumName/selection, and undo labels say Restore.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:29:05 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 2928880e81 Import: onDeleted policy (skip|restore|fresh) for files in Recently Deleted; library.emptyRecentlyDeleted
A file that is in Recently Deleted was always skipped as a duplicate with no way
forward (#298). The report now flags such duplicates (existingDeleted); onDeleted
restores the trashed photo with its edits or replaces it with a fresh import; and
Empty Recently Deleted removes every trashed photo in one undoable step.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:16:42 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 14a03052de Filmstrip: show every selected photo as selected, not only the active one (#298)
After Select All in the loupe only the active filmstrip cell was highlighted,
so the selection looked like a single photo. Cells now use Selection::state_of;
selected-but-not-active cells get the selected fill and a grey outline.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:01:50 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 7f6e4e48f7 Selection::state_of: one answer to active / selected / not selected for every view
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 11:01:50 -04:00
sebastian pfluegelmeier 912f56cac8 LR-VIEW-ZOOM: add trackpad zoom and pan with stable cursors 2026-10-08 16:38:56 +02:00
Nathaniel LedfordandClaude Sonnet 5.5 0e254bfbc6 Crop UI: lock toggle, custom ratio, edge-safe handle drags (#295)
The crop overlay now reports pointer positions to crop.drag instead of
computing rectangles itself. The Crop panel gets a visible Lock toggle, a
custom W × H entry, a dropdown chevron and a button label that names the
active ratio ("Original", a preset, or 1.37 : 1) instead of pixel sizes.
LR-CROP-RECT / LR-CROP-ASPECT parity rows updated.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 10:35:46 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 8d8178dc0a Engine: crop.drag command; validate custom crop ratios (#295)
crop.drag {handle, from, to, start?} runs drag_crop through the command
layer so the UI, CLI, control channel and MCP agree; a locked crop keeps the
shape of its frame. crop.aspect now rejects non-finite, non-positive and
beyond-20:1 ratios and non-numeric arrays instead of storing a degenerate
lock that produced an empty crop.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 10:35:46 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 90c63af951 Crop: drag_crop domain operation for handle drags (#295)
Dragging a crop handle past the image edge used to hand the raw rectangle to
CropGeometry::constrained, which slid the whole frame toward the centre and
moved the anchored corner. drag_crop owns the drag instead: the opposite
edges stay put, a locked ratio holds on all eight handles (edges grow about
their midline, sliding along a blocked side), the frame stops at the image
edge and slides along it, and it keeps a minimum size. Hostile numbers return
the start crop. Covered by Given/When/Then scenarios and property tests.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 10:35:46 -04:00
midasdfandCodex 69640df8a7 LR-EXP-WATERMARK: shape Japanese vertical watermark glyphs
Co-Authored-By: Codex <noreply@openai.com>
2026-10-08 23:34:43 +09:00
Hanmo a47afdc1f4 M1: merge upstream main and resolve documentation conflicts 2026-10-08 22:18:13 +08:00
Stano BustorandGPT-6 Luna b4a192a54e UI: preserve preview aspect ratio across views
Keep embedded and decoded preview proportions consistent in the justified
grid, photo views, alternate detail previews, and culling previews.

Co-Authored-By: GPT-6 Luna <noreply@openai.com>
2026-10-08 16:00:00 +02:00
Hanmo 4256865cf4 M1: tint labelled thumbnails and colour label feedback 2026-10-08 21:42:21 +08:00
Hanmo 57c9e252c1 M1: show bottom confirmation for colour label actions 2026-10-08 21:25:02 +08:00
Nathaniel LedfordandClaude Sonnet 5.5 46c4a2709d Sidebar: names end in an ellipsis at the count; bars end at the panel edge
A name that does not fit is cut with an ellipsis before the photo count (the
full name on hover) instead of running past it; scrolling the sidebar sideways
or widening it shows more. A row asks for room for at most 140 pt of its name,
so depth, not one long name, makes the sidebar scroll. Selection and hover
bars end at the panel's edge when the content is wider.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 09:06:18 -04:00
Nathaniel LedfordandClaude Sonnet 5.5 198286e589 Folders: round-4 review fixes (counts at the edge, edge-space names, smart albums)
- ui: counts stay at the visible edge when the sidebar scrolls sideways
  (with the row's colour behind them where a long name runs under); the
  smart-album dialog's live count includes the album's folder
- catalog: a folder path is used as given (a name with a space at its edge is
  not its neighbour: Remove acted on the wrong folder); a plain POSIX path
  is checked against the folder without building a key (about half the cost
  on a big library, with a test that it agrees with the careful check)
- engine: editing a smart album's rules keeps the folder the editor cannot
  show; a shown folder that loses its last photo gives way to All Photos;
  library.state and view.json name the folder only while it is shown; a blank
  folder filter is no filter

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 09:06:18 -04:00
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
issuenateandClaude Opus 5.5 88c1e768f1 TIFF: decode 1-, 2- and 4-bit samples
Bilevel scans, CCITT fax images and 2- or 4-bit gray TIFFs were rejected with
"sample buffer too short". The `tiff` crate returns such samples packed, most
significant bits first, eight, four or two to a byte with each row padded to a
whole byte; the converter expects one byte per sample. They are now spread out
one per byte and scaled to 0–255 (255, 85 and 17 times the sample: exact) before
conversion. 3-, 5-, 6- and 7-bit samples, and planar images with more than one
sample narrower than a byte, are refused with an "unsupported" error.

The new test builds 1-bit (both photometric conventions, a width that leaves row
padding, set padding bits), 2-bit and 4-bit strips in code, plus a truncated
strip that must fail cleanly; it fails without the fix with the old error. A
600×400 bilevel image, uncompressed and CCITT G4, now decodes to the same pixels
PIL reads from it.

The module documentation no longer claims palette support: the `tiff` crate
refuses RGBPalette images on every read path, so the palette branch here has
never been reached. The parity row lists palette TIFF as missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:47:51 +02:00