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.
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user