Add overwrite confirmation dialog and preset file drop import

- When overwrite behavior is "Ask", show dialog before processing
  listing conflicting files with Overwrite/Skip/Auto-rename options
- Workflow page accepts .pixstrip-preset file drag-and-drop for import
- Split run_processing into two phases to support async dialog
This commit is contained in:
2026-03-06 17:07:53 +02:00
parent f8fd073735
commit 3109f97786

View File

@@ -1687,11 +1687,12 @@ fn run_processing(_window: &adw::ApplicationWindow, ui: &WizardUi) {
job.preserve_directory_structure = cfg.preserve_dir_structure; job.preserve_directory_structure = cfg.preserve_dir_structure;
job.output_dpi = cfg.output_dpi; job.output_dpi = cfg.output_dpi;
let ask_overwrite = cfg.overwrite_behavior == 0;
job.overwrite_behavior = match cfg.overwrite_behavior { job.overwrite_behavior = match cfg.overwrite_behavior {
1 => pixstrip_core::operations::OverwriteBehavior::AutoRename, 1 => pixstrip_core::operations::OverwriteBehavior::AutoRename,
2 => pixstrip_core::operations::OverwriteBehavior::Overwrite, 2 => pixstrip_core::operations::OverwriteBehavior::Overwrite,
3 => pixstrip_core::operations::OverwriteBehavior::Skip, 3 => pixstrip_core::operations::OverwriteBehavior::Skip,
_ => pixstrip_core::operations::OverwriteBehavior::AutoRename, // 0 "Ask" defaults to auto-rename in batch _ => pixstrip_core::operations::OverwriteBehavior::AutoRename,
}; };
drop(cfg); drop(cfg);
@@ -1700,6 +1701,66 @@ fn run_processing(_window: &adw::ApplicationWindow, ui: &WizardUi) {
job.add_source(file); job.add_source(file);
} }
// Check for existing output files when "Ask" overwrite behavior is set
if ask_overwrite {
let output_dir = ui.state.output_dir.borrow().clone()
.unwrap_or_else(|| {
files[0].parent()
.unwrap_or_else(|| std::path::Path::new("."))
.join("processed")
});
if output_dir.exists() {
let conflicts: Vec<String> = files.iter()
.filter_map(|f| {
let name = f.file_name()?;
let out_path = output_dir.join(name);
if out_path.exists() { Some(name.to_string_lossy().into()) } else { None }
})
.take(10)
.collect();
if !conflicts.is_empty() {
let msg = if conflicts.len() == 10 {
format!("{} files already exist in the output folder (showing first 10):\n\n{}", conflicts.len(), conflicts.join("\n"))
} else {
format!("{} files already exist in the output folder:\n\n{}", conflicts.len(), conflicts.join("\n"))
};
let confirm = adw::AlertDialog::builder()
.heading("Files Already Exist")
.body(&msg)
.build();
confirm.add_response("rename", "Auto-rename");
confirm.add_response("skip", "Skip Existing");
confirm.add_response("overwrite", "Overwrite All");
confirm.set_response_appearance("overwrite", adw::ResponseAppearance::Destructive);
confirm.set_default_response(Some("rename"));
confirm.set_close_response("rename");
let ui_c = ui.clone();
let window_c = _window.clone();
let mut job_c = job;
confirm.choose(Some(_window), gtk::gio::Cancellable::NONE, move |response| {
job_c.overwrite_behavior = match response.as_str() {
"overwrite" => pixstrip_core::operations::OverwriteBehavior::Overwrite,
"skip" => pixstrip_core::operations::OverwriteBehavior::Skip,
_ => pixstrip_core::operations::OverwriteBehavior::AutoRename,
};
continue_processing(&window_c, &ui_c, job_c);
});
return;
}
}
}
continue_processing(_window, ui, job);
}
fn continue_processing(
_window: &adw::ApplicationWindow,
ui: &WizardUi,
job: pixstrip_core::pipeline::ProcessingJob,
) {
// Build processing UI inline in the nav_view // Build processing UI inline in the nav_view
let processing_page = crate::processing::build_processing_page(); let processing_page = crate::processing::build_processing_page();
ui.nav_view.push(&processing_page); ui.nav_view.push(&processing_page);