diff --git a/pixstrip-core/src/storage.rs b/pixstrip-core/src/storage.rs index 6fd49d5..46a91e4 100644 --- a/pixstrip-core/src/storage.rs +++ b/pixstrip-core/src/storage.rs @@ -189,6 +189,7 @@ pub struct SessionState { pub watermark_enabled: Option, pub rename_enabled: Option, pub last_seen_version: Option, + pub expanded_sections: std::collections::HashMap, } pub struct SessionStore { diff --git a/pixstrip-gtk/src/app.rs b/pixstrip-gtk/src/app.rs index 536d0d5..1d26e53 100644 --- a/pixstrip-gtk/src/app.rs +++ b/pixstrip-gtk/src/app.rs @@ -102,6 +102,19 @@ pub struct AppState { pub job_config: Rc>, pub detailed_mode: bool, pub batch_queue: Rc>, + pub expanded_sections: Rc>>, +} + +impl AppState { + /// Get the expanded state for a named section, falling back to the skill level default + pub fn is_section_expanded(&self, section: &str) -> bool { + self.expanded_sections.borrow().get(section).copied().unwrap_or(self.detailed_mode) + } + + /// Set and persist an expander's state + pub fn set_section_expanded(&self, section: &str, expanded: bool) { + self.expanded_sections.borrow_mut().insert(section.to_string(), expanded); + } } /// A queued batch of images with their processing settings @@ -300,6 +313,7 @@ fn build_ui(app: &adw::Application) { output_dir: Rc::new(RefCell::new(None)), detailed_mode: app_cfg.skill_level.is_advanced(), batch_queue: Rc::new(RefCell::new(BatchQueue::default())), + expanded_sections: Rc::new(RefCell::new(sess_state.expanded_sections.clone())), job_config: Rc::new(RefCell::new(JobConfig { resize_enabled: if remember { sess_state.resize_enabled.unwrap_or(true) } else { true }, resize_width: if remember { sess_state.resize_width.unwrap_or(1200) } else { 1200 }, @@ -574,6 +588,9 @@ fn build_ui(app: &adw::Application) { state.rename_enabled = Some(cfg.rename_enabled); } + // Always save expanded section states + state.expanded_sections = app_state_for_close.expanded_sections.borrow().clone(); + let _ = session.save(&state); glib::Propagation::Proceed }); diff --git a/pixstrip-gtk/src/steps/step_adjustments.rs b/pixstrip-gtk/src/steps/step_adjustments.rs index c445130..2344fd3 100644 --- a/pixstrip-gtk/src/steps/step_adjustments.rs +++ b/pixstrip-gtk/src/steps/step_adjustments.rs @@ -98,8 +98,16 @@ pub fn build_adjustments_page(state: &AppState) -> adw::NavigationPage { .title("Advanced Adjustments") .subtitle("Brightness, contrast, saturation, effects") .show_enable_switch(false) + .expanded(state.is_section_expanded("adjustments-advanced")) .build(); + { + let st = state.clone(); + adjust_expander.connect_expanded_notify(move |row| { + st.set_section_expanded("adjustments-advanced", row.is_expanded()); + }); + } + // Brightness slider (-100 to +100) let brightness_row = adw::ActionRow::builder() .title("Brightness") diff --git a/pixstrip-gtk/src/steps/step_compress.rs b/pixstrip-gtk/src/steps/step_compress.rs index 036ff4d..ac02a96 100644 --- a/pixstrip-gtk/src/steps/step_compress.rs +++ b/pixstrip-gtk/src/steps/step_compress.rs @@ -343,9 +343,16 @@ pub fn build_compress_page(state: &AppState) -> adw::NavigationPage { let advanced_expander = adw::ExpanderRow::builder() .title("Per-Format Quality") .subtitle("Fine-tune quality for each format individually") - .expanded(state.detailed_mode) + .expanded(state.is_section_expanded("compress-advanced")) .build(); + { + let st = state.clone(); + advanced_expander.connect_expanded_notify(move |row| { + st.set_section_expanded("compress-advanced", row.is_expanded()); + }); + } + let jpeg_row = adw::SpinRow::builder() .title("JPEG Quality") .subtitle("1-100, higher is better quality") diff --git a/pixstrip-gtk/src/steps/step_convert.rs b/pixstrip-gtk/src/steps/step_convert.rs index 2553044..28d65d0 100644 --- a/pixstrip-gtk/src/steps/step_convert.rs +++ b/pixstrip-gtk/src/steps/step_convert.rs @@ -145,9 +145,16 @@ pub fn build_convert_page(state: &AppState) -> adw::NavigationPage { .title("Format Mapping") .subtitle("Different input formats can convert to different outputs") .show_enable_switch(false) - .expanded(state.detailed_mode) + .expanded(state.is_section_expanded("convert-advanced")) .build(); + { + let st = state.clone(); + advanced_expander.connect_expanded_notify(move |row| { + st.set_section_expanded("convert-advanced", row.is_expanded()); + }); + } + let progressive_row = adw::SwitchRow::builder() .title("Progressive JPEG") .subtitle("Loads gradually in browsers, slightly larger") diff --git a/pixstrip-gtk/src/steps/step_resize.rs b/pixstrip-gtk/src/steps/step_resize.rs index 840785c..108ab3e 100644 --- a/pixstrip-gtk/src/steps/step_resize.rs +++ b/pixstrip-gtk/src/steps/step_resize.rs @@ -372,9 +372,16 @@ pub fn build_resize_page(state: &AppState) -> adw::NavigationPage { .title("Advanced Options") .subtitle("Resize algorithm, DPI, upscale behavior") .show_enable_switch(false) - .expanded(state.detailed_mode) + .expanded(state.is_section_expanded("resize-advanced")) .build(); + { + let st = state.clone(); + advanced_expander.connect_expanded_notify(move |row| { + st.set_section_expanded("resize-advanced", row.is_expanded()); + }); + } + let upscale_row = adw::SwitchRow::builder() .title("Allow Upscaling") .subtitle("Enlarge images smaller than target size") diff --git a/pixstrip-gtk/src/steps/step_watermark.rs b/pixstrip-gtk/src/steps/step_watermark.rs index aef7bbe..3f6fa2b 100644 --- a/pixstrip-gtk/src/steps/step_watermark.rs +++ b/pixstrip-gtk/src/steps/step_watermark.rs @@ -336,9 +336,16 @@ pub fn build_watermark_page(state: &AppState) -> adw::NavigationPage { .title("Advanced Options") .subtitle("Opacity, rotation, tiling, margin") .show_enable_switch(false) - .expanded(state.detailed_mode) + .expanded(state.is_section_expanded("watermark-advanced")) .build(); + { + let st = state.clone(); + advanced_expander.connect_expanded_notify(move |row| { + st.set_section_expanded("watermark-advanced", row.is_expanded()); + }); + } + // Text color picker let color_row = adw::ActionRow::builder() .title("Text Color")