mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-26 03:11:14 +00:00
Merge #2701@da434b059 (presets dropped with no library open are refused) into round3a-integration
crates/ui-egui/src/lib.rs: the batch's handle_dropped_files refuses presets while no library is open, as #2701 does. The drop card says so, and its "photos wait" line is desktop-only (the web build's drops import into its session as before). photos_dropped_with_no_library_open_wait_for_one also drops a preset; LR-IMP-DRAGDROP row updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2385,5 +2385,6 @@
|
||||
"Not answering yet: the drive may be asleep or offline": "Pas encore de réponse : le disque est peut-être en veille ou hors ligne",
|
||||
"This library couldn't be checked": "Impossible de vérifier cette bibliothèque",
|
||||
"Checking recent libraries": "Vérification des bibliothèques récentes",
|
||||
"The photos are imported once a library is open": "Les photos seront importées dès qu'une bibliothèque sera ouverte"
|
||||
"The photos are imported once a library is open": "Les photos seront importées dès qu'une bibliothèque sera ouverte",
|
||||
"Open a library first, then drop the presets again": "Ouvrez d'abord une bibliothèque, puis déposez à nouveau les préréglages"
|
||||
}
|
||||
|
||||
@@ -36,12 +36,16 @@ fn lines(app: &LightcraftApp, paths: Vec<String>, unknown: bool) -> Vec<String>
|
||||
out.push(crate::i18n::tr("Drop to open the face model").to_string());
|
||||
}
|
||||
let plural = |n: usize| if n == 1 { "" } else { "s" };
|
||||
if !drop.presets.is_empty() {
|
||||
// no library open yet (desktop: the web build's drops import into its session as before):
|
||||
// photos wait for the library chosen, presets are refused (the drop handler does the same)
|
||||
let waiting = crate::panels::library_problem::holds_drops(app) && !cfg!(target_arch = "wasm32");
|
||||
if !drop.presets.is_empty() && waiting {
|
||||
out.push(crate::i18n::tr("Open a library first, then drop the presets again").to_string());
|
||||
} else if !drop.presets.is_empty() {
|
||||
let n = drop.presets.len();
|
||||
out.push(crate::i18n::tr_format!("Drop to import {n} preset{}", plural(n), n = n));
|
||||
}
|
||||
if !drop.photos.is_empty() && crate::panels::library_problem::holds_drops(app) {
|
||||
// no library open yet: they wait for the one chosen (the drop handler holds them)
|
||||
if !drop.photos.is_empty() && waiting {
|
||||
out.push(crate::i18n::tr("The photos are imported once a library is open").to_string());
|
||||
} else if !drop.photos.is_empty() && app.lightroom.is_some() && !cfg!(target_arch = "wasm32") {
|
||||
// the drop is refused while a Lightroom catalog import owns the catalog
|
||||
|
||||
@@ -1300,7 +1300,12 @@ impl LightcraftApp {
|
||||
self.toast(ctx, e);
|
||||
}
|
||||
if !drop.presets.is_empty() {
|
||||
let _ = self.run("file.importPresets", serde_json::json!({"paths": drop.presets}));
|
||||
// presets live in a library: with none open they would go with the session it replaces
|
||||
if panels::library_problem::holds_drops(self) {
|
||||
self.toast(ctx, crate::i18n::tr("Open a library first, then drop the presets again"));
|
||||
} else {
|
||||
let _ = self.run("file.importPresets", serde_json::json!({"paths": drop.presets}));
|
||||
}
|
||||
}
|
||||
if drop.photos.is_empty() {
|
||||
return;
|
||||
|
||||
@@ -260,11 +260,18 @@ fn photos_dropped_with_no_library_open_wait_for_one() {
|
||||
let dir = Scratch::new("no-library");
|
||||
let mut h = app(&dir);
|
||||
h.app.library_problem = Some(crate::panels::library_problem::LibraryProblem::new(dir.path("Gone"), "not found"));
|
||||
drop_files(&mut h, &[dir.path("trip/a.png")], true);
|
||||
std::fs::write(dir.path("warm.lcpreset"), "{}").unwrap();
|
||||
drop_files(&mut h, &[dir.path("trip/a.png"), dir.path("warm.lcpreset")], true);
|
||||
assert!(said(&h, "once a library is open"), "{:?}", h.painted_text());
|
||||
assert!(said(&h, "drop the presets again") && !said(&h, "1 preset"), "{:?}", h.painted_text());
|
||||
drop_files(&mut h, &[], true);
|
||||
drop_files(&mut h, &[dir.path("trip/a.png"), dir.path("trip/b.png")], false);
|
||||
assert_eq!(h.app.library_problem.as_ref().map(|p| p.pending_import.len()), Some(2));
|
||||
assert!(h.app.ui.dialog.is_none() && h.app.import.is_none(), "no review, no import into the temporary session");
|
||||
assert_eq!(photos(&h), 0);
|
||||
// a preset belongs to a library: refused, not imported into the session the library replaces
|
||||
h.app.ui.toast = None;
|
||||
drop_files(&mut h, &[dir.path("warm.lcpreset")], false);
|
||||
let toast = h.app.ui.toast.as_ref().map(|t| t.0.clone()).unwrap_or_default();
|
||||
assert!(toast.contains("drop the presets again"), "{toast}");
|
||||
}
|
||||
|
||||
@@ -168,7 +168,8 @@ are `button:libraryRetry`, `button:libraryChoose`, `button:libraryTemporary` (Co
|
||||
`button:libraryQuit`. A temporary session shows a banner (`indicator:temporarySession`, `button:libraryReopen`) and
|
||||
writes nothing. `app.openLibrary` opening a library ends it. `pendingImport` counts the files waiting for a
|
||||
library: those given on the command line, and photos dropped on the window while it (or the launch list below) is
|
||||
up; they are imported into the library that opens, or into the temporary session.
|
||||
up (desktop app); they are imported into the library that opens, or into the temporary session. Presets dropped
|
||||
then are refused with a toast.
|
||||
|
||||
### Choosing the library at launch
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ differences and missing bindings are in [ui-parity.md](ui-parity.md#shortcuts).
|
||||
| Id | Feature | Tier | Status | Evidence | Missing / notes |
|
||||
|---|---|---|---|---|---|
|
||||
| LR-IMP-ADD-DIALOG | Add photos/folders | P0 | ✅ | `cmd:file.addPhotos`, `cmd:library.importPreview`, `cmd:library.import` (`mode`, `album`, `albumName`, `preset`, `keywords`), `crates/ui-egui/src/import.rs` | review dialog (Import Photos): the scanned source (a scanned folder is not added to Local), candidate grid with thumbnails and checkboxes (duplicates by path/content marked and unchecked; with several file types, a toggle per type checks or unchecks all of its files, e.g. the raws without the JPEGs beside them, issue #344) filling a resizable window (issue #337), transfer mode (add in place / copy / move, each explained), album (existing/new): the destination picker follows the sidebar folder hierarchy and order, searches full paths, and distinguishes duplicate names by their folder path; folders navigate and smart albums are excluded, with None, New album and album-context preselection retained (#2362; `crates/ui-egui/src/album_picker.rs`, `crates/ui-egui/src/tests_album_picker.rs`); preset, keywords; the folder scan runs on a background thread, shown in the activity stack with ✕ to cancel (a NAS folder no longer freezes the window); the import itself (probing, sidecars, copying / moving files) runs on a worker thread and its batches join the library between frames, shown in the activity stack with ✕ to cancel; one undo step. Drag-and-drop goes through the same background import. File dialogs list the importable extensions (`lightcraft_engine::import::EXTENSIONS`) in any letter case on Linux, where GTK and the desktop portal match globs case-sensitively (`apps/lightcraft/src/dialog_filter.rs`, issue #342; 0.4.0 hid `.JPG` / `.NEF`, issue #705). The folder scan, Browse Folder, drag-and-drop and the sidecar lookup match extensions in any case (`crates/engine/src/tests_import.rs`) |
|
||||
| LR-IMP-DRAGDROP | Drop files/folders to import | P0 | ✅ | `crates/ui-egui/src/lib.rs` (dropped files → the import review), `crates/ui-egui/src/drop_overlay.rs`, `crates/ui-egui/src/tests_drop_import.rs` | while files are dragged over the window a veil and a card say what dropping does (review N items for import, import N presets, open the face model; a note to close the open dialog first when one is open); photos and folders open the import review as File ▸ Import does (Settings ▸ Import ▸ Import dropped files without review imports them at once; the web build always does); a drop while a dialog is open (also in the web build) or while an import is running is refused with a toast, and the card says so; a finished scan waits for an open dialog to close before its review opens; the control channel's `ui.dropFiles` hovers or drops files for scripts; dropping onto a specific album not supported |
|
||||
| LR-IMP-DRAGDROP | Drop files/folders to import | P0 | ✅ | `crates/ui-egui/src/lib.rs` (dropped files → the import review), `crates/ui-egui/src/drop_overlay.rs`, `crates/ui-egui/src/tests_drop_import.rs` | while files are dragged over the window a veil and a card say what dropping does (review N items for import, import N presets, open the face model; a note to close the open dialog first when one is open); photos and folders open the import review as File ▸ Import does (Settings ▸ Import ▸ Import dropped files without review imports them at once; the web build always does); with no library open on the desktop (the launch list, a library that couldn't open) photos wait for the library opened and presets are refused, and the card says so; a drop while a dialog is open (also in the web build) or while an import is running is refused with a toast, and the card says so; a finished scan waits for an open dialog to close before its review opens; the control channel's `ui.dropFiles` hovers or drops files for scripts; dropping onto a specific album not supported |
|
||||
| LR-IMP-DUPES | Skip duplicates by content | P1 | ✅ | `crates/engine/src/import.rs`, `crates/engine/src/tests_import.rs` | |
|
||||
| LR-IMP-DEVICE | Import from camera/card | P1 | ✅ | `cmd:library.devices`, `cmd:file.addFromDevice`, `crates/engine/src/devices.rs` | mounted volumes with a DCIM folder (macOS /Volumes, Linux /media and /run/media, Windows drive letters); File → Import from Device → the import review, copying into the library by default; menus serve the last scan and rescan in the background (never blocking a frame; hot-plugs repaint); copies are verified (a new file, synced, checked against the content hash the scan computed — byte compare with the source when there is none, issue #134; a bad copy is removed and reported as failed, never counted as imported; taken names get -1, -2…, never replaced — issue #96, `crates/engine/src/import_move.rs`); no PTP/MTP (cameras that don't mount as a disk); Settings → Import → Cameras and Cards can open the import review when a camera or card is connected (off by default; a card that was already in doesn't ask, and an open dialog or running import is finished first; `crates/ui-egui/src/import.rs`) |
|
||||
| LR-IMP-AUTO | Watched-folder auto import | P2 | ✅ | `cmd:library.autoImport`, `cmd:library.autoImportScan`, `crates/ui-egui/src/panels/settings.rs` | Settings ▸ Import ▸ Auto Import: a watched folder whose new photos are added (in place or copied) once complete, into an optional album; scanned every 3 s |
|
||||
@@ -798,7 +798,7 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-23 | minor | LRC-LIB-CATALOG-SWITCH, LR-PREF-GENERAL: Settings ▸ General ▸ At launch (Open the last library / Ask me) with a launch window listing the recent libraries, Alt/Option at launch asks once, File ▸ Open Recent Library ▸ Remove from List and `app.recentLibraries {remove}` (issue #1290); status and counts unchanged (✅) |
|
||||
| 2026-10-23 | minor | LRC-LIB-CATALOG-SWITCH, LR-PREF-GENERAL: Settings ▸ General ▸ At launch (Open the last library / Ask me) with a launch window listing the recent libraries, Alt/Option at launch asks once, File ▸ Open Recent Library ▸ Remove from List and `app.recentLibraries {remove}` (issue #1290); photos dropped while no library is open wait for the one opened (presets are refused then); status and counts unchanged (✅) |
|
||||
| 2026-10-23 | minor | LRC-LIB-CATALOG-IMPORT: Import Lightroom Catalog… (and Open Library's offer for a Lightroom catalog) asks whether the catalog merges into the open library or goes into a new library made next to it; Settings ▸ General or "Don't ask again" switches the question off; `file.importLightroom` takes `into` / `name` / `location` (#2672); status unchanged (🟡) |
|
||||
| 2026-10-22 | minor | LR-VIEW-INFOOVERLAY: the info overlay shows the star rating and flag, and in the full-screen preview on macOS it starts below the window controls (issue #2460); status unchanged |
|
||||
| 2026-10-22 | patch | KEY-GRID: both grid rows in View show the cycle shortcut and follow keymap changes; direct bindings and native accelerator ownership are preserved (#2500); status and counts unchanged |
|
||||
|
||||
@@ -35,6 +35,9 @@
|
||||
- File ▸ Open Recent Library ▸ **Remove from List** forgets one library, and the launch window's **Remove from
|
||||
List** does the same. Only the entry goes: the library and its photos stay where they are. Agents use
|
||||
`app.recentLibraries {remove: path}`; its list now also says when each library was last opened (`lastOpened`).
|
||||
- Photos dropped on the window while the list (or the window of a library that couldn't open) is up wait for the
|
||||
library you open and are imported into it, as files given on the command line are; presets dropped then are
|
||||
refused with a note, since they belong to a library.
|
||||
|
||||
## 2026-10-21
|
||||
|
||||
|
||||
Reference in New Issue
Block a user