From 99adcea647a5d13a3a6e4c2e27b6f2d228019241 Mon Sep 17 00:00:00 2001 From: Jamie Gravendeel Date: Mon, 1 Dec 2025 15:53:05 +0100 Subject: [PATCH] window: Add status pages --- cartridges/ui/window.blp | 128 +++++++++++++++++++++++++-------------- cartridges/ui/window.py | 8 ++- 2 files changed, 90 insertions(+), 46 deletions(-) diff --git a/cartridges/ui/window.blp b/cartridges/ui/window.blp index bd35865..67a9971 100644 --- a/cartridges/ui/window.blp +++ b/cartridges/ui/window.blp @@ -47,6 +47,10 @@ template $Window: Adw.ApplicationWindow { Adw.NavigationPage { title: bind template.title; + styles [ + "view", + ] + child: Adw.ToolbarView { [top] Adw.HeaderBar { @@ -125,68 +129,102 @@ template $Window: Adw.ApplicationWindow { } } - content: ScrolledWindow { - hscrollbar-policy: never; + content: Adw.ViewStack { + enable-transitions: true; + visible-child-name: bind $_if_else(grid.model as .n-items, "grid", $_if_else(template.search-text, "empty-search", $_if_else(template.show-hidden, "empty-hidden", "empty") as ) as ) as ; - child: GridView grid { + Adw.ViewStackPage { name: "grid"; - single-click-activate: true; - activate => $_activate_game(); - model: NoSelection { - model: SortListModel { - sorter: CustomSorter sorter {}; + child: ScrolledWindow { + hscrollbar-policy: never; - model: FilterListModel { - watch-items: true; + child: GridView grid { + name: "grid"; + single-click-activate: true; + activate => $_activate_game(); - filter: EveryFilter { - AnyFilter { - StringFilter { - expression: expr item as <$Game>.name; - search: bind template.search-text; - } + model: NoSelection { + model: SortListModel { + sorter: CustomSorter sorter {}; - StringFilter { - expression: expr item as <$Game>.developer; - search: bind template.search-text; - } - } + model: FilterListModel { + watch-items: true; - BoolFilter { - expression: expr item as <$Game>.hidden; - invert: bind template.show-hidden inverted; - } + filter: EveryFilter { + AnyFilter { + StringFilter { + expression: expr item as <$Game>.name; + search: bind template.search-text; + } - BoolFilter { - expression: expr item as <$Game>.removed; - invert: true; - } + StringFilter { + expression: expr item as <$Game>.developer; + search: bind template.search-text; + } + } - BoolFilter { - expression: expr item as <$Game>.blacklisted; - invert: true; - } + BoolFilter { + expression: expr item as <$Game>.hidden; + invert: bind template.show-hidden inverted; + } + + BoolFilter { + expression: expr item as <$Game>.removed; + invert: true; + } + + BoolFilter { + expression: expr item as <$Game>.blacklisted; + invert: true; + } + }; + + model: bind template.games; + }; }; + }; - model: bind template.games; + factory: BuilderListItemFactory { + template ListItem { + child: $GameItem { + game: bind template.item; + }; + } }; }; }; + } - factory: BuilderListItemFactory { - template ListItem { - child: $GameItem { - game: bind template.item; - }; - } + Adw.ViewStackPage { + name: "empty-search"; + + child: Adw.StatusPage { + icon-name: "edit-find-symbolic"; + title: _("No Games Found"); + description: _("Try a different search"); }; - }; - }; + } - styles [ - "view", - ] + Adw.ViewStackPage { + name: "empty-hidden"; + + child: Adw.StatusPage { + icon-name: "view-conceal-symbolic"; + title: _("No Hidden Games"); + description: _("Games you hide will appear here"); + }; + } + + Adw.ViewStackPage { + name: "empty"; + + child: Adw.StatusPage { + icon-name: bind template.application as .application-id; + title: _("No Games"); + }; + } + }; }; } diff --git a/cartridges/ui/window.py b/cartridges/ui/window.py index a0c7773..afb33c5 100644 --- a/cartridges/ui/window.py +++ b/cartridges/ui/window.py @@ -6,7 +6,7 @@ import locale from collections.abc import Generator from datetime import UTC, datetime from gettext import gettext as _ -from typing import Any +from typing import Any, TypeVar from gi.repository import Adw, Gdk, Gio, GLib, GObject, Gtk @@ -25,6 +25,8 @@ SORT_MODES = { "oldest": ("added", True), } +_T = TypeVar("_T") + @Gtk.Template.from_resource(f"{PREFIX}/window.ui") class Window(Adw.ApplicationWindow): @@ -83,6 +85,10 @@ class Window(Adw.ApplicationWindow): ), )) + @Gtk.Template.Callback() + def _if_else(self, _obj, condition: bool, first: _T, second: _T) -> _T: + return first if condition else second + @Gtk.Template.Callback() def _activate_game(self, grid: Gtk.GridView, position: int): if isinstance(model := grid.props.model, Gio.ListModel):