Files
cartridges/cartridges/collections.py
2025-12-29 01:29:04 +01:00

118 lines
3.3 KiB
Python

# SPDX-License-Identifier: GPL-3.0-or-later
# SPDX-FileCopyrightText: Copyright 2025 Jamie Gravendeel
from collections.abc import Generator, Iterable
from gettext import gettext as _
from typing import TYPE_CHECKING, Any, cast
from gi.repository import Gio, GLib, GObject
from cartridges import SETTINGS
from cartridges.sources import imported
if TYPE_CHECKING:
from .application import Application
from .ui.window import Window
class Collection(Gio.SimpleActionGroup):
"""Collection data class."""
__gtype_name__ = __qualname__
name = GObject.Property(type=str)
icon = GObject.Property(type=str, default="collection")
game_ids = GObject.Property(type=object)
removed = GObject.Property(type=bool, default=False)
icon_name = GObject.Property(type=str)
@GObject.Property(type=bool, default=True)
def in_model(self) -> bool:
"""Whether `self` has been added to the model."""
return self in model
def __init__(self, **kwargs: Any):
super().__init__(**kwargs)
self.game_ids = self.game_ids or set()
self.bind_property(
"icon",
self,
"icon-name",
GObject.BindingFlags.SYNC_CREATE,
lambda _, name: f"{name}-symbolic",
)
self.add_action(remove := Gio.SimpleAction.new("remove"))
remove.connect("activate", lambda *_: self._remove())
self.bind_property(
"in-model",
remove,
"enabled",
GObject.BindingFlags.SYNC_CREATE,
)
def _remove(self):
self.removed = True
save()
app = cast("Application", Gio.Application.get_default())
window = cast("Window", app.props.active_window)
window.send_toast(_("{} removed").format(self.name), undo=self._undo_remove)
def _undo_remove(self):
self.removed = False
save()
def load():
"""Load collections from GSettings."""
model.splice(0, 0, tuple(_get_collections()))
save()
for collection in model:
collection.notify("in-model")
def save():
"""Save collections to GSettings."""
SETTINGS.set_value(
"collections",
GLib.Variant(
"aa{sv}",
(
{
"name": GLib.Variant.new_string(collection.name),
"icon": GLib.Variant.new_string(collection.icon),
"game-ids": GLib.Variant.new_strv(tuple(collection.game_ids)),
"removed": GLib.Variant.new_boolean(collection.removed),
}
for collection in cast(Iterable[Collection], model)
),
),
)
def _get_collections() -> Generator[Collection]:
imported_ids = {p.stem for p in imported.get_paths()}
for data in SETTINGS.get_value("collections").unpack():
if data.get("removed"):
continue
try:
yield Collection(
name=data["name"],
icon=data["icon"],
game_ids={
ident
for ident in data["game-ids"]
if not ident.startswith(imported.ID) or ident in imported_ids
},
)
except (KeyError, TypeError):
continue
model = Gio.ListStore.new(Collection)