Satisfy rustfmt and clippy on the album and folder picker changes
rustfmt over the files the albums work touched, and the album merge's incoming row as a named struct rather than an eight-field tuple, which clippy's type_complexity refused.
This commit is contained in:
+56
-43
@@ -128,7 +128,11 @@ impl AlbumsController {
|
||||
let borrow = catalog.borrow();
|
||||
let Some(cat) = borrow.as_ref() else { return };
|
||||
if let Err(e) = albums::record_exports(cat.connection(), album, &files) {
|
||||
log::warn!("recording {} exports in album {}: {e}", files.len(), album.0);
|
||||
log::warn!(
|
||||
"recording {} exports in album {}: {e}",
|
||||
files.len(),
|
||||
album.0
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -188,11 +192,12 @@ fn adopt_old_destination(ctl: &AlbumsController, cat: &dr_catalog::Catalog) {
|
||||
return;
|
||||
}
|
||||
let place = Place::Local(export.destination.trim().to_string());
|
||||
match albums::create(conn, "Exports", &place)
|
||||
.and_then(|id| albums::get(conn, id))
|
||||
{
|
||||
match albums::create(conn, "Exports", &place).and_then(|id| albums::get(conn, id)) {
|
||||
Ok(Some(album)) => {
|
||||
log::info!("the export folder {} is now the album “Exports”", export.destination);
|
||||
log::info!(
|
||||
"the export folder {} is now the album “Exports”",
|
||||
export.destination
|
||||
);
|
||||
ctl.settings.edit(|s| s.export.album = album.uuid);
|
||||
}
|
||||
Ok(None) => {}
|
||||
@@ -252,7 +257,10 @@ fn describe(place: Option<&Place>) -> String {
|
||||
fn display_folder(folder: &str) -> String {
|
||||
if folder.starts_with("content://") {
|
||||
let tail = folder.rsplit('/').next().unwrap_or(folder);
|
||||
let decoded = tail.replace("%3A", ":").replace("%2F", "/").replace("%20", " ");
|
||||
let decoded = tail
|
||||
.replace("%3A", ":")
|
||||
.replace("%2F", "/")
|
||||
.replace("%20", " ");
|
||||
return decoded
|
||||
.split_once(':')
|
||||
.map(|(_, p)| p.to_string())
|
||||
@@ -268,7 +276,10 @@ fn render_sheet(window: &AppWindow, ctl: &AlbumsController) {
|
||||
albums.set_sheet_open(false);
|
||||
return;
|
||||
};
|
||||
let server = ctl.library.credentials().is_some_and(|c| !c.account.login.is_empty());
|
||||
let server = ctl
|
||||
.library
|
||||
.credentials()
|
||||
.is_some_and(|c| !c.account.login.is_empty());
|
||||
let refusal = if s.at == Where::Server {
|
||||
refusal(&s.browser.path, ctl)
|
||||
} else {
|
||||
@@ -329,7 +340,9 @@ fn inside(path: &str, root: &str) -> bool {
|
||||
|
||||
/// List the sheet's server folder, and redraw when the answer comes.
|
||||
fn browse(weak: slint::Weak<AppWindow>, ctl: Rc<AlbumsController>, path: String) {
|
||||
let Some(conn) = ctl.library.credentials() else { return };
|
||||
let Some(conn) = ctl.library.credentials() else {
|
||||
return;
|
||||
};
|
||||
if let Some(s) = ctl.sheet.borrow_mut().as_mut() {
|
||||
s.browser.path = path.clone();
|
||||
s.browser.entries.clear();
|
||||
@@ -375,7 +388,10 @@ fn settle(
|
||||
/// Open the sheet — on a new album, or on `editing`.
|
||||
fn open_sheet(window: &AppWindow, ctl: &Rc<AlbumsController>, editing: Option<AlbumId>) {
|
||||
let album = editing.and_then(|id| ctl.rows.borrow().iter().find(|a| a.id == id).cloned());
|
||||
let server = ctl.library.credentials().is_some_and(|c| !c.account.login.is_empty());
|
||||
let server = ctl
|
||||
.library
|
||||
.credentials()
|
||||
.is_some_and(|c| !c.account.login.is_empty());
|
||||
let (at, device_folder, server_path) = match album.as_ref().and_then(|a| a.place.clone()) {
|
||||
Some(Place::Local(f)) => (Where::Device, f, String::new()),
|
||||
Some(Place::Server(p)) => (Where::Server, String::new(), p),
|
||||
@@ -417,14 +433,13 @@ fn save(window: &AppWindow, ctl: &Rc<AlbumsController>) {
|
||||
let Some(cat) = borrow.as_ref() else { return };
|
||||
let conn = cat.connection();
|
||||
match editing {
|
||||
Some(id) => albums::rename(conn, id, &name)
|
||||
.and_then(|()| {
|
||||
let current = albums::get(conn, id)?.and_then(|a| a.place);
|
||||
if current.as_ref() != Some(&place) {
|
||||
albums::set_place(conn, id, &place)?;
|
||||
}
|
||||
Ok(id)
|
||||
}),
|
||||
Some(id) => albums::rename(conn, id, &name).and_then(|()| {
|
||||
let current = albums::get(conn, id)?.and_then(|a| a.place);
|
||||
if current.as_ref() != Some(&place) {
|
||||
albums::set_place(conn, id, &place)?;
|
||||
}
|
||||
Ok(id)
|
||||
}),
|
||||
None => albums::create(conn, &name, &place),
|
||||
}
|
||||
.and_then(|id| Ok((id, albums::get(conn, id)?)))
|
||||
@@ -686,7 +701,9 @@ pub fn wire(
|
||||
let ctl = ctl.clone();
|
||||
albums.on_browse_make(move |name| {
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
let Some(conn) = ctl.library.credentials() else { return };
|
||||
let Some(conn) = ctl.library.credentials() else {
|
||||
return;
|
||||
};
|
||||
let parent = {
|
||||
let mut sheet = ctl.sheet.borrow_mut();
|
||||
let Some(s) = sheet.as_mut() else { return };
|
||||
@@ -700,18 +717,16 @@ pub fn wire(
|
||||
let name = name.trim().to_string();
|
||||
let (weak, ctl2) = (weak.clone(), ctl.clone());
|
||||
let child = name.clone();
|
||||
crate::remote_folders::make(conn, parent.clone(), name, move |result| {
|
||||
match result {
|
||||
Ok(_) => {
|
||||
let path = if parent.is_empty() {
|
||||
child
|
||||
} else {
|
||||
format!("{parent}/{child}")
|
||||
};
|
||||
browse(weak, ctl2, path);
|
||||
}
|
||||
Err(e) => settle(&weak, &ctl2, &parent, Err(e)),
|
||||
crate::remote_folders::make(conn, parent.clone(), name, move |result| match result {
|
||||
Ok(_) => {
|
||||
let path = if parent.is_empty() {
|
||||
child
|
||||
} else {
|
||||
format!("{parent}/{child}")
|
||||
};
|
||||
browse(weak, ctl2, path);
|
||||
}
|
||||
Err(e) => settle(&weak, &ctl2, &parent, Err(e)),
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -720,20 +735,18 @@ pub fn wire(
|
||||
{
|
||||
let weak = window.as_weak();
|
||||
let ctl = ctl.clone();
|
||||
window
|
||||
.global::<ExportOptions>()
|
||||
.on_album_picked(move |i| {
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
let uuid = ctl
|
||||
.rows
|
||||
.borrow()
|
||||
.get(i.max(0) as usize)
|
||||
.map(|a| a.uuid.clone());
|
||||
if let Some(uuid) = uuid {
|
||||
ctl.settings.edit(|s| s.export.album = uuid);
|
||||
}
|
||||
render(&w, &ctl);
|
||||
});
|
||||
window.global::<ExportOptions>().on_album_picked(move |i| {
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
let uuid = ctl
|
||||
.rows
|
||||
.borrow()
|
||||
.get(i.max(0) as usize)
|
||||
.map(|a| a.uuid.clone());
|
||||
if let Some(uuid) = uuid {
|
||||
ctl.settings.edit(|s| s.export.album = uuid);
|
||||
}
|
||||
render(&w, &ctl);
|
||||
});
|
||||
}
|
||||
{
|
||||
let weak = window.as_weak();
|
||||
|
||||
@@ -220,7 +220,9 @@ fn refuse(window: &AppWindow, to: export::Reporting, message: &str) {
|
||||
window.set_export_busy(false);
|
||||
}
|
||||
export::Reporting::Library => {
|
||||
window.global::<Library>().set_library_status(message.into());
|
||||
window
|
||||
.global::<Library>()
|
||||
.set_library_status(message.into());
|
||||
window.global::<Library>().set_library_exporting(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,8 +313,7 @@ fn stage(encoded: &Encoded, remote_dir: &str, outbox: &Path) -> Result<PathBuf,
|
||||
Some(dir) => format!("{dir}\n{}\naccount\n", encoded.name),
|
||||
None => format!("{remote_dir}\n{}\n", encoded.name),
|
||||
};
|
||||
std::fs::write(&record, text)
|
||||
.map_err(|e| format!("{}: {e}", record.display()))?;
|
||||
std::fs::write(&record, text).map_err(|e| format!("{}: {e}", record.display()))?;
|
||||
|
||||
Ok(candidate)
|
||||
}
|
||||
@@ -1503,7 +1502,13 @@ mod tests {
|
||||
std::thread::current().id()
|
||||
));
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
place(&encoded("a.jpg", b"x"), ExportTarget::Remote, "/Shared/Web", &dir).unwrap();
|
||||
place(
|
||||
&encoded("a.jpg", b"x"),
|
||||
ExportTarget::Remote,
|
||||
"/Shared/Web",
|
||||
&dir,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let entry = pending(&dir).pop().expect("one staged export");
|
||||
assert!(entry.account);
|
||||
|
||||
@@ -33,10 +33,10 @@
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use slint::ComponentHandle;
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use raw_window_handle::{HasDisplayHandle as _, HasWindowHandle as _};
|
||||
#[cfg(not(target_os = "android"))]
|
||||
use slint::ComponentHandle;
|
||||
|
||||
use crate::AppWindow;
|
||||
|
||||
|
||||
@@ -506,7 +506,14 @@ fn wire_options(window: &AppWindow, ctl: &Rc<ImportController>) {
|
||||
let ctl = ctl.clone();
|
||||
window.on_import_choose_backup(move || {
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
let start = ctl.settings.settings.borrow().import.backup.trim().to_string();
|
||||
let start = ctl
|
||||
.settings
|
||||
.settings
|
||||
.borrow()
|
||||
.import
|
||||
.backup
|
||||
.trim()
|
||||
.to_string();
|
||||
let (weak, ctl) = (weak.clone(), ctl.clone());
|
||||
crate::folder_dialog::ask(
|
||||
&w,
|
||||
|
||||
@@ -350,7 +350,9 @@ fn wire_folder_picker_navigation(window: &AppWindow, controller: &Rc<LaunchContr
|
||||
let (account, parent) = {
|
||||
let m = ctl.model.borrow();
|
||||
let Some(b) = m.browser.as_ref() else { return };
|
||||
let Some(account) = m.session().cloned() else { return };
|
||||
let Some(account) = m.session().cloned() else {
|
||||
return;
|
||||
};
|
||||
(account, b.path.clone())
|
||||
};
|
||||
let conn = match ctl
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ mod display_ui;
|
||||
mod duplicates;
|
||||
mod duplicates_ui;
|
||||
mod export;
|
||||
mod folder_dialog;
|
||||
pub mod faces;
|
||||
mod folder_dialog;
|
||||
pub use library::render_native;
|
||||
// Generated from the `GESTURE:` comments beside the code that implements each
|
||||
// one — see `tools/traceability`. Regenerate with
|
||||
@@ -68,9 +68,9 @@ mod recovery_ui;
|
||||
mod refine;
|
||||
mod remote;
|
||||
mod remote_folders;
|
||||
pub mod repairs;
|
||||
#[cfg(target_os = "android")]
|
||||
mod saf;
|
||||
pub mod repairs;
|
||||
mod segmentation;
|
||||
mod settings_store;
|
||||
mod settings_ui;
|
||||
|
||||
@@ -661,18 +661,33 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let filter = RatingFilter::default();
|
||||
let cells = read_cells_scoped(&catalog, Some(Scope::Collection(coll)), &filter, 0, 100).unwrap();
|
||||
let cells =
|
||||
read_cells_scoped(&catalog, Some(Scope::Collection(coll)), &filter, 0, 100).unwrap();
|
||||
assert_eq!(cells.len(), 2);
|
||||
for (i, cell) in cells.iter().enumerate() {
|
||||
assert_eq!(
|
||||
ordinal_of_path(&catalog, Some(Scope::Collection(coll)), &filter, false, &cell.remote_path).unwrap(),
|
||||
ordinal_of_path(
|
||||
&catalog,
|
||||
Some(Scope::Collection(coll)),
|
||||
&filter,
|
||||
false,
|
||||
&cell.remote_path
|
||||
)
|
||||
.unwrap(),
|
||||
Some(i),
|
||||
"{} is drawn at row {i} of the collection",
|
||||
cell.remote_path
|
||||
);
|
||||
}
|
||||
assert_eq!(
|
||||
ordinal_of_path(&catalog, Some(Scope::Collection(coll)), &filter, false, "2019/a.CR2").unwrap(),
|
||||
ordinal_of_path(
|
||||
&catalog,
|
||||
Some(Scope::Collection(coll)),
|
||||
&filter,
|
||||
false,
|
||||
"2019/a.CR2"
|
||||
)
|
||||
.unwrap(),
|
||||
None,
|
||||
"not a member"
|
||||
);
|
||||
|
||||
@@ -415,8 +415,8 @@ mod tests {
|
||||
|
||||
let catalog = with_images(10);
|
||||
let ids = image_ids(&catalog);
|
||||
let album = albums::create(catalog.connection(), "Web", &Place::Local("/out".into()))
|
||||
.unwrap();
|
||||
let album =
|
||||
albums::create(catalog.connection(), "Web", &Place::Local("/out".into())).unwrap();
|
||||
// Two files from one photograph, one from another: two cells.
|
||||
albums::record_exports(
|
||||
catalog.connection(),
|
||||
@@ -460,10 +460,22 @@ mod tests {
|
||||
.unwrap();
|
||||
coll::add_images(catalog.connection(), c, &ids[2..5]).unwrap();
|
||||
|
||||
let cells = read_cells_scoped(&catalog, Some(Scope::Collection(c)), &RatingFilter::default(), 0, 120).unwrap();
|
||||
let cells = read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(c)),
|
||||
&RatingFilter::default(),
|
||||
0,
|
||||
120,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(cells.len(), 3);
|
||||
assert_eq!(
|
||||
total_images_scoped(&catalog, Some(Scope::Collection(c)), &RatingFilter::default()).unwrap(),
|
||||
total_images_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(c)),
|
||||
&RatingFilter::default()
|
||||
)
|
||||
.unwrap(),
|
||||
3
|
||||
);
|
||||
// Unscoped is still the whole library.
|
||||
@@ -493,11 +505,22 @@ mod tests {
|
||||
coll::add_images(catalog.connection(), iceland, &ids[0..4]).unwrap();
|
||||
|
||||
// The parent itself has no direct members at all.
|
||||
let cells =
|
||||
read_cells_scoped(&catalog, Some(Scope::Collection(trips)), &RatingFilter::default(), 0, 120).unwrap();
|
||||
let cells = read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(trips)),
|
||||
&RatingFilter::default(),
|
||||
0,
|
||||
120,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(cells.len(), 4, "the set shows what its children hold");
|
||||
assert_eq!(
|
||||
total_images_scoped(&catalog, Some(Scope::Collection(trips)), &RatingFilter::default()).unwrap(),
|
||||
total_images_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(trips)),
|
||||
&RatingFilter::default()
|
||||
)
|
||||
.unwrap(),
|
||||
4
|
||||
);
|
||||
}
|
||||
@@ -522,11 +545,22 @@ mod tests {
|
||||
coll::add_images(catalog.connection(), trips, &ids[0..2]).unwrap();
|
||||
coll::add_images(catalog.connection(), iceland, &ids[0..3]).unwrap();
|
||||
|
||||
let cells =
|
||||
read_cells_scoped(&catalog, Some(Scope::Collection(trips)), &RatingFilter::default(), 0, 120).unwrap();
|
||||
let cells = read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(trips)),
|
||||
&RatingFilter::default(),
|
||||
0,
|
||||
120,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(cells.len(), 3, "images 0..3, each once");
|
||||
assert_eq!(
|
||||
total_images_scoped(&catalog, Some(Scope::Collection(trips)), &RatingFilter::default()).unwrap(),
|
||||
total_images_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(trips)),
|
||||
&RatingFilter::default()
|
||||
)
|
||||
.unwrap(),
|
||||
3
|
||||
);
|
||||
}
|
||||
@@ -542,7 +576,14 @@ mod tests {
|
||||
let c = coll::create(catalog.connection(), "Big", None, CollectionKind::Manual).unwrap();
|
||||
coll::add_images(catalog.connection(), c, &ids).unwrap();
|
||||
|
||||
let page = read_cells_scoped(&catalog, Some(Scope::Collection(c)), &RatingFilter::default(), 10, 5).unwrap();
|
||||
let page = read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(c)),
|
||||
&RatingFilter::default(),
|
||||
10,
|
||||
5,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(page.len(), 5);
|
||||
assert_eq!(page[0].name, "img010.CR2");
|
||||
}
|
||||
@@ -556,13 +597,22 @@ mod tests {
|
||||
let catalog = with_images(10);
|
||||
let c = coll::create(catalog.connection(), "Empty", None, CollectionKind::Manual).unwrap();
|
||||
|
||||
assert!(
|
||||
read_cells_scoped(&catalog, Some(Scope::Collection(c)), &RatingFilter::default(), 0, 120)
|
||||
.unwrap()
|
||||
.is_empty()
|
||||
);
|
||||
assert!(read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(c)),
|
||||
&RatingFilter::default(),
|
||||
0,
|
||||
120
|
||||
)
|
||||
.unwrap()
|
||||
.is_empty());
|
||||
assert_eq!(
|
||||
total_images_scoped(&catalog, Some(Scope::Collection(c)), &RatingFilter::default()).unwrap(),
|
||||
total_images_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(c)),
|
||||
&RatingFilter::default()
|
||||
)
|
||||
.unwrap(),
|
||||
0
|
||||
);
|
||||
}
|
||||
@@ -671,15 +721,29 @@ mod tests {
|
||||
let wanted: Vec<_> = all.iter().rev().copied().collect();
|
||||
dr_catalog::collections::set_order(catalog.connection(), id, &wanted).unwrap();
|
||||
|
||||
let cells = read_cells_scoped(&catalog, Some(Scope::Collection(id)), &RatingFilter::default(), 0, 50).unwrap();
|
||||
let cells = read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(id)),
|
||||
&RatingFilter::default(),
|
||||
0,
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
let drawn: Vec<_> = cells
|
||||
.iter()
|
||||
.map(|c| dr_types::ImageId(c.image_id as u64))
|
||||
.collect();
|
||||
assert_eq!(drawn, wanted, "the grid draws the order that was written");
|
||||
|
||||
let spanned =
|
||||
read_ids_span(&catalog, Some(Scope::Collection(id)), &RatingFilter::default(), false, 0, 4).unwrap();
|
||||
let spanned = read_ids_span(
|
||||
&catalog,
|
||||
Some(Scope::Collection(id)),
|
||||
&RatingFilter::default(),
|
||||
false,
|
||||
0,
|
||||
4,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(spanned, wanted, "and a range resolves through the same one");
|
||||
|
||||
assert_eq!(
|
||||
@@ -715,8 +779,14 @@ mod tests {
|
||||
let reversed: Vec<_> = all.iter().rev().copied().collect();
|
||||
dr_catalog::collections::set_order(catalog.connection(), parent, &reversed).unwrap();
|
||||
|
||||
let cells =
|
||||
read_cells_scoped(&catalog, Some(Scope::Collection(parent)), &RatingFilter::default(), 0, 50).unwrap();
|
||||
let cells = read_cells_scoped(
|
||||
&catalog,
|
||||
Some(Scope::Collection(parent)),
|
||||
&RatingFilter::default(),
|
||||
0,
|
||||
50,
|
||||
)
|
||||
.unwrap();
|
||||
let drawn: Vec<_> = cells
|
||||
.iter()
|
||||
.map(|c| dr_types::ImageId(c.image_id as u64))
|
||||
|
||||
@@ -342,7 +342,7 @@ pub(super) fn load_window(window: &AppWindow, ctl: &Rc<LibraryController>) {
|
||||
.set_library_scope_pinned(match scope {
|
||||
Some(library::Scope::Collection(id)) => {
|
||||
dr_catalog::collections::descendants(catalog.connection(), id)
|
||||
.map(|ids| collection_images(catalog, &ids))
|
||||
.map(|ids| collection_images(catalog, &ids))
|
||||
.map(|images| scope_is_pinned(catalog, &images))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
@@ -1100,9 +1100,15 @@ pub fn wire_named(
|
||||
window.on_browse_presets(move |file| {
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
let (title, pick) = if file {
|
||||
("Import a Lightroom preset", crate::folder_dialog::Pick::File(&["xmp"]))
|
||||
(
|
||||
"Import a Lightroom preset",
|
||||
crate::folder_dialog::Pick::File(&["xmp"]),
|
||||
)
|
||||
} else {
|
||||
("Import a folder of Lightroom presets", crate::folder_dialog::Pick::Folder)
|
||||
(
|
||||
"Import a folder of Lightroom presets",
|
||||
crate::folder_dialog::Pick::Folder,
|
||||
)
|
||||
};
|
||||
let (weak, named) = (weak.clone(), named.clone());
|
||||
crate::folder_dialog::ask(&w, title, pick, None, move |path| {
|
||||
|
||||
@@ -18,7 +18,11 @@ use dr_sync::{Connection, EntryKind, RemotePath};
|
||||
|
||||
/// Child folder names at `path` (empty is the account root), sorted as a
|
||||
/// person reads them.
|
||||
pub fn list(conn: Connection, path: String, done: impl FnOnce(Result<Vec<String>, String>) + 'static) {
|
||||
pub fn list(
|
||||
conn: Connection,
|
||||
path: String,
|
||||
done: impl FnOnce(Result<Vec<String>, String>) + 'static,
|
||||
) {
|
||||
run(conn, done, move |backend| {
|
||||
Box::pin(async move { children(backend.as_ref(), &path).await })
|
||||
});
|
||||
@@ -129,28 +133,34 @@ where
|
||||
let mut done = Some(done);
|
||||
let timer = slint::Timer::default();
|
||||
let held = slot.clone();
|
||||
timer.start(slint::TimerMode::Repeated, Duration::from_millis(100), move || {
|
||||
let outcome = match rx.try_recv() {
|
||||
Ok(result) => result,
|
||||
Err(TryRecvError::Empty) => return,
|
||||
// A worker that panicked drops the sender without sending, and
|
||||
// treating that as "still loading" is how a picker sits on
|
||||
// "Loading…" for ever.
|
||||
Err(TryRecvError::Disconnected) => Err("the folder request failed unexpectedly".into()),
|
||||
};
|
||||
if let Some(done) = done.take() {
|
||||
done(outcome);
|
||||
}
|
||||
// Stopped here, released a turn later: a timer dropped inside its
|
||||
// own callback is freed while Slint is still calling it.
|
||||
if let Some(t) = held.borrow().as_ref() {
|
||||
t.stop();
|
||||
}
|
||||
let held = held.clone();
|
||||
slint::Timer::single_shot(Duration::ZERO, move || {
|
||||
held.borrow_mut().take();
|
||||
});
|
||||
});
|
||||
timer.start(
|
||||
slint::TimerMode::Repeated,
|
||||
Duration::from_millis(100),
|
||||
move || {
|
||||
let outcome = match rx.try_recv() {
|
||||
Ok(result) => result,
|
||||
Err(TryRecvError::Empty) => return,
|
||||
// A worker that panicked drops the sender without sending, and
|
||||
// treating that as "still loading" is how a picker sits on
|
||||
// "Loading…" for ever.
|
||||
Err(TryRecvError::Disconnected) => {
|
||||
Err("the folder request failed unexpectedly".into())
|
||||
}
|
||||
};
|
||||
if let Some(done) = done.take() {
|
||||
done(outcome);
|
||||
}
|
||||
// Stopped here, released a turn later: a timer dropped inside its
|
||||
// own callback is freed while Slint is still calling it.
|
||||
if let Some(t) = held.borrow().as_ref() {
|
||||
t.stop();
|
||||
}
|
||||
let held = held.clone();
|
||||
slint::Timer::single_shot(Duration::ZERO, move || {
|
||||
held.borrow_mut().take();
|
||||
});
|
||||
},
|
||||
);
|
||||
*slot.borrow_mut() = Some(timer);
|
||||
}
|
||||
|
||||
|
||||
+57
-39
@@ -91,7 +91,11 @@ fn text(env: &mut jni::Env, value: JObject) -> jni::errors::Result<Option<String
|
||||
/// activity, and this one's event loop keeps running under it.
|
||||
pub fn pick_tree(chosen: impl FnOnce(String) + 'static) {
|
||||
let started = call("opening the folder picker", |env, activity| {
|
||||
let cls = class(env, activity, jni::jni_str!("paris.tourolle.darkroom.FolderPicker"))?;
|
||||
let cls = class(
|
||||
env,
|
||||
activity,
|
||||
jni::jni_str!("paris.tourolle.darkroom.FolderPicker"),
|
||||
)?;
|
||||
env.call_static_method(
|
||||
&cls,
|
||||
jni::jni_str!("start"),
|
||||
@@ -112,44 +116,52 @@ pub fn pick_tree(chosen: impl FnOnce(String) + 'static) {
|
||||
let mut chosen = Some(chosen);
|
||||
let since = Instant::now();
|
||||
let timer = slint::Timer::default();
|
||||
timer.start(slint::TimerMode::Repeated, Duration::from_millis(250), move || {
|
||||
let answer = call("reading the folder picker", |env, activity| {
|
||||
let cls = class(env, activity, jni::jni_str!("paris.tourolle.darkroom.FolderPicker"))?;
|
||||
let value = env
|
||||
.call_static_method(
|
||||
&cls,
|
||||
jni::jni_str!("poll"),
|
||||
jni::jni_sig!("()Ljava/lang/String;"),
|
||||
&[],
|
||||
)?
|
||||
.l()?;
|
||||
text(env, value)
|
||||
});
|
||||
let finished = match answer {
|
||||
Ok(None) => since.elapsed() > Duration::from_secs(600),
|
||||
Ok(Some(uri)) => {
|
||||
if !uri.is_empty() {
|
||||
if let Some(chosen) = chosen.take() {
|
||||
chosen(uri);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{e}");
|
||||
true
|
||||
}
|
||||
};
|
||||
if finished {
|
||||
if let Some(t) = held.borrow().as_ref() {
|
||||
t.stop();
|
||||
}
|
||||
let held = held.clone();
|
||||
slint::Timer::single_shot(Duration::ZERO, move || {
|
||||
held.borrow_mut().take();
|
||||
timer.start(
|
||||
slint::TimerMode::Repeated,
|
||||
Duration::from_millis(250),
|
||||
move || {
|
||||
let answer = call("reading the folder picker", |env, activity| {
|
||||
let cls = class(
|
||||
env,
|
||||
activity,
|
||||
jni::jni_str!("paris.tourolle.darkroom.FolderPicker"),
|
||||
)?;
|
||||
let value = env
|
||||
.call_static_method(
|
||||
&cls,
|
||||
jni::jni_str!("poll"),
|
||||
jni::jni_sig!("()Ljava/lang/String;"),
|
||||
&[],
|
||||
)?
|
||||
.l()?;
|
||||
text(env, value)
|
||||
});
|
||||
}
|
||||
});
|
||||
let finished = match answer {
|
||||
Ok(None) => since.elapsed() > Duration::from_secs(600),
|
||||
Ok(Some(uri)) => {
|
||||
if !uri.is_empty() {
|
||||
if let Some(chosen) = chosen.take() {
|
||||
chosen(uri);
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("{e}");
|
||||
true
|
||||
}
|
||||
};
|
||||
if finished {
|
||||
if let Some(t) = held.borrow().as_ref() {
|
||||
t.stop();
|
||||
}
|
||||
let held = held.clone();
|
||||
slint::Timer::single_shot(Duration::ZERO, move || {
|
||||
held.borrow_mut().take();
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
*slot.borrow_mut() = Some(timer);
|
||||
}
|
||||
|
||||
@@ -176,7 +188,13 @@ pub fn exists(tree: &str, name: &str) -> bool {
|
||||
|
||||
/// Write an export into the folder. Returns the name it has there, which the
|
||||
/// provider may have changed on a collision.
|
||||
pub fn write(tree: &str, name: &str, mime: &str, bytes: &[u8], replace: bool) -> Result<String, String> {
|
||||
pub fn write(
|
||||
tree: &str,
|
||||
name: &str,
|
||||
mime: &str,
|
||||
bytes: &[u8],
|
||||
replace: bool,
|
||||
) -> Result<String, String> {
|
||||
call("writing to the album folder", |env, activity| {
|
||||
let cls = class(env, activity, jni::jni_str!("paris.tourolle.darkroom.Saf"))?;
|
||||
let jtree = env.new_string(tree)?;
|
||||
|
||||
@@ -26,8 +26,8 @@ use std::rc::Rc;
|
||||
|
||||
use dr_types::settings::budget;
|
||||
use dr_types::{
|
||||
CacheSettings, CollisionPolicy, ColourSpace, ExportFormat, FaceDetector,
|
||||
GroupNavigation, LibrarySettings, OutputSharpening, ScreenSize, Settings, SizingMode,
|
||||
CacheSettings, CollisionPolicy, ColourSpace, ExportFormat, FaceDetector, GroupNavigation,
|
||||
LibrarySettings, OutputSharpening, ScreenSize, Settings, SizingMode,
|
||||
};
|
||||
use slint::ComponentHandle;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user