Add fixed output folder option in settings
Users can now choose between subfolder-next-to-originals or a fixed output folder in Settings > General. The fixed path is selectable via a folder picker dialog and persisted across sessions.
This commit is contained in:
@@ -20,11 +20,84 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
.title("Output")
|
||||
.build();
|
||||
|
||||
// Output mode: subfolder or fixed path
|
||||
let output_mode_row = adw::ComboRow::builder()
|
||||
.title("Default output location")
|
||||
.subtitle("Where processed images are saved by default")
|
||||
.build();
|
||||
let output_mode_model = gtk::StringList::new(&[
|
||||
"Subfolder next to originals",
|
||||
"Fixed output folder",
|
||||
]);
|
||||
output_mode_row.set_model(Some(&output_mode_model));
|
||||
output_mode_row.set_selected(if config.output_fixed_path.is_some() { 1 } else { 0 });
|
||||
|
||||
let subfolder_row = adw::EntryRow::builder()
|
||||
.title("Default output subfolder")
|
||||
.text(&config.output_subfolder)
|
||||
.visible(config.output_fixed_path.is_none())
|
||||
.build();
|
||||
|
||||
let fixed_path_row = adw::ActionRow::builder()
|
||||
.title("Fixed output folder")
|
||||
.subtitle(
|
||||
config.output_fixed_path
|
||||
.as_deref()
|
||||
.unwrap_or("No folder selected"),
|
||||
)
|
||||
.activatable(true)
|
||||
.visible(config.output_fixed_path.is_some())
|
||||
.build();
|
||||
fixed_path_row.add_prefix(>k::Image::from_icon_name("folder-open-symbolic"));
|
||||
|
||||
let choose_fixed_btn = gtk::Button::builder()
|
||||
.icon_name("document-open-symbolic")
|
||||
.tooltip_text("Choose output folder")
|
||||
.valign(gtk::Align::Center)
|
||||
.build();
|
||||
choose_fixed_btn.add_css_class("flat");
|
||||
fixed_path_row.add_suffix(&choose_fixed_btn);
|
||||
|
||||
// Shared state for fixed path
|
||||
let fixed_path_state: std::rc::Rc<std::cell::RefCell<Option<String>>> =
|
||||
std::rc::Rc::new(std::cell::RefCell::new(config.output_fixed_path.clone()));
|
||||
|
||||
// Wire output mode toggle
|
||||
{
|
||||
let sf = subfolder_row.clone();
|
||||
let fp = fixed_path_row.clone();
|
||||
output_mode_row.connect_selected_notify(move |row| {
|
||||
let is_fixed = row.selected() == 1;
|
||||
sf.set_visible(!is_fixed);
|
||||
fp.set_visible(is_fixed);
|
||||
});
|
||||
}
|
||||
|
||||
// Wire fixed path chooser
|
||||
{
|
||||
let fps = fixed_path_state.clone();
|
||||
let fpr = fixed_path_row.clone();
|
||||
choose_fixed_btn.connect_clicked(move |btn| {
|
||||
let fps = fps.clone();
|
||||
let fpr = fpr.clone();
|
||||
let dialog = gtk::FileDialog::builder()
|
||||
.title("Choose Output Folder")
|
||||
.modal(true)
|
||||
.build();
|
||||
if let Some(window) = btn.root().and_then(|r| r.downcast::<gtk::Window>().ok()) {
|
||||
dialog.select_folder(Some(&window), gtk::gio::Cancellable::NONE, move |result| {
|
||||
if let Ok(file) = result
|
||||
&& let Some(path) = file.path()
|
||||
{
|
||||
let path_str = path.display().to_string();
|
||||
fpr.set_subtitle(&path_str);
|
||||
*fps.borrow_mut() = Some(path_str);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let overwrite_row = adw::ComboRow::builder()
|
||||
.title("Default overwrite behavior")
|
||||
.subtitle("What to do when output files already exist")
|
||||
@@ -49,7 +122,9 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
.active(config.remember_settings)
|
||||
.build();
|
||||
|
||||
output_group.add(&output_mode_row);
|
||||
output_group.add(&subfolder_row);
|
||||
output_group.add(&fixed_path_row);
|
||||
output_group.add(&overwrite_row);
|
||||
output_group.add(&remember_row);
|
||||
general_page.add(&output_group);
|
||||
@@ -366,6 +441,8 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let notify = desktop_notify_row.clone();
|
||||
let sound = sound_row.clone();
|
||||
let auto_open = auto_open_row.clone();
|
||||
let output_mode = output_mode_row.clone();
|
||||
let fps_reset = fixed_path_state.clone();
|
||||
reset_button.connect_clicked(move |_| {
|
||||
let defaults = AppConfig::default();
|
||||
subfolder.set_text(&defaults.output_subfolder);
|
||||
@@ -380,6 +457,8 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
notify.set_active(defaults.notify_on_completion);
|
||||
sound.set_active(defaults.play_completion_sound);
|
||||
auto_open.set_active(defaults.auto_open_output);
|
||||
output_mode.set_selected(0);
|
||||
*fps_reset.borrow_mut() = None;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -393,7 +472,11 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
first_run_complete: true,
|
||||
tutorial_complete: true, // preserve if settings are being saved
|
||||
output_subfolder: subfolder_row.text().to_string(),
|
||||
output_fixed_path: None,
|
||||
output_fixed_path: if output_mode_row.selected() == 1 {
|
||||
fixed_path_state.borrow().clone()
|
||||
} else {
|
||||
None
|
||||
},
|
||||
overwrite_behavior: match overwrite_row.selected() {
|
||||
1 => OverwriteBehavior::AutoRename,
|
||||
2 => OverwriteBehavior::Overwrite,
|
||||
|
||||
Reference in New Issue
Block a user