Commit Graph
1561 Commits
Author SHA1 Message Date
skylar taylor-barrick af4c5e102c fix(import): report and optimize Lightroom catalogs (#1406)
Task: LRC-LIB-CATALOG-IMPORT

Count offline records, Local promotions and virtual copies correctly. Keep destination, warnings and errors in a persistent import result, with Show in Library clearing filters. Preserve library-switch ownership, reimport identities, existing edits and one-step undo.

Avoid repeated missing-original probes and unnecessary staged-photo, catalog-operation and develop-patch copies. Preserve upstream phased progress and typed cancellation. Address Astra review findings with regression coverage.

Validated the combined main tree with all eight cargo xtask ci gates (3,462 passing test executions; zero failures), fresh 30k import/persistence/metadata checks, duplicate-free same-session and reopened reimports, and visually inspected headless screenshots. Historical performance comparisons apply to the f730805d production changes before main integration; native Windows import/GUI acceptance remains unqualified.

Generated with Codex.
2026-10-15 03:44:15 +02:00
Nathaniel LedfordandClaude Opus 5.5 62da9e8581 LRC-LIB-LIBFOLDERS: drag photos from the grid onto a Folders row to move them there
Photos dragged from the grid onto a Folders row move there on disk and in the library
(`photo.moveToFolder`: files and XMP sidecars, virtual copies follow, never overwrites, one undo
step), as Move Selected Photos Here in the row's menu does.
- The row lights up, and the label following the pointer says where they go: "Move 2 photos to
  “Porto”" (onto an album the same gesture only adds them, so the two read apart).
- A closed folder held under the pointer for 0.7 s opens, so a folder inside it can be reached.
- Refused, with the reason on release and a not-allowed pointer: a row that covers several disks,
  and Local photos (not in the library). Photos already there say "Already in “Porto”".
- A drop asks first, as Lightroom Classic does: "Move 2 photos to “Porto”?" (their files and
  XMP sidecars move on disk; Edit → Undo moves them back), with Don't ask again, kept in Settings
  as "Confirm before moving photos to another folder on disk" (on by default). The menu's Move
  Selected Photos Here, chosen by name, goes at once. A question left open while another library
  opens (the menu bar and agents reach past a dialog) moves nothing: photo ids are per library.
- The toast says how many moved and that Edit → Undo moves them back; the menu item says the same.
- Photos that leave the view leave the selection, so a Delete or edit next can't reach them unseen.

For NAS and network shares: the copy across volumes now streams (it read the whole file into
memory, a problem for a large raw or video) into a free hidden name that takes the photo's name only
once complete (a share dropping mid-copy left a truncated file under the photo's name, which a
retry reported as the photo already there). New engine tests cover a share going away:
Undo with the share offline or read-only is refused with the reason and kept until it can run,
nothing is deleted and the library stays linked; a connection lost partway through a move puts
back what moved; a file the share can't give back rolls the whole Undo back; and a real
move across devices where the machine has a second file system (`/dev/shm`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 20:58:08 -04:00
Alex ChambersandClaude Opus 5.5 206680fb22 LR-VIEW-BEFOREAFTER: animate both panes during click zoom
Translate the shared animated image rectangle into the Before pane for
whole-frame drawing, cached window tiles and input mapping. Translate the
final target separately so render requests stay stable during the motion.

Cover intermediate mesh bounds and final geometry in both layouts,
including clicks in either pane, return to Fit and cached region tiles.

Fixes #1821

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 02:24:48 +02:00
Michael Anderson e5c6e17bdb LR-MASK-BRUSH: Shift-click draws a straight brush stroke from the last one
A Shift-click with the brush paints a straight line from where the last stroke ended, tapering size, feather and flow when they changed in between, as one undo step. mask.brushStroke takes connect: true for it.
2026-10-14 19:11:34 -05:00
Jason Baldwin 70a12af9a2 LR-IMP-LOCAL: browsing a Local folder keeps or picks the active photo (#1447)
library.browse (engine and the UI's background read) switched the source to the
folder without touching the selection, so the previous view's photo stayed
active: Photo Grid marked nothing, and Detail, the histogram and the info
showed a photo the folder doesn't hold. Browsing now follows library.source's
rule through a shared Session::keep_active_in_view: the active photo stays when
the folder shows it, else the folder's first photo becomes active (also as the
background read's batches arrive).
2026-10-15 00:57:42 +02:00
Jason Baldwin 5c5370fc9b LR-LIB-REMOVE-ALBUM: removing a photo from an album keeps it in its folder (fixes #1805)
In an album the Delete key ran photo.delete, which moved the photo to
Recently Deleted, so it also left its folder views. It now removes the
selection from the album only (album.removePhotos), as in Lightroom; in a
smart album it changes nothing. Photo > Remove from Album shows in normal
albums with the Delete key; Photo > Delete Photo still deletes from the
library. album.removePhotos defaults to the album on screen and returns
{removed, album}.
2026-10-15 00:54:17 +02:00
Jason Baldwin b5169e907c LR-META-XMP: radial masks keep their inside/outside from Lightroom (fixes #1815)
crs:Flipped="true" is how Lightroom Classic writes an ordinary radial mask
(effect inside); it was read as our invert, so every imported radial applied
outside the circle. Established from Lightroom Classic 15.6's exports of
synthetic DNGs:

- MaskGroupBasedCorrections, Version 2: Flipped is the effect-inside flag;
  inverting is the component's MaskInverted.
- MaskGroupBasedCorrections without Version: inside whatever Flipped says
  (Lightroom rewrites both values as Flipped=true, Version=2), and its Feather
  is halved, as Lightroom rescales it on that upgrade.
- Legacy CircularGradientBasedCorrections Radial Filter: outside by default,
  Flipped=true (Invert Mask) is inside.

One mapping serves XMP sidecars, DNG-embedded XMP, presets and .lrcat catalog
import. LightCraft writes no crs: masks, so there is no writer to match.
2026-10-15 00:53:53 +02:00
Nathaniel LedfordandClaude Opus 5.5 d0a9ca09dd Buttons: one component with kinds, sizes and icons
Buttons were egui's plain one, a fill set by hand where one had to stand out (a dialog's confirm,
About's Discord link), with no hover or press shade on a filled one and no shared sizes.

- `crate::button::Button`: what it is for (`Kind`: Primary filled with the accent, Secondary
  with a neutral fill and a border, Danger filled red, Ghost with no fill until hovered), how
  big (`Size`: Small 24, Medium 30, Large 36 points, each with its padding, text and icon size),
  and what it shows (text, an icon before the text, or an icon alone, which takes a name for
  screen readers and its tooltip).
- Hover and press darken it; disabled (or in a disabled part of the window) fades it and takes
  no click, its tooltip or name still shown; a focused one shows an accent ring. A filled kind's
  fill is darkened as little as needed for white to read at 4.5:1 (the light themes' accent and
  the red would be too pale), in every state. Drawn within its own rectangle.
- Named for screen readers, registered for scripts and tests (`.widget(id)`). Its egui id comes
  from the widget id (salted with `.id_salt`, e.g. the dialog's kind, so the keyboard's place
  doesn't carry from one dialog to the next) or from its place in the ui, moved on so buttons
  with the same text side by side stay apart.
- Dialogs' footers (Cancel, the confirm; at least 72 points wide) and About's Discord link use
  it. The Export dialog's expected height in `tests_dialog_fit` grows by the 8 points of its
  footer's 30-point buttons.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:57:58 -04:00
Nathaniel LedfordandClaude Opus 5.5 f50372d808 Dialogs: the confirm button is on the right, filled when it is the next step
A design critique of the first run found the import review's "Import N Photos" a plain button at
the bottom left beside Cancel, though the welcome before it had taught that blue means go.

- Every dialog's footer is right-aligned: the confirm on the right, Cancel to its left, added in
  that order so the keyboard goes through them as the eye does. The row spans the width the
  window gives its content this frame, so it reaches the window's edge without widening it.
- The confirm is filled with the accent when it makes or brings in something (`confirm_style`);
  Delete and Remove, and an informational dialog's Close, stay plain. Which dialogs only show
  something is one list (`only_shows`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:11:36 -04:00
Guillem Hermida 053b7420fe LR-CROP-STRAIGHTEN: turning a crop shrinks it about its centre instead of swapping it for the largest crop (#1794)
CropGeometry::with_angle replaced a crop that no longer fit at the new
angle with the largest centred crop of its aspect. For a crop dragged in
from a corner (which still touches two edges) that happened at the first
fraction of a degree, so the crop jumped back to nearly the whole photo.

A crop that no longer fits now shrinks about its own centre, keeping its
aspect, to the largest size that fits there. The full photo, or a crop
an earlier turn shrank to the largest of its aspect, still follows the
largest crop and grows back towards 0 degrees (#1388). A crop whose
centre is off the turned photo is centred at its own size at most. No
crop the user made ever grows.
2026-10-14 23:09:11 +02:00
FredApps 6d493c9c73 Open the active grid photo with Enter 2026-10-14 22:23:01 +02:00
Michael Anderson 8283ae1687 LR-PREF-GENERAL: Keep the Settings window in place when switching tabs
Anchor Settings at its top edge instead of the center and don't let it get narrower, so the tab row stays under the pointer.
2026-10-14 14:12:36 -05:00
Michael Anderson e65b97e239 Model downloads: Time out and cancel the name lookup (#1532)
The host name lookup blocked with no deadline before the cancel check, and each address then got the full connect timeout. The lookup now runs on a helper thread under the connect deadline, which all addresses share.
2026-10-14 13:56:34 -05:00
Michael Anderson 1f87328c6d Never crash: Write preview cache files from one bounded writer (#1522)
Each deferred cache write started its own thread holding its image, with no limit. One writer thread per cache now takes them in turn, and a write is skipped once 128 MB is waiting.
2026-10-14 13:56:34 -05:00
Michael Anderson 6d080de447 Never crash: Check raw data size before allocating in PEF, TIFF tiles and ARW6 (#1512)
A compressed PEF too short for its size, an uncompressed tile claiming far more samples than it holds, and an ARW6 with a failed tile now get refused before the big buffer is allocated.
2026-10-14 13:56:34 -05:00
Michael Anderson 9ef40b9886 Commands: Refuse malformed photo ids instead of using the selection (#1506)
A wrongly typed id or ids fell back to the selection, or kept only the valid part of the list. Session::targets now returns an error for those, and callers pass it on.
2026-10-14 13:56:33 -05:00
Michael Anderson 30ec48d9b3 LR-META-XMP: Retry automatic XMP sidecar writes that failed
A sidecar write that failed because the folder was offline or read-only was only logged. Keep those photos waiting, write them again once their files are reachable, and tell the user.
2026-10-14 13:56:23 -05:00
Davit MatchakhelidzeandClaude Opus 5.5 af0c1638fe i18n: Georgian (ka) interface language
Adds Georgian (ქართული, code ka, system tags ka / ka-GE / ka_GE) with
complete plain and formats catalogs, the Edit > Language command and the
Settings choice. Sentence-cased messages go through i18n::upper_first,
which leaves Georgian letters alone (upper-casing Mkhedruli would turn it
into Mtavruli). The Settings language choices wrap now that eleven
endonyms no longer fit on one line, and the face-model Remove button goes
through tr().

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YMTAbGNRxnMEzRvYnQGphF
2026-10-14 22:50:28 +04:00
Michael Anderson ef3642c39f LR-IMP-CAMERA-COVERAGE: Nikon D600, D610 and D5000 NEFs drop the columns past the image (#1627) 2026-10-14 13:44:58 -05:00
Michael Anderson 4352147910 Faces: Drop faces made from a photo's old file when it is replaced (#1524) 2026-10-14 13:19:22 -05:00
Marco Arnulfo 2df471b142 Top bar: in full screen the left buttons move into the traffic lights' space (fixes #1763) 2026-10-14 20:19:21 +02:00
Michael Anderson bb9d3d4022 Catalog and downloads: Don't write through a link at a temp file's name (#1502) 2026-10-14 13:13:27 -05:00
Nathaniel LedfordandClaude Opus 5.5 18e808c08f LR-BEHAV-EMPTY-STATES: an empty library leads to Import
A library with no photos opened on the Detail view, whose empty state said "Choose a photo in
the grid or filmstrip" while the grid was empty and hidden: the only screen that mentioned
import was off screen, and Import itself was nowhere but the File menu and its shortcut.

- An empty library (no photos, or only deleted or browsed ones) opens on the Photo Grid with the
  sidebar (Square Grid stays as it is), in the desktop app and in `lightcraft-cli snapshot`. The
  desktop app switches before it notes what its settings file holds, so the switch alone isn't
  saved.
- The grid and the Detail view show "Your library is empty" with Import Photos… (primary) and
  Import Lightroom Catalog… (not on the web) as buttons, and a line saying photos and folders
  can be dropped into the window, with the key Import Photos… is bound to now (`⌘⇧I` on macOS,
  `Ctrl+Shift+I` elsewhere, or a remapped one). Not while a folder is browsed under Local or
  Recently Deleted is shown: their photos aren't in the library but are on screen.
- The right-hand panel says "No photos yet / Import photos to get started" there instead of
  "Select a photo to edit".
- The top bar has an Import button beside Export in every library. The centred search field's
  reserve grows by both sides' share (620, and a 190 minimum), so the filter icon stays clear of
  the icons on the right at every window width, also with macOS's title bar in the window. The
  top bar's icons are named for screen readers, and a refused click says why in a toast.
- `empty_state` is `empty_message` with buttons that do the next step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 14:03:50 -04:00
BuonBredaandClaude Opus 5.5 4551790eab LRC-DEV-LOUPEOVERLAY: a layout image over the loupe (View ▸ Loupe Overlay)
Lightroom Classic's Loupe Overlay ▸ Layout Image: a PNG with transparency (a
cover's masthead and cover lines, a banner's safe areas) drawn over the photo
in the loupe, fitted and centred, following zoom and pan. Opacity and matte
(the photo darkened outside the graphic's box) in steps, ⌥⌘O shows / hides it,
the choice is saved with the UI state. The file is read off the UI thread; an
unreadable one is reported on the canvas. engine::export::read_graphic is the
watermark logo's reader, now shared.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mj2w3LwYjFhMHALZuFp2rU
2026-10-14 19:32:06 +02:00
LabDennis 1f4aaaec47 Fonts: finish Thai fallback delivery for desktop and web releases
Retain the complete reviewed change, including prior integration resolutions,
on current upstream.

#736: deliver Thai UI fonts in desktop and web releases

Use the merged craft-fonts input containing Noto Sans Thai across release,
FreeBSD and Nix builds. Retain the small Thai face in the wasm subset and
reject required release inputs that lack it. Exercise the reported Thai
folder name through all UI families and include original font licence texts
in Windows installers as well as portable packages.

Refs #736; completes delivery of the fallback added in #750.

Validation: UI tests, UI-only strict Clippy, 28 wasm checks, HEIF checks,
assets, layers, parity and formatting pass. All 21 unrelated workspace
failures reproduce with upstream Rust sources and the old font input;
existing Rust 1.95 metadata/engine Clippy findings remain unchanged.
2026-10-14 18:52:15 +02:00
thanat0sandGPT-6-Sol medium 37b8c256ad LRC-LIB-PEOPLE: confirm ranked face suggestions in one batch (#1442)
Co-Authored-By: GPT-6-Sol medium <noreply@openai.com>
2026-10-14 18:40:52 +02:00
Claude 05352e18dd Merge storytold/lightcraft main into LR-MERGE-HDR (white balance)
Brings in batch 35 / v0.8.0. Code merged cleanly; conflicts only in docs: the LR-MERGE-HDR row keeps main's
lens-correction text plus this branch's white-balance item, and this branch's What's New entry moves to the
2026-10-14 section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gRtdWF1E9358FfzhzYqCS
2026-10-14 16:22:53 +00:00
Claude ac17c580f5 Merge storytold/lightcraft main into LR-MERGE-HDR (frame order, clipped pixels)
Brings in #1423 (HDR merges keep the lens corrections), which landed in batch 35 / v0.8.0. hdr.rs merged cleanly:
the result's lens corrections come from the reference frame after the brightness ordering. Conflicts only in docs:
the LR-MERGE-HDR row keeps main's lens-correction text plus this branch's two items, and this branch's What's New
entry moves to the 2026-10-14 section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015gRtdWF1E9358FfzhzYqCS
2026-10-14 16:22:37 +00:00
Marco Arnulfo 17e05759b4 DNG export and Convert / Copy as DNG write the colour a raw without matrices opens with (fixes #1745) 2026-10-14 18:08:53 +02:00
Michael Anderson e8818281d5 LR-IMP-LOCAL: Forget deleted files when browsing from the sidebar too
The sidebar reads the folder on a worker thread and skipped the cleanup library.browse does, so the fix for #1392 didn't reach the app.
2026-10-14 10:40:41 -05:00
G6billandCopilot App 877ef342dd MCP-CONTROL: validate remote reply framing and IDs (#1716)
The connect-mode MCP client accepted any newline-less or wrong-id reply as
the answer to its request. Require a complete newline-terminated reply of
at most 64 MiB, the matching integer id, boolean ok and a result or string
error; otherwise close the connection and report an unknown outcome without
resending. Idless pre-dispatch refusals from the control server still work.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
2026-10-14 15:25:13 +02:00
aGiuliano eac616b542 Merge branch 'main' into fix/Chinese_Japanese_Text_warning 2026-10-14 14:53:25 +02:00
Jason Baldwin 3aa6b3ba31 Merge slideshow-templates into slideshow-export (origin/main: batch 35)
# Conflicts:
#	docs/parity-checklist.md
2026-10-14 14:42:03 +02:00
Jason Baldwin 5f3bdbcb73 Merge slideshow-titles into slideshow-templates (origin/main: batch 35)
# Conflicts:
#	docs/parity-checklist.md
2026-10-14 14:39:47 +02:00
Jason Baldwin 7919c1471d Merge slideshow-overlays into slideshow-titles (origin/main: batch 35)
# Conflicts:
#	docs/parity-checklist.md
2026-10-14 14:37:20 +02:00
Jason Baldwin f776d98167 Merge slideshow-composer into slideshow-overlays (origin/main: batch 35)
# Conflicts:
#	docs/parity-checklist.md
2026-10-14 14:35:02 +02:00
Jason Baldwin 2b766142bc Merge origin/main into focus-point (tracker header/summary/change log, whats-new entry moved under 2026-10-14) 2026-10-14 14:33:49 +02:00
Michael Anderson ead24aded9 LR-PROF-CAMERACOLOR: Add a bundled Nikon D5300 camera profile
Fitted with lightcraft-cli calibrate to 264 of my own D5300 photos.
2026-10-14 07:32:56 -05:00
Michael Anderson 975b08c334 LR-PROF-CAMERACOLOR: Add a bundled Nikon Z 6II camera profile
Fitted with lightcraft-cli calibrate to 296 of my own Z 6II photos.
2026-10-14 07:32:56 -05:00
Michael Anderson 2bc2f60277 LR-PROF-CAMERACOLOR: Add a bundled Nikon Z 8 camera profile
Fitted with lightcraft-cli calibrate to 261 of my own Z 8 photos.
2026-10-14 07:32:56 -05:00
Michael Anderson c854e172e4 LR-PROF-CAMERACOLOR: Match the camera look against lens-corrected JPEGs
The fit compared the uncorrected raw with the corrected JPEG. It now warps the raw with the file's own lens correction when that lines up better.
2026-10-14 07:32:47 -05:00
Michael Anderson 441f46683a LR-IMP-DEVICE: Show the import review when a card is connected
Adds an option under Settings > Import > Cameras and Cards that opens Import from Device when a camera or memory card shows up. It's off by default, and a card that was already in at startup doesn't ask.
2026-10-14 07:32:47 -05:00
Michael Anderson 1acbf88661 LR-META-INFO: Show the lens for Nikon DSLR raws
They don't write a lens name, so read the range from the maker note's Lens tag.
2026-10-14 07:32:46 -05:00
Michael Anderson 02d5d6bc03 LR-MERGE-PANO: Keep panoramas at full resolution when memory allows (#1455)
Drop the 40 MP default and free each photo's pixels once it's projected.
2026-10-14 07:32:45 -05:00
Michael Anderson b0b86aca84 LR-BEHAV-GPU: Turn GPU rendering off after the GPU is lost while running (#1337)
Report it as LightCraft stopping instead of the window failing to open, and start on the CPU next time.
2026-10-14 07:32:44 -05:00
Michael Anderson 697010d520 LR-IMP-LOCAL: Forget untouched records of deleted files when browsing a folder again (#1392)
Rated, flagged or edited photos stay and show as missing.
2026-10-14 07:32:43 -05:00
Jason Baldwin b60c74a6d7 Merge slideshow-playback into slideshow-composer (origin/main: batch 35)
# Conflicts:
#	crates/engine/src/import.rs
#	crates/engine/src/media.rs
#	docs/parity-checklist.md
2026-10-14 14:31:53 +02:00
Jason Baldwin 3aaadd1456 Merge origin/main into slideshow-playback (batch 35: tracker summary refreshed, slideshow rows kept) 2026-10-14 14:29:54 +02:00
Michael Anderson e0690b5f63 LR-EXP-QUALITY: Use optimized Huffman tables for JPEG exports (#1373)
Build the tables from each image's own symbol counts. Same pixels, smaller files.
2026-10-14 07:28:30 -05:00
Nathaniel LedfordandClaude Opus 5.5 d2523e8544 Preview cache: cached thumbnails are no longer taken for the person's photos
The thumbnail cache wrote .jpg files into the library's thumbs folder, which is usually inside
Pictures: photo galleries listed every thumbnail as a photo (issues #610, #1066), and every read
brought the file's date forward, so each launch made them all look new.

- Cache files are named <32 hex>.lcthumb (JPEG data as before). A .jpg of before is taken over
  under the new name when it is asked for; the rest when the cache is tidied, which the engine does
  once per cache folder, on a thread of its own with a row in the activity stack that shows its
  progress and can stop it. Nothing is rendered again.
- Reading writes nothing: what was read is remembered for the session (a full cache lets it go
  last), and only a file that went unused for a week has its date brought forward.
- A folder that holds nothing but the cache gets a CACHEDIR.TAG, when the cache makes it and when
  it is tidied; one that also holds somebody's files is not tagged (issue #98).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 08:26:17 -04:00