use adw::prelude::*; pub fn show_welcome_if_first_launch(window: &adw::ApplicationWindow) { let config = pixstrip_core::storage::ConfigStore::new(); if let Ok(cfg) = config.load() && cfg.first_run_complete { return; } let dialog = build_welcome_dialog(); let win = window.clone(); dialog.connect_closed(move |_| { let config = pixstrip_core::storage::ConfigStore::new(); if let Ok(mut cfg) = config.load() { cfg.first_run_complete = true; let _ = config.save(&cfg); } }); dialog.present(Some(&win)); } fn build_welcome_dialog() -> adw::Dialog { let dialog = adw::Dialog::builder() .title("Welcome to Pixstrip") .content_width(500) .content_height(450) .build(); let nav_view = adw::NavigationView::new(); let welcome_page = build_welcome_page(&nav_view); nav_view.add(&welcome_page); let skill_page = build_skill_page(&nav_view); nav_view.add(&skill_page); let output_page = build_output_page(&dialog); nav_view.add(&output_page); dialog.set_child(Some(&nav_view)); dialog } fn build_welcome_page(nav_view: &adw::NavigationView) -> adw::NavigationPage { let content = gtk::Box::builder() .orientation(gtk::Orientation::Vertical) .spacing(12) .margin_top(24) .margin_bottom(24) .margin_start(24) .margin_end(24) .build(); let status = adw::StatusPage::builder() .title("Welcome to Pixstrip") .description("A quick and powerful batch image processor.\nResize, convert, compress, strip metadata, watermark, and rename - all in a simple wizard.") .icon_name("image-x-generic-symbolic") .vexpand(true) .build(); let next_button = gtk::Button::builder() .label("Get Started") .halign(gtk::Align::Center) .build(); next_button.add_css_class("suggested-action"); next_button.add_css_class("pill"); let nav = nav_view.clone(); next_button.connect_clicked(move |_| { nav.push_by_tag("skill-level"); }); content.append(&status); content.append(&next_button); adw::NavigationPage::builder() .title("Welcome") .tag("welcome") .child(&content) .build() } fn build_skill_page(nav_view: &adw::NavigationView) -> adw::NavigationPage { let content = gtk::Box::builder() .orientation(gtk::Orientation::Vertical) .spacing(12) .margin_top(24) .margin_bottom(24) .margin_start(24) .margin_end(24) .build(); let title = gtk::Label::builder() .label("How much detail do you want?") .css_classes(["title-2"]) .halign(gtk::Align::Start) .build(); let subtitle = gtk::Label::builder() .label("You can change this anytime in Settings.") .css_classes(["dim-label"]) .halign(gtk::Align::Start) .build(); let group = adw::PreferencesGroup::new(); let simple_row = adw::ActionRow::builder() .title("Simple") .subtitle("Fewer options visible, great for quick tasks. Advanced options are still available behind expanders.") .activatable(true) .build(); simple_row.add_prefix(>k::Image::from_icon_name("emblem-ok-symbolic")); let simple_check = gtk::CheckButton::new(); simple_check.set_active(true); simple_row.add_suffix(&simple_check); simple_row.set_activatable_widget(Some(&simple_check)); let detailed_row = adw::ActionRow::builder() .title("Detailed") .subtitle("All options visible by default. Best for power users who want full control.") .activatable(true) .build(); detailed_row.add_prefix(>k::Image::from_icon_name("preferences-system-symbolic")); let detailed_check = gtk::CheckButton::new(); detailed_check.set_group(Some(&simple_check)); detailed_row.add_suffix(&detailed_check); detailed_row.set_activatable_widget(Some(&detailed_check)); group.add(&simple_row); group.add(&detailed_row); let next_button = gtk::Button::builder() .label("Continue") .halign(gtk::Align::Center) .build(); next_button.add_css_class("suggested-action"); next_button.add_css_class("pill"); let nav = nav_view.clone(); next_button.connect_clicked(move |_| { nav.push_by_tag("output-location"); }); content.append(&title); content.append(&subtitle); content.append(&group); content.append(&next_button); adw::NavigationPage::builder() .title("Skill Level") .tag("skill-level") .child(&content) .build() } fn build_output_page(dialog: &adw::Dialog) -> adw::NavigationPage { let content = gtk::Box::builder() .orientation(gtk::Orientation::Vertical) .spacing(12) .margin_top(24) .margin_bottom(24) .margin_start(24) .margin_end(24) .build(); let title = gtk::Label::builder() .label("Where should processed images go?") .css_classes(["title-2"]) .halign(gtk::Align::Start) .build(); let subtitle = gtk::Label::builder() .label("You can change this per-batch or in Settings.") .css_classes(["dim-label"]) .halign(gtk::Align::Start) .build(); let group = adw::PreferencesGroup::new(); let subfolder_row = adw::ActionRow::builder() .title("Subfolder next to originals") .subtitle("Creates a 'processed' folder next to your images") .activatable(true) .build(); subfolder_row.add_prefix(>k::Image::from_icon_name("folder-symbolic")); let subfolder_check = gtk::CheckButton::new(); subfolder_check.set_active(true); subfolder_row.add_suffix(&subfolder_check); subfolder_row.set_activatable_widget(Some(&subfolder_check)); let fixed_row = adw::ActionRow::builder() .title("Fixed output folder") .subtitle("Always save to the same folder") .activatable(true) .build(); fixed_row.add_prefix(>k::Image::from_icon_name("folder-open-symbolic")); let fixed_check = gtk::CheckButton::new(); fixed_check.set_group(Some(&subfolder_check)); fixed_row.add_suffix(&fixed_check); fixed_row.set_activatable_widget(Some(&fixed_check)); group.add(&subfolder_row); group.add(&fixed_row); let done_button = gtk::Button::builder() .label("Start Using Pixstrip") .halign(gtk::Align::Center) .build(); done_button.add_css_class("suggested-action"); done_button.add_css_class("pill"); let dlg = dialog.clone(); done_button.connect_clicked(move |_| { dlg.close(); }); content.append(&title); content.append(&subtitle); content.append(&group); content.append(&done_button); adw::NavigationPage::builder() .title("Output Location") .tag("output-location") .child(&content) .build() }