mirror of
https://github.com/storytold/lightcraft.git
synced 2026-10-31 21:48:53 -06:00
LR-IMP-DEVICE: Show the import review when a card is connected
Adds an option under Settings > Import > Cameras and Cards that opens Import from Device when a camera or memory card shows up. It's off by default, and a card that was already in at startup doesn't ask.
This commit is contained in:
@@ -43,6 +43,9 @@ fn prefs(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
if let Some(v) = i.get("perCamera").and_then(Value::as_bool) {
|
||||
d.per_camera = v;
|
||||
}
|
||||
if let Some(v) = i.get("showOnCard").and_then(Value::as_bool) {
|
||||
d.show_on_card = v;
|
||||
}
|
||||
if let Some(v) = i.get("copyright").and_then(Value::as_str) {
|
||||
d.copyright = v.trim().to_string();
|
||||
}
|
||||
@@ -107,7 +110,7 @@ pub fn specs() -> Vec<CommandSpec> {
|
||||
"Library Preferences",
|
||||
[],
|
||||
None,
|
||||
"{import?: {rawPreset?: presetId|\"default\", otherPreset?: presetId|\"default\", perCamera?: bool, cameras?: [{camera: \"Make Model\", preset: presetId|null}], copyright?: text, creator?: text (given to imported photos without one)}, camera?: {camera, preset?, remove?: bool}, cacheMb?: n (0 = default), forgetLocalDays?: n (forget untouched Local photos of folders not browsed for n days; 0 = never)} — develop defaults applied on import (raws / other images / per camera) and the thumbnail cache size, saved with the library → {xmp, import, cacheMb, forgetLocalDays, persistent}",
|
||||
"{import?: {rawPreset?: presetId|\"default\", otherPreset?: presetId|\"default\", perCamera?: bool, cameras?: [{camera: \"Make Model\", preset: presetId|null}], copyright?: text, creator?: text (given to imported photos without one), showOnCard?: bool (open the import review when a camera or card is connected)}, camera?: {camera, preset?, remove?: bool}, cacheMb?: n (0 = default), forgetLocalDays?: n (forget untouched Local photos of folders not browsed for n days; 0 = never)} — develop defaults applied on import (raws / other images / per camera) and the thumbnail cache size, saved with the library → {xmp, import, cacheMb, forgetLocalDays, persistent}",
|
||||
always,
|
||||
prefs
|
||||
)]
|
||||
|
||||
@@ -104,6 +104,18 @@ impl DeviceWatch {
|
||||
s.list.clone()
|
||||
}
|
||||
|
||||
/// Like [`DeviceWatch::get`], but `None` until the first scan has landed, so an empty list
|
||||
/// means no cards rather than not looked yet.
|
||||
pub fn get_scanned(self: &Arc<Self>) -> Option<Vec<Device>> {
|
||||
let _ = self.get();
|
||||
let s = self.state();
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let scanned = s.scanned.is_some();
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let scanned = false;
|
||||
scanned.then(|| s.list.clone())
|
||||
}
|
||||
|
||||
/// Scan now on this thread, and serve the result to later [`DeviceWatch::get`] calls.
|
||||
pub fn scan_now(&self) -> Vec<Device> {
|
||||
let list = (self.scanner)();
|
||||
@@ -148,6 +160,12 @@ pub fn devices() -> Vec<Device> {
|
||||
global().get()
|
||||
}
|
||||
|
||||
/// [`devices`], but `None` until the first scan lands. The import prompt uses it so a card that was
|
||||
/// already in when LightCraft started isn't taken for a new one.
|
||||
pub fn devices_scanned() -> Option<Vec<Device>> {
|
||||
global().get_scanned()
|
||||
}
|
||||
|
||||
/// Scan the mounted volumes now (blocking), for explicit requests.
|
||||
pub fn devices_now() -> Vec<Device> {
|
||||
global().scan_now()
|
||||
@@ -285,4 +303,24 @@ mod tests {
|
||||
assert!(watch.scan_now().is_empty());
|
||||
assert_eq!(changes.load(Ordering::SeqCst), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_scanned_waits_for_the_first_scan() {
|
||||
let gate = Arc::new(std::sync::atomic::AtomicBool::new(false));
|
||||
let g = gate.clone();
|
||||
let watch = DeviceWatch::new(
|
||||
move || {
|
||||
while !g.load(Ordering::SeqCst) {
|
||||
std::thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
vec![card("NIKON Z 8")]
|
||||
},
|
||||
Duration::from_secs(60),
|
||||
);
|
||||
assert_eq!(watch.get_scanned(), None, "nothing scanned yet");
|
||||
assert_eq!(watch.get_scanned(), None);
|
||||
gate.store(true, Ordering::SeqCst);
|
||||
assert!(until(|| watch.get_scanned().is_some()));
|
||||
assert_eq!(watch.get_scanned(), Some(vec![card("NIKON Z 8")]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +310,8 @@ pub struct ImportDefaults {
|
||||
pub auto_folder: Option<String>,
|
||||
pub auto_copy: bool,
|
||||
pub auto_album: Option<String>,
|
||||
/// Open the import review when a camera or memory card is connected.
|
||||
pub show_on_card: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
@@ -108,7 +108,7 @@ fn preferences_persist_with_the_library() {
|
||||
s.execute("library.xmpPreferences", &json!({"autoWrite": true})).unwrap();
|
||||
s.execute(
|
||||
"library.preferences",
|
||||
&json!({"import": {"rawPreset": "user.rawlook", "perCamera": true}, "camera": {"camera": "Canon EOS R5", "preset": "user.canonlook"}, "cacheMb": 512}),
|
||||
&json!({"import": {"rawPreset": "user.rawlook", "perCamera": true, "showOnCard": true}, "camera": {"camera": "Canon EOS R5", "preset": "user.canonlook"}, "cacheMb": 512}),
|
||||
)
|
||||
.unwrap();
|
||||
s.close_library().unwrap();
|
||||
@@ -118,6 +118,7 @@ fn preferences_persist_with_the_library() {
|
||||
assert!(s.xmp.auto_write);
|
||||
assert_eq!(s.import_defaults.raw_preset.as_deref(), Some("user.rawlook"));
|
||||
assert!(s.import_defaults.per_camera);
|
||||
assert!(s.import_defaults.show_on_card);
|
||||
assert_eq!(s.import_defaults.cameras.len(), 1);
|
||||
assert_eq!(s.import_defaults.preset_for(true, "Canon EOS R5"), Some("user.canonlook"));
|
||||
assert_eq!(s.cache_mb, 512);
|
||||
|
||||
Reference in New Issue
Block a user