From 410b19a334bd6dd4dae71e157a76d6ec4094c781 Mon Sep 17 00:00:00 2001 From: Bruno-Alumn <171815746+Bruno-Alumn@users.noreply.github.com> Date: Fri, 30 Oct 2026 18:42:10 +0100 Subject: [PATCH] LRC-LIB-CATALOG-SWITCH: files waiting for a library wait for a running import instead of being dropped (#2779) --- crates/ui-egui/locales/cs.json | 1 + crates/ui-egui/locales/de.json | 1 + crates/ui-egui/locales/es.json | 1 + crates/ui-egui/locales/fi.json | 1 + crates/ui-egui/locales/fr.json | 1 + crates/ui-egui/locales/id.json | 1 + crates/ui-egui/locales/it.json | 1 + crates/ui-egui/locales/ja.json | 1 + crates/ui-egui/locales/ka.json | 1 + crates/ui-egui/locales/pl.json | 1 + crates/ui-egui/locales/pt-br.json | 1 + crates/ui-egui/locales/ru.json | 1 + crates/ui-egui/locales/sv.json | 1 + crates/ui-egui/locales/uk.json | 1 + crates/ui-egui/locales/vi.json | 1 + crates/ui-egui/locales/zh-hans.json | 1 + crates/ui-egui/locales/zh-hant.json | 1 + crates/ui-egui/src/app.rs | 1 + crates/ui-egui/src/lib.rs | 2 + crates/ui-egui/src/panels/library_problem.rs | 51 +++++++++++++------- crates/ui-egui/src/tests/library_problem.rs | 39 +++++++++++++++ docs/whats-new.md | 7 +++ 22 files changed, 100 insertions(+), 17 deletions(-) diff --git a/crates/ui-egui/locales/cs.json b/crates/ui-egui/locales/cs.json index 52ca94a52..14753445c 100644 --- a/crates/ui-egui/locales/cs.json +++ b/crates/ui-egui/locales/cs.json @@ -2407,6 +2407,7 @@ "Dropped Files": "Přetažené soubory", "Import dropped files without review": "Importovat přetažené soubory bez kontroly", "An import is running": "Import už běží", + "The photos are imported once it ends": "Fotky se naimportují potom", "An import is running. Drop photos when it has finished": "Import už běží. Fotky přetáhněte, až skončí", "Finish Lightroom catalog import before adding photos": "Dokončete import katalogu Lightroom, než přidáte fotky" } diff --git a/crates/ui-egui/locales/de.json b/crates/ui-egui/locales/de.json index e2205db78..2a7ca318d 100644 --- a/crates/ui-egui/locales/de.json +++ b/crates/ui-egui/locales/de.json @@ -3439,6 +3439,7 @@ "Dropped Files": "Abgelegte Dateien", "Import dropped files without review": "Abgelegte Dateien ohne Prüfung importieren", "An import is running": "Ein Import läuft", + "The photos are imported once it ends": "Die Fotos werden danach importiert", "An import is running. Drop photos when it has finished": "Ein Import läuft. Lege die Fotos ab, wenn er fertig ist", "Finish Lightroom catalog import before adding photos": "Schließe den Import des Lightroom-Katalogs ab, bevor du Fotos hinzufügst" } diff --git a/crates/ui-egui/locales/es.json b/crates/ui-egui/locales/es.json index 888af077f..eacc8fb03 100644 --- a/crates/ui-egui/locales/es.json +++ b/crates/ui-egui/locales/es.json @@ -2357,6 +2357,7 @@ "Dropped Files": "Archivos soltados", "Import dropped files without review": "Importar los archivos soltados sin revisión", "An import is running": "Hay una importación en curso", + "The photos are imported once it ends": "Las fotos se importarán después", "An import is running. Drop photos when it has finished": "Hay una importación en curso. Suelta las fotos cuando termine", "Finish Lightroom catalog import before adding photos": "Termina la importación del catálogo de Lightroom antes de añadir fotos" } diff --git a/crates/ui-egui/locales/fi.json b/crates/ui-egui/locales/fi.json index e0a8c622a..4e460171a 100644 --- a/crates/ui-egui/locales/fi.json +++ b/crates/ui-egui/locales/fi.json @@ -2320,6 +2320,7 @@ "Mask Pins": "Maskin nastat", "Photo Counts": "Kuvamäärät", "An import is running": "Tuonti on käynnissä", + "The photos are imported once it ends": "Kuvat tuodaan sen jälkeen", "An import is running. Drop photos when it has finished": "Tuonti on käynnissä. Pudota kuvat, kun se on valmis", "Close the open dialog to drop files here": "Sulje avoin valintaikkuna pudottaaksesi tiedostot tähän", "Close the open dialog, then drop the files again": "Sulje avoin valintaikkuna ja pudota tiedostot sitten uudelleen", diff --git a/crates/ui-egui/locales/fr.json b/crates/ui-egui/locales/fr.json index 3278d6ccd..91fe8a2b6 100644 --- a/crates/ui-egui/locales/fr.json +++ b/crates/ui-egui/locales/fr.json @@ -2353,6 +2353,7 @@ "Dropped Files": "Fichiers déposés", "Import dropped files without review": "Importer les fichiers déposés sans vérification", "An import is running": "Une importation est en cours", + "The photos are imported once it ends": "Les photos seront importées ensuite", "An import is running. Drop photos when it has finished": "Une importation est en cours. Déposez les photos quand elle sera terminée", "Finish Lightroom catalog import before adding photos": "Terminez l'importation du catalogue Lightroom avant d'ajouter des photos", "The library is empty: the catalog's photos, collections and edits become its first.": "La bibliothèque est vide : les photos, collections et retouches du catalogue seront les premières.", diff --git a/crates/ui-egui/locales/id.json b/crates/ui-egui/locales/id.json index 0d6da9b8f..21a1ea00f 100644 --- a/crates/ui-egui/locales/id.json +++ b/crates/ui-egui/locales/id.json @@ -2332,6 +2332,7 @@ "Mask Pins": "Pin masker", "Photo Counts": "Jumlah foto", "An import is running": "Impor sedang berjalan", + "The photos are imported once it ends": "Foto diimpor setelah selesai", "An import is running. Drop photos when it has finished": "Impor sedang berjalan. Jatuhkan foto setelah selesai", "Close the open dialog to drop files here": "Tutup dialog yang terbuka untuk menjatuhkan file di sini", "Close the open dialog, then drop the files again": "Tutup dialog yang terbuka, lalu jatuhkan file lagi", diff --git a/crates/ui-egui/locales/it.json b/crates/ui-egui/locales/it.json index e159fd47d..8c495ffd2 100644 --- a/crates/ui-egui/locales/it.json +++ b/crates/ui-egui/locales/it.json @@ -2360,6 +2360,7 @@ "Dropped Files": "File rilasciati", "Import dropped files without review": "Importa i file rilasciati senza revisione", "An import is running": "Un'importazione è in corso", + "The photos are imported once it ends": "Le foto verranno importate dopo", "An import is running. Drop photos when it has finished": "Un'importazione è in corso. Trascina le foto quando è finita", "Finish Lightroom catalog import before adding photos": "Termina l'importazione del catalogo Lightroom prima di aggiungere foto" } diff --git a/crates/ui-egui/locales/ja.json b/crates/ui-egui/locales/ja.json index e1834555b..135283358 100644 --- a/crates/ui-egui/locales/ja.json +++ b/crates/ui-egui/locales/ja.json @@ -2355,6 +2355,7 @@ "Dropped Files": "ドロップしたファイル", "Import dropped files without review": "ドロップしたファイルを確認せずに読み込む", "An import is running": "読み込み中です", + "The photos are imported once it ends": "終わりしだい写真を読み込みます", "An import is running. Drop photos when it has finished": "読み込み中です。完了してから写真をドロップしてください", "Finish Lightroom catalog import before adding photos": "写真を追加する前に Lightroom カタログの読み込みを完了してください" } diff --git a/crates/ui-egui/locales/ka.json b/crates/ui-egui/locales/ka.json index 32c407700..8b0170b7b 100644 --- a/crates/ui-egui/locales/ka.json +++ b/crates/ui-egui/locales/ka.json @@ -2733,6 +2733,7 @@ "Dropped Files": "ჩაგდებული ფაილები", "Import dropped files without review": "ჩაგდებული ფაილების იმპორტი გადახედვის გარეშე", "An import is running": "იმპორტი მიმდინარეობს", + "The photos are imported once it ends": "ფოტოები ამის შემდეგ შემოიტანება", "An import is running. Drop photos when it has finished": "იმპორტი მიმდინარეობს. ფოტოები ჩააგდეთ, როცა დასრულდება", "Finish Lightroom catalog import before adding photos": "ფოტოების დამატებამდე დაასრულეთ Lightroom-ის კატალოგის იმპორტი" } diff --git a/crates/ui-egui/locales/pl.json b/crates/ui-egui/locales/pl.json index adac22e62..e59be06dc 100644 --- a/crates/ui-egui/locales/pl.json +++ b/crates/ui-egui/locales/pl.json @@ -2282,6 +2282,7 @@ "Dropped Files": "Upuszczone pliki", "Import dropped files without review": "Importuj upuszczone pliki bez przeglądu", "An import is running": "Import jest w toku", + "The photos are imported once it ends": "Zdjęcia zostaną zaimportowane potem", "An import is running. Drop photos when it has finished": "Import jest w toku. Upuść zdjęcia, gdy się zakończy", "Finish Lightroom catalog import before adding photos": "Zakończ import katalogu Lightrooma, zanim dodasz zdjęcia" } diff --git a/crates/ui-egui/locales/pt-br.json b/crates/ui-egui/locales/pt-br.json index e84fb7615..025cf36bf 100644 --- a/crates/ui-egui/locales/pt-br.json +++ b/crates/ui-egui/locales/pt-br.json @@ -2201,6 +2201,7 @@ "Dropped Files": "Arquivos soltos", "Import dropped files without review": "Importar arquivos soltos sem revisão", "An import is running": "Uma importação está em andamento", + "The photos are imported once it ends": "As fotos serão importadas depois", "An import is running. Drop photos when it has finished": "Uma importação está em andamento. Solte as fotos quando ela terminar", "Finish Lightroom catalog import before adding photos": "Conclua a importação do catálogo do Lightroom antes de adicionar fotos" } diff --git a/crates/ui-egui/locales/ru.json b/crates/ui-egui/locales/ru.json index 306804df0..b3edd7333 100644 --- a/crates/ui-egui/locales/ru.json +++ b/crates/ui-egui/locales/ru.json @@ -2348,6 +2348,7 @@ "Dropped Files": "Перетащенные файлы", "Import dropped files without review": "Импортировать перетащенные файлы без проверки", "An import is running": "Импорт уже выполняется", + "The photos are imported once it ends": "Фото будут импортированы после этого", "An import is running. Drop photos when it has finished": "Импорт уже выполняется. Перетащите фото, когда он закончится", "Finish Lightroom catalog import before adding photos": "Завершите импорт каталога Lightroom, прежде чем добавлять фото" } diff --git a/crates/ui-egui/locales/sv.json b/crates/ui-egui/locales/sv.json index 66e69b7ba..a7f13aa1e 100644 --- a/crates/ui-egui/locales/sv.json +++ b/crates/ui-egui/locales/sv.json @@ -2422,6 +2422,7 @@ "Mask Pins": "Masknålar", "Photo Counts": "Antal foton", "An import is running": "En import pågår", + "The photos are imported once it ends": "Bilderna importeras efteråt", "An import is running. Drop photos when it has finished": "En import pågår. Släpp fotona när den är klar", "Close the open dialog to drop files here": "Stäng den öppna dialogrutan för att släppa filer här", "Close the open dialog, then drop the files again": "Stäng den öppna dialogrutan och släpp sedan filerna igen", diff --git a/crates/ui-egui/locales/uk.json b/crates/ui-egui/locales/uk.json index ee694ed4f..fe538841f 100644 --- a/crates/ui-egui/locales/uk.json +++ b/crates/ui-egui/locales/uk.json @@ -2353,6 +2353,7 @@ "Dropped Files": "Перетягнуті файли", "Import dropped files without review": "Імпортувати перетягнуті файли без перегляду", "An import is running": "Імпорт уже виконується", + "The photos are imported once it ends": "Фото буде імпортовано після цього", "An import is running. Drop photos when it has finished": "Імпорт уже виконується. Перетягніть фото, коли він завершиться", "Finish Lightroom catalog import before adding photos": "Завершіть імпорт каталогу Lightroom, перш ніж додавати фото" } diff --git a/crates/ui-egui/locales/vi.json b/crates/ui-egui/locales/vi.json index e4fb8feb8..963e7337f 100644 --- a/crates/ui-egui/locales/vi.json +++ b/crates/ui-egui/locales/vi.json @@ -2228,6 +2228,7 @@ "Mask Pins": "Ghim mặt nạ", "Photo Counts": "Số lượng ảnh", "An import is running": "Đang có một lần nhập chạy", + "The photos are imported once it ends": "Ảnh sẽ được nhập khi việc đó kết thúc", "An import is running. Drop photos when it has finished": "Đang có một lần nhập chạy. Hãy thả ảnh khi nó hoàn tất", "Close the open dialog to drop files here": "Hãy đóng hộp thoại đang mở để thả tệp vào đây", "Close the open dialog, then drop the files again": "Hãy đóng hộp thoại đang mở, rồi thả lại các tệp", diff --git a/crates/ui-egui/locales/zh-hans.json b/crates/ui-egui/locales/zh-hans.json index 270af8a62..89d6b4387 100644 --- a/crates/ui-egui/locales/zh-hans.json +++ b/crates/ui-egui/locales/zh-hans.json @@ -2199,6 +2199,7 @@ "Dropped Files": "拖入的文件", "Import dropped files without review": "不经检查直接导入拖入的文件", "An import is running": "正在导入", + "The photos are imported once it ends": "结束后即导入这些照片", "An import is running. Drop photos when it has finished": "正在导入。导入完成后再拖放照片", "Finish Lightroom catalog import before adding photos": "添加照片前,请先完成 Lightroom 目录的导入" } diff --git a/crates/ui-egui/locales/zh-hant.json b/crates/ui-egui/locales/zh-hant.json index 0408e23ec..6eb261f2f 100644 --- a/crates/ui-egui/locales/zh-hant.json +++ b/crates/ui-egui/locales/zh-hant.json @@ -2156,6 +2156,7 @@ "Dropped Files": "拖放的檔案", "Import dropped files without review": "不經檢查直接匯入拖放的檔案", "An import is running": "正在匯入", + "The photos are imported once it ends": "結束後即匯入這些照片", "An import is running. Drop photos when it has finished": "正在匯入。匯入完成後再拖放照片", "Finish Lightroom catalog import before adding photos": "新增照片前,請先完成 Lightroom 目錄的匯入" } diff --git a/crates/ui-egui/src/app.rs b/crates/ui-egui/src/app.rs index fa10210f0..d158c0429 100644 --- a/crates/ui-egui/src/app.rs +++ b/crates/ui-egui/src/app.rs @@ -102,6 +102,7 @@ impl LightcraftApp { merge: merge::MergeState::default(), import: None, scan: None, + waiting_import: Default::default(), sync: None, sync_owns_changes: false, sync_run: None, diff --git a/crates/ui-egui/src/lib.rs b/crates/ui-egui/src/lib.rs index 8bf57b341..a4787594d 100644 --- a/crates/ui-egui/src/lib.rs +++ b/crates/ui-egui/src/lib.rs @@ -298,6 +298,8 @@ pub struct LightcraftApp { pub import: Option, /// A folder scan in progress (feeds the import review). pub scan: Option, + /// Files that waited for a library and wait for the running import or Synchronize Folder too. + pub waiting_import: panels::library_problem::WaitingImport, /// A Synchronize Folder scan in progress (feeds its dialog). pub sync: Option, /// `session.folder_changes` came from the Synchronize Folder dialog (and goes with it). diff --git a/crates/ui-egui/src/panels/library_problem.rs b/crates/ui-egui/src/panels/library_problem.rs index 544e29449..7f69775e3 100644 --- a/crates/ui-egui/src/panels/library_problem.rs +++ b/crates/ui-egui/src/panels/library_problem.rs @@ -327,6 +327,16 @@ pub struct Chooser { pub over: Option, } +/// Files that waited for a library (the command line, drops on the launch list) and found another +/// import or a Synchronize Folder running when one opened: kept, and imported once it ends instead +/// of being lost (issue #2779). +#[derive(Clone, Debug, Default, PartialEq)] +pub struct WaitingImport { + pub files: Vec, + /// The toast already said why they wait. + told: bool, +} + /// A library that failed to open (set by the host at launch). #[derive(Clone, Debug, Default, PartialEq)] pub struct LibraryProblem { @@ -783,12 +793,7 @@ fn open(app: &mut LightcraftApp, path: Option) { Ok(serde_json::Value::Null) => {} // folder dialog cancelled Ok(_) => { let files = app.library_problem.take().map(|p| p.pending_import).unwrap_or_default(); - // in the background, like files dropped on the window (issue #374) - if !files.is_empty() - && let Err(e) = crate::import::start_paths(app, files) - { - log::warn!("import: {e}"); - } + app.waiting_import.files.extend(files); } Err(e) => { // a failed switch reopens the library that was open behind the launch list @@ -816,6 +821,26 @@ fn open(app: &mut LightcraftApp, path: Option) { } } +/// Import the files that waited for a library, in the background like files dropped on the window +/// (issue #374). While another import or a Synchronize Folder runs they keep waiting, and a toast +/// says why once (issue #2779). +fn import_waiting(app: &mut LightcraftApp, ctx: &egui::Context) { + if app.waiting_import.files.is_empty() { + return; + } + let files = std::mem::take(&mut app.waiting_import.files); + match crate::import::start_paths(app, files.clone()) { + Ok(_) => app.waiting_import = WaitingImport::default(), + Err(e) => { + if !app.waiting_import.told { + app.toast(ctx, format!("{e}. {}", crate::i18n::tr("The photos are imported once it ends"))); + } + app.waiting_import = WaitingImport { files, told: true }; + ctx.request_repaint_after(std::time::Duration::from_millis(250)); + } + } +} + /// Clear the problem once a library is open (e.g. through Settings → Open Library…) — another /// one than the launch list was opened over; offer the list when Alt/Option is held as the window /// appears; and the list's keys. @@ -827,12 +852,9 @@ pub fn logic(app: &mut LightcraftApp, ctx: &egui::Context) { // files from the command line go into the library opened another way (New Library…, // File ▸ Open Library…), as through the window's own buttons let files = app.library_problem.take().map(|p| p.pending_import).unwrap_or_default(); - if !files.is_empty() - && let Err(e) = crate::import::start_paths(app, files) - { - log::warn!("import: {e}"); - } + app.waiting_import.files.extend(files); } + import_waiting(app, ctx); let batch_in_flight = app.synthetic_in_flight; alt_at_launch(app, ctx); // Alt/Option can create the launch list here, after the frame's input was accepted. Drop @@ -1111,12 +1133,7 @@ fn act(app: &mut LightcraftApp, choice: Choice) { p.dismissed = true; } let files = app.library_problem.as_mut().map(|p| std::mem::take(&mut p.pending_import)).unwrap_or_default(); - // in the background, like files dropped on the window (issue #374) - if !files.is_empty() - && let Err(e) = crate::import::start_paths(app, files) - { - log::warn!("import: {e}"); - } + app.waiting_import.files.extend(files); } Choice::Quit => app.ui.quit = true, } diff --git a/crates/ui-egui/src/tests/library_problem.rs b/crates/ui-egui/src/tests/library_problem.rs index 1a2e5a2d9..29a0aca66 100644 --- a/crates/ui-egui/src/tests/library_problem.rs +++ b/crates/ui-egui/src/tests/library_problem.rs @@ -804,3 +804,42 @@ fn typing_reaches_the_launch_lists_own_new_library_prompt() { assert_eq!(command, "app.newLibrary"); assert_eq!(value, "Fresh", "typing reaches the launch list's own text prompt"); } + +/// Issue #2779: files waiting for a library (the command line, drops on the launch list) that +/// find another import running when a library opens are kept, with a toast saying why, and +/// imported once that import ends instead of being dropped. +#[test] +fn waiting_files_wait_for_a_running_import_instead_of_being_dropped() { + let dir = std::env::temp_dir().join(format!("lightcraft-waiting-import-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + let png = |v: u8| { + let img = lightcraft_raster::Rgba8 { width: 8, height: 8, data: vec![[v, 3, 9, 255]; 64] }; + lightcraft_codecs::encode_png(&lightcraft_codecs::EncodeImage::rgba8(&img), &lightcraft_codecs::EncodeMeta::default()).unwrap() + }; + let (busy, waiting) = (dir.join("busy.png"), dir.join("waiting.png")); + std::fs::write(&busy, png(10)).unwrap(); + std::fs::write(&waiting, png(200)).unwrap(); + + let app = LightcraftApp::new(lightcraft_engine::Session::new().with_fs(), Services { png: None, ..Default::default() }); + let mut h = Headless::new(app, [1300.0, 900.0], 1.0); + let lib = dir.join("lib"); + h.app.library_problem = Some(LibraryProblem { + pending_import: vec![waiting.to_string_lossy().to_string()], + ..LibraryProblem::new(lib.to_string_lossy(), "a test error") + }); + h.step(); + // a library opens another way (File ▸ Open Library…) while an import is running + h.app.session.open_library(&lib, false).unwrap(); + crate::import::start_paths(&mut h.app, vec![busy.to_string_lossy().to_string()]).unwrap(); + h.step(); + assert!(h.app.library_problem.is_none(), "the problem is over"); + assert_eq!(h.app.waiting_import.files, vec![waiting.to_string_lossy().to_string()], "the waiting file is kept"); + let toast = h.app.ui.toast.as_ref().map(|t| t.0.clone()).unwrap_or_default(); + assert!(toast.contains("An import is running") && toast.contains("once it ends"), "{toast}"); + + assert!(h.step_until(T, |h| h.app.import.is_none() && h.app.session.catalog.len() == 2), "{} photos", h.app.session.catalog.len()); + assert!(h.app.waiting_import.files.is_empty()); + let _ = h.app.session.close_library(); + let _ = std::fs::remove_dir_all(&dir); +} diff --git a/docs/whats-new.md b/docs/whats-new.md index c6c259200..c7442b75f 100644 --- a/docs/whats-new.md +++ b/docs/whats-new.md @@ -1,5 +1,12 @@ # What's new in LightCraft +## 2026-10-30 + +### Photos waiting for a library wait for a running import too +- Photos given on the command line or dropped on the launch list are imported once a library opens. If another import + or a Synchronize Folder is still running then, they now wait for it to end instead of being dropped, and a message + says so (issue #2779). + ## 2026-10-24 ### Relative-date filters and smart albums follow the clock