diff --git a/data/cartridges.gresource.xml.in b/data/cartridges.gresource.xml.in index 472f6fb..4704591 100644 --- a/data/cartridges.gresource.xml.in +++ b/data/cartridges.gresource.xml.in @@ -1,6 +1,7 @@ + @APP_ID@.metainfo.xml gtk/window.ui gtk/help-overlay.ui gtk/game.ui @@ -11,4 +12,14 @@ library_placeholder.svg library_placeholder_small.svg + + icons/sources/bottles-source-symbolic.svg + icons/sources/flatpak-source-symbolic.svg + icons/sources/heroic-source-symbolic.svg + icons/sources/itch-source-symbolic.svg + icons/sources/legendary-source-symbolic.svg + icons/sources/lutris-source-symbolic.svg + icons/sources/retroarch-source-symbolic.svg + icons/sources/steam-source-symbolic.svg + diff --git a/data/gtk/details-window.blp b/data/gtk/details-window.blp index 6efa0f0..2bef55d 100644 --- a/data/gtk/details-window.blp +++ b/data/gtk/details-window.blp @@ -2,159 +2,151 @@ using Gtk 4.0; using Adw 1; template $DetailsWindow : Adw.Window { - default-width: 480; // Same as Nautilus' properties window - default-height: -1; - modal: true; + default-width: 480; // Same as Nautilus' properties window + default-height: -1; + modal: true; - ShortcutController { - Shortcut { - trigger: "Escape"; - action: "action(window.close)"; - } - } - - Box { - orientation: vertical; - - Adw.HeaderBar HeaderBar { - show-start-title-buttons: false; - show-end-title-buttons: false; - - [start] - Button cancel_button { - label: _("Cancel"); - action-name: "window.close"; - } - - [end] - Button apply_button { - styles [ - "suggested-action", - ] - } + ShortcutController { + Shortcut { + trigger: "Escape"; + action: "action(window.close)"; + } } - Adw.PreferencesPage { - vexpand: true; + Adw.ToolbarView { - Adw.PreferencesGroup cover_group { - Adw.Clamp cover_clamp { - maximum-size: 200; + [top] + Adw.HeaderBar HeaderBar { + show-start-title-buttons: false; + show-end-title-buttons: false; - Overlay { - [overlay] - Spinner spinner { - margin-start: 72; - margin-end: 72; + [start] + Button cancel_button { + label: _("Cancel"); + action-name: "window.close"; } - Overlay cover_overlay { - halign: center; - valign: center; - - [overlay] - Button cover_button_edit { - icon-name: "document-edit-symbolic"; - tooltip-text: _("New Cover"); - halign: end; - valign: end; - margin-bottom: 6; - margin-end: 6; - + [end] + Button apply_button { styles [ - "circular", - "osd", + "suggested-action" ] - } + } + } - [overlay] - Revealer cover_button_delete_revealer { - transition-type: crossfade; - margin-end: 40; + Adw.PreferencesPage { + Adw.PreferencesGroup cover_group { + Adw.Clamp cover_clamp { + maximum-size: 200; + Overlay { + [overlay] + Spinner spinner { + margin-start: 72; + margin-end: 72; + } - Button cover_button_delete { - icon-name: "user-trash-symbolic"; - tooltip-text: _("Delete Cover"); - halign: end; - valign: end; - margin-bottom: 6; - margin-end: 6; + Overlay cover_overlay { + halign: center; + valign: center; - styles [ - "circular", - "osd", - ] + [overlay] + Button cover_button_edit { + icon-name: "document-edit-symbolic"; + tooltip-text: _("New Cover"); + halign: end; + valign: end; + margin-bottom: 6; + margin-end: 6; + + styles [ + "circular", "osd" + ] + } + + [overlay] + Revealer cover_button_delete_revealer { + transition-type: crossfade; + margin-end: 40; + + Button cover_button_delete { + icon-name: "user-trash-symbolic"; + tooltip-text: _("Delete Cover"); + halign: end; + valign: end; + margin-bottom: 6; + margin-end: 6; + + styles [ + "circular", "osd" + ] + } + } + + Picture cover { + width-request: 200; + height-request: 300; + + styles [ + "card" + ] + } + } + } } - } - - Picture cover { - width-request: 200; - height-request: 300; - - styles [ - "card", - ] - } - } - } - } - } - - Adw.PreferencesGroup { - Adw.EntryRow name { - title: _("Title"); - } - - Adw.EntryRow developer { - title: _("Developer (optional)"); - } - } - - Adw.PreferencesGroup { - Adw.EntryRow executable { - title: _("Executable"); - - [suffix] - Button file_chooser_button { - valign: center; - icon-name: "document-open-symbolic"; - tooltip-text: _("Select File"); - - styles [ - "flat", - ] - } - - [suffix] - MenuButton exec_info_button { - valign: center; - icon-name: "help-about-symbolic"; - tooltip-text: _("More Info"); - popover: - Popover exec_info_popover { - focusable: true; - - Label exec_info_label { - use-markup: true; - wrap: true; - max-width-chars: 50; - halign: center; - valign: center; - margin-top: 6; - margin-bottom: 6; - margin-start: 6; - margin-end: 6; - } } - ; + Adw.PreferencesGroup { + Adw.EntryRow name { + title: _("Title"); + } + Adw.EntryRow developer { + title: _("Developer (optional)"); + } + } + Adw.PreferencesGroup { + Adw.EntryRow executable { + title: _("Executable"); - styles [ - "flat", - ] - } + [suffix] + Button file_chooser_button { + valign: center; + icon-name: "document-open-symbolic"; + tooltip-text: _("Select File"); + + styles [ + "flat", + ] + } + + [suffix] + MenuButton exec_info_button { + valign: center; + icon-name: "help-about-symbolic"; + tooltip-text: _("More Info"); + + popover: Popover exec_info_popover { + focusable: true; + + Label exec_info_label { + use-markup: true; + wrap: true; + max-width-chars: 50; + halign: center; + valign: center; + margin-top: 6; + margin-bottom: 6; + margin-start: 6; + margin-end: 6; + } + }; + + styles [ + "flat" + ] + } + + } + } } - } } - } -} +} \ No newline at end of file diff --git a/data/gtk/preferences.blp b/data/gtk/preferences.blp index 9722cae..11b65fc 100644 --- a/data/gtk/preferences.blp +++ b/data/gtk/preferences.blp @@ -2,7 +2,6 @@ using Gtk 4.0; using Adw 1; template $PreferencesWindow : Adw.PreferencesWindow { - default-height: 500; Adw.PreferencesPage general_page { name: "general"; @@ -12,37 +11,22 @@ template $PreferencesWindow : Adw.PreferencesWindow { Adw.PreferencesGroup behavior_group { title: _("Behavior"); - Adw.ActionRow { + Adw.SwitchRow exit_after_launch_switch { title: _("Exit After Launching Games"); - activatable-widget: exit_after_launch_switch; - - Switch exit_after_launch_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow cover_launches_game_switch { title: _("Cover Image Launches Game"); subtitle: _("Swaps the behavior of the cover image and the play button"); - activatable-widget: cover_launches_game_switch; - - Switch cover_launches_game_switch { - valign: center; - } } } Adw.PreferencesGroup images_group { title: _("Images"); - Adw.ActionRow { + Adw.SwitchRow high_quality_images_switch { title: _("High Quality Images"); subtitle: _("Save game covers losslessly at the cost of storage"); - activatable-widget: high_quality_images_switch; - - Switch high_quality_images_switch { - valign: center; - } } } @@ -87,13 +71,8 @@ template $PreferencesWindow : Adw.PreferencesWindow { Adw.PreferencesGroup import_behavior_group { title: _("Behavior"); - Adw.ActionRow { + Adw.SwitchRow remove_missing_switch { title: _("Remove Uninstalled Games"); - activatable-widget: remove_missing_switch; - - Switch remove_missing_switch { - valign: center; - } } } @@ -145,22 +124,12 @@ template $PreferencesWindow : Adw.PreferencesWindow { } } - Adw.ActionRow { + Adw.SwitchRow lutris_import_steam_switch { title: _("Import Steam Games"); - activatable-widget: lutris_import_steam_switch; - - Switch lutris_import_steam_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow lutris_import_flatpak_switch { title: _("Import Flatpak Games"); - activatable-widget: lutris_import_flatpak_switch; - - Switch lutris_import_flatpak_switch { - valign: center; - } } } @@ -180,40 +149,20 @@ template $PreferencesWindow : Adw.PreferencesWindow { } } - Adw.ActionRow { + Adw.SwitchRow heroic_import_epic_switch { title: _("Import Epic Games"); - activatable-widget: heroic_import_epic_switch; - - Switch heroic_import_epic_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow heroic_import_gog_switch { title: _("Import GOG Games"); - activatable-widget: heroic_import_gog_switch; - - Switch heroic_import_gog_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow heroic_import_amazon_switch { title: _("Import Amazon Games"); - activatable-widget: heroic_import_amazon_switch; - - Switch heroic_import_amazon_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow heroic_import_sideload_switch { title: _("Import Sideloaded Games"); - activatable-widget: heroic_import_sideload_switch; - - Switch heroic_import_sideload_switch { - valign: center; - } } } @@ -301,23 +250,13 @@ template $PreferencesWindow : Adw.PreferencesWindow { } } - Adw.ActionRow flatpak_import_launchers_row { + Adw.SwitchRow flatpak_import_launchers_switch { title: _("Import Game Launchers"); - activatable-widget: flatpak_import_launchers_switch; - - Switch flatpak_import_launchers_switch { - valign: center; - } } } - Adw.ActionRow { + Adw.SwitchRow desktop_switch { title: _("Desktop Entries"); - activatable-widget: desktop_switch; - - Switch desktop_switch { - valign: center; - } } } } @@ -338,32 +277,17 @@ template $PreferencesWindow : Adw.PreferencesWindow { Adw.PreferencesGroup sgdb_behavior_group { title: _("Behavior"); - Adw.ActionRow sgdb_switch_row { + Adw.SwitchRow sgdb_switch { title: _("Use SteamGridDB"); subtitle: _("Download images when adding or importing games"); - activatable-widget: sgdb_switch; - - Switch sgdb_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow sgdb_prefer_switch { title: _("Prefer Over Official Images"); - activatable-widget: sgdb_prefer_switch; - - Switch sgdb_prefer_switch { - valign: center; - } } - Adw.ActionRow { + Adw.SwitchRow sgdb_animated_switch { title: _("Prefer Animated Images"); - activatable-widget: sgdb_animated_switch; - - Switch sgdb_animated_switch { - valign: center; - } } } } diff --git a/data/gtk/window.blp b/data/gtk/window.blp index c68e1ee..3d00340 100644 --- a/data/gtk/window.blp +++ b/data/gtk/window.blp @@ -45,339 +45,422 @@ Adw.StatusPage hidden_notice_empty { template $CartridgesWindow : Adw.ApplicationWindow { title: _("Cartridges"); + width-request: 281; + height-request: 100; + + Adw.Breakpoint { + condition ("max-width: 564px") + setters { + overlay_split_view.collapsed: true; + details_view_box.orientation: vertical; + details_view_box.margin-top: 12; + details_view_box.margin-start: 12; + details_view_box.margin-end: 12; + details_view_details_box.margin-start: 0; + details_view_details_box.margin-end: 0; + details_view_title.margin-top: 30; + details_view_title.halign: center; + details_view_developer.halign: center; + details_view_date_box.halign: center; + details_view_toolbar.halign: center; + details_view_toolbar.orientation: vertical; + details_view_play_button.halign: center; + details_view_toolbar_buttons.margin-start: 0; + } + } Adw.ToastOverlay toast_overlay { - Stack stack { - visible-child: library_view; - transition-type: over_left; + Adw.NavigationView navigation_view { + Adw.NavigationPage library_page { + title: _("All Games"); - Overlay details_view { - name: "details_view"; - - [overlay] - Box details_view_box { - orientation: vertical; - - Adw.HeaderBar { - [start] - Button back_button { - tooltip-text: _("Back"); - action-name: "win.go_back"; - icon-name: "go-previous-symbolic"; - } - - [title] - Adw.WindowTitle details_view_header_bar_title { - title: _("Game Details"); - } - - styles [ - "flat", - ] - } - - Adw.Bin { - hexpand: true; - vexpand: true; - - Box { - halign: center; - valign: center; - margin-start: 24; - margin-end: 24; - margin-top: 24; - margin-bottom: 24; - - Adw.Clamp { - maximum-size: 200; - - Overlay { - [overlay] - Spinner details_view_spinner { - margin-start: 72; - margin-end: 72; + Adw.OverlaySplitView overlay_split_view { + [sidebar] + Adw.NavigationPage { + title: _("Cartridges"); + Adw.ToolbarView { + [top] + Adw.HeaderBar { + [start] + Button { + icon-name: "sidebar-show-symbolic"; + action-name: "win.show_sidebar"; + tooltip-text: _("Toggle Sidebar"); } + } - Picture details_view_cover { - halign: end; + 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-symbolic"; + } + Label { + halign: start; + label: _("All Games"); + } + Label all_games_no_label { + hexpand: true; + halign: end; + + styles ["dim-label"] + } + } + Box added_row_box { + margin-top: 12; + margin-bottom: 12; + margin-start: 6; + spacing: 12; + + Image { + icon-name: "list-add-symbolic"; + } + Label { + halign: start; + label: _("Added"); + margin-end: 6; + } + Label added_games_no_label { + hexpand: true; + halign: end; + margin-end: 6; + + styles ["dim-label"] + } + } + ListBoxRow { + selectable: false; + activatable: false; + Label { + label: _("Imported"); + styles ["heading"] + halign: start; + } + } + styles ["navigation-sidebar"] + } + } + } + + Adw.ToolbarView library_view { + + [top] + Adw.HeaderBar header_bar { + + [start] + Revealer { + transition-type: slide_right; + reveal-child: bind overlay_split_view.show-sidebar inverted; + Button show_sidebar_button { + icon-name: "sidebar-show-symbolic"; + action-name: "win.show_sidebar"; + tooltip-text: _("Toggle Sidebar"); + } + } + + [start] + MenuButton { + tooltip-text: _("Add Game"); + icon-name: "list-add-symbolic"; + menu-model: add_games; + } + + [end] + MenuButton primary_menu_button { + tooltip-text: _("Main Menu"); + icon-name: "open-menu-symbolic"; + menu-model: primary_menu; + } + + [end] + ToggleButton search_button { + tooltip-text: _("Search"); + icon-name: "system-search-symbolic"; + action-name: "win.toggle_search"; + } + } + + [top] + SearchBar search_bar { + search-mode-enabled: bind search_button.active bidirectional; + key-capture-widget: navigation_view; + + Adw.Clamp { + maximum-size: 500; + tightening-threshold: 500; + + SearchEntry search_entry { + hexpand: true; + } + } + } + + Overlay library_overlay { + ScrolledWindow scrolledwindow { + FlowBox library { + homogeneous: true; + halign: center; valign: start; - width-request: 200; - height-request: 300; - - styles [ - "card", - ] + column-spacing: 12; + row-spacing: 12; + margin-top: 15; + margin-bottom: 15; + margin-start: 15; + margin-end: 15; + selection-mode: none; } } } + } + } + } + } + } + } - Box { - orientation: vertical; - margin-start: 48; - vexpand: true; +Adw.NavigationPage hidden_library_page { + title: _("Hidden Games"); + + Adw.ToolbarView hidden_library_view { + [top] + Adw.HeaderBar hidden_header_bar { + [end] + MenuButton hidden_primary_menu_button { + tooltip-text: _("Main Menu"); + icon-name: "open-menu-symbolic"; + menu-model: primary_menu; + } + + [end] + ToggleButton hidden_search_button { + tooltip-text: _("Search"); + icon-name: "system-search-symbolic"; + action-name: "win.toggle_search"; + } + } + + [top] + SearchBar hidden_search_bar { + search-mode-enabled: bind hidden_search_button.active bidirectional; + key-capture-widget: hidden_library_view; + + Adw.Clamp { + maximum-size: 500; + tightening-threshold: 500; + + SearchEntry hidden_search_entry { + hexpand: true; + } + } + } + + Overlay hidden_library_overlay { + ScrolledWindow hidden_scrolledwindow { + FlowBox hidden_library { + homogeneous: true; + halign: center; + valign: start; + column-spacing: 12; + row-spacing: 12; + margin-top: 15; + margin-bottom: 15; + margin-start: 15; + margin-end: 15; + selection-mode: none; + } + } + } + + styles [ + "background", + ] + } +} + +Adw.NavigationPage details_page { + title: _("Game Details"); + + Overlay details_view { + name: "details_view"; + + [overlay] + Adw.ToolbarView details_view_toolbar_view { + + [top] + Adw.HeaderBar { + } + + ScrolledWindow { + Box details_view_box { + halign: center; + valign: center; + margin-start: 24; + margin-end: 24; + margin-top: 24; + margin-bottom: 24; + + Adw.Clamp { + maximum-size: 200; + + Overlay { + [overlay] + Spinner details_view_spinner { + margin-start: 72; + margin-end: 72; + } + + Picture details_view_cover { + halign: end; + valign: start; + width-request: 200; + height-request: 300; + + styles [ + "card", + ] + } + } + } + + Box details_view_details_box { + orientation: vertical; + margin-start: 48; + vexpand: true; + valign: center; + + Label details_view_title { + label: _("Game Title"); + hexpand: true; + halign: start; + max-width-chars: 24; + wrap: true; + wrap-mode: word_char; + natural-wrap-mode: word; + + styles [ + "title-1", + ] + } + + Label details_view_developer { + margin-top: 6; + hexpand: true; + halign: start; + max-width-chars: 36; + wrap: true; + wrap-mode: word_char; + natural-wrap-mode: word; + + styles [ + "heading", + ] + } + + Box details_view_date_box { + orientation: horizontal; + margin-top: 15; + hexpand: true; + halign: start; + + Label details_view_added { + wrap: true; + wrap-mode: word_char; + natural-wrap-mode: word; + justify: center; + } + + Label details_view_last_played { + margin-start: 12; + wrap: true; + wrap-mode: word_char; + natural-wrap-mode: word; + justify: center; + } + } + + Box details_view_toolbar { + hexpand: true; + vexpand: true; + valign: center; + + Button details_view_play_button { + name: "details_view_play_button"; + action-name: "app.launch_game"; + label: _("Play"); + halign: start; + margin-top: 24; + + styles [ + "opaque", + "pill", + ] + } + + Box details_view_toolbar_buttons { + halign: start; valign: center; + margin-top: 24; + margin-start: 9; - Label details_view_title { - label: _("Game Title"); - hexpand: true; - halign: start; - max-width-chars: 24; - wrap: true; - wrap-mode: word_char; - natural-wrap-mode: word; + Button { + icon-name: "document-edit-symbolic"; + action-name: "app.edit_game"; + tooltip-text: _("Edit"); styles [ - "title-1", + "raised", + "circular", ] } - Label details_view_developer { - margin-top: 6; - hexpand: true; - halign: start; - max-width-chars: 36; - wrap: true; - wrap-mode: word_char; - natural-wrap-mode: word; + Button details_view_hide_button { + action-name: "app.hide_game"; styles [ - "heading", + "raised", + "circular", ] } - Box { - orientation: horizontal; - margin-top: 15; - hexpand: true; - halign: start; + Button { + icon-name: "user-trash-symbolic"; + action-name: "app.remove_game"; + tooltip-text: _("Remove"); - Label details_view_added { - wrap: true; - wrap-mode: word_char; - natural-wrap-mode: word; - } - - Label details_view_last_played { - margin-start: 12; - wrap: true; - wrap-mode: word_char; - natural-wrap-mode: word; - } + styles [ + "raised", + "circular", + ] } - Box { - hexpand: true; - vexpand: true; - valign: center; + MenuButton { + icon-name: "system-search-symbolic"; + menu-model: search; + tooltip-text: _("Search"); - Button details_view_play_button { - name: "details_view_play_button"; - action-name: "app.launch_game"; - label: _("Play"); - halign: start; - margin-top: 24; - - styles [ - "opaque", - "pill", - ] - } - - Box { - halign: start; - valign: center; - margin-top: 24; - margin-start: 9; - - Button { - icon-name: "document-edit-symbolic"; - action-name: "app.edit_game"; - tooltip-text: _("Edit"); - - styles [ - "raised", - "circular", - ] - } - - Button details_view_hide_button { - action-name: "app.hide_game"; - - styles [ - "raised", - "circular", - ] - } - - Button { - icon-name: "user-trash-symbolic"; - action-name: "app.remove_game"; - tooltip-text: _("Remove"); - - styles [ - "raised", - "circular", - ] - } - - MenuButton { - icon-name: "system-search-symbolic"; - menu-model: search; - tooltip-text: _("Search"); - - styles [ - "raised", - "circular", - ] - } - - styles [ - "toolbar", - ] - } + styles [ + "raised", + "circular", + ] } + + styles [ + "toolbar", + ] } } } } - - Picture details_view_blurred_cover { - keep-aspect-ratio: false; - } } + } - Box library_view { - orientation: vertical; - - Adw.HeaderBar header_bar { - [start] - MenuButton { - tooltip-text: _("Add Game"); - icon-name: "list-add-symbolic"; - menu-model: add_games; - } - - [end] - MenuButton primary_menu_button { - tooltip-text: _("Main Menu"); - icon-name: "open-menu-symbolic"; - menu-model: primary_menu; - } - - [end] - ToggleButton search_button { - tooltip-text: _("Search"); - icon-name: "system-search-symbolic"; - action-name: "win.toggle_search"; - } - } - - SearchBar search_bar { - search-mode-enabled: bind-property search_button.active bidirectional; - key-capture-widget: library_view; - - Adw.Clamp { - maximum-size: 500; - tightening-threshold: 500; - - SearchEntry search_entry { - placeholder-text: _("Search games"); - hexpand: true; - } - } - } - - Adw.Bin library_bin { - ScrolledWindow scrolledwindow { - hexpand: true; - vexpand: true; - - FlowBox library { - homogeneous: true; - halign: center; - valign: start; - column-spacing: 12; - row-spacing: 12; - margin-top: 15; - margin-bottom: 15; - margin-start: 15; - margin-end: 15; - selection-mode: none; - } - } - } - } - - Box hidden_library_view { - orientation: vertical; - - Adw.HeaderBar hidden_header_bar { - [start] - Button hidden_back_button { - tooltip-text: _("Back"); - action-name: "win.go_back"; - icon-name: "go-previous-symbolic"; - } - - [title] - Adw.WindowTitle { - title: _("Hidden Games"); - } - - [end] - MenuButton hidden_primary_menu_button { - tooltip-text: _("Main Menu"); - icon-name: "open-menu-symbolic"; - menu-model: primary_menu; - } - - [end] - ToggleButton hidden_search_button { - tooltip-text: _("Search"); - icon-name: "system-search-symbolic"; - action-name: "win.toggle_search"; - } - } - - SearchBar hidden_search_bar { - search-mode-enabled: bind-property hidden_search_button.active bidirectional; - key-capture-widget: hidden_library_view; - - Adw.Clamp { - maximum-size: 500; - tightening-threshold: 500; - - SearchEntry hidden_search_entry { - placeholder-text: _("Search hidden games"); - hexpand: true; - } - } - } - - Adw.Bin hidden_library_bin { - ScrolledWindow hidden_scrolledwindow { - hexpand: true; - vexpand: true; - - FlowBox hidden_library { - homogeneous: true; - halign: center; - valign: start; - column-spacing: 12; - row-spacing: 12; - margin-top: 15; - margin-bottom: 15; - margin-start: 15; - margin-end: 15; - selection-mode: none; - } - } - } - - styles [ - "background", - ] - } + Picture details_view_blurred_cover { + keep-aspect-ratio: false; } } } diff --git a/data/hu.kramo.Cartridges.gschema.xml.in b/data/hu.kramo.Cartridges.gschema.xml.in index 4e1f3e2..8480e57 100644 --- a/data/hu.kramo.Cartridges.gschema.xml.in +++ b/data/hu.kramo.Cartridges.gschema.xml.in @@ -108,10 +108,10 @@ - 1110 + 1170 - 820 + 795 false @@ -126,6 +126,9 @@ "a-z" + + false + "[]" diff --git a/data/hu.kramo.Cartridges.metainfo.xml.in b/data/hu.kramo.Cartridges.metainfo.xml.in index 8f73e56..f6823a4 100644 --- a/data/hu.kramo.Cartridges.metainfo.xml.in +++ b/data/hu.kramo.Cartridges.metainfo.xml.in @@ -22,7 +22,7 @@ touch - 545 + 280 diff --git a/data/icons/sources/bottles-source-symbolic.svg b/data/icons/sources/bottles-source-symbolic.svg new file mode 100644 index 0000000..fc654c5 --- /dev/null +++ b/data/icons/sources/bottles-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/flatpak-source-symbolic.svg b/data/icons/sources/flatpak-source-symbolic.svg new file mode 100644 index 0000000..87800a3 --- /dev/null +++ b/data/icons/sources/flatpak-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/heroic-source-symbolic.svg b/data/icons/sources/heroic-source-symbolic.svg new file mode 100644 index 0000000..63975d1 --- /dev/null +++ b/data/icons/sources/heroic-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/itch-source-symbolic.svg b/data/icons/sources/itch-source-symbolic.svg new file mode 100644 index 0000000..ff343b3 --- /dev/null +++ b/data/icons/sources/itch-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/legendary-source-symbolic.svg b/data/icons/sources/legendary-source-symbolic.svg new file mode 100644 index 0000000..3dcacfb --- /dev/null +++ b/data/icons/sources/legendary-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/lutris-source-symbolic.svg b/data/icons/sources/lutris-source-symbolic.svg new file mode 100644 index 0000000..a9166c2 --- /dev/null +++ b/data/icons/sources/lutris-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/retroarch-source-symbolic.svg b/data/icons/sources/retroarch-source-symbolic.svg new file mode 100644 index 0000000..0bceb2a --- /dev/null +++ b/data/icons/sources/retroarch-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/data/icons/sources/steam-source-symbolic.svg b/data/icons/sources/steam-source-symbolic.svg new file mode 100644 index 0000000..f66d4cb --- /dev/null +++ b/data/icons/sources/steam-source-symbolic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/flatpak/hu.kramo.Cartridges.Devel.json b/flatpak/hu.kramo.Cartridges.Devel.json index effe704..78737df 100644 --- a/flatpak/hu.kramo.Cartridges.Devel.json +++ b/flatpak/hu.kramo.Cartridges.Devel.json @@ -1,7 +1,7 @@ { "id" : "hu.kramo.Cartridges.Devel", "runtime" : "org.gnome.Platform", - "runtime-version" : "44", + "runtime-version" : "45", "sdk" : "org.gnome.Sdk", "command" : "cartridges", "finish-args" : [ diff --git a/po/cartridges.pot b/po/cartridges.pot index a0c0fb4..92d9987 100644 --- a/po/cartridges.pot +++ b/po/cartridges.pot @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR kramo -# This file is distributed under the same license as the Cartridges~ package. +# This file is distributed under the same license as the Cartridges package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: Cartridges~\n" +"Project-Id-Version: Cartridges\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-08-30 10:28+0200\n" +"POT-Creation-Date: 2023-08-30 10:43+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -19,7 +19,7 @@ msgstr "" #: data/hu.kramo.Cartridges.desktop.in:3 #: data/hu.kramo.Cartridges.metainfo.xml.in:6 data/gtk/window.blp:47 -#: src/main.py:176 +#: data/gtk/window.blp:80 msgid "Cartridges" msgstr "" @@ -53,14 +53,14 @@ msgstr "" msgid "Edit Game Details" msgstr "" -#: data/hu.kramo.Cartridges.metainfo.xml.in:38 data/gtk/window.blp:71 +#: data/hu.kramo.Cartridges.metainfo.xml.in:38 data/gtk/window.blp:286 #: src/details_window.py:71 msgid "Game Details" msgstr "" -#: data/hu.kramo.Cartridges.metainfo.xml.in:42 data/gtk/window.blp:430 -#: src/details_window.py:265 src/importer/importer.py:304 -#: src/importer/importer.py:355 +#: data/hu.kramo.Cartridges.metainfo.xml.in:42 data/gtk/window.blp:513 +#: src/details_window.py:271 src/importer/importer.py:308 +#: src/importer/importer.py:359 msgid "Preferences" msgstr "" @@ -68,52 +68,52 @@ msgstr "" msgid "Cancel" msgstr "" -#: data/gtk/details-window.blp:58 +#: data/gtk/details-window.blp:55 msgid "New Cover" msgstr "" -#: data/gtk/details-window.blp:77 +#: data/gtk/details-window.blp:73 msgid "Delete Cover" msgstr "" -#: data/gtk/details-window.blp:105 data/gtk/game.blp:80 +#: data/gtk/details-window.blp:100 data/gtk/game.blp:80 msgid "Title" msgstr "" -#: data/gtk/details-window.blp:109 +#: data/gtk/details-window.blp:103 msgid "Developer (optional)" msgstr "" -#: data/gtk/details-window.blp:115 +#: data/gtk/details-window.blp:108 msgid "Executable" msgstr "" -#: data/gtk/details-window.blp:121 +#: data/gtk/details-window.blp:114 msgid "Select File" msgstr "" -#: data/gtk/details-window.blp:132 +#: data/gtk/details-window.blp:125 msgid "More Info" msgstr "" -#: data/gtk/game.blp:102 data/gtk/game.blp:121 data/gtk/window.blp:195 +#: data/gtk/game.blp:102 data/gtk/game.blp:121 data/gtk/window.blp:413 msgid "Edit" msgstr "" -#: data/gtk/game.blp:107 src/window.py:190 +#: data/gtk/game.blp:107 src/window.py:348 msgid "Hide" msgstr "" -#: data/gtk/game.blp:112 data/gtk/game.blp:131 data/gtk/preferences.blp:56 -#: data/gtk/window.blp:215 +#: data/gtk/game.blp:112 data/gtk/game.blp:131 data/gtk/preferences.blp:40 +#: data/gtk/window.blp:433 msgid "Remove" msgstr "" -#: data/gtk/game.blp:126 src/window.py:192 +#: data/gtk/game.blp:126 src/window.py:350 msgid "Unhide" msgstr "" -#: data/gtk/help-overlay.blp:11 data/gtk/preferences.blp:9 +#: data/gtk/help-overlay.blp:11 data/gtk/preferences.blp:8 msgid "General" msgstr "" @@ -121,8 +121,8 @@ msgstr "" msgid "Quit" msgstr "" -#: data/gtk/help-overlay.blp:19 data/gtk/window.blp:226 data/gtk/window.blp:269 -#: data/gtk/window.blp:336 +#: data/gtk/help-overlay.blp:19 data/gtk/window.blp:182 data/gtk/window.blp:241 +#: data/gtk/window.blp:444 msgid "Search" msgstr "" @@ -134,8 +134,8 @@ msgstr "" msgid "Shortcuts" msgstr "" -#: data/gtk/help-overlay.blp:34 src/game.py:105 src/preferences.py:124 -#: src/importer/importer.py:379 +#: data/gtk/help-overlay.blp:34 src/game.py:105 src/preferences.py:122 +#: src/importer/importer.py:383 msgid "Undo" msgstr "" @@ -163,155 +163,155 @@ msgstr "" msgid "Remove game" msgstr "" -#: data/gtk/preferences.blp:13 data/gtk/preferences.blp:88 -#: data/gtk/preferences.blp:339 +#: data/gtk/preferences.blp:12 data/gtk/preferences.blp:72 +#: data/gtk/preferences.blp:288 msgid "Behavior" msgstr "" -#: data/gtk/preferences.blp:16 +#: data/gtk/preferences.blp:15 msgid "Exit After Launching Games" msgstr "" -#: data/gtk/preferences.blp:25 +#: data/gtk/preferences.blp:19 msgid "Cover Image Launches Game" msgstr "" -#: data/gtk/preferences.blp:26 +#: data/gtk/preferences.blp:20 msgid "Swaps the behavior of the cover image and the play button" msgstr "" -#: data/gtk/preferences.blp:36 src/details_window.py:85 +#: data/gtk/preferences.blp:25 src/details_window.py:85 msgid "Images" msgstr "" -#: data/gtk/preferences.blp:39 +#: data/gtk/preferences.blp:28 msgid "High Quality Images" msgstr "" -#: data/gtk/preferences.blp:40 +#: data/gtk/preferences.blp:29 msgid "Save game covers losslessly at the cost of storage" msgstr "" -#: data/gtk/preferences.blp:50 +#: data/gtk/preferences.blp:34 msgid "Danger Zone" msgstr "" -#: data/gtk/preferences.blp:53 +#: data/gtk/preferences.blp:37 msgid "Remove All Games" msgstr "" -#: data/gtk/preferences.blp:84 data/gtk/window.blp:27 data/gtk/window.blp:456 +#: data/gtk/preferences.blp:68 data/gtk/window.blp:27 data/gtk/window.blp:539 msgid "Import" msgstr "" -#: data/gtk/preferences.blp:91 +#: data/gtk/preferences.blp:75 msgid "Remove Uninstalled Games" msgstr "" -#: data/gtk/preferences.blp:101 +#: data/gtk/preferences.blp:80 msgid "Sources" msgstr "" -#: data/gtk/preferences.blp:104 src/importer/sources/steam_source.py:114 +#: data/gtk/preferences.blp:83 src/importer/sources/steam_source.py:114 msgid "Steam" msgstr "" -#: data/gtk/preferences.blp:108 data/gtk/preferences.blp:125 -#: data/gtk/preferences.blp:172 data/gtk/preferences.blp:225 -#: data/gtk/preferences.blp:242 data/gtk/preferences.blp:259 -#: data/gtk/preferences.blp:276 data/gtk/preferences.blp:293 +#: data/gtk/preferences.blp:87 data/gtk/preferences.blp:104 +#: data/gtk/preferences.blp:141 data/gtk/preferences.blp:174 +#: data/gtk/preferences.blp:191 data/gtk/preferences.blp:208 +#: data/gtk/preferences.blp:225 data/gtk/preferences.blp:242 msgid "Install Location" msgstr "" -#: data/gtk/preferences.blp:121 src/importer/sources/lutris_source.py:92 +#: data/gtk/preferences.blp:100 src/importer/sources/lutris_source.py:92 msgid "Lutris" msgstr "" -#: data/gtk/preferences.blp:137 +#: data/gtk/preferences.blp:116 msgid "Cache Location" msgstr "" -#: data/gtk/preferences.blp:149 +#: data/gtk/preferences.blp:128 msgid "Import Steam Games" msgstr "" -#: data/gtk/preferences.blp:158 +#: data/gtk/preferences.blp:132 msgid "Import Flatpak Games" msgstr "" -#: data/gtk/preferences.blp:168 src/importer/sources/heroic_source.py:355 +#: data/gtk/preferences.blp:137 src/importer/sources/heroic_source.py:355 msgid "Heroic" msgstr "" -#: data/gtk/preferences.blp:184 +#: data/gtk/preferences.blp:153 msgid "Import Epic Games" msgstr "" -#: data/gtk/preferences.blp:193 +#: data/gtk/preferences.blp:157 msgid "Import GOG Games" msgstr "" -#: data/gtk/preferences.blp:202 +#: data/gtk/preferences.blp:161 msgid "Import Amazon Games" msgstr "" -#: data/gtk/preferences.blp:211 +#: data/gtk/preferences.blp:165 msgid "Import Sideloaded Games" msgstr "" -#: data/gtk/preferences.blp:221 src/importer/sources/bottles_source.py:86 +#: data/gtk/preferences.blp:170 src/importer/sources/bottles_source.py:86 msgid "Bottles" msgstr "" -#: data/gtk/preferences.blp:238 src/importer/sources/itch_source.py:81 +#: data/gtk/preferences.blp:187 src/importer/sources/itch_source.py:81 msgid "itch" msgstr "" -#: data/gtk/preferences.blp:255 src/importer/sources/legendary_source.py:97 +#: data/gtk/preferences.blp:204 src/importer/sources/legendary_source.py:97 msgid "Legendary" msgstr "" -#: data/gtk/preferences.blp:272 src/importer/sources/retroarch_source.py:142 +#: data/gtk/preferences.blp:221 src/importer/sources/retroarch_source.py:142 msgid "RetroArch" msgstr "" -#: data/gtk/preferences.blp:289 src/importer/sources/flatpak_source.py:118 +#: data/gtk/preferences.blp:238 src/importer/sources/flatpak_source.py:118 msgid "Flatpak" msgstr "" -#: data/gtk/preferences.blp:305 +#: data/gtk/preferences.blp:254 msgid "Import Game Launchers" msgstr "" -#: data/gtk/preferences.blp:315 src/importer/sources/desktop_source.py:196 +#: data/gtk/preferences.blp:264 src/importer/sources/desktop_source.py:196 msgid "Desktop Entries" msgstr "" -#: data/gtk/preferences.blp:327 +#: data/gtk/preferences.blp:276 msgid "SteamGridDB" msgstr "" -#: data/gtk/preferences.blp:331 +#: data/gtk/preferences.blp:280 msgid "Authentication" msgstr "" -#: data/gtk/preferences.blp:334 +#: data/gtk/preferences.blp:283 msgid "API Key" msgstr "" -#: data/gtk/preferences.blp:342 +#: data/gtk/preferences.blp:291 msgid "Use SteamGridDB" msgstr "" -#: data/gtk/preferences.blp:343 +#: data/gtk/preferences.blp:292 msgid "Download images when adding or importing games" msgstr "" -#: data/gtk/preferences.blp:352 +#: data/gtk/preferences.blp:296 msgid "Prefer Over Official Images" msgstr "" -#: data/gtk/preferences.blp:361 +#: data/gtk/preferences.blp:300 msgid "Prefer Animated Images" msgstr "" @@ -339,90 +339,94 @@ msgstr "" msgid "Games you hide will appear here." msgstr "" -#: data/gtk/window.blp:64 data/gtk/window.blp:317 -msgid "Back" +#: data/gtk/window.blp:75 data/gtk/window.blp:105 src/main.py:166 +msgid "All Games" msgstr "" -#: data/gtk/window.blp:121 -msgid "Game Title" +#: data/gtk/window.blp:88 data/gtk/window.blp:162 +msgid "Toggle Sidebar" msgstr "" -#: data/gtk/window.blp:176 -msgid "Play" +#: data/gtk/window.blp:125 src/main.py:168 +msgid "Added" msgstr "" -#: data/gtk/window.blp:255 data/gtk/window.blp:449 +#: data/gtk/window.blp:140 +msgid "Imported" +msgstr "" + +#: data/gtk/window.blp:168 data/gtk/window.blp:532 msgid "Add Game" msgstr "" -#: data/gtk/window.blp:262 data/gtk/window.blp:329 +#: data/gtk/window.blp:175 data/gtk/window.blp:234 msgid "Main Menu" msgstr "" -#: data/gtk/window.blp:284 -msgid "Search games" -msgstr "" - -#: data/gtk/window.blp:324 +#: data/gtk/window.blp:227 msgid "Hidden Games" msgstr "" -#: data/gtk/window.blp:351 -msgid "Search hidden games" +#: data/gtk/window.blp:337 +msgid "Game Title" msgstr "" -#: data/gtk/window.blp:388 +#: data/gtk/window.blp:394 +msgid "Play" +msgstr "" + +#: data/gtk/window.blp:471 msgid "Sort" msgstr "" -#: data/gtk/window.blp:391 +#: data/gtk/window.blp:474 msgid "A-Z" msgstr "" -#: data/gtk/window.blp:397 +#: data/gtk/window.blp:480 msgid "Z-A" msgstr "" -#: data/gtk/window.blp:403 +#: data/gtk/window.blp:486 msgid "Newest" msgstr "" -#: data/gtk/window.blp:409 +#: data/gtk/window.blp:492 msgid "Oldest" msgstr "" -#: data/gtk/window.blp:415 +#: data/gtk/window.blp:498 msgid "Last Played" msgstr "" -#: data/gtk/window.blp:422 +#: data/gtk/window.blp:505 msgid "Show Hidden" msgstr "" -#: data/gtk/window.blp:435 +#: data/gtk/window.blp:518 msgid "Keyboard Shortcuts" msgstr "" -#: data/gtk/window.blp:440 +#: data/gtk/window.blp:523 msgid "About Cartridges" msgstr "" #. Translators: Replace this with your name for it to show up in the about window -#: src/main.py:195 +#: src/main.py:207 msgid "translator_credits" msgstr "" #. The variable is the date when the game was added -#: src/window.py:213 +#: src/window.py:371 msgid "Added: {}" msgstr "" -#: src/window.py:216 +#: src/window.py:374 msgid "Never" msgstr "" #. The variable is the date when the game was last played -#: src/window.py:220 +#: src/window.py:378 msgid "Last played: {}" msgstr "" @@ -479,15 +483,15 @@ msgstr "" msgid "Couldn't Add Game" msgstr "" -#: src/details_window.py:171 src/details_window.py:207 +#: src/details_window.py:171 src/details_window.py:213 msgid "Game title cannot be empty." msgstr "" -#: src/details_window.py:177 src/details_window.py:215 +#: src/details_window.py:177 src/details_window.py:221 msgid "Executable cannot be empty." msgstr "" -#: src/details_window.py:206 src/details_window.py:214 +#: src/details_window.py:212 src/details_window.py:220 msgid "Couldn't Apply Preferences" msgstr "" @@ -507,66 +511,66 @@ msgstr "" #. The variable is the title of the game #. The variable is the number of games removed -#: src/game.py:172 src/importer/importer.py:376 +#: src/game.py:169 src/importer/importer.py:380 msgid "{} removed" msgstr "" -#: src/preferences.py:123 +#: src/preferences.py:121 msgid "All games removed" msgstr "" -#: src/preferences.py:172 +#: src/preferences.py:169 msgid "" "An API key is required to use SteamGridDB. You can generate one {}here{}." msgstr "" -#: src/preferences.py:293 +#: src/preferences.py:296 msgid "Installation Not Found" msgstr "" -#: src/preferences.py:294 +#: src/preferences.py:297 msgid "Select a valid directory." msgstr "" -#: src/preferences.py:330 src/importer/importer.py:302 +#: src/preferences.py:333 src/importer/importer.py:306 msgid "Warning" msgstr "" -#: src/preferences.py:364 +#: src/preferences.py:367 msgid "Invalid Directory" msgstr "" -#: src/preferences.py:370 +#: src/preferences.py:373 msgid "Set Location" msgstr "" -#: src/utils/create_dialog.py:33 src/importer/importer.py:303 +#: src/utils/create_dialog.py:33 src/importer/importer.py:307 msgid "Dismiss" msgstr "" -#: src/importer/importer.py:140 +#: src/importer/importer.py:142 msgid "Importing Games…" msgstr "" -#: src/importer/importer.py:323 +#: src/importer/importer.py:327 msgid "The following errors occured during import:" msgstr "" -#: src/importer/importer.py:352 +#: src/importer/importer.py:356 msgid "No new games found" msgstr "" -#: src/importer/importer.py:364 +#: src/importer/importer.py:368 msgid "1 game imported" msgstr "" #. The variable is the number of games -#: src/importer/importer.py:368 +#: src/importer/importer.py:372 msgid "{} games imported" msgstr "" #. A single game removed -#: src/importer/importer.py:372 +#: src/importer/importer.py:376 msgid "1 removed" msgstr "" diff --git a/src/details_window.py b/src/details_window.py index a178d4e..582df58 100644 --- a/src/details_window.py +++ b/src/details_window.py @@ -199,6 +199,12 @@ class DetailsWindow(Adw.Window): } ) + if shared.win.sidebar.get_selected_row().get_child() not in ( + shared.win.all_games_row_box, + shared.win.added_row_box, + ): + shared.win.sidebar.select_row(shared.win.added_row_box.get_parent()) + else: if final_name == "": create_dialog( @@ -246,7 +252,7 @@ class DetailsWindow(Adw.Window): self.game_cover.pictures.remove(self.cover) self.close() - shared.win.show_details_view(self.game) + shared.win.show_details_page(self.game) def update_cover_callback(self, manager: SGDBManager) -> None: # Set the game as not loading diff --git a/src/game.py b/src/game.py index 8dc981e..e1e3141 100644 --- a/src/game.py +++ b/src/game.py @@ -25,7 +25,7 @@ from pathlib import Path from time import time from typing import Any, Optional -from gi.repository import Adw, GLib, GObject, Gtk +from gi.repository import Adw, GObject, Gtk from src import shared from src.game_cover import GameCover @@ -66,8 +66,7 @@ class Game(Gtk.Box): def __init__(self, data: dict[str, Any], **kwargs: Any) -> None: super().__init__(**kwargs) - self.win = shared.win - self.app = self.win.get_application() + self.app = shared.win.get_application() self.version = shared.SPEC_VERSION self.update_values(data) @@ -100,18 +99,19 @@ class Game(Gtk.Box): def create_toast(self, title: str, action: Optional[str] = None) -> None: toast = Adw.Toast.new(title.format(self.name)) toast.set_priority(Adw.ToastPriority.HIGH) + toast.set_use_markup(False) if action: toast.set_button_label(_("Undo")) - toast.connect("button-clicked", self.win.on_undo_action, self, action) + toast.connect("button-clicked", shared.win.on_undo_action, self, action) - if (self, action) in self.win.toasts.keys(): + if (self, action) in shared.win.toasts.keys(): # Dismiss the toast if there already is one - self.win.toasts[(self, action)].dismiss() + shared.win.toasts[(self, action)].dismiss() - self.win.toasts[(self, action)] = toast + shared.win.toasts[(self, action)] = toast - self.win.toast_overlay.add_toast(toast) + shared.win.toast_overlay.add_toast(toast) def launch(self) -> None: self.last_played = int(time()) @@ -144,17 +144,15 @@ class Game(Gtk.Box): self.hidden = not self.hidden self.save() - if self.win.stack.get_visible_child() == self.win.details_view: - self.win.on_go_back_action() + if shared.win.navigation_view.get_visible_page() == shared.win.details_page: + shared.win.navigation_view.pop() self.update() if toast: self.create_toast( # The variable is the title of the game - (_("{} hidden") if self.hidden else _("{} unhidden")).format( - GLib.markup_escape_text(self.name) - ), + (_("{} hidden") if self.hidden else _("{} unhidden")).format(self.name), "hide", ) @@ -164,14 +162,11 @@ class Game(Gtk.Box): self.save() self.update() - if self.win.stack.get_visible_child() == self.win.details_view: - self.win.on_go_back_action() + if shared.win.navigation_view.get_visible_page() == shared.win.details_page: + shared.win.navigation_view.pop() - self.create_toast( - # The variable is the title of the game - _("{} removed").format(GLib.markup_escape_text(self.name)), - "remove", - ) + # The variable is the title of the game + self.create_toast(_("{} removed").format(self.name), "remove") def set_loading(self, state: int) -> None: self.loading += state @@ -202,7 +197,7 @@ class Game(Gtk.Box): if shared.schema.get_boolean("cover-launches-game") ^ button: self.launch() else: - self.win.show_details_view(self) + shared.win.show_details_page(self) def set_play_icon(self) -> None: self.play_button.set_icon_name( diff --git a/src/importer/importer.py b/src/importer/importer.py index 843da70..8db2d8d 100644 --- a/src/importer/importer.py +++ b/src/importer/importer.py @@ -53,6 +53,8 @@ class Importer(ErrorProducer): removed_game_ids: set[str] imported_game_ids: set[str] + close_req_id: int + def __init__(self) -> None: super().__init__() @@ -105,10 +107,13 @@ class Importer(ErrorProducer): def run(self) -> None: """Use several Gio.Task to import games from added sources""" + shared.win.get_application().state = shared.AppState.IMPORT + if self.__class__.summary_toast: self.__class__.summary_toast.dismiss() shared.win.get_application().lookup_action("import").set_enabled(False) + shared.win.get_application().lookup_action("add_game").set_enabled(False) self.create_dialog() @@ -148,6 +153,11 @@ class Importer(ErrorProducer): transient_for=shared.win, deletable=False, ) + + self.close_req_id = self.import_dialog.connect( + "close-request", lambda *_: shared.win.close() + ) + self.import_dialog.present() def source_task_thread_func(self, data: tuple) -> None: @@ -268,10 +278,15 @@ class Importer(ErrorProducer): self.imported_game_ids = shared.store.new_game_ids shared.store.new_game_ids = set() shared.store.duplicate_game_ids = set() + # Disconnect the close-request signal that closes the main window + self.import_dialog.disconnect(self.close_req_id) self.import_dialog.close() self.__class__.summary_toast = self.create_summary_toast() self.create_error_dialog() shared.win.get_application().lookup_action("import").set_enabled(True) + shared.win.get_application().lookup_action("add_game").set_enabled(True) + shared.win.get_application().state = shared.AppState.DEFAULT + shared.win.create_source_rows() def create_error_dialog(self) -> None: """Dialog containing all errors raised by importers""" diff --git a/src/main.py b/src/main.py index 37c2005..fb38d4c 100644 --- a/src/main.py +++ b/src/main.py @@ -59,6 +59,7 @@ from src.window import CartridgesWindow class CartridgesApplication(Adw.Application): + state = shared.AppState.DEFAULT win: CartridgesWindow def __init__(self) -> None: @@ -80,25 +81,28 @@ class CartridgesApplication(Adw.Application): Gtk.Window.set_default_icon_name(shared.APP_ID) # Create the main window - self.win = self.props.active_window # pylint: disable=no-member - if not self.win: - shared.win = self.win = CartridgesWindow(application=self) + win = self.props.active_window # pylint: disable=no-member + if not win: + shared.win = win = CartridgesWindow(application=self) # Save window geometry shared.state_schema.bind( - "width", self.win, "default-width", Gio.SettingsBindFlags.DEFAULT + "width", shared.win, "default-width", Gio.SettingsBindFlags.DEFAULT ) shared.state_schema.bind( - "height", self.win, "default-height", Gio.SettingsBindFlags.DEFAULT + "height", shared.win, "default-height", Gio.SettingsBindFlags.DEFAULT ) shared.state_schema.bind( - "is-maximized", self.win, "maximized", Gio.SettingsBindFlags.DEFAULT + "is-maximized", shared.win, "maximized", Gio.SettingsBindFlags.DEFAULT ) # 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 + shared.win.create_source_rows() # Add rest of the managers for game imports shared.store.add_manager(CoverManager()) @@ -124,26 +128,28 @@ class CartridgesApplication(Adw.Application): ("protondb_search",), ("lutris_search",), ("hltb_search",), - ("show_hidden", ("h",), self.win), - ("go_back", ("Left",), self.win), - ("go_to_parent", ("Up",), self.win), - ("go_home", ("Home",), self.win), - ("toggle_search", ("f",), self.win), - ("escape", ("Escape",), self.win), - ("undo", ("z",), self.win), - ("open_menu", ("F10",), self.win), - ("close", ("w",), self.win), + ("show_sidebar", ("F9",), shared.win), + ("show_hidden", ("h",), shared.win), + ("go_to_parent", ("Up",), shared.win), + ("go_home", ("Home",), shared.win), + ("toggle_search", ("f",), shared.win), + ("escape", ("Escape",), shared.win), + ("undo", ("z",), shared.win), + ("open_menu", ("F10",), shared.win), + ("close", ("w",), shared.win), } ) sort_action = Gio.SimpleAction.new_stateful( "sort_by", GLib.VariantType.new("s"), GLib.Variant("s", "a-z") ) - sort_action.connect("activate", self.win.on_sort_action) - self.win.add_action(sort_action) - self.win.on_sort_action(sort_action, shared.state_schema.get_value("sort-mode")) + sort_action.connect("activate", shared.win.on_sort_action) + shared.win.add_action(sort_action) + shared.win.on_sort_action( + sort_action, shared.state_schema.get_value("sort-mode") + ) - self.win.present() + shared.win.present() def load_games_from_disk(self) -> None: if shared.games_dir.is_dir(): @@ -155,6 +161,15 @@ class CartridgesApplication(Adw.Application): game = Game(data) shared.store.add_game(game, {"skip_save": True}) + def get_source_name(self, source_id: str) -> Any: + if source_id == "all": + name = _("All Games") + elif source_id == "imported": + name = _("Added") + else: + name = globals()[f'{source_id.split("_")[0].title()}Source'].name + return name + def on_about_action(self, *_args: Any) -> None: # Get the debug info from the log files debug_str = "" @@ -171,13 +186,12 @@ class CartridgesApplication(Adw.Application): debug_str += log_file.read() log_file.close() - about = Adw.AboutWindow( - transient_for=self.win, - application_name=_("Cartridges"), - application_icon=shared.APP_ID, - developer_name="kramo", - version=shared.VERSION, - developers=[ + about = Adw.AboutWindow.new_from_appdata( + shared.PREFIX + "/" + shared.APP_ID + ".metainfo.xml", shared.VERSION + ) + about.set_transient_for(shared.win) + about.set_developers( + ( "kramo https://kramo.hu", "Geoffrey Coulaud https://geoffrey-coulaud.fr", "Rilic https://rilic.red", @@ -185,16 +199,19 @@ class CartridgesApplication(Adw.Application): "Paweł Lidwin https://github.com/imLinguin", "Domenico https://github.com/Domefemia", "Rafael Mardojai CM https://mardojai.com", - ], - designers=("kramo https://kramo.hu",), - copyright="© 2022-2023 kramo", - license_type=Gtk.License.GPL_3_0, - issue_url="https://github.com/kra-mo/cartridges/issues/new", - website="https://github.com/kra-mo/cartridges", - # Translators: Replace this with your name for it to show up in the about window - translator_credits=_("translator_credits"), - debug_info=debug_str, - debug_info_filename="cartridges.log", + ) + ) + about.set_designers(("kramo https://kramo.hu",)) + about.set_copyright("© 2022-2023 kramo") + # Translators: Replace this with your name for it to show up in the about window + about.set_translator_credits = (_("translator_credits"),) + about.set_debug_info(debug_str) + about.set_debug_info_filename("cartridges.log") + about.add_legal_section( + "Steam Branding", + "© 2023 Valve Corporation", + Gtk.License.CUSTOM, + "Steam and the Steam logo are trademarks and/or registered trademarks of Valve Corporation in the U.S. and/or other countries.", # pylint: disable=line-too-long ) about.present() @@ -215,13 +232,13 @@ class CartridgesApplication(Adw.Application): return win def on_launch_game_action(self, *_args: Any) -> None: - self.win.active_game.launch() + shared.win.active_game.launch() def on_hide_game_action(self, *_args: Any) -> None: - self.win.active_game.toggle_hidden() + shared.win.active_game.toggle_hidden() def on_edit_game_action(self, *_args: Any) -> None: - DetailsWindow(self.win.active_game) + DetailsWindow(shared.win.active_game) def on_add_game_action(self, *_args: Any) -> None: DetailsWindow() @@ -259,14 +276,14 @@ class CartridgesApplication(Adw.Application): shared.importer.run() def on_remove_game_action(self, *_args: Any) -> None: - self.win.active_game.remove_game() + shared.win.active_game.remove_game() def on_remove_game_details_view_action(self, *_args: Any) -> None: - if self.win.stack.get_visible_child() == self.win.details_view: + if shared.win.navigation_view.get_visible_page() == shared.win.details_page: self.on_remove_game_action() def search(self, uri: str) -> None: - Gio.AppInfo.launch_default_for_uri(f"{uri}{self.win.active_game.name}") + Gio.AppInfo.launch_default_for_uri(f"{uri}{shared.win.active_game.name}") def on_igdb_search_action(self, *_args: Any) -> None: self.search("https://www.igdb.com/search?type=1&q=") diff --git a/src/preferences.py b/src/preferences.py index 3b2b8ea..d9b5008 100644 --- a/src/preferences.py +++ b/src/preferences.py @@ -102,7 +102,6 @@ class PreferencesWindow(Adw.PreferencesWindow): sgdb_key_group = Gtk.Template.Child() sgdb_key_entry_row = Gtk.Template.Child() sgdb_switch = Gtk.Template.Child() - sgdb_switch_row = Gtk.Template.Child() sgdb_prefer_switch = Gtk.Template.Child() sgdb_animated_switch = Gtk.Template.Child() @@ -116,9 +115,8 @@ class PreferencesWindow(Adw.PreferencesWindow): def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) - self.win = shared.win self.file_chooser = Gtk.FileDialog() - self.set_transient_for(self.win) + self.set_transient_for(shared.win) self.toast = Adw.Toast.new(_("All games removed")) self.toast.set_button_label(_("Undo")) @@ -140,7 +138,6 @@ class PreferencesWindow(Adw.PreferencesWindow): if shared.PROFILE == "development": self.reset_action_row.set_visible(True) self.reset_button.connect("clicked", self.reset_app) - self.set_default_size(-1, 560) # Sources settings for source_class in ( @@ -175,15 +172,6 @@ class PreferencesWindow(Adw.PreferencesWindow): ) ) - def set_sgdb_sensitive(widget: Adw.EntryRow) -> None: - if not widget.get_text(): - shared.schema.set_boolean("sgdb", False) - - self.sgdb_switch_row.set_sensitive(widget.get_text()) - - self.sgdb_key_entry_row.connect("changed", set_sgdb_sensitive) - set_sgdb_sensitive(self.sgdb_key_entry_row) - # Switches self.bind_switches( { @@ -205,6 +193,15 @@ class PreferencesWindow(Adw.PreferencesWindow): } ) + def set_sgdb_sensitive(widget: Adw.EntryRow) -> None: + if not widget.get_text(): + shared.schema.set_boolean("sgdb", False) + + self.sgdb_switch.set_sensitive(widget.get_text()) + + self.sgdb_key_entry_row.connect("changed", set_sgdb_sensitive) + set_sgdb_sensitive(self.sgdb_key_entry_row) + def get_switch(self, setting: str) -> Any: return getattr(self, f'{setting.replace("-", "_")}_switch') @@ -220,9 +217,10 @@ class PreferencesWindow(Adw.PreferencesWindow): def choose_folder( self, _widget: Any, callback: Callable, callback_data: Optional[str] = None ) -> None: - self.file_chooser.select_folder(self.win, None, callback, callback_data) + self.file_chooser.select_folder(shared.win, None, callback, callback_data) def undo_remove_all(self, *_args: Any) -> None: + shared.win.get_application().state = shared.AppState.UNDO_REMOVE_ALL_GAMES for game in self.removed_games: game.removed = False game.save() @@ -230,8 +228,12 @@ class PreferencesWindow(Adw.PreferencesWindow): self.removed_games = set() self.toast.dismiss() + shared.win.get_application().state = shared.AppState.DEFAULT + shared.win.create_source_rows() def remove_all_games(self, *_args: Any) -> None: + shared.win.get_application().state = shared.AppState.REMOVE_ALL_GAMES + shared.win.row_selected(None, shared.win.all_games_row_box.get_parent()) for game in shared.store: if not game.removed: self.removed_games.add(game) @@ -239,10 +241,12 @@ class PreferencesWindow(Adw.PreferencesWindow): game.save() game.update() - if self.win.stack.get_visible_child() == self.win.details_view: - self.win.on_go_back_action() + if shared.win.navigation_view.get_visible_page() == shared.win.details_page: + shared.win.navigation_view.pop() self.add_toast(self.toast) + shared.win.get_application().state = shared.AppState.DEFAULT + shared.win.create_source_rows() def reset_app(self, *_args: Any) -> None: rmtree(shared.data_dir / "cartridges", True) diff --git a/src/shared.py.in b/src/shared.py.in index c3b7a3c..19c6c85 100644 --- a/src/shared.py.in +++ b/src/shared.py.in @@ -18,10 +18,20 @@ # 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() + REMOVE_ALL_GAMES = auto() + UNDO_REMOVE_ALL_GAMES = 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 a5005a4..0304e94 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.stack.get_visible_child() == game.win.details_view - 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_view(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/store/store.py b/src/store/store.py index 159da90..f056db3 100644 --- a/src/store/store.py +++ b/src/store/store.py @@ -48,7 +48,7 @@ class Store: """Check if the game is present in the store with the `in` keyword""" if not isinstance(obj, Game): return False - if not (source_mapping := self.source_games.get(obj.source)): + if not (source_mapping := self.source_games.get(obj.base_source)): return False return obj.game_id in source_mapping @@ -150,9 +150,9 @@ class Store: game.connect(signal, manager.run) # Add the game to the store - if not game.source in self.source_games: - self.source_games[game.source] = {} - self.source_games[game.source][game.game_id] = game + if not game.base_source in self.source_games: + self.source_games[game.base_source] = {} + self.source_games[game.base_source][game.game_id] = game # Run the pipeline for the game if not run_pipeline: diff --git a/src/utils/save_cover.py b/src/utils/save_cover.py index 1bff991..336161d 100644 --- a/src/utils/save_cover.py +++ b/src/utils/save_cover.py @@ -61,7 +61,6 @@ def convert_cover( tmp_path, save_all=True, append_images=frames[1:], - disposal=2, ) else: diff --git a/src/window.py b/src/window.py index 5318897..4d76b07 100644 --- a/src/window.py +++ b/src/window.py @@ -31,25 +31,33 @@ from src.utils.relative_date import relative_date class CartridgesWindow(Adw.ApplicationWindow): __gtype_name__ = "CartridgesWindow" + overlay_split_view = Gtk.Template.Child() + navigation_view = Gtk.Template.Child() + sidebar = Gtk.Template.Child() + all_games_row_box = Gtk.Template.Child() + all_games_no_label = Gtk.Template.Child() + added_row_box = Gtk.Template.Child() + added_games_no_label = Gtk.Template.Child() toast_overlay = Gtk.Template.Child() primary_menu_button = Gtk.Template.Child() - stack = Gtk.Template.Child() + show_sidebar_button = Gtk.Template.Child() details_view = Gtk.Template.Child() + library_page = Gtk.Template.Child() library_view = Gtk.Template.Child() library = Gtk.Template.Child() scrolledwindow = Gtk.Template.Child() - library_bin = Gtk.Template.Child() + library_overlay = Gtk.Template.Child() notice_empty = Gtk.Template.Child() notice_no_results = Gtk.Template.Child() search_bar = Gtk.Template.Child() search_entry = Gtk.Template.Child() search_button = Gtk.Template.Child() - details_view_box = Gtk.Template.Child() + details_page = Gtk.Template.Child() + details_view_toolbar_view = Gtk.Template.Child() details_view_cover = Gtk.Template.Child() details_view_spinner = Gtk.Template.Child() details_view_title = Gtk.Template.Child() - details_view_header_bar_title = Gtk.Template.Child() details_view_blurred_cover = Gtk.Template.Child() details_view_play_button = Gtk.Template.Child() details_view_developer = Gtk.Template.Child() @@ -57,11 +65,12 @@ class CartridgesWindow(Adw.ApplicationWindow): details_view_last_played = Gtk.Template.Child() details_view_hide_button = Gtk.Template.Child() + hidden_library_page = Gtk.Template.Child() hidden_primary_menu_button = Gtk.Template.Child() hidden_library = Gtk.Template.Child() hidden_library_view = Gtk.Template.Child() hidden_scrolledwindow = Gtk.Template.Child() - hidden_library_bin = Gtk.Template.Child() + hidden_library_overlay = Gtk.Template.Child() hidden_notice_empty = Gtk.Template.Child() hidden_notice_no_results = Gtk.Template.Child() hidden_search_bar = Gtk.Template.Child() @@ -73,14 +82,139 @@ class CartridgesWindow(Adw.ApplicationWindow): active_game: Game details_view_game_cover: Optional[GameCover] = None sort_state: str = "a-z" + filter_state: str = "all" + source_rows: dict = {} + + def create_source_rows(self) -> None: + def get_removed(source_id: str) -> Any: + removed = tuple( + game.removed or game.hidden or game.blacklisted + for game in shared.store.source_games[source_id].values() + ) + return ( + (count,) if (count := sum(removed)) != len(removed) else False + ) # Return a tuple because 0 == False and 1 == True + + total_games_no = 0 + restored = False + + selected_id = ( + self.source_rows[selected_row][0] + if (selected_row := self.sidebar.get_selected_row()) in self.source_rows + else None + ) + + if selected_row == self.added_row_box.get_parent(): + self.sidebar.select_row(self.added_row_box.get_parent()) + restored = True + + if added_missing := ( + not shared.store.source_games.get("imported") + or not (removed := get_removed("imported")) + ): + self.sidebar.select_row(self.all_games_row_box.get_parent()) + else: + games_no = len(shared.store.source_games["imported"]) - removed[0] + self.added_games_no_label.set_label(str(games_no)) + total_games_no += games_no + self.added_row_box.get_parent().set_visible(not added_missing) + + self.sidebar.get_row_at_index(2).set_visible(False) + + while row := self.sidebar.get_row_at_index(3): + self.sidebar.remove(row) + + for source_id in shared.store.source_games: + if source_id == "imported": + continue + if not (removed := get_removed(source_id)): + continue + + row = Gtk.Box( + margin_top=12, + margin_bottom=12, + margin_start=6, + margin_end=6, + spacing=12, + ) + games_no = len(shared.store.source_games[source_id]) - removed[0] + total_games_no += games_no + + row.append( + Gtk.Image.new_from_icon_name( + "user-desktop-symbolic" + if (split_id := source_id.split("_")[0]) == "desktop" + else f"{split_id}-source-symbolic" + ) + ) + + row.append( + Gtk.Label( + label=self.get_application().get_source_name(source_id), + halign=Gtk.Align.START, + ) + ) + + row.append( + games_no_label := Gtk.Label( + label=games_no, + hexpand=True, + halign=Gtk.Align.END, + ) + ) + + games_no_label.add_css_class("dim-label") + + # Order rows based on the number of games in them + index = 3 + while source_row := self.sidebar.get_row_at_index(index): + if self.source_rows[source_row][1] < games_no: + self.sidebar.insert(row, index) + break + index += 1 + if not row.get_parent(): + self.sidebar.append(row) + + self.source_rows[row.get_parent()] = ( + source_id, + games_no, + ) + + if source_id == selected_id: + self.sidebar.select_row(row.get_parent()) + restored = True + + self.sidebar.get_row_at_index(2).set_visible(True) + + self.all_games_no_label.set_label(str(total_games_no)) + + if not restored: + self.sidebar.select_row(self.all_games_row_box.get_parent()) + + def row_selected(self, _widget: Any, row: Gtk.ListBoxRow | None) -> None: + if not row: + return + match row.get_child(): + case self.all_games_row_box: + value = "all" + case self.added_row_box: + value = "imported" + case _: + value = self.source_rows[row][0] + + self.library_page.set_title(self.get_application().get_source_name(value)) + + 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: Any) -> None: super().__init__(**kwargs) - self.previous_page = self.library_view - - self.details_view.set_measure_overlay(self.details_view_box, True) - self.details_view.set_clip_overlay(self.details_view_box, False) + self.details_view.set_measure_overlay(self.details_view_toolbar_view, True) + self.details_view.set_clip_overlay(self.details_view_toolbar_view, False) self.library.set_filter_func(self.filter_func) self.hidden_library.set_filter_func(self.filter_func) @@ -92,6 +226,12 @@ 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.sidebar.select_row(self.all_games_row_box.get_parent()) + if shared.PROFILE == "development": self.add_css_class("devel") @@ -103,12 +243,13 @@ class CartridgesWindow(Adw.ApplicationWindow): self.search_entry.connect("search-changed", self.search_changed, False) self.hidden_search_entry.connect("search-changed", self.search_changed, True) - self.search_entry.connect("activate", self.show_details_view_search) - self.hidden_search_entry.connect("activate", self.show_details_view_search) + self.search_entry.connect("activate", self.show_details_page_search) + self.hidden_search_entry.connect("activate", self.show_details_page_search) - back_mouse_button = Gtk.GestureClick(button=8) - (back_mouse_button).connect("pressed", self.on_go_back_action) - self.add_controller(back_mouse_button) + 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) @@ -140,25 +281,38 @@ class CartridgesWindow(Adw.ApplicationWindow): if game.removed or game.blacklisted: continue if game.hidden: - if game.filtered and hidden_child != self.hidden_scrolledwindow: + if game.filtered and hidden_child: hidden_child = self.hidden_notice_no_results continue - hidden_child = self.hidden_scrolledwindow + hidden_child = None else: - if game.filtered and child != self.scrolledwindow: + if game.filtered and child: child = self.notice_no_results continue - child = self.scrolledwindow + child = None - self.library_bin.set_child(child) - self.hidden_library_bin.set_child(hidden_child) + def remove_from_overlay(widget: Gtk.Widget) -> None: + if isinstance(widget.get_parent(), Gtk.Overlay): + widget.get_parent().remove_overlay(widget) + + if child: + self.library_overlay.add_overlay(child) + else: + remove_from_overlay(self.notice_empty) + remove_from_overlay(self.notice_no_results) + + if hidden_child: + self.hidden_library_overlay.add_overlay(hidden_child) + else: + remove_from_overlay(self.hidden_notice_empty) + remove_from_overlay(self.hidden_notice_no_results) def filter_func(self, child: Gtk.Widget) -> bool: game = child.get_child() text = ( ( self.hidden_search_entry - if self.stack.get_visible_child() == self.hidden_library_view + if self.navigation_view.get_visible_page() == self.hidden_library_page else self.search_entry ) .get_text() @@ -170,6 +324,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.base_source != self.filter_state: + filtered = True + game.filtered = filtered self.set_library_child() @@ -178,7 +338,7 @@ class CartridgesWindow(Adw.ApplicationWindow): def set_active_game(self, _widget: Any, _pspec: Any, game: Game) -> None: self.active_game = game - def show_details_view(self, game: Game) -> None: + def show_details_page(self, game: Game) -> None: self.active_game = game self.details_view_cover.set_opacity(int(not game.loading)) @@ -205,7 +365,7 @@ class CartridgesWindow(Adw.ApplicationWindow): ) self.details_view_title.set_label(game.name) - self.details_view_header_bar_title.set_title(game.name) + self.details_page.set_title(game.name) date = relative_date(game.added) self.details_view_added.set_label( @@ -220,14 +380,14 @@ class CartridgesWindow(Adw.ApplicationWindow): _("Last played: {}").format(last_played_date) ) - if self.stack.get_visible_child() != self.details_view: - self.navigate(self.details_view) + if self.navigation_view.get_visible_page() != self.details_page: + self.navigation_view.push(self.details_page) self.set_focus(self.details_view_play_button) self.set_details_view_opacity() def set_details_view_opacity(self, *_args: Any) -> None: - if self.stack.get_visible_child() != self.details_view: + if self.navigation_view.get_visible_page() != self.details_page: return if ( @@ -262,42 +422,26 @@ class CartridgesWindow(Adw.ApplicationWindow): return ((get_value(0) > get_value(1)) ^ order) * 2 - 1 - def navigate(self, next_page: Gtk.Widget) -> None: - levels = (self.library_view, self.hidden_library_view, self.details_view) - self.stack.set_transition_type( - Gtk.StackTransitionType.UNDER_RIGHT - if levels.index(self.stack.get_visible_child()) - levels.index(next_page) - > 0 - else Gtk.StackTransitionType.OVER_LEFT + def set_show_hidden(self, navigation_view: Adw.NavigationView, *_args: Any) -> None: + self.lookup_action("show_hidden").set_enabled( + navigation_view.get_visible_page() == self.library_page ) - if next_page in (self.library_view, self.hidden_library_view): - self.previous_page = next_page - self.lookup_action("show_hidden").set_enabled( - next_page == self.library_view - ) - - self.stack.set_visible_child(next_page) - - def on_go_back_action(self, *_args: Any) -> None: - if self.stack.get_visible_child() == self.hidden_library_view: - self.navigate(self.library_view) - elif self.stack.get_visible_child() == self.details_view: - self.on_go_to_parent_action() + def on_show_sidebar_action(self, *_args: Any) -> None: + shared.state_schema.set_boolean( + "show-sidebar", (value := not self.overlay_split_view.get_show_sidebar()) + ) + self.overlay_split_view.set_show_sidebar(value) def on_go_to_parent_action(self, *_args: Any) -> None: - if self.stack.get_visible_child() == self.details_view: - self.navigate( - self.hidden_library_view - if self.previous_page == self.hidden_library_view - else self.library_view - ) + if self.navigation_view.get_visible_page() == self.details_page: + self.navigation_view.pop() def on_go_home_action(self, *_args: Any) -> None: - self.navigate(self.library_view) + self.navigation_view.pop_to_page(self.library_page) def on_show_hidden_action(self, *_args: Any) -> None: - self.navigate(self.hidden_library_view) + self.navigation_view.push(self.hidden_library_page) def on_sort_action(self, action: Gio.SimpleAction, state: GLib.Variant) -> None: action.set_state(state) @@ -307,10 +451,10 @@ class CartridgesWindow(Adw.ApplicationWindow): shared.state_schema.set_string("sort-mode", self.sort_state) def on_toggle_search_action(self, *_args: Any) -> None: - if self.stack.get_visible_child() == self.library_view: + if self.navigation_view.get_visible_page() == self.library_page: search_bar = self.search_bar search_entry = self.search_entry - elif self.stack.get_visible_child() == self.hidden_library_view: + elif self.navigation_view.get_visible_page() == self.hidden_library_page: search_bar = self.hidden_search_bar search_entry = self.hidden_search_entry else: @@ -330,9 +474,9 @@ class CartridgesWindow(Adw.ApplicationWindow): ): self.on_toggle_search_action() else: - self.on_go_back_action() + self.navigation_view.pop() - def show_details_view_search(self, widget: Gtk.Widget) -> None: + def show_details_page_search(self, widget: Gtk.Widget) -> None: library = ( self.hidden_library if widget == self.hidden_search_entry else self.library ) @@ -343,7 +487,7 @@ class CartridgesWindow(Adw.ApplicationWindow): break if self.filter_func(child): - self.show_details_view(child.get_child()) + self.show_details_page(child.get_child()) break index += 1 @@ -377,9 +521,9 @@ class CartridgesWindow(Adw.ApplicationWindow): self.toasts.pop((game, undo)) def on_open_menu_action(self, *_args: Any) -> None: - if self.stack.get_visible_child() == self.library_view: + if self.navigation_view.get_visible_page() == self.library_page: self.primary_menu_button.popup() - elif self.stack.get_visible_child() == self.hidden_library_view: + elif self.navigation_view.get_visible_page() == self.hidden_library_page: self.hidden_primary_menu_button.popup() def on_close_action(self, *_args: Any) -> None: