games: Load cover art
This commit is contained in:
@@ -1,18 +1,22 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
# SPDX-FileCopyrightText: Copyright 2025 Zoey Ahmed
|
# SPDX-FileCopyrightText: Copyright 2025 Zoey Ahmed
|
||||||
|
# SPDX-FileCopyrightText: Copyright 2025 kramo
|
||||||
|
|
||||||
from collections.abc import Generator
|
from collections.abc import Generator
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import cast
|
||||||
|
|
||||||
from gi.repository import (
|
from gi.repository import (
|
||||||
|
Gdk,
|
||||||
Gio,
|
Gio,
|
||||||
GLib,
|
GLib,
|
||||||
GObject,
|
GObject,
|
||||||
Json, # pyright: ignore[reportAttributeAccessIssue, reportUnknownVariableType]
|
Json, # pyright: ignore[reportAttributeAccessIssue, reportUnknownVariableType]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
DATA_DIR = Path(GLib.get_user_data_dir(), "cartridges")
|
||||||
GAMES_DIR = Path(GLib.get_user_data_dir(), "cartridges", "games")
|
GAMES_DIR = DATA_DIR / "games"
|
||||||
|
COVERS_DIR = DATA_DIR / "covers"
|
||||||
|
|
||||||
|
|
||||||
class Game(GObject.Object):
|
class Game(GObject.Object):
|
||||||
@@ -32,16 +36,32 @@ class Game(GObject.Object):
|
|||||||
blacklisted = GObject.Property(type=bool, default=False)
|
blacklisted = GObject.Property(type=bool, default=False)
|
||||||
version = GObject.Property(type=float, default=2.0)
|
version = GObject.Property(type=float, default=2.0)
|
||||||
|
|
||||||
|
cover = GObject.Property(type=Gdk.Texture)
|
||||||
|
|
||||||
|
|
||||||
def load() -> Generator[Game]:
|
def load() -> Generator[Game]:
|
||||||
"""Load the user's games from disk."""
|
"""Load the user's games from disk."""
|
||||||
for game in GAMES_DIR.iterdir():
|
for path in GAMES_DIR.glob("*.json"):
|
||||||
data = game.read_text("utf-8")
|
|
||||||
try:
|
try:
|
||||||
yield Json.gobject_from_data(Game, data, len(data))
|
data = path.read_text("utf-8")
|
||||||
|
except UnicodeError:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
game = cast(Game, Json.gobject_from_data(Game, data, len(data)))
|
||||||
except GLib.Error:
|
except GLib.Error:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
cover_path = COVERS_DIR / game.game_id
|
||||||
|
for ext in ".gif", ".tiff":
|
||||||
|
filename = str(cover_path.with_suffix(ext))
|
||||||
|
try:
|
||||||
|
game.cover = Gdk.Texture.new_from_filename(filename)
|
||||||
|
except GLib.Error:
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield game
|
||||||
|
|
||||||
|
|
||||||
model = Gio.ListStore.new(Game)
|
model = Gio.ListStore.new(Game)
|
||||||
model.splice(0, 0, tuple(load()))
|
model.splice(0, 0, tuple(load()))
|
||||||
|
|||||||
8
cartridges/ui/style.css
Normal file
8
cartridges/ui/style.css
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#grid {
|
||||||
|
padding: 6px 12px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#grid > child {
|
||||||
|
padding: 12px;
|
||||||
|
border-radius: 24px;
|
||||||
|
}
|
||||||
@@ -2,5 +2,6 @@
|
|||||||
<gresources>
|
<gresources>
|
||||||
<gresource prefix="@PREFIX@">
|
<gresource prefix="@PREFIX@">
|
||||||
<file>window.ui</file>
|
<file>window.ui</file>
|
||||||
|
<file>style.css</file>
|
||||||
</gresource>
|
</gresource>
|
||||||
</gresources>
|
</gresources>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ using Adw 1;
|
|||||||
|
|
||||||
template $Window: Adw.ApplicationWindow {
|
template $Window: Adw.ApplicationWindow {
|
||||||
title: _("Cartridges");
|
title: _("Cartridges");
|
||||||
default-width: 800;
|
default-width: 920;
|
||||||
default-height: 600;
|
default-height: 700;
|
||||||
|
|
||||||
ShortcutController {
|
ShortcutController {
|
||||||
Shortcut {
|
Shortcut {
|
||||||
@@ -28,18 +28,43 @@ template $Window: Adw.ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
content: GridView {
|
content: ScrolledWindow {
|
||||||
model: NoSelection {
|
child: GridView {
|
||||||
model: bind template.games;
|
name: "grid";
|
||||||
};
|
|
||||||
|
|
||||||
factory: BuilderListItemFactory {
|
model: NoSelection {
|
||||||
template ListItem {
|
model: bind template.games;
|
||||||
child: Label {
|
};
|
||||||
label: bind template.item as <$Game>.name;
|
|
||||||
};
|
factory: BuilderListItemFactory {
|
||||||
}
|
template ListItem {
|
||||||
|
child: Box {
|
||||||
|
orientation: vertical;
|
||||||
|
spacing: 12;
|
||||||
|
|
||||||
|
Picture {
|
||||||
|
paintable: bind template.item as <$Game>.cover;
|
||||||
|
width-request: 200;
|
||||||
|
height-request: 300;
|
||||||
|
halign: center;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"card",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
label: bind template.item as <$Game>.name;
|
||||||
|
ellipsize: middle;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"view",
|
||||||
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ ignore = [
|
|||||||
"Q002",
|
"Q002",
|
||||||
"Q003",
|
"Q003",
|
||||||
"S310",
|
"S310",
|
||||||
|
"TC006",
|
||||||
"TD",
|
"TD",
|
||||||
"TRY301",
|
"TRY301",
|
||||||
"W191",
|
"W191",
|
||||||
|
|||||||
Reference in New Issue
Block a user