Say a photograph is downloading, and how far, instead of failing
The develop view reported a remote original on its way through the error message, so it read "Could not load image" over "Downloading…". It did so on every step along the roll, including a cached frame that was ready within a tick, so each step flashed the error. Waiting is now its own state. On the step, the grid's thumbnail of the photograph stands in at once. Only when a transfer is really on the wire does it dim under "Not on this device yet", with a line like "Downloading — 12.4 of 38.0 MB" and a progress bar. The bytes come from a new RemoteBackend::get_reporting. The Nextcloud backend overrides it to read the body chunk by chunk; the default reports once at the end. Progress is kept in the in-flight registry by path, because a step usually lands on a frame the prefetcher is already fetching. The catalog's file length stands in when the server sends no Content-Length.
This commit is contained in:
+40
-2
@@ -411,6 +411,12 @@ fn is_supported(p: &Path) -> bool {
|
||||
/// rect chosen for the first — or, since local masking became a mode, would
|
||||
/// open the next photograph with a mask stack it does not have.
|
||||
fn reset_view_state(window: &AppWindow) {
|
||||
// Whatever the last open was waiting for, this one is not — until the
|
||||
// remote path says otherwise.
|
||||
window.set_load_pending(false);
|
||||
window.set_load_waiting("".into());
|
||||
window.set_load_fraction(-1.0);
|
||||
window.set_has_load_preview(false);
|
||||
window.global::<Develop>().set_view_mode(ViewMode::Photo);
|
||||
window.set_zoom(1.0);
|
||||
window.set_zoomed(false);
|
||||
@@ -2769,7 +2775,17 @@ fn wire_remote_open(
|
||||
|
||||
log::info!("fetching {path} for develop");
|
||||
|
||||
w.set_load_error("Downloading…".into());
|
||||
// TRACES: FR-NC-6a
|
||||
// The grid's thumbnail stands in from this moment, so the step
|
||||
// lands on this photograph rather than on the last one's pixels
|
||||
// or an empty frame. Whether to say anything about a download is
|
||||
// decided below, once one is actually running.
|
||||
let (preview, size) = library.preview_for_path(&w, &path);
|
||||
if let Some(p) = preview {
|
||||
w.set_load_preview(p);
|
||||
w.set_has_load_preview(true);
|
||||
}
|
||||
w.set_load_pending(true);
|
||||
|
||||
let rx = library::spawn_full_fetch(conn, path.clone(), cache);
|
||||
|
||||
@@ -2803,7 +2819,26 @@ fn wire_remote_open(
|
||||
slint::TimerMode::Repeated,
|
||||
std::time::Duration::from_millis(50),
|
||||
move || {
|
||||
let Ok(got) = rx.try_recv() else { return };
|
||||
let Ok(got) = rx.try_recv() else {
|
||||
// TRACES: FR-NC-6a
|
||||
// Still coming. Said only once the original is on the
|
||||
// wire — a read from the cache lands before there is
|
||||
// a transfer to find, and so never flashes a headline.
|
||||
// Read by path, because the transfer is as often the
|
||||
// prefetcher's as this open's own.
|
||||
if current.get() == mine {
|
||||
if let (Some(w), Some((received, declared))) =
|
||||
(weak.upgrade(), library::transfer_progress(&path))
|
||||
{
|
||||
let (text, fraction) =
|
||||
activity::describe_download(received, declared.or(size));
|
||||
w.set_load_waiting(text.as_str().into());
|
||||
w.set_load_fraction(fraction);
|
||||
job.detail(text);
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
// Landed — this timer has done its job.
|
||||
held.stop();
|
||||
let Some(w) = weak.upgrade() else { return };
|
||||
@@ -2819,6 +2854,9 @@ fn wire_remote_open(
|
||||
log::debug!("{name}: landed after the view moved on");
|
||||
return;
|
||||
}
|
||||
w.set_load_pending(false);
|
||||
w.set_load_waiting("".into());
|
||||
w.set_has_load_preview(false);
|
||||
|
||||
let bytes = match got {
|
||||
Ok(b) => b,
|
||||
|
||||
Reference in New Issue
Block a user