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() {