collections: Add initial UI
This commit is contained in:
53
cartridges/ui/collections.py
Normal file
53
cartridges/ui/collections.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2025 Jamie Gravendeel
|
||||||
|
|
||||||
|
from typing import Any, override
|
||||||
|
|
||||||
|
from gi.repository import Adw, GObject, Gtk
|
||||||
|
|
||||||
|
from cartridges.collections import Collection
|
||||||
|
from cartridges.games import Game
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionFilter(Gtk.Filter):
|
||||||
|
"""Filter games based on a selected collection."""
|
||||||
|
|
||||||
|
__gtype_name__ = __qualname__
|
||||||
|
|
||||||
|
@GObject.Property(type=Collection)
|
||||||
|
def collection(self) -> Collection | None:
|
||||||
|
"""The collection used for filtering."""
|
||||||
|
return self._collection
|
||||||
|
|
||||||
|
@collection.setter
|
||||||
|
def collection(self, collection: Collection | None):
|
||||||
|
self._collection = collection
|
||||||
|
self.changed(Gtk.FilterChange.DIFFERENT)
|
||||||
|
|
||||||
|
@override
|
||||||
|
def do_match(self, game: Game) -> bool: # pyright: ignore[reportIncompatibleMethodOverride]
|
||||||
|
if not self.collection:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return game.game_id in self.collection.game_ids
|
||||||
|
|
||||||
|
|
||||||
|
class CollectionSidebarItem(Adw.SidebarItem): # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
"""A sidebar item representing a collection."""
|
||||||
|
|
||||||
|
@GObject.Property(type=Collection)
|
||||||
|
def collection(self) -> Collection:
|
||||||
|
"""The collection that `self` represents."""
|
||||||
|
return self._collection
|
||||||
|
|
||||||
|
@collection.setter
|
||||||
|
def collection(self, collection: Collection):
|
||||||
|
self._collection = collection
|
||||||
|
flags = GObject.BindingFlags.SYNC_CREATE
|
||||||
|
collection.bind_property("name", self, "title", flags)
|
||||||
|
collection.bind_property("icon-name", self, "icon-name", flags)
|
||||||
|
|
||||||
|
def __init__(self, **kwargs: Any):
|
||||||
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
|
self.bind_property("title", self, "tooltip", GObject.BindingFlags.SYNC_CREATE)
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
python.install_sources(
|
python.install_sources(
|
||||||
files(
|
files(
|
||||||
'__init__.py',
|
'__init__.py',
|
||||||
|
'collections.py',
|
||||||
'cover.py',
|
'cover.py',
|
||||||
'game_details.py',
|
'game_details.py',
|
||||||
'game_item.py',
|
'game_item.py',
|
||||||
|
|||||||
@@ -10,6 +10,11 @@ Adw.ShortcutsDialog shortcuts_dialog {
|
|||||||
accelerator: "<Control>f";
|
accelerator: "<Control>f";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Adw.ShortcutsItem {
|
||||||
|
title: _("Toggle Sidebar");
|
||||||
|
accelerator: "F9";
|
||||||
|
}
|
||||||
|
|
||||||
Adw.ShortcutsItem {
|
Adw.ShortcutsItem {
|
||||||
title: _("Main Menu");
|
title: _("Main Menu");
|
||||||
accelerator: "F10";
|
accelerator: "F10";
|
||||||
|
|||||||
@@ -26,12 +26,25 @@ template $Window: Adw.ApplicationWindow {
|
|||||||
action: "action(win.undo)";
|
action: "action(win.undo)";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shortcut {
|
||||||
|
trigger: "F9";
|
||||||
|
action: "action(win.show-sidebar)";
|
||||||
|
}
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
trigger: "<Control>w";
|
trigger: "<Control>w";
|
||||||
action: "action(window.close)";
|
action: "action(window.close)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Adw.Breakpoint {
|
||||||
|
condition ("max-width: 730px") // 3 columns + 48px of inherent padding
|
||||||
|
|
||||||
|
setters {
|
||||||
|
split_view.collapsed: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
content: Adw.NavigationView navigation_view {
|
content: Adw.NavigationView navigation_view {
|
||||||
Adw.NavigationPage {
|
Adw.NavigationPage {
|
||||||
title: bind template.title;
|
title: bind template.title;
|
||||||
@@ -41,198 +54,267 @@ template $Window: Adw.ApplicationWindow {
|
|||||||
"view",
|
"view",
|
||||||
]
|
]
|
||||||
|
|
||||||
child: Adw.ToolbarView {
|
child: Adw.OverlaySplitView split_view {
|
||||||
[top]
|
sidebar-width-unit: px;
|
||||||
Adw.HeaderBar header_bar {
|
min-sidebar-width: 224; // Width of 1 column
|
||||||
title-widget: Adw.Clamp clamp {
|
max-sidebar-width: bind split_view.min-sidebar-width;
|
||||||
tightening-threshold: bind clamp.maximum-size;
|
|
||||||
|
|
||||||
child: CenterBox title_box {
|
sidebar: Adw.NavigationPage {
|
||||||
hexpand: true;
|
title: bind template.title;
|
||||||
|
|
||||||
center-widget: SearchEntry search_entry {
|
child: Adw.ToolbarView {
|
||||||
hexpand: true;
|
[top]
|
||||||
placeholder-text: _("Search games");
|
Adw.HeaderBar {
|
||||||
search-started => $_search_started();
|
show-title: bind $_show_sidebar_title(template.settings as <Settings>.gtk-decoration-layout) as <bool>;
|
||||||
search-changed => $_search_changed();
|
|
||||||
activate => $_search_activate();
|
|
||||||
stop-search => $_stop_search();
|
|
||||||
};
|
|
||||||
|
|
||||||
end-widget: MenuButton sort_button {
|
[start]
|
||||||
icon-name: "filter-symbolic";
|
Button {
|
||||||
tooltip-text: _("Sort & Filter");
|
visible: bind split_view.show-sidebar;
|
||||||
margin-start: 6;
|
action-name: "win.show-sidebar";
|
||||||
|
icon-name: "sidebar-show-symbolic";
|
||||||
|
tooltip-text: _("Toggle Sidebar");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
menu-model: menu {
|
content: Adw.Sidebar sidebar {
|
||||||
section {
|
activated => $_navigate();
|
||||||
label: _("Sort");
|
|
||||||
|
|
||||||
item {
|
Adw.SidebarSection {
|
||||||
label: _("Last Played");
|
Adw.SidebarItem {
|
||||||
action: "win.sort-mode";
|
icon-name: "view-grid-symbolic";
|
||||||
target: "last_played";
|
title: _("All Games");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
item {
|
Adw.SidebarSection collections {
|
||||||
label: _("A-Z");
|
title: _("Collections");
|
||||||
action: "win.sort-mode";
|
}
|
||||||
target: "a-z";
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
label: _("Z-A");
|
|
||||||
action: "win.sort-mode";
|
|
||||||
target: "z-a";
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
label: _("Newest");
|
|
||||||
action: "win.sort-mode";
|
|
||||||
target: "newest";
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
label: _("Oldest");
|
|
||||||
action: "win.sort-mode";
|
|
||||||
target: "oldest";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
section {
|
|
||||||
item (_("Show Hidden Games"), "win.show-hidden")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
|
||||||
[start]
|
content: Adw.NavigationPage {
|
||||||
Button {
|
title: _("Games");
|
||||||
icon-name: "list-add-symbolic";
|
|
||||||
tooltip-text: _("Add Game");
|
|
||||||
action-name: "win.add";
|
|
||||||
}
|
|
||||||
|
|
||||||
[end]
|
child: Adw.ToolbarView {
|
||||||
MenuButton main_menu_button {
|
[top]
|
||||||
icon-name: "open-menu-symbolic";
|
Adw.HeaderBar header_bar {
|
||||||
tooltip-text: _("Main Menu");
|
title-widget: Adw.Clamp clamp {
|
||||||
primary: true;
|
tightening-threshold: bind clamp.maximum-size;
|
||||||
|
|
||||||
menu-model: menu {
|
child: CenterBox title_box {
|
||||||
item (_("Keyboard Shortcuts"), "app.shortcuts")
|
hexpand: true;
|
||||||
item (_("About Cartridges"), "app.about")
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
content: Adw.ToastOverlay toast_overlay {
|
center-widget: SearchEntry search_entry {
|
||||||
child: Adw.ViewStack {
|
hexpand: true;
|
||||||
enable-transitions: true;
|
placeholder-text: _("Search games");
|
||||||
visible-child-name: bind $_if_else(
|
search-started => $_search_started();
|
||||||
grid.model as <NoSelection>.n-items,
|
search-changed => $_search_changed();
|
||||||
"grid",
|
activate => $_search_activate();
|
||||||
$_if_else(
|
stop-search => $_stop_search();
|
||||||
template.search-text,
|
};
|
||||||
"empty-search",
|
|
||||||
$_if_else(template.show-hidden, "empty-hidden", "empty") as <string>
|
|
||||||
) as <string>
|
|
||||||
) as <string>;
|
|
||||||
|
|
||||||
Adw.ViewStackPage {
|
end-widget: MenuButton sort_button {
|
||||||
name: "grid";
|
icon-name: "filter-symbolic";
|
||||||
|
tooltip-text: _("Sort & Filter");
|
||||||
|
margin-start: 6;
|
||||||
|
|
||||||
child: ScrolledWindow {
|
menu-model: menu {
|
||||||
hscrollbar-policy: never;
|
section {
|
||||||
|
label: _("Sort");
|
||||||
|
|
||||||
child: GridView grid {
|
item {
|
||||||
|
label: _("Last Played");
|
||||||
|
action: "win.sort-mode";
|
||||||
|
target: "last_played";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("A-Z");
|
||||||
|
action: "win.sort-mode";
|
||||||
|
target: "a-z";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Z-A");
|
||||||
|
action: "win.sort-mode";
|
||||||
|
target: "z-a";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Newest");
|
||||||
|
action: "win.sort-mode";
|
||||||
|
target: "newest";
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
label: _("Oldest");
|
||||||
|
action: "win.sort-mode";
|
||||||
|
target: "oldest";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
section {
|
||||||
|
item (_("Show Hidden Games"), "win.show-hidden")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
[start]
|
||||||
|
Button {
|
||||||
|
visible: bind split_view.show-sidebar inverted;
|
||||||
|
action-name: "win.show-sidebar";
|
||||||
|
icon-name: "sidebar-show-symbolic";
|
||||||
|
tooltip-text: _("Toggle Sidebar");
|
||||||
|
}
|
||||||
|
|
||||||
|
[start]
|
||||||
|
Button {
|
||||||
|
icon-name: "list-add-symbolic";
|
||||||
|
tooltip-text: _("Add Game");
|
||||||
|
action-name: "win.add";
|
||||||
|
}
|
||||||
|
|
||||||
|
[end]
|
||||||
|
MenuButton main_menu_button {
|
||||||
|
icon-name: "open-menu-symbolic";
|
||||||
|
tooltip-text: _("Main Menu");
|
||||||
|
primary: true;
|
||||||
|
|
||||||
|
menu-model: menu {
|
||||||
|
item (_("Keyboard Shortcuts"), "app.shortcuts")
|
||||||
|
item (_("About Cartridges"), "app.about")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
content: Adw.ToastOverlay toast_overlay {
|
||||||
|
child: Adw.ViewStack {
|
||||||
|
enable-transitions: true;
|
||||||
|
visible-child-name: bind $_if_else(
|
||||||
|
grid.model as <NoSelection>.n-items,
|
||||||
|
"grid",
|
||||||
|
$_if_else(
|
||||||
|
template.search-text,
|
||||||
|
"empty-search",
|
||||||
|
$_if_else(
|
||||||
|
template.show-hidden,
|
||||||
|
"empty-hidden",
|
||||||
|
$_if_else(template.collection, "empty-collection", "empty") as <string>
|
||||||
|
) as <string>
|
||||||
|
) as <string>
|
||||||
|
) as <string>;
|
||||||
|
|
||||||
|
Adw.ViewStackPage {
|
||||||
name: "grid";
|
name: "grid";
|
||||||
single-click-activate: true;
|
|
||||||
activate => $_show_details();
|
|
||||||
|
|
||||||
model: NoSelection {
|
child: ScrolledWindow {
|
||||||
model: SortListModel {
|
hscrollbar-policy: never;
|
||||||
sorter: $GameSorter sorter {};
|
|
||||||
|
|
||||||
model: FilterListModel {
|
child: GridView grid {
|
||||||
watch-items: true;
|
name: "grid";
|
||||||
|
single-click-activate: true;
|
||||||
|
activate => $_show_details();
|
||||||
|
|
||||||
filter: EveryFilter {
|
model: NoSelection {
|
||||||
AnyFilter {
|
model: SortListModel {
|
||||||
StringFilter {
|
sorter: $GameSorter sorter {};
|
||||||
expression: expr item as <$Game>.name;
|
|
||||||
search: bind template.search-text;
|
|
||||||
}
|
|
||||||
|
|
||||||
StringFilter {
|
model: FilterListModel {
|
||||||
expression: expr item as <$Game>.developer;
|
watch-items: true;
|
||||||
search: bind template.search-text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BoolFilter {
|
filter: EveryFilter {
|
||||||
expression: expr item as <$Game>.hidden;
|
$CollectionFilter {
|
||||||
invert: bind template.show-hidden inverted;
|
collection: bind template.collection;
|
||||||
}
|
}
|
||||||
|
|
||||||
BoolFilter {
|
AnyFilter {
|
||||||
expression: expr item as <$Game>.removed;
|
StringFilter {
|
||||||
invert: true;
|
expression: expr item as <$Game>.name;
|
||||||
}
|
search: bind template.search-text;
|
||||||
|
}
|
||||||
|
|
||||||
BoolFilter {
|
StringFilter {
|
||||||
expression: expr item as <$Game>.blacklisted;
|
expression: expr item as <$Game>.developer;
|
||||||
invert: true;
|
search: bind template.search-text;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
position: bind template.position;
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
factory: BuilderListItemFactory {
|
Adw.ViewStackPage {
|
||||||
template ListItem {
|
name: "empty-search";
|
||||||
child: $GameItem {
|
|
||||||
game: bind template.item;
|
child: Adw.StatusPage {
|
||||||
position: bind template.position;
|
icon-name: "edit-find-symbolic";
|
||||||
};
|
title: _("No Games Found");
|
||||||
}
|
description: _("Try a different search");
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
|
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-collection";
|
||||||
|
|
||||||
|
child: Adw.StatusPage {
|
||||||
|
icon-name: bind template.collection as <$Collection>.icon-name;
|
||||||
|
title: bind $_format(_("No Games in {}"), template.collection as <$Collection>.name) as <string>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Adw.ViewStackPage {
|
||||||
|
name: "empty";
|
||||||
|
|
||||||
|
child: Adw.StatusPage {
|
||||||
|
icon-name: bind template.application as <Application>.application-id;
|
||||||
|
title: _("No Games");
|
||||||
|
description: _("Use the + button to add games");
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
Adw.ViewStackPage {
|
|
||||||
name: "empty-search";
|
|
||||||
|
|
||||||
child: Adw.StatusPage {
|
|
||||||
icon-name: "edit-find-symbolic";
|
|
||||||
title: _("No Games Found");
|
|
||||||
description: _("Try a different search");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
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>.application-id;
|
|
||||||
title: _("No Games");
|
|
||||||
description: _("Use the + button to add games");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,10 +10,15 @@ from typing import Any, TypeVar, cast
|
|||||||
|
|
||||||
from gi.repository import Adw, Gio, GLib, GObject, Gtk
|
from gi.repository import Adw, Gio, GLib, GObject, Gtk
|
||||||
|
|
||||||
from cartridges import games, state_settings
|
from cartridges import collections, games, state_settings
|
||||||
|
from cartridges.collections import Collection
|
||||||
from cartridges.config import PREFIX, PROFILE
|
from cartridges.config import PREFIX, PROFILE
|
||||||
from cartridges.games import Game
|
from cartridges.games import Game
|
||||||
|
|
||||||
|
from .collections import (
|
||||||
|
CollectionFilter, # noqa: F401
|
||||||
|
CollectionSidebarItem,
|
||||||
|
)
|
||||||
from .game_details import GameDetails
|
from .game_details import GameDetails
|
||||||
from .game_item import GameItem # noqa: F401
|
from .game_item import GameItem # noqa: F401
|
||||||
from .games import GameSorter
|
from .games import GameSorter
|
||||||
@@ -40,6 +45,8 @@ class Window(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
__gtype_name__ = __qualname__
|
__gtype_name__ = __qualname__
|
||||||
|
|
||||||
|
split_view: Adw.OverlaySplitView = Gtk.Template.Child()
|
||||||
|
collections: Adw.SidebarSection = Gtk.Template.Child() # pyright: ignore[reportAttributeAccessIssue]
|
||||||
navigation_view: Adw.NavigationView = Gtk.Template.Child()
|
navigation_view: Adw.NavigationView = Gtk.Template.Child()
|
||||||
header_bar: Adw.HeaderBar = Gtk.Template.Child()
|
header_bar: Adw.HeaderBar = Gtk.Template.Child()
|
||||||
title_box: Gtk.CenterBox = Gtk.Template.Child()
|
title_box: Gtk.CenterBox = Gtk.Template.Child()
|
||||||
@@ -53,6 +60,9 @@ class Window(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
search_text = GObject.Property(type=str)
|
search_text = GObject.Property(type=str)
|
||||||
show_hidden = GObject.Property(type=bool, default=False)
|
show_hidden = GObject.Property(type=bool, default=False)
|
||||||
|
collection = GObject.Property(type=Collection)
|
||||||
|
|
||||||
|
settings = GObject.Property(type=Gtk.Settings)
|
||||||
|
|
||||||
@GObject.Property(type=Gio.ListStore)
|
@GObject.Property(type=Gio.ListStore)
|
||||||
def games(self) -> Gio.ListStore:
|
def games(self) -> Gio.ListStore:
|
||||||
@@ -65,14 +75,22 @@ class Window(Adw.ApplicationWindow):
|
|||||||
if PROFILE == "development":
|
if PROFILE == "development":
|
||||||
self.add_css_class("devel")
|
self.add_css_class("devel")
|
||||||
|
|
||||||
|
self.settings = self.get_settings()
|
||||||
|
|
||||||
flags = Gio.SettingsBindFlags.DEFAULT
|
flags = Gio.SettingsBindFlags.DEFAULT
|
||||||
state_settings.bind("width", self, "default-width", flags)
|
state_settings.bind("width", self, "default-width", flags)
|
||||||
state_settings.bind("height", self, "default-height", flags)
|
state_settings.bind("height", self, "default-height", flags)
|
||||||
state_settings.bind("is-maximized", self, "maximized", flags)
|
state_settings.bind("is-maximized", self, "maximized", flags)
|
||||||
|
state_settings.bind("show-sidebar", self.split_view, "show-sidebar", flags)
|
||||||
|
|
||||||
# https://gitlab.gnome.org/GNOME/gtk/-/issues/7901
|
# https://gitlab.gnome.org/GNOME/gtk/-/issues/7901
|
||||||
self.search_entry.set_key_capture_widget(self)
|
self.search_entry.set_key_capture_widget(self)
|
||||||
|
self.collections.bind_model(
|
||||||
|
collections.model,
|
||||||
|
lambda collection: CollectionSidebarItem(collection=collection),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.add_action(state_settings.create_action("show-sidebar"))
|
||||||
self.add_action(state_settings.create_action("sort-mode"))
|
self.add_action(state_settings.create_action("sort-mode"))
|
||||||
self.add_action(Gio.PropertyAction.new("show-hidden", self, "show-hidden"))
|
self.add_action(Gio.PropertyAction.new("show-hidden", self, "show-hidden"))
|
||||||
self.add_action_entries((
|
self.add_action_entries((
|
||||||
@@ -102,6 +120,18 @@ class Window(Adw.ApplicationWindow):
|
|||||||
|
|
||||||
self.toast_overlay.add_toast(toast)
|
self.toast_overlay.add_toast(toast)
|
||||||
|
|
||||||
|
@Gtk.Template.Callback()
|
||||||
|
def _show_sidebar_title(self, _obj, layout: str) -> bool:
|
||||||
|
right_window_controls = layout.replace("appmenu", "").startswith(":")
|
||||||
|
return right_window_controls and not sys.platform.startswith("darwin")
|
||||||
|
|
||||||
|
@Gtk.Template.Callback()
|
||||||
|
def _navigate(self, sidebar: Adw.Sidebar, index: int): # pyright: ignore[reportAttributeAccessIssue]
|
||||||
|
item = sidebar.get_item(index)
|
||||||
|
self.collection = (
|
||||||
|
item.collection if isinstance(item, CollectionSidebarItem) else None
|
||||||
|
)
|
||||||
|
|
||||||
@Gtk.Template.Callback()
|
@Gtk.Template.Callback()
|
||||||
def _setup_gamepad_monitor(self, *_args):
|
def _setup_gamepad_monitor(self, *_args):
|
||||||
if sys.platform.startswith("linux"):
|
if sys.platform.startswith("linux"):
|
||||||
@@ -112,6 +142,10 @@ class Window(Adw.ApplicationWindow):
|
|||||||
def _if_else(self, _obj, condition: object, first: _T, second: _T) -> _T:
|
def _if_else(self, _obj, condition: object, first: _T, second: _T) -> _T:
|
||||||
return first if condition else second
|
return first if condition else second
|
||||||
|
|
||||||
|
@Gtk.Template.Callback()
|
||||||
|
def _format(self, _obj, string: str, *args: Any) -> str:
|
||||||
|
return string.format(*args)
|
||||||
|
|
||||||
@Gtk.Template.Callback()
|
@Gtk.Template.Callback()
|
||||||
def _show_details(self, grid: Gtk.GridView, position: int):
|
def _show_details(self, grid: Gtk.GridView, position: int):
|
||||||
self.details.game = cast(Gio.ListModel, grid.props.model).get_item(position)
|
self.details.game = cast(Gio.ListModel, grid.props.model).get_item(position)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="@PREFIX@/icons/scalable/actions">
|
<gresource prefix="@PREFIX@/icons/scalable/actions">
|
||||||
|
<file>collection-symbolic.svg</file>
|
||||||
<file>filter-symbolic.svg</file>
|
<file>filter-symbolic.svg</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
|||||||
@@ -25,5 +25,8 @@
|
|||||||
</choices>
|
</choices>
|
||||||
<default>"last_played"</default>
|
<default>"last_played"</default>
|
||||||
</key>
|
</key>
|
||||||
|
<key name="show-sidebar" type="b">
|
||||||
|
<default>false</default>
|
||||||
|
</key>
|
||||||
</schema>
|
</schema>
|
||||||
</schemalist>
|
</schemalist>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ cartridges/gamepads.py
|
|||||||
cartridges/games.py
|
cartridges/games.py
|
||||||
cartridges/sources/__init__.py
|
cartridges/sources/__init__.py
|
||||||
cartridges/sources/steam.py
|
cartridges/sources/steam.py
|
||||||
|
cartridges/ui/collections.py
|
||||||
cartridges/ui/cover.blp
|
cartridges/ui/cover.blp
|
||||||
cartridges/ui/cover.py
|
cartridges/ui/cover.py
|
||||||
cartridges/ui/game-details.blp
|
cartridges/ui/game-details.blp
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ reportUnknownLambdaType = "none"
|
|||||||
reportUnknownMemberType = "none"
|
reportUnknownMemberType = "none"
|
||||||
reportUnknownParameterType = "none"
|
reportUnknownParameterType = "none"
|
||||||
reportUnknownVariableType = "none"
|
reportUnknownVariableType = "none"
|
||||||
|
reportUntypedBaseClass = "none"
|
||||||
reportUntypedFunctionDecorator = "none"
|
reportUntypedFunctionDecorator = "none"
|
||||||
reportUnusedImport = "none"
|
reportUnusedImport = "none"
|
||||||
reportUnusedVariable = "none"
|
reportUnusedVariable = "none"
|
||||||
|
|||||||
Reference in New Issue
Block a user