Commit Graph
350 Commits
Author SHA1 Message Date
francoisgn 9578651eab Merge PR #2541: Make control-server timeout tests independent of client resc 2026-10-22 22:31:14 +03:00
francoisgn 007047a3bb Merge PR #2205: LR-IMP-DRAGDROP: files dragged over the window show what a d
# Conflicts:
#	crates/ui-egui/locales/cs.json
#	crates/ui-egui/locales/de.json
#	crates/ui-egui/locales/es.json
#	crates/ui-egui/locales/fi.json
#	crates/ui-egui/locales/fr.json
#	crates/ui-egui/locales/id.json
#	crates/ui-egui/locales/it.json
#	crates/ui-egui/locales/ja.json
#	crates/ui-egui/locales/ka.json
#	crates/ui-egui/locales/pl.json
#	crates/ui-egui/locales/pt-br.json
#	crates/ui-egui/locales/ru.json
#	crates/ui-egui/locales/sv.json
#	crates/ui-egui/locales/uk.json
#	crates/ui-egui/locales/vi.json
#	crates/ui-egui/locales/zh-hans.json
#	crates/ui-egui/locales/zh-hant.json
#	crates/ui-egui/src/state.rs
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-22 22:30:24 +03:00
francoisgn 927e071873 Merge PR #2453: Web: the page title names the open photo and unsaved changes
# Conflicts:
#	docs/web.md
2026-10-22 22:28:50 +03:00
francoisgn cbedf7b5b1 Merge PR #2455: Web: lightcraft.command refuses params that aren't a JSON ob 2026-10-22 22:28:42 +03:00
francoisgn 4abb3bc860 Merge PR #2430: fix(web): import picker accept list misses many raw formats 2026-10-22 22:28:42 +03:00
francoisgn 139ff42984 Merge PR #1417: Edit in PhotoCraft: say why it didn't open; find PhotoCraft 2026-10-22 22:28:41 +03:00
francoisgn cd6bc4be6f Merge PR #2513: KEY-GRID: show the cycle shortcut in the View menu (#2500)
# Conflicts:
#	docs/parity-checklist.md
2026-10-22 22:28:41 +03:00
tylerphotosandCodex 6677edd107 KEY-GRID: reconcile grid shortcut hints with current main
Preserve upstream menu additions and progress documentation while retaining
the focused grid shortcut and native ownership fix. All eight CI gates, five
Windows regressions and native acceptance passed on this exact merged tree.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-22 07:35:20 -05:00
tylerphotosandCodex 01cbf8f2eb KEY-GRID: refresh native handles when shortcut ownership changes
Include effective accelerators in the shared native menu cache key,
with a regression for same-text direct-to-cycle key transfer.
Document the touched menu helpers.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-22 07:13:14 -05:00
Alex ChambersandGPT-6 Astra ff101914bf freebsd-control-timeout: remove client scheduling races from tests
Queue fixture input before the server's next idle read. Half-close writes
before the final reply and join the worker before reading that reply.
Keep slow-work timing, ordered exact replies, empty EOF and slot checks.
Production code is unchanged. The hosted FreeBSD trigger is unproved.

Validation: cargo xtask ci passed all eight gates on macOS arm64.

Co-Authored-By: GPT-6 Astra <noreply@openai.com>
2026-10-22 08:58:10 +02:00
Nathaniel LedfordandClaude 434da7ae68 MENU-BAR: menu switches are named for what they show, and no two commands share a name
Switches read "Show Focus Point ✓" next to "Filmstrip ✓"; now every switch
is named for the thing and the check mark says whether it is on (Focus
Point, Clipping, Photo Counts, Mask Overlay, All Mask Overlays, Mask Pins,
Layout Image). Show Original stays: it is a view, not a switch.

Names that meant two things: View ▸ Detail and the Edit section Detail
(Detail View now, like Reference View), Window ▸ Edit and the Edit menu
(Edit Panel), Compare and Compare Before and After (Before/After Side by
Side, next to Split and Top/Bottom), and Clear/Discard Preview Cache (one
command, now Discard Preview Cache everywhere). New labels in all 13
catalogs. Tests: no "Show …" switch; no two menu commands share a label or
a menu's name.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-22 02:00:54 -04:00
Nathaniel LedfordandClaude Opus 5.5 d4753ae787 LR-IMP-DRAGDROP: the web drop notice is made from the import report, with a test of the mapping
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:58:51 -04:00
Nathaniel LedfordandClaude Opus 5.5 6881a8c585 LR-IMP-DRAGDROP: the web drop's notice names every outcome of the drop
Review fix: a drop that adds some photos and fails others showed only the first outcome.
`i18n::dropped_photos_outcome` joins the translated added, restored and not-readable parts with a
plain " · " and returns nothing for a drop that only found duplicates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:58:51 -04:00
Nathaniel LedfordandClaude Opus 5.5 222925c7d5 LR-IMP-DRAGDROP: a web drop whose files could not be read says so
Review follow-up: after counting what the import did, a drop where every file failed showed no
notice at all. It now says how many photos were not readable (existing translated key).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:58:51 -04:00
Nathaniel LedfordandClaude Opus 5.5 c1e3f20f5b LR-IMP-DRAGDROP: align the pl Lightroom wording and stop the web drop toasting "Added 0"
Review fixes:
- pl "Finish Lightroom catalog import before adding photos" uses "Lightrooma", as the other pl Lightroom strings do
- the web drop's toast counts imported photos, says "Restored n photos from Recently Deleted" (already translated) when it only restored some, and says nothing when it only found duplicates

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:58:50 -04:00
Nathaniel LedfordandClaude Opus 5.5 34cfc9cd3b LR-IMP-DRAGDROP: count what the web drop added, reject bad ui.dropFiles paths, and say the drop is refused during a Lightroom import
Review fixes:
- the web build's "Added n photos" toast counts the photos `library.import` reports, not the paths submitted
- `ui.dropFiles` rejects a `paths` list with a non-string entry instead of dropping part of it
- the hover card says a drop will be refused while a Lightroom catalog import is pending, and that refusal text is now translated in all 13 catalogs

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:58:50 -04:00
Nathaniel LedfordandClaude f84347a88e LR-IMP-DRAGDROP: review follow-ups
A finished scan waits for an open dialog before opening its review; drops are refused while an import runs (and, on the web, while a dialog is open); orphaned doc comment restored to builtin_label.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-22 01:58:50 -04:00
Nathaniel LedfordandClaude 266f623480 LR-IMP-DRAGDROP: show what a file drop will do and open the import review
While files are dragged over the window a veil and a card say what dropping
does (review N items, import N presets, open the face model; close the open
dialog first when one is open). Dropped photos and folders open the import
review like File > Import; Settings > Import can import them at once. A drop
while a dialog is open is refused with a toast. The web build now reports
unreadable and failed drops. Adds the control request ui.dropFiles.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-22 01:58:44 -04:00
tylerphotosandCodex 48e1cde8b7 KEY-GRID: show live cycle shortcut in View menus
Fixes #2500. Preserve direct menu selection and native accelerator ownership.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-21 22:32:43 -05:00
aiongg 67d6e1879f Merge PR #1991: Control port: don't clone the connection's socket (Windows: launched programs kept it open)
apps/lightcraft/src/control_server.rs: serve() keeps #2027's idle read timeout and #1991's single-stream serve_lines (no try_clone); #1991's Windows test passes IDLE_TIMEOUT
2026-10-22 02:37:18 +00:00
aiongg 04e20de345 Merge PR #2027: #1952: expire idle control connections
contributors/people.toml: union of new people entries
2026-10-22 02:36:51 +00:00
Dylan M. Taylor bfb23db2ca Use chrono instead of hand-rolled UTC conversion (#2457)
* Use chrono for UTC/calendar conversion instead of hand-rolled copies

Replaces the hand-rolled Howard Hinnant civil/days-from-civil copies and the
leap-year/days-in-month table with chrono as a workspace dependency:
- apps/lightcraft/src/logging.rs: timestamp (log line time)
- crates/catalog/src/dates.rs: civil + weekday
- crates/catalog/src/stacks.rs: iso_seconds (date -> seconds)
- crates/engine/src/cmd/face_recognize.rs: capture_secs (native only)
- crates/meta/src/datetime.rs: DateTime::unix_seconds and the valid() day check
Output formats and semantics are unchanged (pre-epoch clamp, day rollover that
normalize_iso relies on, leap-second tolerance, EXIF/XMP parsing). chrono uses
only std, so wasm stays safe. AGENTS.md/CLAUDE.md now say time goes through chrono.

Follow-up to storytold/cadcraft#1785

* Never panic on a clock outside chrono's range; keep 5-digit years unprefixed

chrono's From<SystemTime> unwraps, so a clock past year 262143 panicked
inside the logger. timestamp now uses the fallible DateTime::from_timestamp
and reads such a clock as the epoch, keeping the old pre-epoch clamp.

timestamp and catalog's civil write years past 9999 with {:04} like the old
{y:04} did, because %Y would add a '+'. Tests cover the out-of-range and
5-digit-year cases.

* Don't build an unrepresentable SystemTime in the far-future test

UNIX_EPOCH + Duration::from_secs(u64::MAX / 2) overflows Windows'
SystemTime and panicked before timestamp() ran, failing the Windows
test job. Build it with checked_add and only assert where it exists.

* time: preserve old out-of-range date conversion (no epoch fallback)

`DateTime::from_timestamp(...).unwrap_or_default()` silently reset any instant
past chrono's year range to 1970-01-01, changing output the old hand-rolled
Howard-Hinnant code converted exactly (e.g. 10_000_000_000_000 s was
318857-05-20 17:46:40, not the epoch). Restore the old conversion domain with a
cycle-based helper that routes the calendar through chrono (the calendar
repeats every 400 years = 146_097 days, so month/day/time come from chrono and
only the year is carried in i128, keeping every i64 exact).

- apps/lightcraft/src/logging.rs: `timestamp` via `utc_parts`; keep the
  pre-1970 epoch clamp; u64 secs past i64::MAX saturate, not epoch.
- crates/catalog/src/dates.rs: `civil` cycle-based (the callers stay inside
  0000-9999, but a far clock no longer resets to the epoch).

Pinned old outputs in tests:
  logging u64::MAX/2 s -> 292277026596-12-04T15:30:07.000Z (was epoch),
          10_000_000_000_000 s -> 318857-05-20T17:46:40.000Z
  civil 10_000_000_000_000 -> 318857-05-20T17:46:40,
        -10_000_000_000_000 -> -314918-08-13T06:13:20, i64 extremes

* Don't build a year-318857 SystemTime unchecked in the logging test

Windows' SystemTime only reaches about year 30828, so
UNIX_EPOCH + Duration::from_secs(10_000_000_000_000) panicked before
timestamp() ran and failed the Windows test job. Build it with
checked_add and assert where the platform can hold it. The year-10000
case fits everywhere and stays unconditional.

* Name the 400-year range extension as the one exception to the time rule

The rule said never to hand-roll calendar math, but the range fix
(shifting by whole 400-year Gregorian cycles so dates past chrono's year
range keep their old output) is cycle arithmetic, so the rule and the code
disagreed. The rule now names that exception: the library still computes
month, day and time, and only whole cycles are carried in the year.

* Say the library computes month and day; time-of-day is plain arithmetic

Narrows the range-extension wording: the date library computes the
calendar fields, and splitting seconds into hours, minutes and seconds
is ordinary arithmetic, which is what the code does.
2026-10-21 19:36:36 -04:00
aiongg 21903294bf Merge track r1-rawcat into next
crates/ui-egui/locales/{cs,it,pl}-formats.json: kept the translations and added the track's new keys.
docs/parity-checklist.md: newer header line; revision rows from both sides.
docs/whats-new.md: both tracks' 2026-10-15 entries.
2026-10-21 14:58:55 +00:00
aiongg a1455fa7cd Merge PR #1988: #1507: web start-up treats only NotFoundError as a missing file
apps/lightcraft-web/src/files.rs: keeps #1987's and #1988's tests
docs/whats-new.md: keeps both 2026-10-15 entries
2026-10-21 14:56:12 +00:00
aiongg 5443225c3c Merge track r1-i18nci into next 2026-10-21 14:54:41 +00:00
Bruno-Alumn 45f61ef5ef Web: a finished save repaints, so the title drops its unsaved mark (#2397) 2026-10-21 11:58:16 +00:00
Bruno-Alumn 79f11e098c Web: lightcraft.command refuses params that aren't a JSON object
The page's automation call parsed its params with a fallback to {}, so a
typo such as lightcraft.command("photo.delete", "{ids: [3]}") ran
photo.delete with no params, which acts on the selection. Params must
now be a JSON object (blank text or null is {}); anything else rejects
the promise and runs nothing, as the control channel and MCP already do.
2026-10-21 01:05:03 +00:00
joblonfk001 b8e335370d fix(web): derive file picker accept list from engine extensions
The web import picker hard-coded a 13-extension accept list, so raws the engine imports (CR3, NRW, RAF, ORF, RW2, RWL, RAW, PEF, SRW, …) were silently filtered out of the dialog on Windows/Edge, which matches accept case-sensitively. Generate the list from EXTENSIONS, each extension in both cases. Fixes #2212.
2026-10-21 08:09:19 +08:00
Bruno-Alumn 8ef46aa088 Web: the page title names the open photo and unsaved changes (#2397)
eframe's web runner doesn't handle ViewportCommand::Title, so the web
build never named what was open, and a host embedding the page could
only guess whether a dropped file had opened. The page title is now
"<file name> — LightCraft" for the active photo, with " •" after the
name while changes are not yet written to browser storage, and the
window title when no photo is active. It is set only when it changes.
2026-10-21 00:02:23 +00:00
Andrew FrahnandClaude Sonnet 5.5 6f9f7dd7e9 Review: skip wrapper desktop entries, pick newest AppImage across both folders
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 12:17:30 +11:00
Andrew FrahnandClaude Sonnet 5.5 a656f99e47 Edit in PhotoCraft: restore the Windows/desktop-entry tests, test PATH lookup, sort AppImages by version
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 09:59:33 +11:00
Andrew Frahn 380d3017b0 Merge upstream/main 2026-10-20 09:19:54 +11:00
eliets2 01495684d9 web: Auto language follows the browser's languages (#2085)
default_language() — what the Auto setting resolves to — only read LIGHTCRAFT_LANGUAGE,
which does not exist in a browser, so the web build always started in English. ui-egui
gains an installable default (set_default_language + a pure locale_from_tags that picks
the first shippable language from BCP-47 tags via Locale::parse_tag), and the web app
installs it at startup from navigator.languages (falling back to navigator.language),
read fallibly through js_sys::Reflect so it also works from a worker. Desktop never
installs the override and is unchanged; a language stored in ui.json still wins, which is
exactly Auto semantics.

Tests: locale_from_tags takes the first shippable language (it-IT -> Italiano,
unsupported-first skips ahead, zh-TW -> zh-hant, ja_JP.UTF-8 -> Japanese, pt-BR region
variant), empty/unsupported -> En fallback.
2026-10-17 22:30:14 +03:00
ronibalthazar a43c3c2a89 #1952: expire idle control connections 2026-10-16 14:15:48 +01:00
LochLogicandClaude Opus 5.5 16f5a9f0ca Control port: don't clone the connection's socket (Windows: launched programs held it open)
serve() read through stream.try_clone(). On Windows a cloned socket handle is
inheritable (std's accept/connect sockets are not), so every program the app
started while a control client was connected (the browser for a link,
Explorer for Show in Explorer, an external editor) got a copy of the
connection. When the server then closed it, the client saw nothing until that
program exited, and then a reset instead of a clean close. Read and write
through the one stream (&TcpStream is Read and Write) instead.

Regression test (Windows): a program started while a client is connected no
longer delays or resets the close; it failed with ConnectionReset before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 23:16:51 -06:00
Marco Arnulfo e14db89462 LR-EXP-BITDEPTH: app.export refuses a bitDepth the format doesn't have (part of #1952) 2026-10-16 02:21:07 +02:00
Claude 37a3ab4177 #1507: web start-up treats only NotFoundError as a missing file
OPFS lookups turned any exception into "absent", and start-up only logged
other read errors, so a library with an unreadable file opened incomplete
and the next save could overwrite the stored copy. Only NotFoundError now
means absent; when a stored library file or the active-library pointer
can't be read, the library isn't opened, nothing is saved and the window
names the file. An unreadable thumbnail index no longer deletes every
stored thumbnail as unindexed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-15 23:08:54 +00:00
Claude abf29ea392 #1508: web backup refuses to start while changes are unsaved
The browser backup copies the stored library files, so while a save to
browser storage is failing it reported success but left out the queued
changes. It now refuses with the number of unsaved changes and why
(Session::unsaved), and is allowed again once they are written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AbegtYaPuwqZ81pGfELsFK
2026-10-15 21:53:46 +00:00
Brandon Thomas 9ca113defa Merge PR #1135 (rebased)
# Conflicts:
#	xtask/src/main.rs
2026-10-15 00:53:45 -04:00
Brandon Thomas b3012745d5 Merge PR #1215 (rebased)
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-15 00:52:31 -04:00
Brandon Thomas b29a1a8cc2 Merge PR #1215
# Conflicts:
#	crates/engine/src/lib.rs
#	crates/engine/src/pdf.rs
#	crates/ui-egui/src/lib.rs
#	crates/ui-egui/src/menus.rs
#	crates/ui-egui/src/panels/dialogs.rs
#	crates/ui-egui/src/state.rs
#	docs/gaps.md
#	docs/parity-checklist.md
2026-10-15 00:22:08 -04:00
Brandon ThomasandClaude Opus 5.5 1a120a86a2 Merge PR #1761
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:59:13 -04:00
Brandon Thomas 9ca3cd0926 Merge PR #1135
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	README.md
#	crates/raw/Cargo.toml
#	crates/ui-egui/src/theme.rs
#	xtask/src/main.rs
2026-10-14 23:23:18 -04:00
Brandon Thomas ad23861454 Merge PR #1625
# Conflicts:
#	apps/lightcraft/src/main.rs
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-14 22:33:14 -04:00
Brandon Thomas c8c97883cd Merge PR #1548
# Conflicts:
#	crates/ui-egui/locales/de-formats.json
#	crates/ui-egui/locales/de.json
#	crates/ui-egui/locales/es-formats.json
#	crates/ui-egui/locales/es.json
#	crates/ui-egui/locales/fr-formats.json
#	crates/ui-egui/locales/fr.json
#	crates/ui-egui/locales/ja-formats.json
#	crates/ui-egui/locales/ja.json
#	crates/ui-egui/locales/pt-br-formats.json
#	crates/ui-egui/locales/pt-br.json
#	crates/ui-egui/locales/ru-formats.json
#	crates/ui-egui/locales/ru.json
#	crates/ui-egui/locales/uk-formats.json
#	crates/ui-egui/locales/uk.json
#	crates/ui-egui/locales/zh-hans-formats.json
#	crates/ui-egui/locales/zh-hans.json
#	crates/ui-egui/locales/zh-hant-formats.json
#	crates/ui-egui/locales/zh-hant.json
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-14 22:32:39 -04:00
Brandon Thomas 18db8588b9 Merge PR #1490
# Conflicts:
#	docs/parity-checklist.md
#	docs/ui-parity.md
2026-10-14 22:32:25 -04:00
Brandon Thomas de5ec99f61 Merge PR #1489
# Conflicts:
#	docs/parity-checklist.md
#	docs/whats-new.md
2026-10-14 22:32:24 -04:00
Brandon Thomas fe2ba9191a Merge PR #1791 2026-10-14 22:31:46 -04:00
Brandon Thomas 9d45f6b168 Merge PR #1733 2026-10-14 22:29:37 -04:00
Brandon Thomas a8f0f5d60b Merge PR #1715
# Conflicts:
#	docs/gaps.md
#	docs/parity-checklist.md
#	docs/target-app-parity.md
2026-10-14 22:29:33 -04:00