Merge the batch export, and settle the seven-branch merge
Resolves the last of the parallel work. Two conflicts worth recording, because both were semantic rather than textual: `render_for_export` gained a colour space on master while the batch branch was rewriting the single-image export path around it. Kept both: the batch request supersedes the synchronous path, and the space still has to be chosen at render time because the conversion happens in the shader before the clip to 0..1. `render_open_frame` takes it as an argument rather than reaching for a controller it does not hold. The map-wait moved into `readback::await_mapping` on one branch while another was editing the constant it used, so `READBACK_POLL_LIMIT` survived the merge with no callers. Removed rather than left for clippy to find later. 1164 tests pass, clippy clean, fmt clean. Traceability 53.0% -> 54.3%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -674,6 +674,19 @@ in property <bool> panel-visible: true;
|
||||
in property <string> export-label: "Export";
|
||||
in property <bool> export-busy: false;
|
||||
in property <string> export-status;
|
||||
/// TRACES: FR-EXP-7
|
||||
/// Whether an export would be queued for the server rather than written to
|
||||
/// this device. The grid says the same thing as the develop button, but it
|
||||
/// composes its own label around a selection count — so it is given the
|
||||
/// fact and not the sentence.
|
||||
in property <bool> export-to-server: false;
|
||||
/// Whether a batch is running. The grid's export button becomes its cancel
|
||||
/// button; there is nowhere else a long batch can be stopped from.
|
||||
in property <bool> library-exporting: false;
|
||||
/// Export the grid's selection in the background (FR-EXP-7).
|
||||
callback library-export-selection();
|
||||
/// TRACES: NFR-ARCH-3
|
||||
callback library-cancel-export();
|
||||
/// Show or hide the develop column.
|
||||
callback toggle-panel();
|
||||
/// Export the image on screen, using the settings as they stand.
|
||||
@@ -957,6 +970,12 @@ in property <bool> panel-visible: true;
|
||||
root.paste-settings-to-selection();
|
||||
}
|
||||
|
||||
// TRACES: FR-EXP-7
|
||||
exporting: root.library-exporting;
|
||||
export-to-server: root.export-to-server;
|
||||
export-selection => { root.library-export-selection(); }
|
||||
cancel-export => { root.library-cancel-export(); }
|
||||
|
||||
sweep-done: root.library-sweep-done;
|
||||
sweep-total: root.library-sweep-total;
|
||||
|
||||
|
||||
@@ -456,11 +456,17 @@ component HeaderActions inherits HorizontalLayout {
|
||||
/// Whether settings have been copied, and what pasting them would apply.
|
||||
in property <bool> settings-armed: false;
|
||||
in property <string> settings-summary;
|
||||
/// TRACES: FR-EXP-7
|
||||
/// Whether a batch is running, and where its files are going.
|
||||
in property <bool> exporting: false;
|
||||
in property <bool> export-to-server: false;
|
||||
/// Centres each button in a 44px header. Off in the disclosure row, which
|
||||
/// is sized to its content.
|
||||
in property <bool> centred: true;
|
||||
in property <length> row-height: 44px;
|
||||
|
||||
callback export-selection();
|
||||
callback cancel-export();
|
||||
callback paste-settings-to-selection();
|
||||
callback remove-from-collection();
|
||||
callback change-library();
|
||||
@@ -486,6 +492,37 @@ component HeaderActions inherits HorizontalLayout {
|
||||
clicked => { root.paste-settings-to-selection(); }
|
||||
}
|
||||
|
||||
// TRACES: FR-EXP-7 | NFR-ARCH-3
|
||||
// Export the selection, and stop the batch that is running.
|
||||
//
|
||||
// One button doing both, because they are the same thought a moment apart
|
||||
// and a separate cancel would have to appear from somewhere — shifting the
|
||||
// row under the pointer at the exact moment the user is reaching for it.
|
||||
//
|
||||
// It stays while a batch runs whatever the selection has since become: the
|
||||
// run is what the button now refers to, and a batch of three hundred that
|
||||
// could only be stopped by not changing the selection would be a trap.
|
||||
//
|
||||
// The count is in the label rather than behind a confirmation, exactly as
|
||||
// the paste above puts it there: "Export 40" read before the click is worth
|
||||
// more than a dialogue asking the same question after it.
|
||||
if root.selected-count > 0 || root.exporting: Button {
|
||||
text: root.exporting
|
||||
? "Cancel export"
|
||||
: (root.export-to-server
|
||||
? "Export " + root.selected-count + " to Nextcloud"
|
||||
: "Export " + root.selected-count);
|
||||
active: root.exporting;
|
||||
y: root.centred ? (root.row-height - self.height) / 2 : 0;
|
||||
clicked => {
|
||||
if (root.exporting) {
|
||||
root.cancel-export();
|
||||
} else {
|
||||
root.export-selection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Removing from a collection is only meaningful while the grid is scoped
|
||||
// to one. Offering it unscoped would invite the reading "remove from the
|
||||
// library", which nothing here does.
|
||||
@@ -753,6 +790,15 @@ export component LibraryGrid inherits Rectangle {
|
||||
in property <string> settings-summary;
|
||||
callback paste-settings-to-selection();
|
||||
|
||||
// TRACES: FR-EXP-7
|
||||
// Exporting the selection. The grid owns neither the settings that decide
|
||||
// where the files go nor the worker that writes them — it reports what is
|
||||
// selected and asks, exactly as it does for a paste.
|
||||
in property <bool> exporting: false;
|
||||
in property <bool> export-to-server: false;
|
||||
callback export-selection();
|
||||
callback cancel-export();
|
||||
|
||||
// --- the keyboard cursor ------------------------------------------------
|
||||
//
|
||||
// Where the keyboard is in the library, as an **image ordinal** — not a
|
||||
@@ -891,6 +937,10 @@ export component LibraryGrid inherits Rectangle {
|
||||
scope-pinned: root.scope-pinned;
|
||||
settings-armed: root.settings-armed;
|
||||
settings-summary: root.settings-summary;
|
||||
exporting: root.exporting;
|
||||
export-to-server: root.export-to-server;
|
||||
export-selection => { root.export-selection(); }
|
||||
cancel-export => { root.cancel-export(); }
|
||||
paste-settings-to-selection => { root.paste-settings-to-selection(); }
|
||||
remove-from-collection => { root.remove-from-collection(); }
|
||||
change-library => { root.change-library(); }
|
||||
@@ -938,6 +988,10 @@ export component LibraryGrid inherits Rectangle {
|
||||
scope-pinned: root.scope-pinned;
|
||||
settings-armed: root.settings-armed;
|
||||
settings-summary: root.settings-summary;
|
||||
exporting: root.exporting;
|
||||
export-to-server: root.export-to-server;
|
||||
export-selection => { root.export-selection(); }
|
||||
cancel-export => { root.cancel-export(); }
|
||||
paste-settings-to-selection => { root.paste-settings-to-selection(); }
|
||||
remove-from-collection => { root.remove-from-collection(); }
|
||||
change-library => { root.change-library(); }
|
||||
|
||||
Reference in New Issue
Block a user