Redact: Save As after Undo past saved redactions proposes the name without _Redacted

After Undo past a saved Apply redactions, Save asks where but proposed the
redacted copy's own name, so the dialog's default was the redacted file.
It now proposes the name without _Redacted.
This commit is contained in:
dotCooCoo
2026-10-30 22:10:53 -07:00
parent ebafc30ed1
commit 3dae849175
3 changed files with 30 additions and 2 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ pub use save::{SaveTarget, write_atomically};
#[cfg(test)]
pub(crate) use save::{is_mail_temp_copy, save_dialog_folder};
#[cfg(test)]
use save::{write_atomically_syncing, write_atomically_with};
use save::{unredacted_file_name, write_atomically_syncing, write_atomically_with};
/// Text typed into a new text box that isn't added to the page yet.
fn new_text_typed(v: &crate::DocView) -> bool {
+17
View File
@@ -62,6 +62,9 @@ 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);
// The restored content is not a redacted copy: propose the name without `_Redacted`, so
// the dialog's default is not the redacted file.
let name = if unredacted && !redacted { unredacted_file_name(&name) } else { name };
let target = if not_delivered || unredacted { SaveTarget::As } else { target };
#[cfg(not(target_arch = "wasm32"))]
{
@@ -257,6 +260,20 @@ pub(crate) fn is_mail_temp_copy(path: &str) -> bool {
|| p.contains("/library/containers/com.apple.mail/data/library/mail downloads/")
}
/// `name` without the `_Redacted` that [`pdfcraft_engine::redacted_file_name`] adds before the
/// extension ("contract_Redacted.pdf" gives "contract.pdf"). Any other name is returned as it is.
pub(crate) fn unredacted_file_name(name: &str) -> String {
let cut = name.len().saturating_sub(4);
let (stem, ext) = match (name.get(..cut), name.get(cut..)) {
(Some(stem), Some(ext)) if ext.eq_ignore_ascii_case(".pdf") => (stem, ext),
_ => (name, ""),
};
match stem.strip_suffix("_Redacted") {
Some(base) if !base.is_empty() => format!("{base}{ext}"),
_ => name.to_string(),
}
}
/// The folder a Save As style dialog should open in for a document stored at `path`: the
/// document's own folder, as Acrobat and Foxit do, instead of whichever folder the system picks.
/// `None` (keep the system's choice) for a new document, a path with no parent, or an email
+12 -1
View File
@@ -1,4 +1,15 @@
use super::{SaveTarget, is_mail_temp_copy, save_dialog_folder, write_atomically, write_atomically_syncing, write_atomically_with};
use super::{
SaveTarget, is_mail_temp_copy, save_dialog_folder, unredacted_file_name, write_atomically, write_atomically_syncing, write_atomically_with,
};
#[test]
fn restored_content_is_not_proposed_under_the_redacted_name() {
assert_eq!(unredacted_file_name("contract_Redacted.pdf"), "contract.pdf");
assert_eq!(unredacted_file_name("SCAN_Redacted.PDF"), "SCAN.PDF");
assert_eq!(unredacted_file_name("Untitled_Redacted"), "Untitled");
assert_eq!(unredacted_file_name("contract.pdf"), "contract.pdf");
assert_eq!(unredacted_file_name("_Redacted.pdf"), "_Redacted.pdf");
}
#[test]
fn save_dialogs_open_in_the_documents_folder() {