Replace single NavigationView with ViewSwitcher (Installed, Catalog, Updates)
Restructure the app from a single NavigationView into an AdwViewStack with 3 top-level pages: Installed, Catalog, and Updates. Each page keeps its own header bar while an AdwViewSwitcherBar at the bottom provides tab-style navigation between them. The Installed page retains its own NavigationView for detail drill-down. The catalog action now switches the ViewStack tab instead of pushing a page.
This commit is contained in:
@@ -27,6 +27,7 @@ use crate::ui::library_view::{LibraryState, LibraryView};
|
|||||||
use crate::ui::preferences;
|
use crate::ui::preferences;
|
||||||
use crate::ui::security_report;
|
use crate::ui::security_report;
|
||||||
use crate::ui::update_dialog;
|
use crate::ui::update_dialog;
|
||||||
|
use crate::ui::updates_view;
|
||||||
use crate::ui::widgets;
|
use crate::ui::widgets;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
@@ -35,7 +36,8 @@ mod imp {
|
|||||||
pub struct DriftwoodWindow {
|
pub struct DriftwoodWindow {
|
||||||
pub settings: OnceCell<gio::Settings>,
|
pub settings: OnceCell<gio::Settings>,
|
||||||
pub toast_overlay: OnceCell<adw::ToastOverlay>,
|
pub toast_overlay: OnceCell<adw::ToastOverlay>,
|
||||||
pub navigation_view: OnceCell<adw::NavigationView>,
|
pub view_stack: OnceCell<adw::ViewStack>,
|
||||||
|
pub installed_nav: OnceCell<adw::NavigationView>,
|
||||||
pub library_view: OnceCell<LibraryView>,
|
pub library_view: OnceCell<LibraryView>,
|
||||||
pub database: OnceCell<Rc<Database>>,
|
pub database: OnceCell<Rc<Database>>,
|
||||||
pub drop_overlay: OnceCell<gtk::Box>,
|
pub drop_overlay: OnceCell<gtk::Box>,
|
||||||
@@ -48,7 +50,8 @@ mod imp {
|
|||||||
Self {
|
Self {
|
||||||
settings: OnceCell::new(),
|
settings: OnceCell::new(),
|
||||||
toast_overlay: OnceCell::new(),
|
toast_overlay: OnceCell::new(),
|
||||||
navigation_view: OnceCell::new(),
|
view_stack: OnceCell::new(),
|
||||||
|
installed_nav: OnceCell::new(),
|
||||||
library_view: OnceCell::new(),
|
library_view: OnceCell::new(),
|
||||||
database: OnceCell::new(),
|
database: OnceCell::new(),
|
||||||
drop_overlay: OnceCell::new(),
|
drop_overlay: OnceCell::new(),
|
||||||
@@ -162,9 +165,41 @@ impl DriftwoodWindow {
|
|||||||
// Library view (contains header bar, search, grid/list, empty state)
|
// Library view (contains header bar, search, grid/list, empty state)
|
||||||
let library_view = LibraryView::new(&menu);
|
let library_view = LibraryView::new(&menu);
|
||||||
|
|
||||||
// Navigation view
|
// Installed view: NavigationView for drill-down (detail, dashboard, etc.)
|
||||||
let navigation_view = adw::NavigationView::new();
|
let installed_nav = adw::NavigationView::new();
|
||||||
navigation_view.push(&library_view.page);
|
installed_nav.push(&library_view.page);
|
||||||
|
|
||||||
|
// Catalog view
|
||||||
|
let catalog_page = catalog_view::build_catalog_page(self.database());
|
||||||
|
|
||||||
|
// Updates view
|
||||||
|
let updates_toolbar = updates_view::build_updates_view(self.database());
|
||||||
|
|
||||||
|
// ViewStack with 3 top-level pages
|
||||||
|
let view_stack = adw::ViewStack::new();
|
||||||
|
view_stack.set_vexpand(true);
|
||||||
|
|
||||||
|
let installed_vs_page = view_stack.add_titled(&installed_nav, Some("installed"), &i18n("Installed"));
|
||||||
|
installed_vs_page.set_icon_name(Some("view-grid-symbolic"));
|
||||||
|
|
||||||
|
let catalog_vs_page = view_stack.add_titled(&catalog_page, Some("catalog"), &i18n("Catalog"));
|
||||||
|
catalog_vs_page.set_icon_name(Some("system-software-install-symbolic"));
|
||||||
|
|
||||||
|
let updates_vs_page = view_stack.add_titled(&updates_toolbar, Some("updates"), &i18n("Updates"));
|
||||||
|
updates_vs_page.set_icon_name(Some("software-update-available-symbolic"));
|
||||||
|
|
||||||
|
// ViewSwitcherBar at the bottom for tab navigation
|
||||||
|
let view_switcher_bar = adw::ViewSwitcherBar::builder()
|
||||||
|
.stack(&view_stack)
|
||||||
|
.reveal(true)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// Main content box: ViewStack + bottom switcher bar
|
||||||
|
let main_box = gtk::Box::builder()
|
||||||
|
.orientation(gtk::Orientation::Vertical)
|
||||||
|
.build();
|
||||||
|
main_box.append(&view_stack);
|
||||||
|
main_box.append(&view_switcher_bar);
|
||||||
|
|
||||||
// Drop overlay - centered opaque card over a dimmed scrim
|
// Drop overlay - centered opaque card over a dimmed scrim
|
||||||
let drop_overlay_icon = gtk::Image::builder()
|
let drop_overlay_icon = gtk::Image::builder()
|
||||||
@@ -253,9 +288,9 @@ impl DriftwoodWindow {
|
|||||||
drop_overlay_content.add_controller(click);
|
drop_overlay_content.add_controller(click);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Overlay wraps navigation view so the drop indicator sits on top
|
// Overlay wraps main content so the drop indicator sits on top
|
||||||
let overlay = gtk::Overlay::new();
|
let overlay = gtk::Overlay::new();
|
||||||
overlay.set_child(Some(&navigation_view));
|
overlay.set_child(Some(&main_box));
|
||||||
overlay.add_overlay(&drop_overlay_content);
|
overlay.add_overlay(&drop_overlay_content);
|
||||||
|
|
||||||
// Toast overlay wraps the overlay
|
// Toast overlay wraps the overlay
|
||||||
@@ -353,7 +388,7 @@ impl DriftwoodWindow {
|
|||||||
|
|
||||||
// Wire up card/row activation to push detail view (or toggle selection)
|
// Wire up card/row activation to push detail view (or toggle selection)
|
||||||
{
|
{
|
||||||
let nav = navigation_view.clone();
|
let nav = installed_nav.clone();
|
||||||
let db = self.database().clone();
|
let db = self.database().clone();
|
||||||
let window_weak = self.downgrade();
|
let window_weak = self.downgrade();
|
||||||
library_view.connect_grid_activated(move |record_id| {
|
library_view.connect_grid_activated(move |record_id| {
|
||||||
@@ -371,7 +406,7 @@ impl DriftwoodWindow {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
let nav = navigation_view.clone();
|
let nav = installed_nav.clone();
|
||||||
let db = self.database().clone();
|
let db = self.database().clone();
|
||||||
let window_weak = self.downgrade();
|
let window_weak = self.downgrade();
|
||||||
library_view.connect_list_activated(move |record_id| {
|
library_view.connect_list_activated(move |record_id| {
|
||||||
@@ -394,7 +429,7 @@ impl DriftwoodWindow {
|
|||||||
{
|
{
|
||||||
let db = self.database().clone();
|
let db = self.database().clone();
|
||||||
let window_weak = self.downgrade();
|
let window_weak = self.downgrade();
|
||||||
navigation_view.connect_popped(move |_nav, page| {
|
installed_nav.connect_popped(move |_nav, page| {
|
||||||
if page.tag().as_deref() == Some("detail") {
|
if page.tag().as_deref() == Some("detail") {
|
||||||
if let Some(window) = window_weak.upgrade() {
|
if let Some(window) = window_weak.upgrade() {
|
||||||
// Update window title for accessibility (WCAG 2.4.8)
|
// Update window title for accessibility (WCAG 2.4.8)
|
||||||
@@ -413,7 +448,7 @@ impl DriftwoodWindow {
|
|||||||
// Update window title when navigating to sub-pages (WCAG 2.4.8 Location)
|
// Update window title when navigating to sub-pages (WCAG 2.4.8 Location)
|
||||||
{
|
{
|
||||||
let window_weak = self.downgrade();
|
let window_weak = self.downgrade();
|
||||||
navigation_view.connect_pushed(move |nav| {
|
installed_nav.connect_pushed(move |nav| {
|
||||||
if let Some(window) = window_weak.upgrade() {
|
if let Some(window) = window_weak.upgrade() {
|
||||||
if let Some(page) = nav.visible_page() {
|
if let Some(page) = nav.visible_page() {
|
||||||
let page_title = page.title();
|
let page_title = page.title();
|
||||||
@@ -439,9 +474,13 @@ impl DriftwoodWindow {
|
|||||||
.set(toast_overlay)
|
.set(toast_overlay)
|
||||||
.expect("ToastOverlay already set");
|
.expect("ToastOverlay already set");
|
||||||
self.imp()
|
self.imp()
|
||||||
.navigation_view
|
.view_stack
|
||||||
.set(navigation_view)
|
.set(view_stack)
|
||||||
.expect("NavigationView already set");
|
.expect("ViewStack already set");
|
||||||
|
self.imp()
|
||||||
|
.installed_nav
|
||||||
|
.set(installed_nav)
|
||||||
|
.expect("InstalledNav already set");
|
||||||
if self.imp().library_view.set(library_view).is_err() {
|
if self.imp().library_view.set(library_view).is_err() {
|
||||||
panic!("LibraryView already set");
|
panic!("LibraryView already set");
|
||||||
}
|
}
|
||||||
@@ -454,7 +493,7 @@ impl DriftwoodWindow {
|
|||||||
let dashboard_action = gio::ActionEntry::builder("dashboard")
|
let dashboard_action = gio::ActionEntry::builder("dashboard")
|
||||||
.activate(|window: &Self, _, _| {
|
.activate(|window: &Self, _, _| {
|
||||||
let db = window.database().clone();
|
let db = window.database().clone();
|
||||||
let nav = window.imp().navigation_view.get().unwrap();
|
let nav = window.imp().installed_nav.get().unwrap();
|
||||||
let page = dashboard::build_dashboard_page(&db);
|
let page = dashboard::build_dashboard_page(&db);
|
||||||
nav.push(&page);
|
nav.push(&page);
|
||||||
})
|
})
|
||||||
@@ -554,7 +593,7 @@ impl DriftwoodWindow {
|
|||||||
let security_report_action = gio::ActionEntry::builder("security-report")
|
let security_report_action = gio::ActionEntry::builder("security-report")
|
||||||
.activate(|window: &Self, _, _| {
|
.activate(|window: &Self, _, _| {
|
||||||
let db = window.database().clone();
|
let db = window.database().clone();
|
||||||
let nav = window.imp().navigation_view.get().unwrap();
|
let nav = window.imp().installed_nav.get().unwrap();
|
||||||
let page = security_report::build_security_report_page(&db);
|
let page = security_report::build_security_report_page(&db);
|
||||||
nav.push(&page);
|
nav.push(&page);
|
||||||
})
|
})
|
||||||
@@ -568,13 +607,11 @@ impl DriftwoodWindow {
|
|||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
// Catalog browser action
|
// Catalog browser action - switches to catalog tab
|
||||||
let catalog_action = gio::ActionEntry::builder("catalog")
|
let catalog_action = gio::ActionEntry::builder("catalog")
|
||||||
.activate(|window: &Self, _, _| {
|
.activate(|window: &Self, _, _| {
|
||||||
let db = window.database().clone();
|
let view_stack = window.imp().view_stack.get().unwrap();
|
||||||
let catalog_page = catalog_view::build_catalog_page(&db);
|
view_stack.set_visible_child_name("catalog");
|
||||||
let nav = window.imp().navigation_view.get().unwrap();
|
|
||||||
nav.push(&catalog_page);
|
|
||||||
})
|
})
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user