Wire welcome dialog with navigation and first-run detection

- Welcome dialog buttons navigate between pages
- Done button closes dialog and marks first_run_complete
- Show welcome dialog on first launch only
- Add first_run_complete field to AppConfig with serde(default)
This commit is contained in:
2026-03-06 11:43:25 +02:00
parent c20e0db2ff
commit f353bbe5e6
3 changed files with 47 additions and 11 deletions

View File

@@ -159,6 +159,8 @@ fn build_ui(app: &adw::Application) {
ui.step_indicator.set_current(0);
window.present();
crate::welcome::show_welcome_if_first_launch(&window);
}
fn build_menu() -> gtk::gio::Menu {

View File

@@ -1,7 +1,26 @@
use adw::prelude::*;
#[allow(dead_code)]
pub fn build_welcome_dialog() -> adw::Dialog {
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)
@@ -10,23 +29,20 @@ pub fn build_welcome_dialog() -> adw::Dialog {
let nav_view = adw::NavigationView::new();
// Page 1: Welcome
let welcome_page = build_welcome_page();
let welcome_page = build_welcome_page(&nav_view);
nav_view.add(&welcome_page);
// Page 2: Skill level
let skill_page = build_skill_page();
let skill_page = build_skill_page(&nav_view);
nav_view.add(&skill_page);
// Page 3: Output defaults
let output_page = build_output_page();
let output_page = build_output_page(&dialog);
nav_view.add(&output_page);
dialog.set_child(Some(&nav_view));
dialog
}
fn build_welcome_page() -> adw::NavigationPage {
fn build_welcome_page(nav_view: &adw::NavigationView) -> adw::NavigationPage {
let content = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(12)
@@ -50,6 +66,11 @@ fn build_welcome_page() -> adw::NavigationPage {
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);
@@ -60,7 +81,7 @@ fn build_welcome_page() -> adw::NavigationPage {
.build()
}
fn build_skill_page() -> adw::NavigationPage {
fn build_skill_page(nav_view: &adw::NavigationView) -> adw::NavigationPage {
let content = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(12)
@@ -116,6 +137,11 @@ fn build_skill_page() -> adw::NavigationPage {
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);
@@ -128,7 +154,7 @@ fn build_skill_page() -> adw::NavigationPage {
.build()
}
fn build_output_page() -> adw::NavigationPage {
fn build_output_page(dialog: &adw::Dialog) -> adw::NavigationPage {
let content = gtk::Box::builder()
.orientation(gtk::Orientation::Vertical)
.spacing(12)
@@ -184,6 +210,11 @@ fn build_output_page() -> adw::NavigationPage {
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);