From e7d27cc1c46b3caaa36004bcfa9ed7b3ea129a00 Mon Sep 17 00:00:00 2001
From: kramo <93832451+kra-mo@users.noreply.github.com>
Date: Fri, 7 Jul 2023 21:25:08 +0200
Subject: [PATCH] Implement source filtering
---
data/gtk/window.blp | 40 +++++++++++---
data/hu.kramo.Cartridges.gschema.xml.in | 3 --
src/details_window.py | 3 +-
src/importer/importer.py | 3 ++
src/main.py | 7 +++
src/shared.py.in | 8 +++
src/store/managers/display_manager.py | 24 +++++----
src/window.py | 71 +++++++++++++++++++++++--
8 files changed, 135 insertions(+), 24 deletions(-)
diff --git a/data/gtk/window.blp b/data/gtk/window.blp
index a8d4909..a2e115e 100644
--- a/data/gtk/window.blp
+++ b/data/gtk/window.blp
@@ -88,16 +88,44 @@ template $CartridgesWindow : Adw.ApplicationWindow {
}
}
- ListBox {
- Box {
+ ListBox sidebar {
+ Box all_games_row_box {
+ margin-top: 12;
+ margin-bottom: 12;
+ margin-start: 6;
+ margin-end: 6;
+ spacing: 12;
+
Image {
- icon-name: "view-grid";
- margin-start: 3;
- margin-end: 9;
+ icon-name: "view-grid-symbolic";
}
Label {
halign: start;
- label: _("All");
+ label: _("All Games");
+ }
+ }
+ Box added_row_box {
+ margin-top: 12;
+ margin-bottom: 12;
+ margin-start: 6;
+ margin-end: 6;
+ spacing: 12;
+
+ Image {
+ icon-name: "list-add-symbolic";
+ }
+ Label {
+ halign: start;
+ label: _("Added");
+ }
+ }
+ ListBoxRow {
+ selectable: false;
+ activatable: false;
+ Label {
+ label: _("Imported");
+ styles ["heading"]
+ halign: start;
}
}
styles ["navigation-sidebar"]
diff --git a/data/hu.kramo.Cartridges.gschema.xml.in b/data/hu.kramo.Cartridges.gschema.xml.in
index b0022d9..b18fc12 100644
--- a/data/hu.kramo.Cartridges.gschema.xml.in
+++ b/data/hu.kramo.Cartridges.gschema.xml.in
@@ -109,9 +109,6 @@
false
-
- "all"
-
"[]"
diff --git a/src/details_window.py b/src/details_window.py
index 532ee1a..0ca94f2 100644
--- a/src/details_window.py
+++ b/src/details_window.py
@@ -158,11 +158,12 @@ class DetailsWindow(Adw.Window):
source_id = "imported"
numbers = [0]
game_id: str
- for game_id in shared.source_games[source_id]:
+ for game_id in shared.store.source_games.get(source_id, set()):
prefix = "imported_"
if not game_id.startswith(prefix):
continue
numbers.append(int(game_id.replace(prefix, "", 1)))
+
game_number = max(numbers) + 1
self.game = Game(
diff --git a/src/importer/importer.py b/src/importer/importer.py
index 8b30c6b..fba0483 100644
--- a/src/importer/importer.py
+++ b/src/importer/importer.py
@@ -91,6 +91,7 @@ class Importer(ErrorProducer):
def run(self):
"""Use several Gio.Task to import games from added sources"""
+ shared.win.get_application().state = shared.AppState.IMPORT
shared.win.get_application().lookup_action("import").set_enabled(False)
self.create_dialog()
@@ -224,6 +225,8 @@ class Importer(ErrorProducer):
self.summary_toast = self.create_summary_toast()
self.create_error_dialog()
shared.win.get_application().lookup_action("import").set_enabled(True)
+ shared.win.get_application().state = shared.AppState.DEFAULT
+ shared.win.create_source_rows()
def create_error_dialog(self):
"""Dialog containing all errors raised by importers"""
diff --git a/src/main.py b/src/main.py
index 4488473..c29ee4d 100644
--- a/src/main.py
+++ b/src/main.py
@@ -53,6 +53,7 @@ from src.window import CartridgesWindow
class CartridgesApplication(Adw.Application):
+ state = shared.AppState.DEFAULT
win = None
def __init__(self):
@@ -86,7 +87,10 @@ class CartridgesApplication(Adw.Application):
# Load games from disk
shared.store.add_manager(FileManager(), False)
shared.store.add_manager(DisplayManager())
+ self.state = shared.AppState.LOAD_FROM_DISK
self.load_games_from_disk()
+ self.state = shared.AppState.DEFAULT
+ self.win.create_source_rows()
# Add rest of the managers for game imports
shared.store.add_manager(LocalCoverManager())
@@ -141,6 +145,9 @@ class CartridgesApplication(Adw.Application):
game = Game(data)
shared.store.add_game(game, {"skip_save": True})
+ def get_source_name(self, source_id):
+ return globals()[f"{source_id.title()}Source"].name
+
def on_about_action(self, *_args):
# Get the debug info from the log files
debug_str = ""
diff --git a/src/shared.py.in b/src/shared.py.in
index 92fc574..81e31b1 100644
--- a/src/shared.py.in
+++ b/src/shared.py.in
@@ -18,10 +18,18 @@
# SPDX-License-Identifier: GPL-3.0-or-later
import os
+from enum import IntEnum, auto
from pathlib import Path
from gi.repository import Gdk, Gio, GLib
+
+class AppState(IntEnum):
+ DEFAULT = auto()
+ LOAD_FROM_DISK = auto()
+ IMPORT = auto()
+
+
APP_ID = "@APP_ID@"
VERSION = "@VERSION@"
PREFIX = "@PREFIX@"
diff --git a/src/store/managers/display_manager.py b/src/store/managers/display_manager.py
index bd66e92..1602d59 100644
--- a/src/store/managers/display_manager.py
+++ b/src/store/managers/display_manager.py
@@ -17,6 +17,7 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
+from src import shared
from src.game import Game
from src.game_cover import GameCover
from src.store.managers.manager import Manager
@@ -46,27 +47,30 @@ class DisplayManager(Manager):
"notify::visible", game.toggle_play, None
)
game.menu_button.get_popover().connect(
- "notify::visible", game.win.set_active_game, game
+ "notify::visible", shared.win.set_active_game, game
)
- if game.game_id in game.win.game_covers:
- game.game_cover = game.win.game_covers[game.game_id]
+ if game.game_id in shared.win.game_covers:
+ game.game_cover = shared.win.game_covers[game.game_id]
game.game_cover.add_picture(game.cover)
else:
game.game_cover = GameCover({game.cover}, game.get_cover_path())
- game.win.game_covers[game.game_id] = game.game_cover
+ shared.win.game_covers[game.game_id] = game.game_cover
if (
- game.win.navigation_view.get_visible_page() == game.win.details_page
- and game.win.active_game == game
+ shared.win.navigation_view.get_visible_page() == shared.win.details_page
+ and shared.win.active_game == game
):
- game.win.show_details_page(game)
+ shared.win.show_details_page(game)
if not game.removed and not game.blacklisted:
if game.hidden:
- game.win.hidden_library.append(game)
+ shared.win.hidden_library.append(game)
else:
- game.win.library.append(game)
+ shared.win.library.append(game)
game.get_parent().set_focusable(False)
- game.win.set_library_child()
+ shared.win.set_library_child()
+
+ if shared.win.get_application().state == shared.AppState.DEFAULT:
+ shared.win.create_source_rows()
diff --git a/src/window.py b/src/window.py
index 0ebbe72..19ecb5e 100644
--- a/src/window.py
+++ b/src/window.py
@@ -29,6 +29,9 @@ class CartridgesWindow(Adw.ApplicationWindow):
overlay_split_view = Gtk.Template.Child()
navigation_view = Gtk.Template.Child()
+ sidebar = Gtk.Template.Child()
+ all_games_row_box = Gtk.Template.Child()
+ added_row_box = Gtk.Template.Child()
toast_overlay = Gtk.Template.Child()
primary_menu_button = Gtk.Template.Child()
show_sidebar_button = Gtk.Template.Child()
@@ -73,6 +76,57 @@ class CartridgesWindow(Adw.ApplicationWindow):
active_game = None
details_view_game_cover = None
sort_state = "a-z"
+ filter_state = "all"
+ source_rows = {}
+
+ def create_source_rows(self):
+ self.sidebar.get_row_at_index(2).set_visible(False)
+
+ while row := self.sidebar.get_row_at_index(3):
+ self.sidebar.remove(row)
+
+ def get_removed(source_id):
+ for game in shared.store.source_games[source_id].values():
+ if game.removed:
+ return True
+ return False
+
+ for source_id in shared.store.source_games:
+ if source_id == "imported":
+ continue
+ if get_removed(source_id):
+ continue
+
+ row = Gtk.Label(
+ label=self.get_application().get_source_name(source_id),
+ halign=Gtk.Align.START,
+ margin_top=12,
+ margin_bottom=12,
+ margin_start=6,
+ margin_end=6,
+ )
+
+ self.sidebar.append(row)
+ self.source_rows[row.get_parent()] = source_id
+ self.sidebar.get_row_at_index(2).set_visible(True)
+
+ def row_selected(self, widget, row):
+ if not row:
+ widget.select_row(self.all_games_row_box.get_parent())
+ try:
+ value = self.source_rows[row]
+ except KeyError:
+ match row.get_child():
+ case self.all_games_row_box:
+ value = "all"
+ case self.added_row_box:
+ value = "imported"
+
+ self.filter_state = value
+ self.library.invalidate_filter()
+
+ if self.overlay_split_view.get_collapsed():
+ self.overlay_split_view.set_show_sidebar(False)
def __init__(self, **kwargs):
super().__init__(**kwargs)
@@ -90,7 +144,11 @@ class CartridgesWindow(Adw.ApplicationWindow):
self.notice_empty.set_icon_name(shared.APP_ID + "-symbolic")
- self.overlay_split_view.set_show_sidebar(shared.state_schema.get_boolean("show-sidebar"))
+ self.overlay_split_view.set_show_sidebar(
+ shared.state_schema.get_boolean("show-sidebar")
+ )
+
+ self.sidebar.select_row(self.all_games_row_box.get_parent())
if shared.PROFILE == "development":
self.add_css_class("devel")
@@ -109,6 +167,8 @@ class CartridgesWindow(Adw.ApplicationWindow):
self.navigation_view.connect("popped", self.set_show_hidden)
self.navigation_view.connect("pushed", self.set_show_hidden)
+ self.sidebar.connect("row-selected", self.row_selected)
+
style_manager = Adw.StyleManager.get_default()
style_manager.connect("notify::dark", self.set_details_view_opacity)
style_manager.connect("notify::high-contrast", self.set_details_view_opacity)
@@ -151,9 +211,6 @@ class CartridgesWindow(Adw.ApplicationWindow):
remove_from_overlay(self.hidden_notice_no_results)
def filter_func(self, child):
- if shared.state_schema.get_string("filter") != "all":
- pass
-
game = child.get_child()
text = (
(
@@ -170,6 +227,12 @@ class CartridgesWindow(Adw.ApplicationWindow):
or (text in game.developer.lower() if game.developer else False)
)
+ if not filtered:
+ if self.filter_state == "all":
+ pass
+ elif game.source != self.filter_state:
+ filtered = True
+
game.filtered = filtered
self.set_library_child()