From ebafc30ed1cd82f2ba2ad1d8124ba6f43dbb40c7 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Fri, 30 Oct 2026 22:04:03 -0700 Subject: [PATCH] Redact: Save writes in place once the web build delivered the redactions In the web build Save kept sending Save As to the host after the redacted file was delivered, because the delivered steps stay counted for the _Redacted name. Save now asks where only for steps applied since the last delivery. --- crates/ui-egui/src/canvas.rs | 5 +++-- crates/ui-egui/src/editing/save.rs | 5 ++++- crates/ui-egui/tests/it/redact.rs | 31 ++++++++++++++++++++++++++++++ 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/crates/ui-egui/src/canvas.rs b/crates/ui-egui/src/canvas.rs index 705766005c..17219bb8ac 100644 --- a/crates/ui-egui/src/canvas.rs +++ b/crates/ui-egui/src/canvas.rs @@ -451,8 +451,9 @@ pub struct DocView { /// Redact tool: the box being drawn, and a mark to add (page, quads) for the app to style. pub redact_drag: crate::redact_ui::AreaDrag, pub pending_redaction: Option<(usize, Vec<[f64; 8]>)>, - /// How many Apply redactions steps are in effect in this view. While it is above 0, Save asks - /// where and proposes the name with `_Redacted` ([`pdfcraft_engine::redacted_file_name`]). + /// How many Apply redactions steps are in effect in this view. While it is above 0, Save + /// proposes the name with `_Redacted` ([`pdfcraft_engine::redacted_file_name`]), and while it is + /// above `redactions_downloaded`, Save asks where. /// Undo of an Apply redactions step takes one off and Redo adds it back. Reload and a desktop /// save set it to 0, and Revert sets it to `redactions_downloaded`; after a desktop save the document has the name it was saved /// under. A web download keeps it, so later downloads carry the `_Redacted` name. diff --git a/crates/ui-egui/src/editing/save.rs b/crates/ui-egui/src/editing/save.rs index 81d1ff115e..2e9e8e72ab 100644 --- a/crates/ui-egui/src/editing/save.rs +++ b/crates/ui-egui/src/editing/save.rs @@ -49,7 +49,10 @@ impl PdfCraftApp { let Some(doc) = self.session.get(id) else { return false }; let (name, path) = (doc.name.clone(), doc.path.clone()); // After Apply redactions, Save asks where and proposes the name with `_Redacted`. + // In the web build a delivered step stays counted, so only the steps applied since the + // last delivery make Save ask where. let redacted = self.views.get(index).is_some_and(|v| v.redactions_applied > 0); + let not_delivered = self.views.get(index).is_some_and(|v| v.redactions_applied > v.redactions_downloaded); let name = if redacted { pdfcraft_engine::redacted_file_name(&name) } else { name }; // Undo past a saved Apply redactions brings back content that the file on disk has // redacted: ask where instead of writing it over that file. In the web build a delivered @@ -59,7 +62,7 @@ impl PdfCraftApp { .views .get(index) .is_some_and(|v| v.redactions_undone_after_save > 0 || v.saved_redactions_cut_off || v.redactions_applied < v.redactions_downloaded); - let target = if redacted || unredacted { SaveTarget::As } else { target }; + let target = if not_delivered || unredacted { SaveTarget::As } else { target }; #[cfg(not(target_arch = "wasm32"))] { let doc_path = path.clone(); diff --git a/crates/ui-egui/tests/it/redact.rs b/crates/ui-egui/tests/it/redact.rs index ff97c49b9e..9a7f637722 100644 --- a/crates/ui-egui/tests/it/redact.rs +++ b/crates/ui-egui/tests/it/redact.rs @@ -280,6 +280,37 @@ fn undoing_delivered_redactions_asks_where() { let _ = std::fs::remove_dir_all(&dir); } +/// Once every Apply redactions step is delivered, Save writes in place again even though the web +/// build keeps the steps counted for the `_Redacted` name. +#[test] +fn delivered_redactions_save_in_place() { + let dir = std::env::temp_dir().join(format!("pdfcraft-redacted-delivered-save-{}", std::process::id())); + let _ = std::fs::remove_dir_all(&dir); + std::fs::create_dir_all(&dir).unwrap(); + let original = dir.join("contract.pdf"); + std::fs::write(&original, include_bytes!("../data/form.pdf")).unwrap(); + let path = original.to_string_lossy().into_owned(); + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(move |_cc| { + let mut app = PdfCraftApp::new(); + app.set_option("language", "en").unwrap(); + app.open_path(&path); + app + }); + crate::support::settle(&mut h); + h.state_mut().execute("redact.pages"); + h.run_steps(2); + h.get_by_label("OK").click(); + h.run_steps(3); + assert!(h.state_mut().execute("redact.apply")); + h.run_steps(2); + h.get_by_label("Apply").click(); + h.run_steps(4); + // The state a web save leaves: the step is delivered and stays counted. + h.state_mut().views[0].redactions_downloaded = 1; + assert!(h.state_mut().save_active(SaveTarget::InPlace), "Save writes in place after the step is delivered"); + let _ = std::fs::remove_dir_all(&dir); +} + /// Undo of Apply redactions brings back Save in place; Redo makes Save ask where again. #[test] fn undoing_apply_redactions_saves_in_place_again() {