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(&separator);
|
||||||
bottom_bar.append(&bottom_box);
|
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
|
// Main content layout
|
||||||
let content_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
let content_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
|
||||||
content_box.append(step_indicator.widget());
|
content_box.append(step_indicator.widget());
|
||||||
content_box.append(&nav_view);
|
content_box.append(&nav_view);
|
||||||
|
content_box.append(&watch_revealer);
|
||||||
|
|
||||||
// Queue side panel
|
// Queue side panel
|
||||||
let (queue_panel, queue_list_box) = build_queue_panel(&app_state);
|
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) {
|
fn build_queue_panel(_state: &AppState) -> (gtk::Box, gtk::ListBox) {
|
||||||
let panel = gtk::Box::builder()
|
let panel = gtk::Box::builder()
|
||||||
.orientation(gtk::Orientation::Vertical)
|
.orientation(gtk::Orientation::Vertical)
|
||||||
|
|||||||
Reference in New Issue
Block a user