mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-29 20:48:33 -06:00
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>
This commit is contained in:
co-authored by
Claude
parent
266f623480
commit
f84347a88e
@@ -508,6 +508,12 @@ impl WebApp {
|
||||
|
||||
fn import_dropped(&mut self, ctx: &egui::Context) {
|
||||
let dropped = ctx.input(|i| i.raw.dropped_files.clone());
|
||||
// a dialog is on screen (the card said so while the files hovered): nothing is read or imported
|
||||
// (files read from an earlier drop still finish below)
|
||||
if !dropped.is_empty() && self.app.ui.dialog.is_some() {
|
||||
self.app.toast(ctx, lightcraft_ui_egui::i18n::tr("Close the open dialog, then drop the files again"));
|
||||
return;
|
||||
}
|
||||
for f in dropped {
|
||||
let (originals, backend, ctx) = (self.originals.clone(), self.backend.clone(), ctx.clone());
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
|
||||
@@ -2400,5 +2400,7 @@
|
||||
"Drop to open the face model": "Pusťte pro otevření modelu obličejů",
|
||||
"Drop to import": "Pusťte pro import",
|
||||
"Dropped Files": "Přetažené soubory",
|
||||
"Import dropped files without review": "Importovat přetažené soubory bez kontroly"
|
||||
"Import dropped files without review": "Importovat přetažené soubory bez kontroly",
|
||||
"An import is running": "Import už běží",
|
||||
"An import is running. Drop photos when it has finished": "Import už běží. Fotky přetáhněte, až skončí"
|
||||
}
|
||||
|
||||
@@ -3428,5 +3428,7 @@
|
||||
"Drop to open the face model": "Ablegen, um das Gesichtsmodell zu öffnen",
|
||||
"Drop to import": "Ablegen zum Importieren",
|
||||
"Dropped Files": "Abgelegte Dateien",
|
||||
"Import dropped files without review": "Abgelegte Dateien ohne Prüfung importieren"
|
||||
"Import dropped files without review": "Abgelegte Dateien ohne Prüfung importieren",
|
||||
"An import is running": "Ein Import läuft",
|
||||
"An import is running. Drop photos when it has finished": "Ein Import läuft. Lege die Fotos ab, wenn er fertig ist"
|
||||
}
|
||||
|
||||
@@ -2348,5 +2348,7 @@
|
||||
"Drop to open the face model": "Suelta para abrir el modelo de caras",
|
||||
"Drop to import": "Suelta para importar",
|
||||
"Dropped Files": "Archivos soltados",
|
||||
"Import dropped files without review": "Importar los archivos soltados sin revisión"
|
||||
"Import dropped files without review": "Importar los archivos soltados sin revisión",
|
||||
"An import is running": "Hay una importación en curso",
|
||||
"An import is running. Drop photos when it has finished": "Hay una importación en curso. Suelta las fotos cuando termine"
|
||||
}
|
||||
|
||||
@@ -2346,5 +2346,7 @@
|
||||
"Drop to open the face model": "Déposez pour ouvrir le modèle de visages",
|
||||
"Drop to import": "Déposez pour importer",
|
||||
"Dropped Files": "Fichiers déposés",
|
||||
"Import dropped files without review": "Importer les fichiers déposés sans vérification"
|
||||
"Import dropped files without review": "Importer les fichiers déposés sans vérification",
|
||||
"An import is running": "Une importation est en cours",
|
||||
"An import is running. Drop photos when it has finished": "Une importation est en cours. Déposez les photos quand elle sera terminée"
|
||||
}
|
||||
|
||||
@@ -2352,5 +2352,7 @@
|
||||
"Drop to open the face model": "Rilascia per aprire il modello dei volti",
|
||||
"Drop to import": "Rilascia per importare",
|
||||
"Dropped Files": "File rilasciati",
|
||||
"Import dropped files without review": "Importa i file rilasciati senza revisione"
|
||||
"Import dropped files without review": "Importa i file rilasciati senza revisione",
|
||||
"An import is running": "Un'importazione è in corso",
|
||||
"An import is running. Drop photos when it has finished": "Un'importazione è in corso. Trascina le foto quando è finita"
|
||||
}
|
||||
|
||||
@@ -2348,5 +2348,7 @@
|
||||
"Drop to open the face model": "ドロップして顔モデルを開く",
|
||||
"Drop to import": "ドロップして読み込み",
|
||||
"Dropped Files": "ドロップしたファイル",
|
||||
"Import dropped files without review": "ドロップしたファイルを確認せずに読み込む"
|
||||
"Import dropped files without review": "ドロップしたファイルを確認せずに読み込む",
|
||||
"An import is running": "読み込み中です",
|
||||
"An import is running. Drop photos when it has finished": "読み込み中です。完了してから写真をドロップしてください"
|
||||
}
|
||||
|
||||
@@ -2725,5 +2725,7 @@
|
||||
"Drop to open the face model": "ჩააგდეთ სახეების მოდელის გასახსნელად",
|
||||
"Drop to import": "ჩააგდეთ იმპორტისთვის",
|
||||
"Dropped Files": "ჩაგდებული ფაილები",
|
||||
"Import dropped files without review": "ჩაგდებული ფაილების იმპორტი გადახედვის გარეშე"
|
||||
"Import dropped files without review": "ჩაგდებული ფაილების იმპორტი გადახედვის გარეშე",
|
||||
"An import is running": "იმპორტი მიმდინარეობს",
|
||||
"An import is running. Drop photos when it has finished": "იმპორტი მიმდინარეობს. ფოტოები ჩააგდეთ, როცა დასრულდება"
|
||||
}
|
||||
|
||||
@@ -2275,5 +2275,7 @@
|
||||
"Drop to open the face model": "Upuść, aby otworzyć model twarzy",
|
||||
"Drop to import": "Upuść, aby zaimportować",
|
||||
"Dropped Files": "Upuszczone pliki",
|
||||
"Import dropped files without review": "Importuj upuszczone pliki bez przeglądu"
|
||||
"Import dropped files without review": "Importuj upuszczone pliki bez przeglądu",
|
||||
"An import is running": "Import jest w toku",
|
||||
"An import is running. Drop photos when it has finished": "Import jest w toku. Upuść zdjęcia, gdy się zakończy"
|
||||
}
|
||||
|
||||
@@ -2194,5 +2194,7 @@
|
||||
"Drop to open the face model": "Solte para abrir o modelo de rostos",
|
||||
"Drop to import": "Solte para importar",
|
||||
"Dropped Files": "Arquivos soltos",
|
||||
"Import dropped files without review": "Importar arquivos soltos sem revisão"
|
||||
"Import dropped files without review": "Importar arquivos soltos sem revisão",
|
||||
"An import is running": "Uma importação está em andamento",
|
||||
"An import is running. Drop photos when it has finished": "Uma importação está em andamento. Solte as fotos quando ela terminar"
|
||||
}
|
||||
|
||||
@@ -2341,5 +2341,7 @@
|
||||
"Drop to open the face model": "Отпустите, чтобы открыть модель лиц",
|
||||
"Drop to import": "Отпустите для импорта",
|
||||
"Dropped Files": "Перетащенные файлы",
|
||||
"Import dropped files without review": "Импортировать перетащенные файлы без проверки"
|
||||
"Import dropped files without review": "Импортировать перетащенные файлы без проверки",
|
||||
"An import is running": "Импорт уже выполняется",
|
||||
"An import is running. Drop photos when it has finished": "Импорт уже выполняется. Перетащите фото, когда он закончится"
|
||||
}
|
||||
|
||||
@@ -2346,5 +2346,7 @@
|
||||
"Drop to open the face model": "Відпустіть, щоб відкрити модель облич",
|
||||
"Drop to import": "Відпустіть для імпорту",
|
||||
"Dropped Files": "Перетягнуті файли",
|
||||
"Import dropped files without review": "Імпортувати перетягнуті файли без перегляду"
|
||||
"Import dropped files without review": "Імпортувати перетягнуті файли без перегляду",
|
||||
"An import is running": "Імпорт уже виконується",
|
||||
"An import is running. Drop photos when it has finished": "Імпорт уже виконується. Перетягніть фото, коли він завершиться"
|
||||
}
|
||||
|
||||
@@ -2192,5 +2192,7 @@
|
||||
"Drop to open the face model": "松开鼠标以打开人脸模型",
|
||||
"Drop to import": "松开鼠标以导入",
|
||||
"Dropped Files": "拖入的文件",
|
||||
"Import dropped files without review": "不经检查直接导入拖入的文件"
|
||||
"Import dropped files without review": "不经检查直接导入拖入的文件",
|
||||
"An import is running": "正在导入",
|
||||
"An import is running. Drop photos when it has finished": "正在导入。导入完成后再拖放照片"
|
||||
}
|
||||
|
||||
@@ -2149,5 +2149,7 @@
|
||||
"Drop to open the face model": "放開滑鼠以開啟人臉模型",
|
||||
"Drop to import": "放開滑鼠以匯入",
|
||||
"Dropped Files": "拖放的檔案",
|
||||
"Import dropped files without review": "不經檢查直接匯入拖放的檔案"
|
||||
"Import dropped files without review": "不經檢查直接匯入拖放的檔案",
|
||||
"An import is running": "正在匯入",
|
||||
"An import is running. Drop photos when it has finished": "正在匯入。匯入完成後再拖放照片"
|
||||
}
|
||||
|
||||
@@ -40,7 +40,9 @@ fn lines(app: &LightcraftApp, paths: Vec<String>, unknown: bool) -> Vec<String>
|
||||
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() {
|
||||
if !drop.photos.is_empty() && crate::import::running(app) && !cfg!(target_arch = "wasm32") {
|
||||
out.push(crate::i18n::tr("An import is running. Drop photos when it has finished").to_string());
|
||||
} else if !drop.photos.is_empty() {
|
||||
let n = drop.photos.len();
|
||||
// the web build has no review to open: its drops import at once
|
||||
if app.ui.settings.import_dropped_directly || cfg!(target_arch = "wasm32") {
|
||||
|
||||
@@ -263,8 +263,6 @@ fn catalog_verbatim(language: Locale) -> BTreeMap<String, &'static str> {
|
||||
// `locales/*-formats.json`.
|
||||
include!(concat!(env!("OUT_DIR"), "/tr-formats.rs"));
|
||||
|
||||
/// A stock preset's or profile's name in the UI language; an imported or user-edited name stays
|
||||
/// exactly as its owner wrote it.
|
||||
/// The web build's notice for a dropped file the browser could not read.
|
||||
pub fn dropped_file_unreadable(name: &str, error: &str) -> String {
|
||||
tr_format!("Could not read {name}: {e}", name = name, e = error)
|
||||
@@ -317,6 +315,8 @@ pub fn upper_first(text: &str) -> String {
|
||||
}
|
||||
}
|
||||
|
||||
/// A stock preset's or profile's name in the UI language; an imported or user-edited name stays
|
||||
/// exactly as its owner wrote it.
|
||||
pub fn builtin_label(source: &str, builtin: bool) -> &str {
|
||||
if builtin { tr(source) } else { source }
|
||||
}
|
||||
|
||||
@@ -556,6 +556,7 @@ pub fn browse(app: &mut LightcraftApp, path: &str, subfolders: Option<bool>) ->
|
||||
|
||||
/// Collect a finished scan and open the review (called every frame).
|
||||
pub fn poll_scan(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
show_pending_review(app, ctx);
|
||||
let Some(task) = app.scan.as_ref() else { return };
|
||||
ctx.request_repaint_after(std::time::Duration::from_millis(100));
|
||||
let out = match task.rx.try_recv() {
|
||||
@@ -626,7 +627,36 @@ pub fn poll_scan(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
// only an album the review offers (it may have been deleted while the scan ran)
|
||||
d.album = task.album.filter(|id| app.session.catalog.album(lightcraft_catalog::AlbumId(*id)).is_some_and(|a| !a.folder && !a.is_smart()));
|
||||
d.sources = task.sources;
|
||||
app.ui.dialog = Some(crate::state::Dialog::Import { opts: Box::new(d) });
|
||||
app.review_pending = Some(crate::state::Dialog::Import { opts: Box::new(d) });
|
||||
show_pending_review(app, ctx);
|
||||
}
|
||||
|
||||
/// Open the review of a finished scan once no other dialog is open (a face model's licence, Settings…
|
||||
/// opened while the scan ran stays), checked again shortly while it waits.
|
||||
fn show_pending_review(app: &mut LightcraftApp, ctx: &egui::Context) {
|
||||
if app.review_pending.is_none() {
|
||||
return;
|
||||
}
|
||||
if app.ui.dialog.is_none() {
|
||||
app.ui.dialog = app.review_pending.take();
|
||||
} else {
|
||||
ctx.request_repaint_after(std::time::Duration::from_millis(100));
|
||||
}
|
||||
}
|
||||
|
||||
/// Tests: a review scan that never ends while the returned value lives, so a drop meets it running.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn stall_scan(app: &mut LightcraftApp) -> Box<dyn std::any::Any> {
|
||||
let progress = std::sync::Arc::new(ScanProgress::default());
|
||||
let (tx, rx) = std::sync::mpsc::channel::<ScanOutput>();
|
||||
let guard = scan_guard(app, &progress, false);
|
||||
app.scan = Some(ScanTask { progress, rx, copy: false, album: None, browse: false, sources: Vec::new(), guard });
|
||||
Box::new(tx)
|
||||
}
|
||||
|
||||
/// Whether an import (or the review's scan) is running, which a drop of photos must not replace.
|
||||
pub fn running(app: &LightcraftApp) -> bool {
|
||||
app.import.is_some() || app.scan.as_ref().is_some_and(|t| !t.browse)
|
||||
}
|
||||
|
||||
impl ScanTask {
|
||||
@@ -691,8 +721,8 @@ pub fn start(app: &mut LightcraftApp, d: &ImportDialog) -> Result<Value, String>
|
||||
/// Start importing `paths` (files or folders) in the background, e.g. dropped on the window.
|
||||
pub fn start_paths(app: &mut LightcraftApp, paths: Vec<String>) -> Result<Value, String> {
|
||||
busy_synchronizing(app)?;
|
||||
if app.import.is_some() || app.scan.as_ref().is_some_and(|t| !t.browse) {
|
||||
return Err("an import is running".into());
|
||||
if running(app) {
|
||||
return Err(crate::i18n::tr("An import is running").to_string());
|
||||
}
|
||||
let undo0 = app.session.undo.len();
|
||||
let total = paths.len();
|
||||
|
||||
@@ -458,6 +458,8 @@ pub struct LightcraftApp {
|
||||
pub lightroom_last: Option<Value>,
|
||||
/// A completed import result waiting for another modal dialog to close.
|
||||
pub(crate) lightroom_result: Option<state::Dialog>,
|
||||
/// The import review of a finished scan, waiting for another dialog to close.
|
||||
pub(crate) review_pending: Option<state::Dialog>,
|
||||
/// The library generation the window title and the recent list were last updated for.
|
||||
pub shown_library: Option<u64>,
|
||||
/// A background export in progress.
|
||||
@@ -557,6 +559,7 @@ impl LightcraftApp {
|
||||
lightroom: None,
|
||||
lightroom_last: None,
|
||||
lightroom_result: None,
|
||||
review_pending: None,
|
||||
shown_library: None,
|
||||
export: None,
|
||||
tasks: Default::default(),
|
||||
@@ -1276,6 +1279,10 @@ impl LightcraftApp {
|
||||
self.toast(ctx, "Finish Lightroom catalog import before adding photos");
|
||||
return;
|
||||
}
|
||||
if import::running(self) {
|
||||
self.toast(ctx, crate::i18n::tr("An import is running"));
|
||||
return;
|
||||
}
|
||||
let started = if self.ui.settings.import_dropped_directly {
|
||||
// read and added on a worker thread (dropped folders can be large, or on a slow drive)
|
||||
import::start_paths(self, drop.photos).map(|_| ())
|
||||
|
||||
@@ -146,3 +146,56 @@ fn a_drop_while_a_dialog_is_open_leaves_the_dialog_and_imports_nothing() {
|
||||
assert_eq!(photos(&h), 0);
|
||||
assert!(h.app.ui.toast.is_some(), "the person is told why");
|
||||
}
|
||||
|
||||
/// The scan of a dropped folder finishing while another dialog is open (the face model's licence, Settings…)
|
||||
/// keeps that dialog; the review opens, with the scan's photos, once it is closed.
|
||||
#[test]
|
||||
fn a_finished_scan_waits_for_the_open_dialog_before_opening_the_review() {
|
||||
let dir = Scratch::new("waits");
|
||||
let mut h = app(&dir);
|
||||
crate::import::open(&mut h.app, vec![dir.path("trip")]).unwrap();
|
||||
h.app.ui.dialog = Some(Dialog::WhatsNew);
|
||||
assert!(h.step_until(SETTLE, |h| h.app.scan.is_none()), "the scan ends");
|
||||
for _ in 0..10 {
|
||||
h.step();
|
||||
}
|
||||
assert!(matches!(h.app.ui.dialog, Some(Dialog::WhatsNew)), "the dialog the person had open stays");
|
||||
h.app.ui.dialog = None;
|
||||
assert!(h.step_until(T, |h| matches!(h.app.ui.dialog, Some(Dialog::Import { .. }))), "the review opens once the dialog is closed");
|
||||
let Some(Dialog::Import { opts }) = &h.app.ui.dialog else { panic!("no import review") };
|
||||
assert_eq!(opts.candidates.len(), 2, "the scan's photos were kept");
|
||||
}
|
||||
|
||||
/// A drop while an import runs would open a review whose OK replaces the running import: it is
|
||||
/// refused instead, and the card says so.
|
||||
#[test]
|
||||
fn a_drop_while_an_import_runs_is_refused() {
|
||||
let dir = Scratch::new("running");
|
||||
let mut h = app(&dir);
|
||||
write_png(&dir.path("more/c.png"), 3);
|
||||
let _scan = crate::import::stall_scan(&mut h.app);
|
||||
drop_files(&mut h, &[dir.path("more/c.png")], true);
|
||||
assert!(said(&h, "An import is running"), "{:?}", h.painted_text());
|
||||
assert!(!said(&h, "review"), "{:?}", h.painted_text());
|
||||
drop_files(&mut h, &[dir.path("more")], false);
|
||||
for _ in 0..30 {
|
||||
h.step();
|
||||
}
|
||||
assert!(h.app.ui.dialog.is_none(), "no review opened");
|
||||
assert!(h.app.scan.is_some() && h.app.import.is_none(), "the running scan was left alone and nothing else started");
|
||||
assert!(h.app.ui.toast.is_some(), "the person is told why");
|
||||
assert_eq!(photos(&h), 0);
|
||||
}
|
||||
|
||||
/// An import that is running stays the one that runs: a direct drop doesn't start a second.
|
||||
#[test]
|
||||
fn a_direct_drop_while_an_import_runs_is_refused_too() {
|
||||
let dir = Scratch::new("running-direct");
|
||||
let mut h = app(&dir);
|
||||
h.app.ui.settings.import_dropped_directly = true;
|
||||
write_png(&dir.path("more/c.png"), 3);
|
||||
let _scan = crate::import::stall_scan(&mut h.app);
|
||||
drop_files(&mut h, &[dir.path("more")], false);
|
||||
assert!(h.app.import.is_none(), "no second import");
|
||||
assert!(h.app.ui.toast.is_some());
|
||||
}
|
||||
|
||||
@@ -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 is refused with a toast; 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); 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 |
|
||||
@@ -927,4 +927,4 @@ Latin stays upright. Advanced Japanese composition remains open. Regression cove
|
||||
| 2026-10-16 | minor | LR-VIEW-PHOTOGRID: when the photos shown change by those an edit touched (an import's batch, a capture time, a crop), the grid reads only those photos' dates and shapes again instead of every photo of the list (a 16-photo batch at 181,749 photos: grid frame 101 ms → 7 ms); status unchanged |
|
||||
| 2026-10-19 | minor | LRC-LIB-LIBFOLDERS: the sidebar trees indent by a narrower step (14 / 12 / 10 / 8 pt) when the deepest open row would not fit the panel, instead of cutting its name or scrolling sideways at once (issue #2298); status unchanged (✅) |
|
||||
| 2026-10-15 | patch | LR-EXP-DIM: Width & Height (`fit: widthHeight`) limits the width and the height as the photo stands, beside Dimensions (W × H, either orientation), as in Lightroom (#1620); status unchanged (✅) |
|
||||
| 2026-10-17 | minor | LR-IMP-DRAGDROP: files dragged over the window show what dropping will do, and dropped photos and folders open the import review (Settings ▸ Import can import them at once); a drop while a dialog is open is refused; the web build tells the person when a dropped file can't be read or imported. LR-BEHAV-EMPTY-STATES, LR-BEHAV-DRAGDROP: text updated; status unchanged (✅) |
|
||||
| 2026-10-17 | minor | LR-IMP-DRAGDROP: files dragged over the window show what dropping will do, and dropped photos and folders open the import review (Settings ▸ Import can import them at once); a drop while a dialog is open or an import is running is refused; a finished scan no longer replaces an open dialog; the web build tells the person when a dropped file can't be read or imported. LR-BEHAV-EMPTY-STATES, LR-BEHAV-DRAGDROP: text updated; status unchanged (✅) |
|
||||
|
||||
+4
-1
@@ -5,7 +5,10 @@
|
||||
### Dropping files shows what will happen
|
||||
- While files are dragged over the window, it dims and a card says what dropping will do: review the photos and
|
||||
folders for import, import the presets, or open the face model. If a dialog is open, the card asks you to close it
|
||||
first, and a drop is refused with a message instead of replacing the dialog.
|
||||
first, and a drop is refused with a message instead of replacing the dialog. The same goes while an import is
|
||||
running, and in the web version.
|
||||
- The import review of a finished scan (a drop, or File ▸ Import) no longer replaces a dialog you opened in the
|
||||
meantime; it opens as soon as that dialog is closed.
|
||||
- Photos and folders dropped on the window now open the same import review as File ▸ Import, so you pick add, copy or
|
||||
move, the destination and a preset before anything is imported. Settings ▸ Import ▸ "Import dropped files without
|
||||
review" brings back the old behaviour of importing at once.
|
||||
|
||||
Reference in New Issue
Block a user