From 45247cdac5c09c2382b78eb2d4b2bdbfc42047f9 Mon Sep 17 00:00:00 2001 From: lashman Date: Fri, 6 Mar 2026 17:29:02 +0200 Subject: [PATCH] Add collapsible watch folders panel in main window Toggle button in the header bar reveals a bottom panel showing active watch folders with their linked presets and watching status. The add button opens Settings for full watch folder configuration. --- pixstrip-gtk/src/app.rs | 131 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/pixstrip-gtk/src/app.rs b/pixstrip-gtk/src/app.rs index 3d5d9cd..586bc06 100644 --- a/pixstrip-gtk/src/app.rs +++ b/pixstrip-gtk/src/app.rs @@ -456,10 +456,35 @@ fn build_ui(app: &adw::Application) { bottom_bar.append(&separator); bottom_bar.append(&bottom_box); + // Watch folders collapsible panel + let watch_revealer = gtk::Revealer::builder() + .transition_type(gtk::RevealerTransitionType::SlideUp) + .reveal_child(false) + .build(); + + let watch_panel = build_watch_folder_panel(); + watch_revealer.set_child(Some(&watch_panel)); + + // Watch folder toggle button in header + let watch_button = gtk::ToggleButton::builder() + .icon_name("folder-visiting-symbolic") + .tooltip_text("Watch Folders") + .build(); + watch_button.add_css_class("flat"); + header.pack_start(&watch_button); + + { + let revealer = watch_revealer.clone(); + watch_button.connect_toggled(move |btn| { + revealer.set_reveal_child(btn.is_active()); + }); + } + // Main content layout let content_box = gtk::Box::new(gtk::Orientation::Vertical, 0); content_box.append(step_indicator.widget()); content_box.append(&nav_view); + content_box.append(&watch_revealer); // Queue side panel let (queue_panel, queue_list_box) = build_queue_panel(&app_state); @@ -3048,6 +3073,112 @@ fn format_duration(ms: u64) -> String { } } +fn build_watch_folder_panel() -> gtk::Box { + let panel = gtk::Box::builder() + .orientation(gtk::Orientation::Vertical) + .spacing(0) + .build(); + + panel.append(>k::Separator::new(gtk::Orientation::Horizontal)); + + let inner = gtk::Box::builder() + .orientation(gtk::Orientation::Vertical) + .spacing(8) + .margin_top(8) + .margin_bottom(8) + .margin_start(12) + .margin_end(12) + .build(); + + let header_box = gtk::Box::builder() + .orientation(gtk::Orientation::Horizontal) + .spacing(8) + .build(); + + let header_label = gtk::Label::builder() + .label("Watch Folders") + .css_classes(["heading"]) + .hexpand(true) + .halign(gtk::Align::Start) + .build(); + header_box.append(&header_label); + + // Quick add button + let add_btn = gtk::Button::builder() + .icon_name("list-add-symbolic") + .tooltip_text("Add watch folder") + .build(); + add_btn.add_css_class("flat"); + header_box.append(&add_btn); + + inner.append(&header_box); + + // List of active watch folders + let list_box = gtk::ListBox::builder() + .selection_mode(gtk::SelectionMode::None) + .css_classes(["boxed-list"]) + .build(); + + let empty_label = gtk::Label::builder() + .label("No watch folders active. Add one in Settings or click +.") + .css_classes(["dim-label", "caption"]) + .halign(gtk::Align::Center) + .wrap(true) + .margin_top(4) + .margin_bottom(4) + .build(); + + // Populate from config + let config_store = pixstrip_core::storage::ConfigStore::new(); + let config = config_store.load().unwrap_or_default(); + let has_folders = !config.watch_folders.is_empty(); + + for folder in &config.watch_folders { + if !folder.active { + continue; + } + let display_name = folder.path.file_name() + .and_then(|n| n.to_str()) + .unwrap_or_else(|| folder.path.to_str().unwrap_or("Unknown")); + + let row = adw::ActionRow::builder() + .title(display_name) + .subtitle(&folder.preset_name) + .build(); + row.add_prefix(>k::Image::from_icon_name("folder-visiting-symbolic")); + + // Status indicator + let status = gtk::Label::builder() + .label("Watching") + .css_classes(["caption", "accent"]) + .valign(gtk::Align::Center) + .build(); + row.add_suffix(&status); + + list_box.append(&row); + } + + empty_label.set_visible(!has_folders || config.watch_folders.iter().all(|f| !f.active)); + list_box.set_visible(has_folders && config.watch_folders.iter().any(|f| f.active)); + + inner.append(&list_box); + inner.append(&empty_label); + + // Wire add button to open Settings > Watch Folders + { + let inner_ref = inner.clone(); + add_btn.connect_clicked(move |btn| { + if let Some(root) = btn.root() { + root.activate_action("win.show-settings", None).ok(); + } + let _ = &inner_ref; + }); + } + + panel.append(&inner); + panel +} + fn build_queue_panel(_state: &AppState) -> (gtk::Box, gtk::ListBox) { let panel = gtk::Box::builder() .orientation(gtk::Orientation::Vertical)