Wire all wizard step controls to shared JobConfig state

All four configurable steps (resize, convert, compress, metadata) now
have signal handlers that update the shared JobConfig via AppState.
The run_processing function builds ProcessingJob from actual user
choices instead of hardcoded values. Fixed clippy warnings (collapsed
if-let chain, removed needless borrow).
This commit is contained in:
2026-03-06 11:51:01 +02:00
parent eeb418ccdd
commit b855955786
6 changed files with 333 additions and 161 deletions

View File

@@ -1,6 +1,8 @@
use adw::prelude::*;
use crate::app::AppState;
use pixstrip_core::types::ImageFormat;
pub fn build_convert_page() -> adw::NavigationPage {
pub fn build_convert_page(state: &AppState) -> adw::NavigationPage {
let scrolled = gtk::ScrolledWindow::builder()
.hscrollbar_policy(gtk::PolicyType::Never)
.vexpand(true)
@@ -15,11 +17,13 @@ pub fn build_convert_page() -> adw::NavigationPage {
.margin_end(24)
.build();
let cfg = state.job_config.borrow();
// Enable toggle
let enable_row = adw::SwitchRow::builder()
.title("Enable Format Conversion")
.subtitle("Convert images to a different format")
.active(false)
.active(cfg.convert_enabled)
.build();
let enable_group = adw::PreferencesGroup::new();
@@ -31,67 +35,52 @@ pub fn build_convert_page() -> adw::NavigationPage {
.title("Output Format")
.build();
let formats = [
("Keep Original", "No conversion - output in same format as input"),
("JPEG", "Universal photo format, lossy compression"),
("PNG", "Lossless format, good for graphics and screenshots"),
("WebP", "Modern web format, excellent compression, wide support"),
("AVIF", "Next-gen format, best compression, growing support"),
];
let format_flow = gtk::FlowBox::builder()
.selection_mode(gtk::SelectionMode::Single)
.max_children_per_line(5)
.min_children_per_line(2)
.row_spacing(8)
.column_spacing(8)
.homogeneous(true)
let format_row = adw::ComboRow::builder()
.title("Convert to")
.subtitle("Choose the output format for all images")
.build();
let format_model = gtk::StringList::new(&[
"Keep Original",
"JPEG - universal, lossy",
"PNG - lossless, graphics",
"WebP - modern, excellent compression",
]);
format_row.set_model(Some(&format_model));
for (name, desc) in &formats {
let card = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(4)
.halign(gtk::Align::Center)
.valign(gtk::Align::Center)
.build();
card.add_css_class("card");
card.set_size_request(140, 80);
// Set initial selection
format_row.set_selected(match cfg.convert_format {
None => 0,
Some(ImageFormat::Jpeg) => 1,
Some(ImageFormat::Png) => 2,
Some(ImageFormat::WebP) => 3,
_ => 0,
});
let inner = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(4)
.margin_top(12)
.margin_bottom(12)
.margin_start(8)
.margin_end(8)
.halign(gtk::Align::Center)
.valign(gtk::Align::Center)
.vexpand(true)
.build();
let name_label = gtk::Label::builder()
.label(*name)
.css_classes(["heading"])
.build();
let desc_label = gtk::Label::builder()
.label(*desc)
.css_classes(["caption", "dim-label"])
.wrap(true)
.justify(gtk::Justification::Center)
.max_width_chars(18)
.build();
inner.append(&name_label);
inner.append(&desc_label);
card.append(&inner);
format_flow.append(&card);
}
format_group.add(&format_flow);
format_group.add(&format_row);
content.append(&format_group);
drop(cfg);
// Wire signals
{
let jc = state.job_config.clone();
enable_row.connect_active_notify(move |row| {
jc.borrow_mut().convert_enabled = row.is_active();
});
}
{
let jc = state.job_config.clone();
format_row.connect_selected_notify(move |row| {
let mut c = jc.borrow_mut();
c.convert_format = match row.selected() {
1 => Some(ImageFormat::Jpeg),
2 => Some(ImageFormat::Png),
3 => Some(ImageFormat::WebP),
_ => None,
};
});
}
scrolled.set_child(Some(&content));
let clamp = adw::Clamp::builder()