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()