Add What's New dialog, accessibility labels, focus management
This commit is contained in:
@@ -349,6 +349,7 @@ fn build_menu() -> gtk::gio::Menu {
|
||||
menu.append(Some("Settings"), Some("win.show-settings"));
|
||||
menu.append(Some("History"), Some("win.show-history"));
|
||||
menu.append(Some("Keyboard Shortcuts"), Some("win.show-shortcuts"));
|
||||
menu.append(Some("What's New"), Some("win.show-whats-new"));
|
||||
menu
|
||||
}
|
||||
|
||||
@@ -500,6 +501,16 @@ fn setup_window_actions(window: &adw::ApplicationWindow, ui: &WizardUi) {
|
||||
action_group.add_action(&action);
|
||||
}
|
||||
|
||||
// What's New action
|
||||
{
|
||||
let window = window.clone();
|
||||
let action = gtk::gio::SimpleAction::new("show-whats-new", None);
|
||||
action.connect_activate(move |_, _| {
|
||||
show_whats_new_dialog(&window);
|
||||
});
|
||||
action_group.add_action(&action);
|
||||
}
|
||||
|
||||
// Connect button clicks
|
||||
ui.back_button.connect_clicked({
|
||||
let action_group = action_group.clone();
|
||||
@@ -541,6 +552,13 @@ fn navigate_to_step(ui: &WizardUi, target: usize) {
|
||||
if target < ui.pages.len() {
|
||||
ui.nav_view.replace(&ui.pages[..=target]);
|
||||
ui.title.set_subtitle(&ui.pages[target].title());
|
||||
|
||||
// Focus management - move focus to first interactive element on new step
|
||||
// Use idle callback to let the page fully render first
|
||||
let page = ui.pages[target].clone();
|
||||
glib::idle_add_local_once(move || {
|
||||
page.child_focus(gtk::DirectionType::TabForward);
|
||||
});
|
||||
}
|
||||
|
||||
// Update dynamic content on certain steps
|
||||
@@ -857,6 +875,78 @@ fn show_history_dialog(window: &adw::ApplicationWindow) {
|
||||
dialog.present(Some(window));
|
||||
}
|
||||
|
||||
fn show_whats_new_dialog(window: &adw::ApplicationWindow) {
|
||||
let dialog = adw::Dialog::builder()
|
||||
.title("What's New")
|
||||
.content_width(450)
|
||||
.content_height(350)
|
||||
.build();
|
||||
|
||||
let toolbar_view = adw::ToolbarView::new();
|
||||
let header = adw::HeaderBar::new();
|
||||
toolbar_view.add_top_bar(&header);
|
||||
|
||||
let scrolled = gtk::ScrolledWindow::builder()
|
||||
.hscrollbar_policy(gtk::PolicyType::Never)
|
||||
.vexpand(true)
|
||||
.build();
|
||||
|
||||
let content = gtk::Box::builder()
|
||||
.orientation(gtk::Orientation::Vertical)
|
||||
.spacing(12)
|
||||
.margin_top(12)
|
||||
.margin_bottom(12)
|
||||
.margin_start(24)
|
||||
.margin_end(24)
|
||||
.build();
|
||||
|
||||
let version_label = gtk::Label::builder()
|
||||
.label("Pixstrip 0.1.0")
|
||||
.css_classes(["title-1"])
|
||||
.halign(gtk::Align::Start)
|
||||
.build();
|
||||
|
||||
let subtitle_label = gtk::Label::builder()
|
||||
.label("First release")
|
||||
.css_classes(["dim-label"])
|
||||
.halign(gtk::Align::Start)
|
||||
.build();
|
||||
|
||||
content.append(&version_label);
|
||||
content.append(&subtitle_label);
|
||||
|
||||
let changes_group = adw::PreferencesGroup::builder()
|
||||
.title("Changes in this version")
|
||||
.build();
|
||||
|
||||
let features = [
|
||||
("Wizard workflow", "Step-by-step batch image processing"),
|
||||
("Resize", "Width/height, social media presets, fit-in-box"),
|
||||
("Convert", "JPEG, PNG, WebP, AVIF, GIF, TIFF conversion"),
|
||||
("Compress", "Quality presets with per-format controls"),
|
||||
("Metadata", "Strip all, privacy mode, photographer mode"),
|
||||
("Watermark", "Text and image watermarks with positioning"),
|
||||
("Rename", "Prefix, suffix, counter, template engine"),
|
||||
("Adjustments", "Brightness, contrast, crop, trim, effects"),
|
||||
];
|
||||
|
||||
for (title, subtitle) in &features {
|
||||
let row = adw::ActionRow::builder()
|
||||
.title(*title)
|
||||
.subtitle(*subtitle)
|
||||
.build();
|
||||
row.add_prefix(>k::Image::from_icon_name("emblem-ok-symbolic"));
|
||||
changes_group.add(&row);
|
||||
}
|
||||
|
||||
content.append(&changes_group);
|
||||
|
||||
scrolled.set_child(Some(&content));
|
||||
toolbar_view.set_content(Some(&scrolled));
|
||||
dialog.set_child(Some(&toolbar_view));
|
||||
dialog.present(Some(window));
|
||||
}
|
||||
|
||||
fn run_processing(_window: &adw::ApplicationWindow, ui: &WizardUi) {
|
||||
let files = ui.state.loaded_files.borrow().clone();
|
||||
if files.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user