Fix edge cases and consistency issues
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
use adw::prelude::*;
|
||||
use std::cell::Cell;
|
||||
use pixstrip_core::config::{AppConfig, ErrorBehavior, OverwriteBehavior, SkillLevel};
|
||||
use pixstrip_core::storage::ConfigStore;
|
||||
|
||||
@@ -8,7 +9,13 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
.build();
|
||||
|
||||
let config_store = ConfigStore::new();
|
||||
let config = config_store.load().unwrap_or_default();
|
||||
let config = match config_store.load() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
eprintln!("Failed to load config, using defaults: {}", e);
|
||||
AppConfig::default()
|
||||
}
|
||||
};
|
||||
|
||||
// General page
|
||||
let general_page = adw::PreferencesPage::builder()
|
||||
@@ -24,12 +31,14 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let output_mode_row = adw::ComboRow::builder()
|
||||
.title("Default output location")
|
||||
.subtitle("Where processed images are saved by default")
|
||||
.use_subtitle(true)
|
||||
.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_list_factory(Some(&crate::steps::full_text_list_factory()));
|
||||
output_mode_row.set_selected(if config.output_fixed_path.is_some() { 1 } else { 0 });
|
||||
|
||||
let subfolder_row = adw::EntryRow::builder()
|
||||
@@ -101,6 +110,7 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let overwrite_row = adw::ComboRow::builder()
|
||||
.title("Default overwrite behavior")
|
||||
.subtitle("What to do when output files already exist")
|
||||
.use_subtitle(true)
|
||||
.build();
|
||||
let overwrite_model = gtk::StringList::new(&[
|
||||
"Ask before overwriting",
|
||||
@@ -109,6 +119,7 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
"Skip existing files",
|
||||
]);
|
||||
overwrite_row.set_model(Some(&overwrite_model));
|
||||
overwrite_row.set_list_factory(Some(&crate::steps::full_text_list_factory()));
|
||||
overwrite_row.set_selected(match config.overwrite_behavior {
|
||||
OverwriteBehavior::Ask => 0,
|
||||
OverwriteBehavior::AutoRename => 1,
|
||||
@@ -136,9 +147,11 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let skill_row = adw::ComboRow::builder()
|
||||
.title("Detail level")
|
||||
.subtitle("Controls how many options are visible by default")
|
||||
.use_subtitle(true)
|
||||
.build();
|
||||
let skill_model = gtk::StringList::new(&["Simple", "Detailed"]);
|
||||
skill_row.set_model(Some(&skill_model));
|
||||
skill_row.set_list_factory(Some(&crate::steps::full_text_list_factory()));
|
||||
skill_row.set_selected(match config.skill_level {
|
||||
SkillLevel::Simple => 0,
|
||||
SkillLevel::Detailed => 1,
|
||||
@@ -188,11 +201,22 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
.build();
|
||||
|
||||
let fm_copy = *fm;
|
||||
let reverting = std::rc::Rc::new(std::cell::Cell::new(false));
|
||||
let reverting_clone = reverting.clone();
|
||||
row.connect_active_notify(move |row| {
|
||||
if row.is_active() {
|
||||
let _ = fm_copy.install();
|
||||
if reverting_clone.get() {
|
||||
return;
|
||||
}
|
||||
let result = if row.is_active() {
|
||||
fm_copy.install()
|
||||
} else {
|
||||
let _ = fm_copy.uninstall();
|
||||
fm_copy.uninstall()
|
||||
};
|
||||
if let Err(e) = result {
|
||||
eprintln!("File manager integration error for {}: {}", fm_copy.name(), e);
|
||||
reverting_clone.set(true);
|
||||
row.set_active(!row.is_active());
|
||||
reverting_clone.set(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -231,9 +255,11 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let threads_row = adw::ComboRow::builder()
|
||||
.title("Processing threads")
|
||||
.subtitle("Auto uses all available CPU cores")
|
||||
.use_subtitle(true)
|
||||
.build();
|
||||
let threads_model = gtk::StringList::new(&["Auto", "1", "2", "4", "8"]);
|
||||
threads_row.set_model(Some(&threads_model));
|
||||
threads_row.set_list_factory(Some(&crate::steps::full_text_list_factory()));
|
||||
threads_row.set_selected(match config.thread_count {
|
||||
pixstrip_core::config::ThreadCount::Auto => 0,
|
||||
pixstrip_core::config::ThreadCount::Manual(1) => 1,
|
||||
@@ -245,9 +271,11 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let error_row = adw::ComboRow::builder()
|
||||
.title("On error")
|
||||
.subtitle("What to do when an image fails to process")
|
||||
.use_subtitle(true)
|
||||
.build();
|
||||
let error_model = gtk::StringList::new(&["Skip and continue", "Pause on error"]);
|
||||
error_row.set_model(Some(&error_model));
|
||||
error_row.set_list_factory(Some(&crate::steps::full_text_list_factory()));
|
||||
error_row.set_selected(match config.error_behavior {
|
||||
ErrorBehavior::SkipAndContinue => 0,
|
||||
ErrorBehavior::PauseOnError => 1,
|
||||
@@ -287,6 +315,53 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
.active(config.reduced_motion)
|
||||
.build();
|
||||
|
||||
// Wire high contrast to apply immediately
|
||||
{
|
||||
contrast_row.connect_active_notify(move |row| {
|
||||
if let Some(settings) = gtk::Settings::default() {
|
||||
if row.is_active() {
|
||||
settings.set_gtk_theme_name(Some("HighContrast"));
|
||||
} else {
|
||||
// Revert to the default Adwaita theme
|
||||
settings.set_gtk_theme_name(Some("Adwaita"));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Wire large text to apply immediately
|
||||
{
|
||||
let original_dpi: std::rc::Rc<Cell<i32>> = std::rc::Rc::new(Cell::new(0));
|
||||
let orig_dpi = original_dpi.clone();
|
||||
large_text_row.connect_active_notify(move |row| {
|
||||
if let Some(settings) = gtk::Settings::default() {
|
||||
if row.is_active() {
|
||||
// Store original DPI before modifying
|
||||
let current_dpi = settings.gtk_xft_dpi();
|
||||
if current_dpi > 0 {
|
||||
orig_dpi.set(current_dpi);
|
||||
settings.set_gtk_xft_dpi(current_dpi * 5 / 4);
|
||||
}
|
||||
} else {
|
||||
// Restore the original DPI (only if we actually changed it)
|
||||
let saved = orig_dpi.get();
|
||||
if saved > 0 {
|
||||
settings.set_gtk_xft_dpi(saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Wire reduced motion to apply immediately
|
||||
{
|
||||
motion_row.connect_active_notify(move |row| {
|
||||
if let Some(settings) = gtk::Settings::default() {
|
||||
settings.set_gtk_enable_animations(!row.is_active());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
a11y_group.add(&contrast_row);
|
||||
a11y_group.add(&large_text_row);
|
||||
a11y_group.add(&motion_row);
|
||||
@@ -443,6 +518,9 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
let auto_open = auto_open_row.clone();
|
||||
let output_mode = output_mode_row.clone();
|
||||
let fps_reset = fixed_path_state.clone();
|
||||
let wfs_reset = watch_folders_state.clone();
|
||||
let wl_reset = watch_list.clone();
|
||||
let el_reset = empty_label.clone();
|
||||
reset_button.connect_clicked(move |_| {
|
||||
let defaults = AppConfig::default();
|
||||
subfolder.set_text(&defaults.output_subfolder);
|
||||
@@ -459,6 +537,10 @@ pub fn build_settings_dialog() -> adw::PreferencesDialog {
|
||||
auto_open.set_active(defaults.auto_open_output);
|
||||
output_mode.set_selected(0);
|
||||
*fps_reset.borrow_mut() = None;
|
||||
// Clear watch folders
|
||||
wfs_reset.borrow_mut().clear();
|
||||
wl_reset.remove_all();
|
||||
el_reset.set_visible(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -539,11 +621,13 @@ fn build_watch_folder_row(
|
||||
let preset_row = adw::ComboRow::builder()
|
||||
.title("Linked Preset")
|
||||
.subtitle("Preset to apply to new images")
|
||||
.use_subtitle(true)
|
||||
.build();
|
||||
let preset_model = gtk::StringList::new(
|
||||
&preset_names.iter().map(|s| s.as_str()).collect::<Vec<_>>(),
|
||||
);
|
||||
preset_row.set_model(Some(&preset_model));
|
||||
preset_row.set_list_factory(Some(&crate::steps::full_text_list_factory()));
|
||||
|
||||
// Set selected to matching preset
|
||||
let selected_idx = preset_names.iter()
|
||||
|
||||
Reference in New Issue
Block a user