Commit Graph
1897 Commits
Author SHA1 Message Date
aiongg eb9ef0a40e Merge PR #2824: KEYC-METADATA: Cmd+Alt+Shift+C / V copy and paste metadata 2026-10-25 02:23:21 +00:00
aiongg 5c46163e66 Merge PR #2778: LRC-PRINT-TEMPLATES: print templates export to a file and import from one 2026-10-25 02:23:20 +00:00
aiongg f923967c63 Merge PR #2786: LRC-SS-PLAYBACK: a manual slideshow waits for the arrow keys 2026-10-25 02:23:20 +00:00
dotCooCoo cc557e189d KEYC-METADATA: Cmd+Alt+Shift+C / V copy and paste metadata
Copy Metadata and Paste Metadata had no shortcut. They now use
Cmd+Option+Shift+C and Cmd+Option+Shift+V on macOS and
Ctrl+Alt+Shift+C and Ctrl+Alt+Shift+V on Windows and Linux, the keys
Lightroom Classic's keyboard shortcut page lists for copying and
pasting metadata in the Library module. Both keys also work when
Windows and Linux deliver them as clipboard events. The KEYC-METADATA
row now lists the keys LightCraft binds (Cmd+S, the two new keys and
Alt+1 to Alt+9 for keyword sets) and every other key of that table
that is still missing. Gap 28 in docs/gaps.md and the Library keys in
docs/ui-parity.md list the two new keys.
2026-10-24 09:13:54 -07:00
Brandon Thomas 5f8593a074 Merge PR #673 2026-10-24 10:20:14 -04:00
Brandon Thomas f7d11bf750 Merge PR #1956 (with maintainer follow-up)
# Conflicts:
#	docs/whats-new.md
2026-10-24 10:20:14 -04:00
Brandon Thomas 82c39a9847 Merge PR #2011 (with maintainer follow-up)
# Conflicts:
#	docs/whats-new.md
2026-10-24 10:20:14 -04:00
Brandon Thomas d7e7639d7a Merge PR #2800 2026-10-24 10:20:13 -04:00
Brandon Thomas 3f1e5c21d6 Merge PR #2775
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-24 10:20:13 -04:00
Brandon Thomas 57c639246b Merge PR #2762
# Conflicts:
#	docs/parity-checklist.md
2026-10-24 10:20:13 -04:00
Brandon ThomasandClaude Opus 5.5 c19e1bd095 Tone Curve: What's New and parity row for the draggable parametric graph; the hover test compares with a frame away from the line
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:19:51 -04:00
Brandon ThomasandClaude Opus 5.5 0deec1251f Merge main into #673
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:14:13 -04:00
Brandon ThomasandClaude Opus 5.5 a1ee846ad6 Merge main into #2011
Resolves the parity summary (regenerated), drops a duplicated #[cfg(test)], files the What's New entry
under today's date and bumps the checklist's Last updated line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:13:16 -04:00
Brandon ThomasandClaude Opus 5.5 5ba9b48d30 Merge main into #2800
main replaced "Show Clipping" with "Clipping": the PR's Beschneidung term moves to the new key.
Also takes CodeRabbit's two wording suggestions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:08:20 -04:00
Julian ZahnowandClaude Opus 5.5 18b84f97d1 i18n(de): review the interface strings and formats messages
A pass over all 2,565 interface strings and 299 formats messages of the
German catalogs (What's New lines not included). 108 messages change:

- Lightroom terms: Tönung (Tint), Beschneidung (Clipping)
- one word per thing: Bedienfeld (panel; Bereich stays for sidebar
  sections), Begleitdatei (sidecar), Dia (slide), Zuschnitt (crop),
  Farbmarkierung (label) where "Markierung" read as the pick/reject flag,
  Verschlusszeit, Smart-Album, Perspektivkorrektur (Upright),
  Aktivitätsstapel
- "Ihre Dateien/Fotos" at the start of a sentence read as the formal
  "your" in a du catalog; rephrased
- double colons and "1 Fotos" in count messages, awkward phrasings
- spaced en dash instead of em dash, no space before a final ellipsis,
  German quotes around {profile}

The terms are listed in docs/localization-de.md; localization-parity
records the review.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 15:28:43 +02:00
dotCooCoo adf94a87cb LRC-SS-PLAYBACK: a manual slideshow waits for the arrow keys
The slideshow always advanced on its own after the slide duration.
The new Manual slideshow setting (Settings > Slideshow > Playback, or
manual in slideshow.playback and view.slideshow) keeps each slide, the
intro and the ending up until the right or left arrow or the control
bar changes it. Space, Esc, random order and repeat work as before.
Exports still use the slide duration. The setting is saved with the
library and in slideshow templates; a template without it reads as off.
2026-10-24 01:46:49 -07:00
ronibalthazar 522ae832ec fix: scope relative-date expiry to referenced albums 2026-10-24 07:28:51 +01:00
dotCooCoo 59e9a6a4f3 LRC-PRINT-TEMPLATES: print templates export to a file and import from one
The Print dialog's templates could be saved, applied and deleted, but
not moved to another library or another computer. Each saved template
now has an Export… button that writes it to a .lcprint file, and
Import… beside Save adds templates from such files.

print.template.export {name, path} writes {format, version, name,
settings}. print.template.import {path} reads at most 256 KB, checks
the format, version, name and every setting as a saved template's
settings are checked, drops cell photos and guides, and adds the
template under its name, or under "name (2)" and so on when the name is
in use. The buttons appear where the host provides open and save
dialogs: the desktop app does, and the web build does not.
2026-10-23 23:18:35 -07:00
ronibalthazar 18c56f03d4 fix: expire relative-date view caches on minute change 2026-10-24 07:02:22 +01:00
francoisgnandClaude Opus 5.5 cf93349071 Merge #2701@9c7bdbd44 (exists docs, root-safe permission test) into round3a-integration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 06:56:55 +03:00
francoisgnandClaude Opus 5.5 1b22c3b870 Round 3a: cull takes the view before an open drag ends; language commands listed
CodeRabbit on #2689 (head 496291276):
- `cull` takes the view it hands on from before ending an open drag, so the
  drag's own commit can't change it first. (In practice the view already
  follows the drag's preview, so the photo is out of it mid-drag either way;
  this is the order every caller should use.)
- LR-BEHAV-LOCALE cites the commands of all 18 languages.
- Two 2026-10-21 revision rows moved above the 2026-10-20 ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 06:56:54 +03:00
francoisgnandClaude Opus 5.5 9c7bdbd44c #1290: exists docs match the code; the permission test skips as root
CodeRabbit on #2689 (head 496291276):
- docs/control-protocol.md, `app.recentLibraries`'s doc, `is_missing`'s
  doc: a folder that can't be listed is `exists: null` (couldn't tell), not
  `false`, since 142e496f5; the launch window still shows why for every
  reason.
- a_failed_lookup_doesnt_mark_a_recent_library_missing skips (System) when a
  folder with no permissions can still be read, as when running as root.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 06:54:39 +03:00
francoisgnandClaude Opus 5.5 496291276c Merge PR #2468@218e7451c (its main merge) into round3a-integration
Its code is already in the batch; docs keep the batch's version, headers list
#2468's change entries too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:50:46 +03:00
francoisgnandClaude Opus 5.5 538b261067 Merge upstream/main (#2763) into round3a-integration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:50:04 +03:00
Dylan M. TaylorandCodebuff 4ae3089420 security: bounded keyword, repair and journal-recovery work (CodeRabbit) (#2763)
* security: harden dev-tool scripts and the testkit skip-log test (CodeRabbit)

- tools/install-sam3.sh: the HF bearer token went through curl's argv, where
  `ps` exposes it to other local accounts (CWE-214); it now travels through
  a private 0600 temp config file removed on exit.
- packaging/macos/import-cert.sh: the decoded .p12 was written to a
  predictable path in a shared TMPDIR, where a precreated attacker-readable
  file would receive it (CWE-377); both cert and keychain are created inside
  a mktemp -d 0700 directory now.
- docs/showcase/run.py: the reply reader copied whole responses with no size
  cap (obvious quadratic-copy and unbounded-memory DoS). It accumulates in a
  bytearray now and closes the connection past 128 MiB.
- tools/spectral_camera_table.py: alias/make/model strings and comments from
  the rawtoaces-data checkout moved directly into Rust source; one newline in
  a comment became Rust code. External text is now escaped as Rust literal
  content and comments are normalized to one printable line.
- crates/testkit: appended_lines_accumulate reused a pip-predictable temp
  dir by creating it with create_dir_all and carried on after failing to
  remove its log path, so the append would follow an attacker-planted
  symlink (CWE-59); it now fails the test if the directory exists instead of
  testing through it, and removes any existing log path only after clearly
  checking it, always failing the test instead of proceeding when removal fails.

Findings #10080/#10078 PR (rows 2, 6, 8, 9, 15 of the
storytold-lightcraft-agent-findings report).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

* security: bounded catalog keyword, repair, journal recovery work (CodeRabbit)

- keywords: from_file searched every hierarchical level for each flat keyword
  and `same` lower-cased two strings per comparison — one lowered level set
  instead (CWE-407, row 97).
- keywords: parse_keyword_list scanned each keyword's growing synonym list per
  line — a lowered-synonym set per keyword instead (CWE-407, row 100).
- keywords: keyword_tree stored every level's prefix twice, so a photo XMP
  keyword nested deeper than a list file accepts made stored bytes quadratic
  in the level count; the tree caps at MAX_LEVELS, and keyword_list_text names
  whatever lies deeper from the photos' and list's own spellings, so the file
  still reads back (CWE-400, row 103).
- catalog: repair validated a folder chain once per album — memoized by chain
  now, so a valid chain in a flat snapshot costs one walk overall (CWE-407,
  row 101).
- store: journal append and truncate follow a planted catalog.log symlink;
  both refuse any non-regular file at the name before writing through it
  (CWE-59, row 107), like the staging writes since #1502.
- journal: resync re-validated the whole remaining suffix UTF-8 for every
  candidate record start; a whole line is validated once (covering every
  candidate in it), and an invalid line's re-checks stop at a 64 MiB budget,
  with the tail then staying a torn one the damaged path keeps and reports
  (CWE-407, row 109).

New tests: from_file case-insensitive level match, synonyms kept once, a
4096-level keyword cut at MAX_LEVELS, a link at catalog.log refused, and
resync over a fragment of 1024 record starts.

Findings rows 97, 100, 101, 103, 107, 109 of the
storytold-lightcraft-agent-findings report.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>

---------

Co-authored-by: Codebuff <noreply@codebuff.com>
2026-10-23 22:45:21 -04:00
francoisgnandClaude Opus 5.5 8ada8a196a Merge #2701@142e496f5 (a failed lookup isn't "not found"; no timer on found libraries) into round3a-integration
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:34:24 +03:00
francoisgnandClaude Opus 5.5 142e496f5b #1290: a failed lookup isn't "not found"; recent libraries aren't checked on a timer
CodeRabbit on #2689:
- `unavailable` used `exists()` / `is_dir()`, which are false for any
  error: a parent folder that can't be read or a share that timed out came
  out as "Not found" and greyed the entry out. Only an absent path is "not
  found" now; other lookup errors are "This library couldn't be checked:
  <reason>" (LookupFailed), and a folder that refuses to be listed is no
  longer counted as missing either (it is there: permissions, macOS
  privacy), so neither is greyed out and opening says why.
- Every recent library was checked again every 30 s while the app ran,
  waking external drives and network shares. A library not found is looked
  for again every 30 s (a drive plugged back in; an absent path wakes
  nothing); the others only when the window comes back to the front, for
  the 8 entries shown; paths never checked are checked once.
Tests a_failed_lookup_doesnt_mark_a_recent_library_missing and
recent_libraries_are_checked_again_only_when_the_window_comes_back fail with
the old lookup / the old timer / no timer for libraries not found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:34:11 +03:00
francoisgnandClaude Opus 5.5 dc3263065e Round 3a: an open slider drag ends before a rating or a deletion moves the selection on
CodeRabbit on #2689 (head 02743d187):
- crates/engine/src/cmd/library.rs: `cull` (#2327: a rating, flag or label
  that takes the active photo out of the view) and `photo.delete` /
  `photo.deletePermanently` moved the active photo without ending an open
  interaction, unlike `step` and `library.select`: the drag stayed open with
  no undo step. Each ends it now before its own change, so the drag is its
  own undo step and comes first: undo brings the rating or the photo back,
  with its edit, then the edit (Delete Permanently's undo restores the
  edit too). Test an_open_edit_ends_before_the_selection_moves_on (rating,
  delete, delete permanently) fails without the fix.
- docs/parity-checklist.md (LR-BEHAV-LOCALIZE) and docs/localization.md: list
  every shipped language (Polish, and the others the row lacked; Italian in
  the localization doc).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 05:30:45 +03:00
Nathaniel Ledford 7995a0062b LRC-LIB-FILTERBAR: showing an album drops the album the filter held
library.source cleared the filter's library folder when a library folder became the source, but not the filter's album when an album did. LibrarySource::to_filter makes the album shown replace the filter's, so the grid was right; but the filter bar has no album chip, so the old album stayed in the filter unseen and narrowed the next source (All Photos, Picks). As for a library folder, the one shown now wins.
2026-10-23 21:58:19 -04:00
midasdf 218e7451c0 Merge remote-tracking branch 'origin/main' into jp/photo-paper-sizes
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-24 10:08:32 +09:00
francoisgnandClaude Opus 5.5 02743d187d Merge PR #1922@6c17d29ae (middle-button pan whatever the tool) into round3a-integration
crates/ui-egui/src/lib.rs: the batch's module list (tests_capture_time) with
#1922's. LR-VIEW-ZOOM: the batch's row plus #1922's middle-button sentence.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:45:31 +03:00
francoisgnandClaude Opus 5.5 c5df3eea40 Merge #2701@f56e8c67a (its upstream merge) into round3a-integration
Docs only, and the batch's side already holds everything #2701's merge
resolved (its rows that differ are main's rows other batch PRs edited).
Tracker summary recomputed (`cargo xtask parity --write`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:43:16 +03:00
francoisgnandClaude Opus 5.5 f56e8c67a7 Merge upstream/main (integration batch 43) into feat/issue-1290-launch-library-choice
docs/parity-checklist.md: header lists both sides' changes, revision rows of
both sides newest-first, summary recomputed (`cargo xtask parity --write`).
docs/whats-new.md: #1290's entry joins upstream's 2026-10-23 section.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:32:25 +03:00
francoisgnandClaude Opus 5.5 987c54bb51 Merge PR #1499@8d71b7999 (graphic watermarks and HDR JPEG size limits, onto batch 43) into round3a-integration
docs/parity-checklist.md: header lists both sides' changes; #1499's two new
dated prose entries (2026-10-23, 2026-10-24) become revision rows like its
two earlier ones, so the history stays one table.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:27:33 +03:00
francoisgnandClaude Opus 5.5 144d900c21 Merge upstream/main (integration batch 43, #2729, #2737, #2412) into round3a-integration
Conflicts:
- apps/lightcraft/src/native_menu.rs: upstream's item swapping (macOS keys
  given up for real, Help menu not swapped, Settings / Quit tracked) with
  KEY-GRID's keymap-aware rows. `Item.label` stays the text the row shows
  (native_item_presentation), so `Item::native_label` reuses it instead of
  formatting it again; Settings / Quit store theirs through
  display_item_label, as upstream's native_label did. No early return after
  a rebuild (upstream).
- crates/ui-egui/src/i18n.rs: upstream's tests (#2729: one test per check
  across languages, gaps reported, never a failure) plus the batch's two new
  ones (dropped-photos notice, Polish counts); production code as merged.
- grid.rs, keyword_list.rs, masking.rs: the translation tests #2729 removed
  stay removed; the batch's new keyword and segmenter tests stay.
- cmd/library.rs, ui-egui/src/lib.rs: both test modules, each with its
  #[cfg(test)].
- xtask/src/main.rs: #2302's test_selected and upstream's translation_gaps.
- docs: tracker / gap rows take both sides' edits, headers list both sides'
  changes, history rows of both sides newest-first. What's New: one section
  per date, newest first (the batch had 10-22 above 10-23, and second 10-21
  and 10-19 sections); no line lost.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 02:26:48 +03:00
KetbomeandClaude Opus 5.5 6c17d29aed LR-VIEW-ZOOM: a middle-button drag pans the photo whatever tool is active
In Detail, dragging with the middle button (the mouse wheel pressed) pans the
zoomed photo with a hand cursor, in every tool. Remove / Heal / Clone, the
mask brushes and Crop no longer have to be left to look around a zoomed photo,
and they don't paint or move during that drag: it is handled with the pinch and
scroll gestures, before the tool overlays.

Right-click keeps the photo's context menu and Space keeps the zoom toggle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 20:17:57 -03:00
deunderscorepaulanddeepseek-flash 79e1dea851 Histogram: drag its tonal zones to adjust the Basic tones
Lightroom Classic's histogram is a control surface: its plot is split into five
tonal zones and each one moves the Basic control it names. The Edit panel's
histogram now does the same, wired through the engine like every slider.

- Zones: Blacks 0.00-0.15, Shadows 0.15-0.35, Exposure 0.35-0.65, Highlights
  0.65-0.85 and Whites 0.85-1.00 of the plot's width, each naming the develop
  control it adjusts (light.blacks ... light.whites), so its range, default and
  steps are the panel's own control specs -- no copy of them.
- The zone the press landed in stays locked for the whole drag (the new
  Gesture::HistogramDrag), so the pointer may cross the others without switching
  control. The strip under the plot (the readout and the EXIF line) and the
  clipping buttons in the plot's top corners are not zones.
- A sideways drag dispatches develop.set between develop.beginInteraction and
  develop.endInteraction -- the sliders' own path -- so the draft render follows
  the drag live, nothing is committed while it goes on, and the release lands the
  whole drag as one undo step. Travel of the plot's width sweeps the control's
  whole range (Shift a tenth, as the sliders' fine drag) and clamps to its spec;
  the unrounded value is carried from frame to frame so a slow drag adds up
  rather than rounding back to the step it already has, and the first reported
  frame takes the whole travel from the press, since egui withholds a drag until
  the pointer has left its click threshold.
- Hovering a zone tints it and names it with its value in the strip under the
  plot ("Exposure: +0.45 EV"), replacing the EXIF line, and the pointer shows the
  sideways-resize cursor. A double-click in a zone puts that control back to its
  default in one undo step.

Tests: the zone mapping at every boundary, the tiling and the controls' specs,
the drag/rounding/clamping arithmetic (hostile input included) and the readout
wording; end to end through the control channel: a drag per zone, the zone lock
across the plot, the Shift ratio, clamping at both ends, live dispatch with one
undo step on the release, the double-click reset, the hover highlight, readout
and cursor, and a drag on the readout strip or clipping chevrons changing nothing.

Docs: the tracker's LRC-DEV-HISTOGRAM-DRAG row added and LR-VIEW-HISTOGRAM's
"no drag-to-adjust" note replaced, with the summary regenerated by
`cargo xtask parity --write`; a dated entry in docs/whats-new.md.

Sources: own design; the zone layout and Lightroom Classic's histogram-region
behaviour as the reference (observed read-only).

Co-Authored-By: deepseek-flash <noreply@deepseek.com>
2026-10-24 00:17:07 +02:00
nevicia2010-hub 8d71b79993 LR-EXP-WATERMARK: integrate batch 43 while preserving export fixes 2026-10-24 00:14:33 +02:00
nevicia2010-hub 11bbada692 LR-EXP: integrate upstream export changes and parity records 2026-10-24 00:01:09 +02:00
Brandon ThomasandClaude Opus 5.5 82eef5b266 Integration: What's New lists 2026-10-23 above 2026-10-22
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 17:21:34 -04:00
Brandon Thomas 73f1b4906e Merge PR #2622
# Conflicts:
#	docs/gaps.md
2026-10-23 17:21:18 -04:00
Brandon Thomas 1acd2938ea Merge PR #2546
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-23 17:21:18 -04:00
Brandon Thomas 708e8a8bfc Merge PR #2688
# Conflicts:
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-23 17:21:17 -04:00
Brandon Thomas 92bd08ba5c Merge PR #2618
# Conflicts:
#	docs/whats-new.md
2026-10-23 17:21:17 -04:00
Brandon Thomas bbf9b713f2 Merge PR #2526
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-23 17:21:17 -04:00
Brandon Thomas e700170dc6 Merge PR #2727
# Conflicts:
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-23 17:21:17 -04:00
Brandon Thomas b106ceaca1 Merge PR #2621
# Conflicts:
#	docs/whats-new.md
2026-10-23 17:21:16 -04:00
Brandon Thomas 4d9914d4db Merge PR #2709 2026-10-23 17:21:16 -04:00
Brandon Thomas d9db2d32e7 Merge PR #2596 2026-10-23 17:21:16 -04:00
aiongg b264557916 i18n: missing translations are reported, never a failure (#2729)
A message a catalog lacks, or translates as an empty string, shows in
English and fails nothing:

- build.rs no longer requires every formats catalog to carry the same
  messages, and tr_format! gets a last arm that formats the English
  source, so a message no catalog has builds.
- Coverage tests (every language translates X) and tests of one
  language's exact wording are gone; the language-switching, layout,
  date, placeholder and user-value tests read the catalog's own value
  instead of a hard-coded translation.
- i18n::tests::translation_gaps_report lists, per language, the plain
  and format messages it lacks and its untranslated What's New lines.
  It always passes; cargo xtask ci
  runs it from the test step's binary after the tests.
- catalogs_load checks that every catalog file is a JSON object of
  strings with each key once; it.json named "Dimensions" twice.
2026-10-23 16:42:28 -04:00