Say on the import page where the photographs end up
Three lint findings and the gap the third one was pointing at. `Context::library_label` was dead: the page named the folder on this machine and said nothing at all about the server, which is half of what the Import button commits to and the half that takes minutes rather than seconds. It now names both, and states the order — copied and verified here first, then uploaded (FR-NC-7b) — beside the destinations rather than beside the button, because someone watching a slow upload needs to already know the photographs are safe on disk. The label is cached when the page opens rather than read in `render`: reaching it goes through the context closure to the account, and `render` runs on every keystroke. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,7 +25,7 @@ use dr_ingest::{DuplicatePolicy, Options, TransferMode, DEFAULT_TEMPLATE};
|
||||
use dr_types::{FormatFilter, ImportSettings};
|
||||
|
||||
use crate::activity::{Activity, ActivityLog, Kind};
|
||||
use crate::import::{self, Message, Outcome, Request, Upload};
|
||||
use crate::import::{self, Message, Request, Upload};
|
||||
use crate::AppWindow;
|
||||
|
||||
/// How often the drain runs while an import is going.
|
||||
@@ -46,7 +46,11 @@ pub struct Context {
|
||||
/// The signed-in account, where there is one. `None` means the import is
|
||||
/// local-only, which is a perfectly good way to use the application.
|
||||
pub upload: Option<Upload>,
|
||||
/// The library folder on the server, for the label the page shows.
|
||||
/// The library folder on the server.
|
||||
///
|
||||
/// Shown on the page, because once an account is signed in "where do these
|
||||
/// end up" has two answers, and giving only the local one answers half the
|
||||
/// question the Import button is about to commit to.
|
||||
pub library_label: String,
|
||||
/// Which file types to take off a card.
|
||||
pub filter: FormatFilter,
|
||||
@@ -69,6 +73,12 @@ pub struct ImportController {
|
||||
survey: RefCell<Option<(usize, u64)>>,
|
||||
surveying: Cell<bool>,
|
||||
|
||||
/// The server folder originals are uploaded to, as the page shows it.
|
||||
///
|
||||
/// Cached when the page opens rather than fetched in `render`: the context
|
||||
/// closure reaches the account, and `render` runs on every keystroke.
|
||||
upload_target: RefCell<String>,
|
||||
|
||||
running: Cell<bool>,
|
||||
fraction: Cell<f32>,
|
||||
status: RefCell<String>,
|
||||
@@ -98,6 +108,7 @@ impl ImportController {
|
||||
card: RefCell::new(String::new()),
|
||||
survey: RefCell::new(None),
|
||||
surveying: Cell::new(false),
|
||||
upload_target: RefCell::new(String::new()),
|
||||
running: Cell::new(false),
|
||||
fraction: Cell::new(0.0),
|
||||
status: RefCell::new(String::new()),
|
||||
@@ -242,6 +253,16 @@ pub fn render(window: &AppWindow, ctl: &Rc<ImportController>) {
|
||||
);
|
||||
|
||||
window.set_import_destination(stored.destination.as_str().into());
|
||||
// Empty where no account is signed in, or where the user turned the upload
|
||||
// off — the page then shows one destination because there is one.
|
||||
window.set_import_upload_target(
|
||||
if stored.upload {
|
||||
ctl.upload_target.borrow().clone()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
window.set_import_folder_template(stored.folder_template.as_str().into());
|
||||
window.set_import_template_preview(preview(&stored, crate::library::now_secs()).into());
|
||||
|
||||
@@ -313,7 +334,8 @@ where
|
||||
ctl.edit(|s| s.destination = home.display().to_string());
|
||||
}
|
||||
}
|
||||
let _ = context();
|
||||
*ctl.upload_target.borrow_mut() =
|
||||
context().map(|c| c.library_label).unwrap_or_default();
|
||||
ctl.refresh_volumes();
|
||||
*ctl.status.borrow_mut() = String::new();
|
||||
*ctl.error.borrow_mut() = String::new();
|
||||
@@ -536,12 +558,11 @@ fn start(
|
||||
};
|
||||
|
||||
let stored = ctl.options();
|
||||
let backup = stored
|
||||
.backup
|
||||
.trim()
|
||||
.is_empty()
|
||||
.then_some(None)
|
||||
.unwrap_or_else(|| Some(PathBuf::from(stored.backup.trim())));
|
||||
let backup = if stored.backup.trim().is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(PathBuf::from(stored.backup.trim()))
|
||||
};
|
||||
|
||||
let request = Request {
|
||||
card: PathBuf::from(ctl.card.borrow().clone()),
|
||||
|
||||
@@ -749,6 +749,7 @@ export component AppWindow inherits Window {
|
||||
in property <bool> import-surveying: false;
|
||||
in property <string> import-survey-summary: "";
|
||||
in property <string> import-destination: "";
|
||||
in property <string> import-upload-target: "";
|
||||
in property <string> import-folder-template: "";
|
||||
in property <string> import-template-preview: "";
|
||||
in property <[string]> import-mode-labels;
|
||||
@@ -1066,6 +1067,7 @@ in property <bool> panel-visible: true;
|
||||
surveying: root.import-surveying;
|
||||
survey-summary: root.import-survey-summary;
|
||||
destination: root.import-destination;
|
||||
upload-target: root.import-upload-target;
|
||||
folder-template: root.import-folder-template;
|
||||
template-preview: root.import-template-preview;
|
||||
mode-labels: root.import-mode-labels;
|
||||
|
||||
@@ -87,6 +87,10 @@ export component ImportPage inherits Rectangle {
|
||||
// --- where they are going --------------------------------------------
|
||||
/// The library root. Shown, not editable — see the header comment.
|
||||
in property <string> destination;
|
||||
/// The folder on the server the originals go on to, once they are safely
|
||||
/// on disk (FR-NC-7b). Empty when no account is signed in, which hides the
|
||||
/// line rather than showing an empty one.
|
||||
in property <string> upload-target;
|
||||
in-out property <string> folder-template;
|
||||
/// The template expanded against a real date, so the answer to "what will
|
||||
/// this do" is on screen rather than in the manual.
|
||||
@@ -274,6 +278,24 @@ export component ImportPage inherits Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
if root.upload-target != "": HorizontalLayout {
|
||||
spacing: Theme.gap;
|
||||
Label { text: "Server"; }
|
||||
Value {
|
||||
text: root.upload-target;
|
||||
overflow: elide;
|
||||
horizontal-stretch: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Said once, here, rather than beside the Import button:
|
||||
// the order is the promise, and a user watching a slow
|
||||
// upload needs to already know the photographs are on disk.
|
||||
if root.upload-target != "": Caption {
|
||||
text: "Copied here and verified first, then uploaded.";
|
||||
wrap: word-wrap;
|
||||
}
|
||||
|
||||
TextRow {
|
||||
label: "Folders";
|
||||
text <=> root.folder-template;
|
||||
|
||||
Reference in New Issue
Block a user