Skip to main content

mimick/library/
sidebar.rs

1//! Sidebar navigation panel for the library window.
2//!
3//! Builds the split-pane sidebar containing album rows, fixed navigation
4//! entries (All Assets, Explore, Local, Timeline), and the folder-scoped
5//! album list. Handles selection changes to drive the main grid view source.
6
7use gtk::prelude::*;
8use libadwaita::prelude::*;
9
10/// Contains references to the side navigation panel widgets and lists.
11pub struct SidebarParts {
12    pub root: gtk::Box,
13    pub connection_row: libadwaita::ActionRow,
14    pub server_row: libadwaita::ActionRow,
15    pub fixed_list: gtk::ListBox,
16    pub albums_list: gtk::ListBox,
17}
18
19/// Construct the hierarchical side navigation sidebar panel.
20pub fn build_sidebar() -> SidebarParts {
21    let root = gtk::Box::builder()
22        .orientation(gtk::Orientation::Vertical)
23        .spacing(12)
24        .margin_top(12)
25        .margin_bottom(12)
26        .margin_start(12)
27        .margin_end(12)
28        .width_request(200)
29        .build();
30
31    let fixed_list = gtk::ListBox::builder()
32        .selection_mode(gtk::SelectionMode::Single)
33        .css_classes(vec!["boxed-list".to_string()])
34        .build();
35
36    let connection_row = libadwaita::ActionRow::builder()
37        .title("Connection")
38        .subtitle("Offline")
39        .title_lines(1)
40        .subtitle_lines(1)
41        .activatable(true)
42        .build();
43    let server_row = libadwaita::ActionRow::builder()
44        .title("Server")
45        .subtitle("Statistics unavailable")
46        .title_lines(1)
47        .subtitle_lines(1)
48        .activatable(true)
49        .build();
50    let connection_list = gtk::ListBox::builder()
51        .selection_mode(gtk::SelectionMode::None)
52        .css_classes(vec!["boxed-list".to_string()])
53        .build();
54    connection_list.append(&connection_row);
55    connection_list.append(&server_row);
56
57    fixed_list.append(&action_row(
58        "Photos",
59        "Timeline of every photo and video",
60        "image-x-generic-symbolic",
61        "photos",
62    ));
63    fixed_list.append(&action_row(
64        "Search",
65        "Find photos, videos, and text",
66        "system-search-symbolic",
67        "search",
68    ));
69    fixed_list.append(&action_row(
70        "Explore",
71        "People, places, and things",
72        "view-grid-symbolic",
73        "explore",
74    ));
75    fixed_list.append(&action_row(
76        "Albums",
77        "Recent, owned, and shared",
78        "folder-pictures-symbolic",
79        "albums",
80    ));
81
82    let albums_header = gtk::Label::builder()
83        .label("Albums")
84        .xalign(0.0)
85        .css_classes(vec!["heading".to_string(), "dim-label".to_string()])
86        .margin_top(6)
87        .build();
88
89    let albums_list = gtk::ListBox::builder()
90        .selection_mode(gtk::SelectionMode::Single)
91        .css_classes(vec!["boxed-list".to_string()])
92        .build();
93
94    let albums_scroll = gtk::ScrolledWindow::builder()
95        .hscrollbar_policy(gtk::PolicyType::Never)
96        .vexpand(true)
97        .child(&albums_list)
98        .build();
99
100    root.append(&fixed_list);
101    root.append(&albums_header);
102    root.append(&albums_scroll);
103    root.append(&connection_list);
104
105    SidebarParts {
106        root,
107        connection_row,
108        server_row,
109        fixed_list,
110        albums_list,
111    }
112}
113
114/// Construct a navigation list row decorated with an icon and titles.
115fn action_row(title: &str, subtitle: &str, icon_name: &str, key: &str) -> libadwaita::ActionRow {
116    let row = libadwaita::ActionRow::builder()
117        .title(title)
118        .subtitle(subtitle)
119        .title_lines(1)
120        .subtitle_lines(1)
121        .tooltip_text(key)
122        .activatable(true)
123        .build();
124    let icon = gtk::Image::from_icon_name(icon_name);
125    row.add_prefix(&icon);
126    row
127}