Enhance save preset dialog with settings summary and update option

Replace simple alert dialog with full dialog showing workflow summary,
new preset name entry, and option to update existing user presets.
Never overwrites built-in presets.
This commit is contained in:
2026-03-06 15:43:45 +02:00
parent 1d33be1e3d
commit 33659a323b

View File

@@ -2047,40 +2047,128 @@ fn import_preset(window: &adw::ApplicationWindow, ui: &WizardUi) {
} }
fn save_preset_dialog(window: &adw::ApplicationWindow, ui: &WizardUi) { fn save_preset_dialog(window: &adw::ApplicationWindow, ui: &WizardUi) {
let dialog = adw::AlertDialog::builder() let dialog = adw::Dialog::builder()
.heading("Save as Preset") .title("Save as Preset")
.body("Enter a name for this workflow preset") .content_width(400)
.content_height(500)
.build(); .build();
let entry = gtk::Entry::builder() let toolbar = adw::ToolbarView::new();
.placeholder_text("My Workflow") let header = adw::HeaderBar::new();
toolbar.add_top_bar(&header);
let scrolled = gtk::ScrolledWindow::builder()
.hscrollbar_policy(gtk::PolicyType::Never)
.vexpand(true)
.build();
let content = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(12)
.margin_top(12)
.margin_bottom(12)
.margin_start(24) .margin_start(24)
.margin_end(24) .margin_end(24)
.build(); .build();
dialog.set_extra_child(Some(&entry));
dialog.add_response("cancel", "Cancel"); // Show summary of current settings
dialog.add_response("save", "Save"); let cfg = ui.state.job_config.borrow();
dialog.set_response_appearance("save", adw::ResponseAppearance::Suggested); let summary = build_preset_description(&cfg);
dialog.set_default_response(Some("save")); drop(cfg);
let ui = ui.clone(); let summary_group = adw::PreferencesGroup::builder()
dialog.connect_response(None, move |dlg, response| { .title("Workflow Summary")
if response == "save" { .description(&summary)
let extra = dlg.extra_child(); .build();
let name = extra content.append(&summary_group);
.as_ref()
.and_then(|w| w.downcast_ref::<gtk::Entry>())
.map(|e| e.text().to_string())
.unwrap_or_default();
// Name entry
let name_group = adw::PreferencesGroup::builder()
.title("Save as New Preset")
.build();
let name_entry = adw::EntryRow::builder()
.title("Preset Name")
.build();
name_group.add(&name_entry);
let save_new_button = gtk::Button::builder()
.label("Save New Preset")
.halign(gtk::Align::Center)
.margin_top(8)
.build();
save_new_button.add_css_class("suggested-action");
save_new_button.add_css_class("pill");
content.append(&name_group);
content.append(&save_new_button);
// "Update existing" section - show user presets
let store = pixstrip_core::storage::PresetStore::new();
let user_presets: Vec<String> = store
.list()
.unwrap_or_default()
.into_iter()
.filter(|p| p.is_custom)
.map(|p| p.name)
.collect();
if !user_presets.is_empty() {
let update_group = adw::PreferencesGroup::builder()
.title("Or Update Existing Preset")
.description("Overwrite an existing user preset with current settings")
.build();
for preset_name in &user_presets {
let row = adw::ActionRow::builder()
.title(preset_name)
.activatable(true)
.build();
row.add_prefix(&gtk::Image::from_icon_name("document-save-symbolic"));
row.add_suffix(&gtk::Image::from_icon_name("go-next-symbolic"));
let ui_c = ui.clone();
let dlg_c = dialog.clone();
let pname = preset_name.clone();
row.connect_activated(move |_| {
let cfg = ui_c.state.job_config.borrow();
let preset = build_preset_from_config(&cfg, &pname);
drop(cfg);
let store = pixstrip_core::storage::PresetStore::new();
match store.save(&preset) {
Ok(()) => {
let toast = adw::Toast::new(&format!("Updated preset: {}", pname));
ui_c.toast_overlay.add_toast(toast);
}
Err(e) => {
let toast = adw::Toast::new(&format!("Failed to update: {}", e));
ui_c.toast_overlay.add_toast(toast);
}
}
dlg_c.close();
});
update_group.add(&row);
}
content.append(&update_group);
}
// Wire save new button
{
let ui_c = ui.clone();
let dlg_c = dialog.clone();
let entry_c = name_entry.clone();
save_new_button.connect_clicked(move |_| {
let name = entry_c.text().to_string();
if name.trim().is_empty() { if name.trim().is_empty() {
let toast = adw::Toast::new("Please enter a name for the preset"); let toast = adw::Toast::new("Please enter a name for the preset");
ui.toast_overlay.add_toast(toast); ui_c.toast_overlay.add_toast(toast);
return; return;
} }
let cfg = ui.state.job_config.borrow(); let cfg = ui_c.state.job_config.borrow();
let preset = build_preset_from_config(&cfg, &name); let preset = build_preset_from_config(&cfg, &name);
drop(cfg); drop(cfg);
@@ -2088,15 +2176,20 @@ fn save_preset_dialog(window: &adw::ApplicationWindow, ui: &WizardUi) {
match store.save(&preset) { match store.save(&preset) {
Ok(()) => { Ok(()) => {
let toast = adw::Toast::new(&format!("Saved preset: {}", name)); let toast = adw::Toast::new(&format!("Saved preset: {}", name));
ui.toast_overlay.add_toast(toast); ui_c.toast_overlay.add_toast(toast);
} }
Err(e) => { Err(e) => {
let toast = adw::Toast::new(&format!("Failed to save: {}", e)); let toast = adw::Toast::new(&format!("Failed to save: {}", e));
ui.toast_overlay.add_toast(toast); ui_c.toast_overlay.add_toast(toast);
} }
} }
} dlg_c.close();
}); });
}
scrolled.set_child(Some(&content));
toolbar.set_content(Some(&scrolled));
dialog.set_child(Some(&toolbar));
dialog.present(Some(window)); dialog.present(Some(window));
} }