diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..8ac6b8c
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,6 @@
+version: 2
+updates:
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "monthly"
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a05b5c2..ecc1664 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,8 +1,9 @@
+name: CI
on:
push:
branches: [main]
pull_request:
-name: CI
+
concurrency:
group: release-${{ github.sha }}
jobs:
@@ -10,18 +11,18 @@ jobs:
name: Flatpak
runs-on: ubuntu-latest
container:
- image: bilelmoussaoui/flatpak-github-actions:gnome-45
+ image: bilelmoussaoui/flatpak-github-actions:gnome-46
options: --privileged
steps:
- - name: Checkout
- uses: actions/checkout@v4
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Flatpak Builder
+ uses: flatpak/flatpak-github-actions/flatpak-builder@v6.3
+ with:
+ bundle: page.kramo.Cartridges.Devel.flatpak
+ manifest-path: build-aux/flatpak/page.kramo.Cartridges.Devel.json
- - name: Flatpak Builder
- uses: flatpak/flatpak-github-actions/flatpak-builder@v6.3
- with:
- bundle: page.kramo.Cartridges.Devel.flatpak
- manifest-path: flatpak/page.kramo.Cartridges.Devel.json
-
windows:
name: Windows
runs-on: windows-latest
@@ -50,10 +51,49 @@ jobs:
timeout 2 cartridges; [ "$?" -eq "124" ]
- name: Inno Setup
- run: iscc ".\_build\windows\Cartridges.iss"
+ run: iscc ".\_build\build-aux\windows\Cartridges.iss"
- name: Upload Artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: Windows Installer
- path: _build/windows/Output/Cartridges Setup.exe
+ path: _build/build-aux/windows/Output/Cartridges Windows.exe
+
+ macos:
+ name: macOS
+ runs-on: macos-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Set up Homebrew
+ id: set-up-homebrew
+ uses: Homebrew/actions/setup-homebrew@master
+
+ - name: Install Dependencies
+ run: |
+ brew install meson pygobject3 libadwaita adwaita-icon-theme desktop-file-utils pyinstaller pillow
+ pip3 install --break-system-packages requests PyYAML pyobjc
+
+ - name: Meson Build
+ run: |
+ meson setup _build -Dtiff_compression=jpeg
+ ninja install -C _build
+
+ - name: PyInstaller
+ env:
+ PYTHONPATH: /opt/homebrew/opt/homebrew/lib/python3.12/site-packages
+ run: |
+ cd build-aux/macos
+ pyinstaller ./cartridges.spec
+
+ - name: Zip
+ run: |
+ cd build-aux/macos/dist
+ zip -yr Cartridges\ macOS.zip Cartridges.app
+
+ - name: Upload Artifact
+ uses: actions/upload-artifact@v4
+ with:
+ path: build-aux/macos/dist/Cartridges macOS.zip
+ name: macOS Application
diff --git a/.github/workflows/publish-release.yml b/.github/workflows/publish-release.yml
index e118484..205cd2d 100644
--- a/.github/workflows/publish-release.yml
+++ b/.github/workflows/publish-release.yml
@@ -1,10 +1,11 @@
+name: Publish Release
on:
push:
- tags:
- "*"
-name: Publish Release
+ tags: "*"
+
concurrency:
group: release-${{ github.sha }}
+
jobs:
publish-release:
name: Publish Release
@@ -14,7 +15,7 @@ jobs:
uses: actions/checkout@v4
- name: Download workflow artifact
- uses: dawidd6/action-download-artifact@v3.0.0
+ uses: dawidd6/action-download-artifact@v6
with:
workflow: ci.yml
commit: ${{ github.sha }}
@@ -37,9 +38,11 @@ jobs:
run: echo tag_name=${GITHUB_REF#refs/tags/} >> $GITHUB_OUTPUT
- name: Publish release
- uses: softprops/action-gh-release@v0.1.15
+ uses: softprops/action-gh-release@v2.0.8
with:
- files: Windows Installer/Cartridges Setup.exe
+ files: |
+ Windows Installer/Cartridges Windows.exe
+ macOS Application/Cartridges macOS.zip
fail_on_unmatched_files: true
tag_name: ${{ steps.get_tag_name.outputs.tag_name }}
body_path: release_notes
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index b8ab73b..228cc8b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -33,6 +33,11 @@ The project can be translated on [Weblate](https://hosted.weblate.org/engage/car
2. From the MSYS2 shell, install the required dependencies listed [here](https://github.com/kra-mo/cartridges/blob/main/.github/workflows/ci.yml).
3. Build it via Meson.
+## For macOS
+1. Install [Homebrew](https://brew.sh/).
+2. Using `brew` and `pip3`, install the required dependencies listed [here](https://github.com/kra-mo/cartridges/blob/main/.github/workflows/ci.yml).
+3. Build it via Meson.
+
## Meson
```bash
git clone https://github.com/kra-mo/cartridges.git
diff --git a/README.md b/README.md
index 8f6f906..8a66c08 100644
--- a/README.md
+++ b/README.md
@@ -65,11 +65,9 @@ Thank you for your generosity! 💜
## Linux
-### Flathub
-
The app is available on Flathub.
-
+
## Windows
@@ -84,6 +82,13 @@ Note: Windows might present you with a warning when trying to install the app. T
Install the latest release with the command: `winget install cartridges`.
+## macOS
+
+1. Download the latest release from [Releases](https://github.com/kra-mo/cartridges/releases).
+2. Move the app into your Applications folder.
+
+Note: macOS might tell you that the application could not be checked for malicious software or something similar. In this case, open System Settings > Privacy & Security, scroll down, find the warning about Cartridges and click "Open Anyway". More information can be found [here](https://support.apple.com/en-us/102445).
+
## Building manually
See [Building](https://github.com/kra-mo/cartridges/blob/main/CONTRIBUTING.md#building).
diff --git a/flatpak/page.kramo.Cartridges.Devel.json b/build-aux/flatpak/page.kramo.Cartridges.Devel.json
similarity index 94%
rename from flatpak/page.kramo.Cartridges.Devel.json
rename to build-aux/flatpak/page.kramo.Cartridges.Devel.json
index e728b7d..f0f217f 100644
--- a/flatpak/page.kramo.Cartridges.Devel.json
+++ b/build-aux/flatpak/page.kramo.Cartridges.Devel.json
@@ -102,6 +102,19 @@
"sha256": "bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"
}
]
+ },
+ {
+ "name": "cartridges",
+ "builddir": true,
+ "buildsystem": "meson",
+ "run-tests": true,
+ "config-opts": ["-Dprofile=development"],
+ "sources": [
+ {
+ "type": "dir",
+ "path": "../.."
+ }
+ ]
}
]
},
diff --git a/build-aux/macos/cartridges.spec b/build-aux/macos/cartridges.spec
new file mode 100644
index 0000000..7bb5e57
--- /dev/null
+++ b/build-aux/macos/cartridges.spec
@@ -0,0 +1,59 @@
+# -*- mode: python ; coding: utf-8 -*-
+
+
+a = Analysis(
+ ["../../_build/cartridges/cartridges"],
+ pathex=[],
+ binaries=[],
+ datas=[("../../_build/data/cartridges.gresource", "Resources")],
+ hiddenimports=[],
+ hookspath=[],
+ hooksconfig={
+ "gi": {
+ "module-versions": {
+ "Gtk": "4.0",
+ },
+ },
+ },
+ runtime_hooks=[],
+ excludes=[],
+ noarchive=False,
+ optimize=0,
+)
+pyz = PYZ(a.pure)
+
+exe = EXE(
+ pyz,
+ a.scripts,
+ [],
+ exclude_binaries=True,
+ name="Cartridges",
+ debug=False,
+ bootloader_ignore_signals=False,
+ strip=False,
+ upx=True,
+ console=False,
+ disable_windowed_traceback=False,
+ argv_emulation=False,
+ target_arch=None,
+ codesign_identity=None,
+ entitlements_file=None,
+)
+coll = COLLECT(
+ exe,
+ a.binaries,
+ a.datas,
+ strip=False,
+ upx=True,
+ upx_exclude=[],
+ name="Cartridges",
+)
+app = BUNDLE(
+ coll,
+ name="Cartridges.app",
+ icon="./icon.icns",
+ bundle_identifier="page.kramo.Cartridges",
+ info_plist={
+ "LSApplicationCategoryType": "public.app-category.games",
+ },
+)
diff --git a/build-aux/macos/icon.icns b/build-aux/macos/icon.icns
new file mode 100644
index 0000000..8276dbd
Binary files /dev/null and b/build-aux/macos/icon.icns differ
diff --git a/windows/Cartridges.iss.in b/build-aux/windows/Cartridges.iss.in
similarity index 93%
rename from windows/Cartridges.iss.in
rename to build-aux/windows/Cartridges.iss.in
index d785c3a..9027ea6 100644
--- a/windows/Cartridges.iss.in
+++ b/build-aux/windows/Cartridges.iss.in
@@ -15,10 +15,10 @@ AppSupportURL=https://github.com/kra-mo/cartridges/issues
AppUpdatesURL={#MyAppURL}
DefaultDirName={autopf64}\{#MyAppName}
DisableProgramGroupPage=yes
-LicenseFile=..\..\LICENSE
+LicenseFile=..\..\..\LICENSE
PrivilegesRequiredOverridesAllowed=dialog
-OutputBaseFilename=Cartridges Setup
-SetupIconFile=..\..\windows\icon.ico
+OutputBaseFilename=Cartridges Windows
+SetupIconFile=..\..\..\build-aux\windows\icon.ico
Compression=lzma
SolidCompression=yes
WizardStyle=modern
@@ -49,7 +49,7 @@ Source: "D:\a\_temp\msys64\ucrt64\share\icons\*"; DestDir: "{app}\share\icons";
Source: "D:\a\_temp\msys64\ucrt64\share\glib-2.0\*"; DestDir: "{app}\share\glib-2.0"; Flags: recursesubdirs ignoreversion
Source: "D:\a\_temp\msys64\ucrt64\share\gtk-4.0\*"; DestDir: "{app}\share\gtk-4.0"; Flags: recursesubdirs ignoreversion
-Source: "..\..\windows\icon.ico"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion
+Source: "..\..\..\build-aux\windows\icon.ico"; DestDir: "{app}"; Flags: recursesubdirs ignoreversion
[Icons]
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\bin\{#MyAppExeName}"; Parameters: """{app}\bin\cartridges"""; IconFilename: "{app}\icon.ico"
diff --git a/windows/icon.ico b/build-aux/windows/icon.ico
similarity index 100%
rename from windows/icon.ico
rename to build-aux/windows/icon.ico
diff --git a/windows/meson.build b/build-aux/windows/meson.build
similarity index 84%
rename from windows/meson.build
rename to build-aux/windows/meson.build
index 959e7ff..4889029 100644
--- a/windows/meson.build
+++ b/build-aux/windows/meson.build
@@ -3,5 +3,5 @@ configure_file(
output: 'Cartridges.iss',
configuration: conf,
install: true,
- install_dir: '.'
-)
\ No newline at end of file
+ install_dir: '.',
+)
diff --git a/cartridges/application_delegate.py b/cartridges/application_delegate.py
new file mode 100644
index 0000000..7fe61bf
--- /dev/null
+++ b/cartridges/application_delegate.py
@@ -0,0 +1,121 @@
+# application_delegate.py
+#
+# Copyright 2024 kramo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+"""A set of methods that manage your app’s life cycle and its interaction
+with common system services."""
+
+from typing import Any
+
+from AppKit import NSApp, NSApplication, NSMenu, NSMenuItem # type: ignore
+from Foundation import NSObject # type: ignore
+from gi.repository import Gio # type: ignore
+
+from cartridges import shared
+
+
+class ApplicationDelegate(NSObject): # type: ignore
+ """A set of methods that manage your app’s life cycle and its interaction
+ with common system services."""
+
+ def applicationDidFinishLaunching_(self, *_args: Any) -> None:
+ main_menu = NSApp.mainMenu()
+
+ add_game_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "Add Game", "add:", "n"
+ )
+
+ import_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "Import", "import:", "i"
+ )
+
+ file_menu = NSMenu.alloc().init()
+ file_menu.addItem_(add_game_menu_item)
+ file_menu.addItem_(import_menu_item)
+
+ file_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "File", None, ""
+ )
+ file_menu_item.setSubmenu_(file_menu)
+ main_menu.addItem_(file_menu_item)
+
+ show_hidden_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "Show Hidden", "hidden:", "h"
+ )
+
+ windows_menu = NSMenu.alloc().init()
+
+ view_menu = NSMenu.alloc().init()
+ view_menu.addItem_(show_hidden_menu_item)
+
+ view_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "View", None, ""
+ )
+ view_menu_item.setSubmenu_(view_menu)
+ main_menu.addItem_(view_menu_item)
+
+ windows_menu = NSMenu.alloc().init()
+
+ windows_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "Window", None, ""
+ )
+ windows_menu_item.setSubmenu_(windows_menu)
+ main_menu.addItem_(windows_menu_item)
+
+ NSApp.setWindowsMenu_(windows_menu)
+
+ keyboard_shortcuts_menu_item = (
+ NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "Keyboard Shortcuts", "shortcuts:", "?"
+ )
+ )
+
+ help_menu = NSMenu.alloc().init()
+ help_menu.addItem_(keyboard_shortcuts_menu_item)
+
+ help_menu_item = NSMenuItem.alloc().initWithTitle_action_keyEquivalent_(
+ "Help", None, ""
+ )
+ help_menu_item.setSubmenu_(help_menu)
+ main_menu.addItem_(help_menu_item)
+
+ NSApp.setHelpMenu_(help_menu)
+
+ def add_(self, *_args: Any) -> None:
+ if (not shared.win) or (not (app := shared.win.get_application())):
+ return
+
+ app.lookup_action("add_game").activate()
+
+ def import_(self, *_args: Any) -> None:
+ if (not shared.win) or (not (app := shared.win.get_application())):
+ return
+
+ app.lookup_action("import").activate()
+
+ def hidden_(self, *_args: Any) -> None:
+ if not shared.win:
+ return
+
+ shared.win.lookup_action("show_hidden").activate()
+
+ def shortcuts_(self, *_args: Any) -> None:
+ if (not shared.win) or (not (overlay := shared.win.get_help_overlay())):
+ return
+
+ overlay.present()
diff --git a/cartridges/cartridges.in b/cartridges/cartridges.in
index 84410da..0eac260 100755
--- a/cartridges/cartridges.in
+++ b/cartridges/cartridges.in
@@ -2,7 +2,7 @@
# cartridges.in
#
-# Copyright 2022-2023 kramo
+# Copyright 2022-2024 kramo
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -24,6 +24,8 @@ import locale
import os
import signal
import sys
+from pathlib import Path
+from platform import system
VERSION = "@VERSION@"
@@ -36,7 +38,7 @@ else:
sys.path.insert(1, PKGDATADIR)
signal.signal(signal.SIGINT, signal.SIG_DFL)
-if os.name != "nt":
+if system() == "Linux":
locale.bindtextdomain("cartridges", LOCALEDIR)
locale.textdomain("cartridges")
gettext.install("cartridges", LOCALEDIR)
@@ -44,9 +46,15 @@ else:
gettext.install("cartridges")
if __name__ == "__main__":
- from gi.repository import Gio
+ from gi.repository import Gio, GLib
- resource = Gio.Resource.load(os.path.join(PKGDATADIR, "cartridges.gresource"))
+ try:
+ # For a macOS application bundle
+ resource = Gio.Resource.load(
+ str(Path(__file__).parent / "Resources" / "cartridges.gresource")
+ )
+ except GLib.GError:
+ resource = Gio.Resource.load(os.path.join(PKGDATADIR, "cartridges.gresource"))
resource._register() # pylint: disable=protected-access
from cartridges import main
diff --git a/cartridges/details_dialog.py b/cartridges/details_dialog.py
index 76ca4d1..a31837b 100644
--- a/cartridges/details_dialog.py
+++ b/cartridges/details_dialog.py
@@ -17,9 +17,11 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
-import os
+# pyright: reportAssignmentType=none
+
import shlex
from pathlib import Path
+from sys import platform
from time import time
from typing import Any, Optional
@@ -40,28 +42,35 @@ from cartridges.utils.save_cover import convert_cover, save_cover
class DetailsDialog(Adw.Dialog):
__gtype_name__ = "DetailsDialog"
- cover_overlay = Gtk.Template.Child()
- cover = Gtk.Template.Child()
- cover_button_edit = Gtk.Template.Child()
- cover_button_delete_revealer = Gtk.Template.Child()
- cover_button_delete = Gtk.Template.Child()
- spinner = Gtk.Template.Child()
+ cover_overlay: Gtk.Overlay = Gtk.Template.Child()
+ cover: Gtk.Picture = Gtk.Template.Child()
+ cover_button_edit: Gtk.Button = Gtk.Template.Child()
+ cover_button_delete_revealer: Gtk.Revealer = Gtk.Template.Child()
+ cover_button_delete: Gtk.Button = Gtk.Template.Child()
+ spinner: Gtk.Spinner = Gtk.Template.Child()
- name = Gtk.Template.Child()
- developer = Gtk.Template.Child()
- executable = Gtk.Template.Child()
+ name: Adw.EntryRow = Gtk.Template.Child()
+ developer: Adw.EntryRow = Gtk.Template.Child()
+ executable: Adw.EntryRow = Gtk.Template.Child()
- exec_info_label = Gtk.Template.Child()
- exec_info_popover = Gtk.Template.Child()
- file_chooser_button = Gtk.Template.Child()
+ exec_info_label: Gtk.Label = Gtk.Template.Child()
+ exec_info_popover: Gtk.Popover = Gtk.Template.Child()
+ file_chooser_button: Gtk.Button = Gtk.Template.Child()
- apply_button = Gtk.Template.Child()
+ apply_button: Gtk.Button = Gtk.Template.Child()
cover_changed: bool = False
+ is_open: bool = False
+
def __init__(self, game: Optional[Game] = None, **kwargs: Any):
super().__init__(**kwargs)
- self.game: Game = game
+
+ # Make it so only one dialog can be open at a time
+ self.__class__.is_open = True
+ self.connect("closed", lambda *_: self.set_is_open(False))
+
+ self.game: Optional[Game] = game
self.game_cover: GameCover = GameCover({self.cover})
if self.game:
@@ -106,7 +115,7 @@ class DetailsDialog(Adw.Dialog):
# As in software
exe_name = _("program")
- if os.name == "nt":
+ if platform == "win32":
exe_name += ".exe"
# Translate this string as you would translate "path to {}"
exe_path = _("C:\\path\\to\\{}").format(exe_name)
@@ -118,7 +127,7 @@ class DetailsDialog(Adw.Dialog):
exe_path = _("/path/to/{}").format(exe_name)
# Translate this string as you would translate "path to {}"
file_path = _("/path/to/{}").format(file_name)
- command = "xdg-open"
+ command = "open" if platform == "darwin" else "xdg-open"
# pylint: disable=line-too-long
exec_info_text = _(
@@ -325,3 +334,6 @@ class DetailsDialog(Adw.Dialog):
def choose_cover(self, *_args: Any) -> None:
self.image_file_dialog.open(self.get_root(), None, self.set_cover)
+
+ def set_is_open(self, is_open: bool) -> None:
+ self.__class__.is_open = is_open
diff --git a/cartridges/importer/heroic_source.py b/cartridges/importer/heroic_source.py
index 306c91e..46e8627 100644
--- a/cartridges/importer/heroic_source.py
+++ b/cartridges/importer/heroic_source.py
@@ -355,7 +355,7 @@ class HeroicSource(URLExecutableSource):
name = _("Heroic")
iterable_class = HeroicSourceIterable
url_format = "heroic://launch/{runner}/{app_name}"
- available_on = {"linux", "win32"}
+ available_on = {"linux", "win32", "darwin"}
locations: HeroicLocations
@@ -377,6 +377,7 @@ class HeroicSource(URLExecutableSource):
/ "config"
/ "heroic",
shared.appdata_dir / "heroic",
+ shared.app_support_dir / "heroic",
),
paths={
"config.json": LocationSubPath("config.json"),
diff --git a/cartridges/importer/itch_source.py b/cartridges/importer/itch_source.py
index 2a73594..6f198f9 100644
--- a/cartridges/importer/itch_source.py
+++ b/cartridges/importer/itch_source.py
@@ -81,7 +81,7 @@ class ItchSource(URLExecutableSource):
name = _("itch")
iterable_class = ItchSourceIterable
url_format = "itch://caves/{cave_id}/launch"
- available_on = {"linux", "win32"}
+ available_on = {"linux", "win32", "darwin"}
locations: ItchLocations
@@ -95,6 +95,7 @@ class ItchSource(URLExecutableSource):
shared.config_dir / "itch",
shared.host_config_dir / "itch",
shared.appdata_dir / "itch",
+ shared.app_support_dir / "itch",
),
paths={
"butler.db": LocationSubPath("db/butler.db"),
diff --git a/cartridges/importer/source.py b/cartridges/importer/source.py
index b46f0dc..74ee37b 100644
--- a/cartridges/importer/source.py
+++ b/cartridges/importer/source.py
@@ -125,6 +125,8 @@ class URLExecutableSource(ExecutableFormatSource):
return "start " + self.url_format
case "linux":
return "xdg-open " + self.url_format
+ case "darwin":
+ return "open " + self.url_format
case other:
raise NotImplementedError(
f"No URL handler command available for {other}"
diff --git a/cartridges/importer/steam_source.py b/cartridges/importer/steam_source.py
index b3a1f99..4179784 100644
--- a/cartridges/importer/steam_source.py
+++ b/cartridges/importer/steam_source.py
@@ -112,7 +112,7 @@ class SteamLocations(NamedTuple):
class SteamSource(URLExecutableSource):
source_id = "steam"
name = _("Steam")
- available_on = {"linux", "win32"}
+ available_on = {"linux", "win32", "darwin"}
iterable_class = SteamSourceIterable
url_format = "steam://rungameid/{game_id}"
@@ -128,6 +128,7 @@ class SteamSource(URLExecutableSource):
shared.data_dir / "Steam",
shared.flatpak_dir / "com.valvesoftware.Steam" / "data" / "Steam",
shared.programfiles32_dir / "Steam",
+ shared.app_support_dir / "Steam",
),
paths={
"libraryfolders.vdf": LocationSubPath(
diff --git a/cartridges/main.py b/cartridges/main.py
index 7deb799..fac4549 100644
--- a/cartridges/main.py
+++ b/cartridges/main.py
@@ -24,6 +24,7 @@ import shlex
import sys
from time import time
from typing import Any, Optional
+from urllib.parse import quote
import gi
@@ -40,7 +41,7 @@ from cartridges.importer.bottles_source import BottlesSource
from cartridges.importer.desktop_source import DesktopSource
from cartridges.importer.flatpak_source import FlatpakSource
from cartridges.importer.heroic_source import HeroicSource
-from cartridges.importer.importer import Importer
+from cartridges.importer.importer import Importer # yo dawg
from cartridges.importer.itch_source import ItchSource
from cartridges.importer.legendary_source import LegendarySource
from cartridges.importer.lutris_source import LutrisSource
@@ -57,6 +58,12 @@ from cartridges.store.store import Store
from cartridges.utils.run_executable import run_executable
from cartridges.window import CartridgesWindow
+if sys.platform == "darwin":
+ from AppKit import NSApp # type: ignore
+ from PyObjCTools import AppHelper
+
+ from cartridges.application_delegate import ApplicationDelegate
+
class CartridgesApplication(Adw.Application):
state = shared.AppState.DEFAULT
@@ -87,10 +94,28 @@ class CartridgesApplication(Adw.Application):
self.add_main_option_entries((search, launch))
+ if sys.platform == "darwin":
+ if settings := Gtk.Settings.get_default():
+ settings.props.gtk_decoration_layout = "close,minimize,maximize:"
+
+ def setup_app_delegate() -> None:
+ NSApp.setDelegate_(ApplicationDelegate.alloc().init()) # type: ignore
+ AppHelper.runEventLoop() # type: ignore
+
+ GLib.Thread.new(None, setup_app_delegate)
+
def do_activate(self) -> None: # pylint: disable=arguments-differ
"""Called on app creation"""
- setup_logging()
+ if os.getenv("XDG_CURRENT_DESKOP") == "COSMIC":
+ Gio.AppInfo.launch_default_for_uri("https://stopthemingmy.app")
+ self.quit()
+
+ try:
+ setup_logging()
+ except ValueError:
+ pass
+
log_system_info()
# Set fallback icon-name
@@ -280,7 +305,7 @@ class CartridgesApplication(Adw.Application):
_parameter: Any = None,
page_name: Optional[str] = None,
expander_row: Optional[str] = None,
- ) -> CartridgesWindow:
+ ) -> Optional[CartridgesPreferences]:
if CartridgesPreferences.is_open:
return
@@ -303,6 +328,9 @@ class CartridgesApplication(Adw.Application):
DetailsDialog(shared.win.active_game).present(shared.win)
def on_add_game_action(self, *_args: Any) -> None:
+ if DetailsDialog.is_open:
+ return
+
DetailsDialog().present(shared.win)
def on_import_action(self, *_args: Any) -> None:
@@ -345,7 +373,7 @@ class CartridgesApplication(Adw.Application):
self.on_remove_game_action()
def search(self, uri: str) -> None:
- Gio.AppInfo.launch_default_for_uri(f"{uri}{shared.win.active_game.name}")
+ Gio.AppInfo.launch_default_for_uri(f"{uri}{quote(shared.win.active_game.name)}")
def on_igdb_search_action(self, *_args: Any) -> None:
self.search("https://www.igdb.com/search?type=1&q=")
@@ -375,7 +403,11 @@ class CartridgesApplication(Adw.Application):
if action[1:2]:
self.set_accels_for_action(
f"app.{action[0]}" if scope == self else f"win.{action[0]}",
- action[1],
+ (
+ tuple(s.replace("", "") for s in action[1])
+ if sys.platform == "darwin"
+ else action[1]
+ ),
)
scope.add_action(simple_action)
diff --git a/cartridges/meson.build b/cartridges/meson.build
index 61da5c3..ee10a4f 100644
--- a/cartridges/meson.build
+++ b/cartridges/meson.build
@@ -1,11 +1,11 @@
-moduledir = join_paths(python_dir, 'cartridges')
+moduledir = python_dir / 'cartridges'
configure_file(
input: 'cartridges.in',
output: 'cartridges',
configuration: conf,
install: true,
- install_dir: get_option('bindir')
+ install_dir: get_option('bindir'),
)
install_subdir('importer', install_dir: moduledir)
@@ -15,17 +15,14 @@ install_subdir('logging', install_dir: moduledir)
install_subdir('errors', install_dir: moduledir)
install_data(
[
+ 'application_delegate.py',
'main.py',
'window.py',
'preferences.py',
'details_dialog.py',
'game.py',
'game_cover.py',
- configure_file(
- input: 'shared.py.in',
- output: 'shared.py',
- configuration: conf
- )
+ configure_file(input: 'shared.py.in', output: 'shared.py', configuration: conf),
],
- install_dir: moduledir
+ install_dir: moduledir,
)
diff --git a/cartridges/preferences.py b/cartridges/preferences.py
index ba1f85c..857efc6 100644
--- a/cartridges/preferences.py
+++ b/cartridges/preferences.py
@@ -17,6 +17,8 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
+# pyright: reportAssignmentType=none
+
import logging
import re
from pathlib import Path
@@ -30,6 +32,7 @@ from cartridges import shared
from cartridges.errors.friendly_error import FriendlyError
from cartridges.game import Game
from cartridges.importer.bottles_source import BottlesSource
+from cartridges.importer.desktop_source import DesktopSource
from cartridges.importer.flatpak_source import FlatpakSource
from cartridges.importer.heroic_source import HeroicSource
from cartridges.importer.itch_source import ItchSource
@@ -47,69 +50,69 @@ from cartridges.utils.create_dialog import create_dialog
class CartridgesPreferences(Adw.PreferencesDialog):
__gtype_name__ = "CartridgesPreferences"
- general_page = Gtk.Template.Child()
- import_page = Gtk.Template.Child()
- sgdb_page = Gtk.Template.Child()
+ general_page: Adw.PreferencesPage = Gtk.Template.Child()
+ import_page: Adw.PreferencesPage = Gtk.Template.Child()
+ sgdb_page: Adw.PreferencesPage = Gtk.Template.Child()
- sources_group = Gtk.Template.Child()
+ sources_group: Adw.PreferencesGroup = Gtk.Template.Child()
- exit_after_launch_switch = Gtk.Template.Child()
- cover_launches_game_switch = Gtk.Template.Child()
- high_quality_images_switch = Gtk.Template.Child()
+ exit_after_launch_switch: Adw.SwitchRow = Gtk.Template.Child()
+ cover_launches_game_switch: Adw.SwitchRow = Gtk.Template.Child()
+ high_quality_images_switch: Adw.SwitchRow = Gtk.Template.Child()
- remove_missing_switch = Gtk.Template.Child()
+ remove_missing_switch: Adw.SwitchRow = Gtk.Template.Child()
- steam_expander_row = Gtk.Template.Child()
- steam_data_action_row = Gtk.Template.Child()
- steam_data_file_chooser_button = Gtk.Template.Child()
+ steam_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ steam_data_action_row: Adw.ActionRow = Gtk.Template.Child()
+ steam_data_file_chooser_button: Gtk.Button = Gtk.Template.Child()
- lutris_expander_row = Gtk.Template.Child()
- lutris_data_action_row = Gtk.Template.Child()
- lutris_data_file_chooser_button = Gtk.Template.Child()
- lutris_import_steam_switch = Gtk.Template.Child()
- lutris_import_flatpak_switch = Gtk.Template.Child()
+ lutris_expander_row: Adw.ExpanderRowClass = Gtk.Template.Child()
+ lutris_data_action_row: Adw.ActionRow = Gtk.Template.Child()
+ lutris_data_file_chooser_button: Gtk.Button = Gtk.Template.Child()
+ lutris_import_steam_switch: Adw.SwitchRow = Gtk.Template.Child()
+ lutris_import_flatpak_switch: Adw.SwitchRow = Gtk.Template.Child()
- heroic_expander_row = Gtk.Template.Child()
- heroic_config_action_row = Gtk.Template.Child()
- heroic_config_file_chooser_button = Gtk.Template.Child()
- heroic_import_epic_switch = Gtk.Template.Child()
- heroic_import_gog_switch = Gtk.Template.Child()
- heroic_import_amazon_switch = Gtk.Template.Child()
- heroic_import_sideload_switch = Gtk.Template.Child()
+ heroic_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ heroic_config_action_row: Adw.ActionRow = Gtk.Template.Child()
+ heroic_config_file_chooser_button: Gtk.Button = Gtk.Template.Child()
+ heroic_import_epic_switch: Adw.SwitchRow = Gtk.Template.Child()
+ heroic_import_gog_switch: Adw.SwitchRow = Gtk.Template.Child()
+ heroic_import_amazon_switch: Adw.SwitchRow = Gtk.Template.Child()
+ heroic_import_sideload_switch: Adw.SwitchRow = Gtk.Template.Child()
- bottles_expander_row = Gtk.Template.Child()
- bottles_data_action_row = Gtk.Template.Child()
- bottles_data_file_chooser_button = Gtk.Template.Child()
+ bottles_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ bottles_data_action_row: Adw.ActionRow = Gtk.Template.Child()
+ bottles_data_file_chooser_button: Gtk.Button = Gtk.Template.Child()
- itch_expander_row = Gtk.Template.Child()
- itch_config_action_row = Gtk.Template.Child()
- itch_config_file_chooser_button = Gtk.Template.Child()
+ itch_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ itch_config_action_row: Adw.ActionRow = Gtk.Template.Child()
+ itch_config_file_chooser_button: Gtk.Button = Gtk.Template.Child()
- legendary_expander_row = Gtk.Template.Child()
- legendary_config_action_row = Gtk.Template.Child()
- legendary_config_file_chooser_button = Gtk.Template.Child()
+ legendary_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ legendary_config_action_row: Adw.ActionRow = Gtk.Template.Child()
+ legendary_config_file_chooser_button: Gtk.Button = Gtk.Template.Child()
- retroarch_expander_row = Gtk.Template.Child()
- retroarch_config_action_row = Gtk.Template.Child()
- retroarch_config_file_chooser_button = Gtk.Template.Child()
+ retroarch_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ retroarch_config_action_row: Adw.ActionRow = Gtk.Template.Child()
+ retroarch_config_file_chooser_button: Gtk.Button = Gtk.Template.Child()
- flatpak_expander_row = Gtk.Template.Child()
- flatpak_system_data_action_row = Gtk.Template.Child()
- flatpak_system_data_file_chooser_button = Gtk.Template.Child()
- flatpak_user_data_action_row = Gtk.Template.Child()
- flatpak_user_data_file_chooser_button = Gtk.Template.Child()
- flatpak_import_launchers_switch = Gtk.Template.Child()
+ flatpak_expander_row: Adw.ExpanderRow = Gtk.Template.Child()
+ flatpak_system_data_action_row: Adw.ActionRow = Gtk.Template.Child()
+ flatpak_system_data_file_chooser_button: Gtk.Button = Gtk.Template.Child()
+ flatpak_user_data_action_row: Adw.ActionRow = Gtk.Template.Child()
+ flatpak_user_data_file_chooser_button: Gtk.Button = Gtk.Template.Child()
+ flatpak_import_launchers_switch: Adw.SwitchRow = Gtk.Template.Child()
- desktop_switch = Gtk.Template.Child()
+ desktop_switch: Adw.SwitchRow = Gtk.Template.Child()
- sgdb_key_group = Gtk.Template.Child()
- sgdb_key_entry_row = Gtk.Template.Child()
- sgdb_switch = Gtk.Template.Child()
- sgdb_prefer_switch = Gtk.Template.Child()
- sgdb_animated_switch = Gtk.Template.Child()
- sgdb_fetch_button = Gtk.Template.Child()
- sgdb_stack = Gtk.Template.Child()
- sgdb_spinner = Gtk.Template.Child()
+ sgdb_key_group: Adw.PreferencesGroup = Gtk.Template.Child()
+ sgdb_key_entry_row: Adw.EntryRow = Gtk.Template.Child()
+ sgdb_switch: Adw.SwitchRow = Gtk.Template.Child()
+ sgdb_prefer_switch: Adw.SwitchRow = Gtk.Template.Child()
+ sgdb_animated_switch: Adw.SwitchRow = Gtk.Template.Child()
+ sgdb_fetch_button: Gtk.Button = Gtk.Template.Child()
+ sgdb_stack: Gtk.Stack = Gtk.Template.Child()
+ sgdb_spinner: Gtk.Spinner = Gtk.Template.Child()
danger_zone_group = Gtk.Template.Child()
remove_all_games_button_row = Gtk.Template.Child()
@@ -168,6 +171,10 @@ class CartridgesPreferences(Adw.PreferencesDialog):
else:
self.init_source_row(source)
+ # Special case for the desktop source
+ if not DesktopSource().is_available:
+ self.desktop_switch.set_visible(False)
+
# SteamGridDB
def sgdb_key_changed(*_args: Any) -> None:
shared.schema.set_string("sgdb-key", self.sgdb_key_entry_row.get_text())
@@ -274,7 +281,7 @@ class CartridgesPreferences(Adw.PreferencesDialog):
) -> None:
self.file_chooser.select_folder(shared.win, None, callback, callback_data)
- def undo_remove_all(self, *_args: Any) -> None:
+ def undo_remove_all(self, *_args: Any) -> bool:
shared.win.get_application().state = shared.AppState.UNDO_REMOVE_ALL_GAMES
for game in self.removed_games:
game.removed = False
@@ -286,6 +293,8 @@ class CartridgesPreferences(Adw.PreferencesDialog):
shared.win.get_application().state = shared.AppState.DEFAULT
shared.win.create_source_rows()
+ return True
+
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())
diff --git a/cartridges/shared.py.in b/cartridges/shared.py.in
index 44852f8..d29f7bf 100644
--- a/cartridges/shared.py.in
+++ b/cartridges/shared.py.in
@@ -64,6 +64,8 @@ local_appdata_dir = Path(
)
programfiles32_dir = Path(getenv("programfiles(x86)") or r"C:\Program Files (x86)")
+app_support_dir = home / "Library" / "Application Support"
+
try:
scale_factor = max(
monitor.get_scale_factor()
@@ -79,4 +81,4 @@ win = None
importer = None
import_time = None
store = None
-log_files = None
+log_files = []
diff --git a/cartridges/shared.pyi b/cartridges/shared.pyi
new file mode 100644
index 0000000..f6e8721
--- /dev/null
+++ b/cartridges/shared.pyi
@@ -0,0 +1,78 @@
+# shared.pyi
+#
+# Copyright 2024 kramo
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see .
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+
+from pathlib import Path
+from typing import Optional
+
+from gi.repository import Gio
+
+from cartridges.importer.importer import Importer
+from cartridges.store.store import Store
+from cartridges.window import CartridgesWindow
+
+
+class AppState:
+ DEFAULT: int
+ LOAD_FROM_DISK: int
+ IMPORT: int
+ REMOVE_ALL_GAMES: int
+ UNDO_REMOVE_ALL_GAMES: int
+
+
+APP_ID: str
+VERSION: str
+PREFIX: str
+PROFILE: str
+TIFF_COMPRESSION: str
+SPEC_VERSION: float
+
+schema: Gio.Settings
+state_schema: Gio.Settings
+
+home: Path
+
+data_dir: Path
+host_data_dir: Path
+
+config_dir: Path
+host_config_dir: Path
+
+cache_dir: Path
+host_cache_dir: Path
+
+flatpak_dir: Path
+
+games_dir: Path
+covers_dir: Path
+
+appdata_dir: Path
+local_appdata_dir: Path
+programfiles32_dir: Path
+
+app_support_dir: Path
+
+
+scale_factor: int
+image_size: int
+
+win: Optional[CartridgesWindow]
+importer: Optional[Importer]
+import_time: Optional[int]
+store = Optional[Store]
+log_files: list[Path]
diff --git a/cartridges/store/managers/steam_api_manager.py b/cartridges/store/managers/steam_api_manager.py
index 77656be..6cc2a0d 100644
--- a/cartridges/store/managers/steam_api_manager.py
+++ b/cartridges/store/managers/steam_api_manager.py
@@ -48,16 +48,10 @@ class SteamAPIManager(AsyncManager):
appid = additional_data.get("steam_appid", None)
if appid is None:
return
-
# Get online metadata
try:
online_data = self.steam_api_helper.get_api_data(appid=appid)
-
- except SteamGameNotFoundError:
- return
-
- except SteamNotAGameError:
+ except (SteamNotAGameError, SteamGameNotFoundError):
game.update_values({"blacklisted": True})
-
else:
game.update_values(online_data)
diff --git a/cartridges/utils/create_dialog.py b/cartridges/utils/create_dialog.py
index 2ff6495..ae213d3 100644
--- a/cartridges/utils/create_dialog.py
+++ b/cartridges/utils/create_dialog.py
@@ -33,7 +33,7 @@ def create_dialog(
dialog.add_response("dismiss", _("Dismiss"))
if extra_option:
- dialog.add_response(extra_option, _(extra_label))
+ dialog.add_response(extra_option, extra_label or "")
dialog.choose(win)
return dialog
diff --git a/cartridges/window.py b/cartridges/window.py
index 1fb9553..4adebc1 100644
--- a/cartridges/window.py
+++ b/cartridges/window.py
@@ -17,9 +17,12 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later
+# pyright: reportAssignmentType=none
+
+from sys import platform
from typing import Any, Optional
-from gi.repository import Adw, Gio, GLib, Gtk
+from gi.repository import Adw, Gio, GLib, Gtk, Pango
from cartridges import shared
from cartridges.game import Game
@@ -31,51 +34,52 @@ from cartridges.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()
- 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_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()
+ overlay_split_view: Adw.OverlaySplitView = Gtk.Template.Child()
+ navigation_view: Adw.NavigationView = Gtk.Template.Child()
+ sidebar_navigation_page: Adw.NavigationPage = Gtk.Template.Child()
+ sidebar: Gtk.ListBox = Gtk.Template.Child()
+ all_games_row_box: Gtk.Box = Gtk.Template.Child()
+ all_games_no_label: Gtk.Label = Gtk.Template.Child()
+ added_row_box: Gtk.Box = Gtk.Template.Child()
+ added_games_no_label: Gtk.Label = Gtk.Template.Child()
+ toast_overlay: Adw.ToastOverlay = Gtk.Template.Child()
+ primary_menu_button: Gtk.MenuButton = Gtk.Template.Child()
+ show_sidebar_button: Gtk.Button = Gtk.Template.Child()
+ details_view: Gtk.Overlay = Gtk.Template.Child()
+ library_page: Adw.NavigationPage = Gtk.Template.Child()
+ library_view: Adw.ToolbarView = Gtk.Template.Child()
+ library: Gtk.FlowBox = Gtk.Template.Child()
+ scrolledwindow: Gtk.ScrolledWindow = Gtk.Template.Child()
+ library_overlay: Gtk.Overlay = Gtk.Template.Child()
+ notice_empty: Adw.StatusPage = Gtk.Template.Child()
+ notice_no_results: Adw.StatusPage = Gtk.Template.Child()
+ search_bar: Gtk.SearchBar = Gtk.Template.Child()
+ search_entry: Gtk.SearchEntry = Gtk.Template.Child()
+ search_button: Gtk.ToggleButton = 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_blurred_cover = Gtk.Template.Child()
- details_view_play_button = Gtk.Template.Child()
- details_view_developer = Gtk.Template.Child()
- details_view_added = Gtk.Template.Child()
- details_view_last_played = Gtk.Template.Child()
- details_view_hide_button = Gtk.Template.Child()
+ details_page: Adw.NavigationPage = Gtk.Template.Child()
+ details_view_toolbar_view: Adw.ToolbarView = Gtk.Template.Child()
+ details_view_cover: Gtk.Picture = Gtk.Template.Child()
+ details_view_spinner: Gtk.Spinner = Gtk.Template.Child()
+ details_view_title: Gtk.Label = Gtk.Template.Child()
+ details_view_blurred_cover: Gtk.Picture = Gtk.Template.Child()
+ details_view_play_button: Gtk.Button = Gtk.Template.Child()
+ details_view_developer: Gtk.Label = Gtk.Template.Child()
+ details_view_added: Gtk.ShortcutLabel = Gtk.Template.Child()
+ details_view_last_played: Gtk.Label = Gtk.Template.Child()
+ details_view_hide_button: Gtk.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_overlay = Gtk.Template.Child()
- hidden_notice_empty = Gtk.Template.Child()
- hidden_notice_no_results = Gtk.Template.Child()
- hidden_search_bar = Gtk.Template.Child()
- hidden_search_entry = Gtk.Template.Child()
- hidden_search_button = Gtk.Template.Child()
+ hidden_library_page: Adw.NavigationPage = Gtk.Template.Child()
+ hidden_primary_menu_button: Gtk.MenuButton = Gtk.Template.Child()
+ hidden_library: Gtk.FlowBox = Gtk.Template.Child()
+ hidden_library_view: Adw.ToolbarView = Gtk.Template.Child()
+ hidden_scrolledwindow: Gtk.ScrolledWindow = Gtk.Template.Child()
+ hidden_library_overlay: Gtk.Overlay = Gtk.Template.Child()
+ hidden_notice_empty: Adw.StatusPage = Gtk.Template.Child()
+ hidden_notice_no_results: Adw.StatusPage = Gtk.Template.Child()
+ hidden_search_bar: Gtk.SearchBar = Gtk.Template.Child()
+ hidden_search_entry: Gtk.SearchEntry = Gtk.Template.Child()
+ hidden_search_button: Gtk.ToggleButton = Gtk.Template.Child()
game_covers: dict = {}
toasts: dict = {}
@@ -152,6 +156,8 @@ class CartridgesWindow(Adw.ApplicationWindow):
Gtk.Label(
label=self.get_application().get_source_name(source_id),
halign=Gtk.Align.START,
+ wrap=True,
+ wrap_mode=Pango.WrapMode.CHAR,
)
)
@@ -213,6 +219,9 @@ class CartridgesWindow(Adw.ApplicationWindow):
def __init__(self, **kwargs: Any) -> None:
super().__init__(**kwargs)
+ if platform == "darwin":
+ self.sidebar_navigation_page.set_title("")
+
self.details_view.set_measure_overlay(self.details_view_toolbar_view, True)
self.details_view.set_clip_overlay(self.details_view_toolbar_view, False)
@@ -443,6 +452,9 @@ class CartridgesWindow(Adw.ApplicationWindow):
self.navigation_view.pop_to_page(self.library_page)
def on_show_hidden_action(self, *_args: Any) -> None:
+ if self.navigation_view.get_visible_page() == self.hidden_library_page:
+ return
+
self.navigation_view.push(self.hidden_library_page)
def on_sort_action(self, action: Gio.SimpleAction, state: GLib.Variant) -> None:
diff --git a/data/gtk/window.blp b/data/gtk/window.blp
index f9351df..47b66cd 100644
--- a/data/gtk/window.blp
+++ b/data/gtk/window.blp
@@ -79,7 +79,7 @@ template $CartridgesWindow: Adw.ApplicationWindow {
sidebar-width-fraction: .2;
[sidebar]
- Adw.NavigationPage {
+ Adw.NavigationPage sidebar_navigation_page {
title: _("Cartridges");
Adw.ToolbarView {
@@ -94,6 +94,8 @@ template $CartridgesWindow: Adw.ApplicationWindow {
}
ScrolledWindow {
+ hscrollbar-policy: never;
+
ListBox sidebar {
Box all_games_row_box {
margin-top: 12;
@@ -109,6 +111,8 @@ template $CartridgesWindow: Adw.ApplicationWindow {
Label {
halign: start;
label: _("All Games");
+ wrap: true;
+ wrap-mode: char;
}
Label all_games_no_label {
@@ -135,6 +139,8 @@ template $CartridgesWindow: Adw.ApplicationWindow {
halign: start;
label: _("Added");
margin-end: 6;
+ wrap: true;
+ wrap-mode: char;
}
Label added_games_no_label {
@@ -175,15 +181,11 @@ template $CartridgesWindow: Adw.ApplicationWindow {
[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");
- }
+ Button show_sidebar_button {
+ icon-name: "sidebar-show-symbolic";
+ action-name: "win.show_sidebar";
+ tooltip-text: _("Toggle Sidebar");
+ visible: bind overlay_split_view.show-sidebar inverted;
}
[start]
diff --git a/data/icons/meson.build b/data/icons/meson.build
index 3d42f8d..88cb576 100644
--- a/data/icons/meson.build
+++ b/data/icons/meson.build
@@ -1,11 +1,11 @@
scalable_dir = join_paths('hicolor', 'scalable', 'apps')
install_data(
join_paths(scalable_dir, ('@0@.svg').format(app_id)),
- install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir)
+ install_dir: join_paths(get_option('datadir'), 'icons', scalable_dir),
)
symbolic_dir = join_paths('hicolor', 'symbolic', 'apps')
install_data(
join_paths(symbolic_dir, ('@0@-symbolic.svg').format(app_id)),
- install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir)
+ install_dir: join_paths(get_option('datadir'), 'icons', symbolic_dir),
)
diff --git a/data/meson.build b/data/meson.build
index 7a467b1..170bed8 100644
--- a/data/meson.build
+++ b/data/meson.build
@@ -1,20 +1,28 @@
-blueprints = custom_target('blueprints',
+blueprints = custom_target(
+ 'blueprints',
input: files(
- 'gtk/help-overlay.blp',
- 'gtk/window.blp',
+ 'gtk/details-dialog.blp',
'gtk/game.blp',
+ 'gtk/help-overlay.blp',
'gtk/preferences.blp',
- 'gtk/details-dialog.blp'
+ 'gtk/window.blp',
),
output: '.',
- command: [find_program('blueprint-compiler'), 'batch-compile', '@OUTPUT@', '@CURRENT_SOURCE_DIR@', '@INPUT@'],
+ command: [
+ find_program('blueprint-compiler'),
+ 'batch-compile',
+ '@OUTPUT@',
+ '@CURRENT_SOURCE_DIR@',
+ '@INPUT@',
+ ],
)
-gnome.compile_resources('cartridges',
+gnome.compile_resources(
+ 'cartridges',
configure_file(
input: 'cartridges.gresource.xml.in',
output: 'cartridges.gresource.xml',
- configuration: conf
+ configuration: conf,
),
gresource_bundle: true,
install: true,
@@ -22,27 +30,26 @@ gnome.compile_resources('cartridges',
dependencies: blueprints,
)
-
if host_machine.system() == 'windows'
desktop_file = configure_file(
input: 'page.kramo.Cartridges.desktop.in',
output: app_id + '.desktop.in',
configuration: conf,
install: true,
- install_dir: join_paths(get_option('datadir'), 'applications')
+ install_dir: join_paths(get_option('datadir'), 'applications'),
)
else
desktop_file = i18n.merge_file(
input: configure_file(
input: 'page.kramo.Cartridges.desktop.in',
output: app_id + '.desktop.in',
- configuration: conf
+ configuration: conf,
),
output: app_id + '.desktop',
type: 'desktop',
po_dir: '../po',
install: true,
- install_dir: join_paths(get_option('datadir'), 'applications')
+ install_dir: join_paths(get_option('datadir'), 'applications'),
)
endif
@@ -59,29 +66,30 @@ if host_machine.system() == 'windows'
output: app_id + '.metainfo.xml',
configuration: conf,
install: true,
- install_dir: join_paths(get_option('datadir'), 'metainfo')
+ install_dir: join_paths(get_option('datadir'), 'metainfo'),
)
else
appstream_file = i18n.merge_file(
input: configure_file(
input: 'page.kramo.Cartridges.metainfo.xml.in',
output: app_id + '.metainfo.xml.in',
- configuration: conf
+ configuration: conf,
),
output: app_id + '.metainfo.xml',
po_dir: '../po',
install: true,
- install_dir: join_paths(get_option('datadir'), 'metainfo')
+ install_dir: join_paths(get_option('datadir'), 'metainfo'),
)
endif
if host_machine.system() != 'windows'
appstreamcli = find_program('appstreamcli', required: false)
if appstreamcli.found()
- test('Validate appstream file',
+ test(
+ 'Validate appstream file',
appstreamcli,
args: ['validate', '--no-net', '--explain', appstream_file],
- workdir: meson.current_build_dir()
+ workdir: meson.current_build_dir(),
)
endif
endif
@@ -90,16 +98,18 @@ install_data(
configure_file(
input: 'page.kramo.Cartridges.gschema.xml.in',
output: app_id + '.gschema.xml',
- configuration: conf
+ configuration: conf,
),
- install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas')
+ install_dir: join_paths(get_option('datadir'), 'glib-2.0/schemas'),
)
compile_schemas = find_program('glib-compile-schemas', required: false)
if compile_schemas.found()
- test('Validate schema file',
- compile_schemas,
- args: ['--strict', '--dry-run', meson.current_source_dir()])
+ test(
+ 'Validate schema file',
+ compile_schemas,
+ args: ['--strict', '--dry-run', meson.current_source_dir()],
+ )
endif
subdir('icons')
diff --git a/data/page.kramo.Cartridges.metainfo.xml.in b/data/page.kramo.Cartridges.metainfo.xml.in
index 53c8809..ba4e6d8 100644
--- a/data/page.kramo.Cartridges.metainfo.xml.in
+++ b/data/page.kramo.Cartridges.metainfo.xml.in
@@ -31,9 +31,9 @@
keyboard
touch
-
+
360
-
+
https://raw.githubusercontent.com/kra-mo/cartridges/main/data/screenshots/1.png
@@ -54,12 +54,18 @@
-
+
- - Fixed an issue with the import dialog not closing
- - Fixed an issue with Lutris games not importing
- - Cartrdiges builds are available for Windows again!
+ - Fixed incorrect modifiers being used for keyboard shortcuts
+
+
+
+
+
+
+ - Cartridges is now available on macOS! You can download it from GitHub.
+ - Updated translations
diff --git a/docs/game_id.json.md b/docs/game_id.json.md
index a886bf0..fd21d69 100644
--- a/docs/game_id.json.md
+++ b/docs/game_id.json.md
@@ -35,7 +35,7 @@ Stored as a Unix time stamp.
The executable to run when launching a game.
-If the source has a URL handler, using that is preferred. In that case, the value should be `"xdg-open url://example/url"` for Linux and `"start url://example/url"` for Windows.
+If the source has a URL handler, using that is preferred. In that case, the value should be `"xdg-open url://example/url"` for Linux, `"start url://example/url"` for Windows and `"open url://example/url"` for macOS.
Stored as either a string (preferred) or an argument vector to be passed to the shell through [subprocess.Popen](https://docs.python.org/3/library/subprocess.html#popen-constructor).
@@ -113,4 +113,4 @@ The version number of the [game_id].json specification.
Cartridges will set the value for itself. Don't touch it.
-Stored as a number.
\ No newline at end of file
+Stored as a number.
diff --git a/meson.build b/meson.build
index 9879fb6..cc1d965 100644
--- a/meson.build
+++ b/meson.build
@@ -1,7 +1,11 @@
-project('cartridges',
- version: '2.8.3',
- meson_version: '>= 0.59.0',
- default_options: [ 'warning_level=2', 'werror=false', ],
+project(
+ 'cartridges',
+ version: '2.9.3',
+ meson_version: '>= 0.59.0',
+ default_options: [
+ 'warning_level=2',
+ 'werror=false',
+ ],
)
# Translations are broken on Windows for multiple reasons
@@ -23,7 +27,7 @@ profile = get_option('profile')
if profile == 'development'
app_id = 'page.kramo.Cartridges.Devel'
prefix = '/page/kramo/Cartridges/Devel'
-elif profile == 'release'
+elif profile == 'release'
app_id = 'page.kramo.Cartridges'
prefix = '/page/kramo/Cartridges'
endif
@@ -44,14 +48,14 @@ subdir('data')
subdir('cartridges')
if host_machine.system() == 'windows'
- subdir('windows')
+ subdir('build-aux/windows')
else
subdir('search-provider')
subdir('po')
endif
gnome.post_install(
- glib_compile_schemas: true,
- gtk_update_icon_cache: true,
+ glib_compile_schemas: true,
+ gtk_update_icon_cache: true,
update_desktop_database: true,
)
diff --git a/po/cs.po b/po/cs.po
index 859a3bb..a92f74a 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -1,13 +1,13 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR kramo
# This file is distributed under the same license as the Cartridges package.
-# foo expert , 2023.
+# foo expert , 2023, 2024.
msgid ""
msgstr ""
"Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-14 12:48+0200\n"
-"PO-Revision-Date: 2023-09-24 16:04+0000\n"
+"PO-Revision-Date: 2024-06-28 07:09+0000\n"
"Last-Translator: foo expert \n"
"Language-Team: Czech \n"
@@ -15,8 +15,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
-"X-Generator: Weblate 5.1-dev\n"
+"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n"
+"X-Generator: Weblate 5.7-dev\n"
#: data/page.kramo.Cartridges.desktop.in:3
#: data/page.kramo.Cartridges.metainfo.xml.in:9
@@ -276,15 +276,13 @@ msgstr "Flatpak"
#. The location of the system-wide data directory
#: data/gtk/preferences.blp:351
-#, fuzzy
msgid "System Location"
-msgstr "Nastavit umístění"
+msgstr "Systémové umístění"
#. The location of the user-specific data directory
#: data/gtk/preferences.blp:369
-#, fuzzy
msgid "User Location"
-msgstr "Nastavit umístění"
+msgstr "Uživatelské umístění"
#: data/gtk/preferences.blp:386
msgid "Import Game Launchers"
@@ -323,17 +321,16 @@ msgid "Prefer Animated Images"
msgstr "Upřednostnit animované obrázky"
#: data/gtk/preferences.blp:433
-#, fuzzy
msgid "Update Covers"
-msgstr "Odstranit obal"
+msgstr "Aktualizovat obálky"
#: data/gtk/preferences.blp:434
msgid "Fetch covers for games already in your library"
-msgstr ""
+msgstr "Najít obálky pro hry ve vaší knihovně"
#: data/gtk/preferences.blp:439
msgid "Update"
-msgstr ""
+msgstr "Aktualizovat"
#: data/gtk/window.blp:6 data/gtk/window.blp:14
msgid "No Games Found"
@@ -417,15 +414,15 @@ msgstr "O Kazetách"
#: data/gtk/window.blp:561
msgid "IGDB"
-msgstr ""
+msgstr "IGDB"
#: data/gtk/window.blp:563
msgid "ProtonDB"
-msgstr ""
+msgstr "ProtonDB"
#: data/gtk/window.blp:565
msgid "HowLongToBeat"
-msgstr ""
+msgstr "HowLongToBeat"
#. The variable is the title of the game
#: cartridges/main.py:205 cartridges/game.py:125
@@ -553,11 +550,11 @@ msgstr ""
#: cartridges/preferences.py:196
msgid "Downloading covers…"
-msgstr ""
+msgstr "Stahování obálek…"
#: cartridges/preferences.py:215
msgid "Covers updated"
-msgstr ""
+msgstr "Obálky aktualizovány"
#: cartridges/preferences.py:360
msgid "Installation Not Found"
diff --git a/po/fa.po b/po/fa.po
index ed4d7ef..2890b68 100644
--- a/po/fa.po
+++ b/po/fa.po
@@ -3,13 +3,14 @@
# This file is distributed under the same license as the Cartridges package.
# سید حسین موسوی فرد , 2023.
# Danial Behzadi , 2023.
+# آوید , 2024.
msgid ""
msgstr ""
"Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-14 12:48+0200\n"
-"PO-Revision-Date: 2023-09-24 16:04+0000\n"
-"Last-Translator: Danial Behzadi \n"
+"PO-Revision-Date: 2024-07-14 20:09+0000\n"
+"Last-Translator: آوید \n"
"Language-Team: Persian \n"
"Language: fa\n"
@@ -17,7 +18,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 5.1-dev\n"
+"X-Generator: Weblate 5.7-dev\n"
#: data/page.kramo.Cartridges.desktop.in:3
#: data/page.kramo.Cartridges.metainfo.xml.in:9
@@ -74,7 +75,7 @@ msgstr "لغو"
#: data/gtk/details-dialog.blp:46
msgid "New Cover"
-msgstr "طرج جلد جدید"
+msgstr "طرح جلد جدید"
#: data/gtk/details-dialog.blp:65
msgid "Delete Cover"
@@ -98,7 +99,7 @@ msgstr "گزینش پرونده"
#: data/gtk/details-dialog.blp:120
msgid "More Info"
-msgstr "اطّلاعات بیشتر"
+msgstr "اطلاعات بیشتر"
#: data/gtk/game.blp:102 data/gtk/game.blp:110 data/gtk/window.blp:443
msgid "Edit"
@@ -127,7 +128,7 @@ msgstr "جستوجو"
#: data/gtk/help-overlay.blp:24 data/gtk/window.blp:543
msgid "Keyboard Shortcuts"
-msgstr "میانبرهیا صفحهکلید"
+msgstr "میانبرهای صفحهکلید"
#: data/gtk/help-overlay.blp:29 cartridges/game.py:103
#: cartridges/preferences.py:134 cartridges/importer/importer.py:394
@@ -182,7 +183,7 @@ msgstr "طرح جلد بازی را اجرا میکند"
#: data/gtk/preferences.blp:21
msgid "Swaps the behavior of the cover image and the play button"
-msgstr "تعویض رفتار تصویر جلد و دکمهٔ بازی کردن"
+msgstr "تغییر رفتار تصویر جلد و دکمهٔ بازی کردن"
#: data/gtk/preferences.blp:26 cartridges/details_dialog.py:82
msgid "Images"
@@ -194,7 +195,7 @@ msgstr "عکسهای با کیفیت بالا"
#: data/gtk/preferences.blp:30
msgid "Save game covers losslessly at the cost of storage"
-msgstr "ذخیرهٔ طرح جلدهای بدون اتلاف به فیمت ذخیرهسازی"
+msgstr "ذخیرهٔ طرح جلدهای بدون اتلاف به قیمت ذخیرهسازی"
#: data/gtk/preferences.blp:35
msgid "Danger Zone"
@@ -206,7 +207,7 @@ msgstr "حذف کردن همهٔ بازیها"
#: data/gtk/preferences.blp:120
msgid "Remove Uninstalled Games"
-msgstr "برداشن بازیهای نصب نشده"
+msgstr "برداشتن بازیهای نصبنشده"
#: data/gtk/preferences.blp:125
msgid "Sources"
@@ -254,7 +255,7 @@ msgstr "درونریزی بازیهای آمازون"
#: data/gtk/preferences.blp:228
msgid "Import Sideloaded Games"
-msgstr "درونریزی بازیهای نصب شده"
+msgstr "درونریزی بازیهای نصبشده"
#: data/gtk/preferences.blp:233 cartridges/importer/bottles_source.py:86
msgid "Bottles"
@@ -278,15 +279,13 @@ msgstr "فلتپک"
#. The location of the system-wide data directory
#: data/gtk/preferences.blp:351
-#, fuzzy
msgid "System Location"
-msgstr "تنظیم مکان"
+msgstr "مکان سامانه"
#. The location of the user-specific data directory
#: data/gtk/preferences.blp:369
-#, fuzzy
msgid "User Location"
-msgstr "تنظیم مکان"
+msgstr "مکان کاربر"
#: data/gtk/preferences.blp:386
msgid "Import Game Launchers"
@@ -322,20 +321,19 @@ msgstr "ترجیح به تصویرهای رسمی"
#: data/gtk/preferences.blp:427
msgid "Prefer Animated Images"
-msgstr "ترچیح تصویرهای پویا"
+msgstr "ترجیح تصویرهای پویا"
#: data/gtk/preferences.blp:433
-#, fuzzy
msgid "Update Covers"
-msgstr "حذف طرح جلد"
+msgstr "بهروزرسانی طرح جلد"
#: data/gtk/preferences.blp:434
msgid "Fetch covers for games already in your library"
-msgstr ""
+msgstr "دریافت طرح جلد بازیهای کنونی کتابخانهتان"
#: data/gtk/preferences.blp:439
msgid "Update"
-msgstr ""
+msgstr "بهروزرسانی"
#: data/gtk/window.blp:6 data/gtk/window.blp:14
msgid "No Games Found"
@@ -359,7 +357,7 @@ msgstr "بدون بازی نهفته"
#: data/gtk/window.blp:41
msgid "Games you hide will appear here"
-msgstr "بازیهایی که پنهان میکنید، اینجا ظاهر خواهند شد"
+msgstr "بازیهایی که پنهان میکنید، اینجا نمایان خواهند شد"
#: data/gtk/window.blp:76 data/gtk/window.blp:111 cartridges/main.py:228
msgid "All Games"
@@ -407,7 +405,7 @@ msgstr "قدیمیترین"
#: data/gtk/window.blp:528
msgid "Last Played"
-msgstr "آخرین بازی شده"
+msgstr "آخرین بازیشده"
#: data/gtk/window.blp:535
msgid "Show Hidden"
@@ -419,15 +417,15 @@ msgstr "دربارهٔ کارتریجها"
#: data/gtk/window.blp:561
msgid "IGDB"
-msgstr ""
+msgstr "IGDB"
#: data/gtk/window.blp:563
msgid "ProtonDB"
-msgstr ""
+msgstr "ProtonDB"
#: data/gtk/window.blp:565
msgid "HowLongToBeat"
-msgstr ""
+msgstr "HowLongToBeat"
#. The variable is the title of the game
#: cartridges/main.py:205 cartridges/game.py:125
@@ -451,7 +449,7 @@ msgstr "هرگز"
#. The variable is the date when the game was last played
#: cartridges/window.py:380
msgid "Last played: {}"
-msgstr "آخرین بازی شده: {}"
+msgstr "آخرین بازیشده: {}"
#: cartridges/details_dialog.py:73
msgid "Apply"
@@ -505,7 +503,7 @@ msgstr ""
"\n"
"\"{}\"\n"
"\n"
-"برای گشودن پروندهٔ {}با برنامهٔ پیشگزیده:\n"
+"برای گشودن پروندهٔ {} با برنامهٔ پیشگزیده:\n"
"\n"
"{} \"{}\"\n"
"\n"
@@ -530,7 +528,7 @@ msgstr "نتوانست ترجیحات را اعمال کند"
#. The variable is the title of the game
#: cartridges/game.py:139
msgid "{} hidden"
-msgstr "{}نهفته"
+msgstr "{} نهفته"
#: cartridges/game.py:139
msgid "{} unhidden"
@@ -555,11 +553,11 @@ msgstr ""
#: cartridges/preferences.py:196
msgid "Downloading covers…"
-msgstr ""
+msgstr "در حال دریافت طرحهای جلد…"
#: cartridges/preferences.py:215
msgid "Covers updated"
-msgstr ""
+msgstr "طرحهای جلد بهروزرسانی شد"
#: cartridges/preferences.py:360
msgid "Installation Not Found"
@@ -599,7 +597,7 @@ msgstr "هیچ بازی جدیدی پیدا نشد"
#: cartridges/importer/importer.py:379
msgid "1 game imported"
-msgstr "۱ بازی درونریخته شد"
+msgstr "یک بازی درونریخته شد"
#. The variable is the number of games
#: cartridges/importer/importer.py:383
diff --git a/po/hi.po b/po/hi.po
index abab0d4..8e60699 100644
--- a/po/hi.po
+++ b/po/hi.po
@@ -8,7 +8,7 @@ msgstr ""
"Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-14 12:48+0200\n"
-"PO-Revision-Date: 2024-03-27 19:15+0000\n"
+"PO-Revision-Date: 2024-05-07 09:07+0000\n"
"Last-Translator: Scrambled777 \n"
"Language-Team: Hindi \n"
@@ -17,7 +17,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 5.5-dev\n"
+"X-Generator: Weblate 5.5.4-dev\n"
#: data/page.kramo.Cartridges.desktop.in:3
#: data/page.kramo.Cartridges.metainfo.xml.in:9
@@ -65,7 +65,7 @@ msgstr "गेम विवरण संपादन"
#: data/gtk/window.blp:542 cartridges/details_dialog.py:267
#: cartridges/importer/importer.py:320 cartridges/importer/importer.py:370
msgid "Preferences"
-msgstr "प्राथमिकताएँ"
+msgstr "प्राथमिकताएं"
#: data/gtk/details-dialog.blp:15
msgid "Cancel"
@@ -77,7 +77,7 @@ msgstr "नया कवर"
#: data/gtk/details-dialog.blp:65
msgid "Delete Cover"
-msgstr "कवर हटाएँ"
+msgstr "कवर मिटाएं"
#: data/gtk/details-dialog.blp:93 data/gtk/game.blp:81
msgid "Title"
@@ -89,7 +89,7 @@ msgstr "विकासकर्ता (वैकल्पिक)"
#: data/gtk/details-dialog.blp:103
msgid "Executable"
-msgstr "एक्सेक्यूटेबल"
+msgstr "निष्पादनयोग्य"
#: data/gtk/details-dialog.blp:109
msgid "Select File"
@@ -109,15 +109,15 @@ msgstr "छुपाएं"
#: data/gtk/game.blp:104 data/gtk/game.blp:112 data/gtk/window.blp:463
msgid "Remove"
-msgstr "हटाएँ"
+msgstr "हटाएं"
#: data/gtk/game.blp:111 cartridges/window.py:352
msgid "Unhide"
-msgstr "सामने लाएँ"
+msgstr "सामने लाएं"
#: data/gtk/help-overlay.blp:11 data/gtk/preferences.blp:9
msgid "General"
-msgstr "जनरल"
+msgstr "सामान्य"
#: data/gtk/help-overlay.blp:14 data/gtk/window.blp:205 data/gtk/window.blp:221
#: data/gtk/window.blp:272 data/gtk/window.blp:288 data/gtk/window.blp:474
@@ -131,7 +131,7 @@ msgstr "कीबोर्ड शॉर्टकट"
#: data/gtk/help-overlay.blp:29 cartridges/game.py:103
#: cartridges/preferences.py:134 cartridges/importer/importer.py:394
msgid "Undo"
-msgstr "पूर्ववत"
+msgstr "पूर्ववत करें"
#: data/gtk/help-overlay.blp:34
msgid "Quit"
@@ -139,11 +139,11 @@ msgstr "छोड़ें"
#: data/gtk/help-overlay.blp:39 data/gtk/window.blp:92 data/gtk/window.blp:185
msgid "Toggle Sidebar"
-msgstr "साइडबार टॉगल करें"
+msgstr "पार्श्वपट्टी टॉगल करें"
#: data/gtk/help-overlay.blp:44 data/gtk/window.blp:198 data/gtk/window.blp:265
msgid "Main Menu"
-msgstr "मुख्य मेन्यू"
+msgstr "मुख्य मेनू"
#: data/gtk/help-overlay.blp:50
msgid "Games"
@@ -160,7 +160,7 @@ msgstr "आयात"
#: data/gtk/help-overlay.blp:63
msgid "Show Hidden Games"
-msgstr "छिपे हुए गेम्स दिखाएँ"
+msgstr "छिपे हुए गेम्स दिखाएं"
#: data/gtk/help-overlay.blp:68
msgid "Remove Game"
@@ -205,7 +205,7 @@ msgstr "सभी गेम्स हटाएं"
#: data/gtk/preferences.blp:120
msgid "Remove Uninstalled Games"
-msgstr "अनइंस्टॉल किए गए गेम्स हटाएं"
+msgstr "अस्थापित गेम्स हटाएं"
#: data/gtk/preferences.blp:125
msgid "Sources"
@@ -291,7 +291,7 @@ msgstr "गेम लॉन्चर आयात करें"
#: data/gtk/preferences.blp:391 cartridges/importer/desktop_source.py:215
msgid "Desktop Entries"
-msgstr "डेस्कटॉप प्रविष्टियाँ"
+msgstr "डेस्कटॉप प्रविष्टियां"
#: data/gtk/preferences.blp:403 data/gtk/window.blp:562
msgid "SteamGridDB"
@@ -319,11 +319,11 @@ msgstr "आधिकारिक छवियों से अधिक प्
#: data/gtk/preferences.blp:427
msgid "Prefer Animated Images"
-msgstr "एनिमेटेड छवियों को प्राथमिकता दें"
+msgstr "सजीव छवियों को प्राथमिकता दें"
#: data/gtk/preferences.blp:433
msgid "Update Covers"
-msgstr "कवर अपडेट करें"
+msgstr "कवर अद्यतन करें"
#: data/gtk/preferences.blp:434
msgid "Fetch covers for games already in your library"
@@ -331,7 +331,7 @@ msgstr "अपनी लाइब्रेरी में पहले से
#: data/gtk/preferences.blp:439
msgid "Update"
-msgstr "अपडेट"
+msgstr "अद्यतन"
#: data/gtk/window.blp:6 data/gtk/window.blp:14
msgid "No Games Found"
@@ -339,7 +339,7 @@ msgstr "कोई गेम नहीं मिला"
#: data/gtk/window.blp:7 data/gtk/window.blp:15
msgid "Try a different search"
-msgstr "कोई भिन्न खोज आज़माएँ।"
+msgstr "भिन्न खोज का प्रयास करें"
#: data/gtk/window.blp:21
msgid "No Games"
@@ -347,7 +347,7 @@ msgstr "कोई गेम नहीं"
#: data/gtk/window.blp:22
msgid "Use the + button to add games"
-msgstr "गेम जोड़ने के लिए + बटन का उपयोग करें।"
+msgstr "गेम जोड़ने के लिए + बटन का उपयोग करें"
#: data/gtk/window.blp:40
msgid "No Hidden Games"
@@ -355,7 +355,7 @@ msgstr "कोई छुपे गेम्स नहीं"
#: data/gtk/window.blp:41
msgid "Games you hide will appear here"
-msgstr "आपके द्वारा छिपाए गए गेम यहां दिखाई देंगे।"
+msgstr "आपके द्वारा छिपाए गए गेम यहां दिखाई देंगे"
#: data/gtk/window.blp:76 data/gtk/window.blp:111 cartridges/main.py:228
msgid "All Games"
@@ -407,7 +407,7 @@ msgstr "अंतिम बार खेला गया"
#: data/gtk/window.blp:535
msgid "Show Hidden"
-msgstr "छुपा हुआ दिखाए"
+msgstr "छुपे हुआ दिखाएं"
#: data/gtk/window.blp:544
msgid "About Cartridges"
@@ -451,7 +451,7 @@ msgstr "अंतिम बार खेला गया: {}"
#: cartridges/details_dialog.py:73
msgid "Apply"
-msgstr "लागू"
+msgstr "लागू करें"
#: cartridges/details_dialog.py:79
msgid "Add New Game"
@@ -463,7 +463,7 @@ msgstr "जोड़ें"
#: cartridges/details_dialog.py:90
msgid "Executables"
-msgstr "एक्सेक्यूटेबल"
+msgstr "निष्पादनयोग्य"
#. Translate this string as you would translate "file"
#: cartridges/details_dialog.py:105
@@ -497,15 +497,16 @@ msgid ""
"\n"
"If the path contains spaces, make sure to wrap it in double quotes!"
msgstr ""
-"एक्सेक्यूटेबल \"{}\" लॉन्च करने के लिए, कमांड का उपयोग करें:\n"
+"निष्पादनयोग्य \"{}\" लॉन्च करने के लिए, कमांड का उपयोग करें:\n"
"\n"
"\"{}\"\n"
"\n"
-"डिफ़ॉल्ट एप्लिकेशन के साथ \"{}\" फाइल खोलने के लिए, इसका उपयोग करें:\n"
+"तयशुदा अनुप्रयोग के साथ \"{}\" फाइल खोलने के लिए, इसका उपयोग करें:\n"
"\n"
"{} \"{}\"\n"
"\n"
-"यदि पथ में रिक्त स्थान हैं, तो इसे दोहरे उद्धरण चिह्नों में लपेटना सुनिश्चित करें!"
+"यदि पथ में रिक्त स्थान हैं, तो इसे दोहरे उद्धरण चिह्नों में लपेटना सुनिश्चित "
+"करें!"
#: cartridges/details_dialog.py:167 cartridges/details_dialog.py:173
msgid "Couldn't Add Game"
@@ -517,11 +518,11 @@ msgstr "गेम का शीर्षक रिक्त नहीं हो
#: cartridges/details_dialog.py:173 cartridges/details_dialog.py:217
msgid "Executable cannot be empty."
-msgstr "Executable खाली नहीं हो सकता।"
+msgstr "निष्पादनयोग्य खाली नहीं हो सकता।"
#: cartridges/details_dialog.py:208 cartridges/details_dialog.py:216
msgid "Couldn't Apply Preferences"
-msgstr "प्राथमिकताएँ लागू नहीं की जा सकीं"
+msgstr "प्राथमिकताएं लागू नहीं की जा सकी"
#. The variable is the title of the game
#: cartridges/game.py:139
@@ -555,7 +556,7 @@ msgstr "कवर डाउनलोड हो रहा है…"
#: cartridges/preferences.py:215
msgid "Covers updated"
-msgstr "कवर अप्डैटिड"
+msgstr "कवर अद्यतित"
#: cartridges/preferences.py:360
msgid "Installation Not Found"
@@ -563,7 +564,7 @@ msgstr "इंस्टालेशन नहीं मिला"
#: cartridges/preferences.py:361
msgid "Select a valid directory"
-msgstr "एक वैध डॉयरेक्टरी का चयन करें।"
+msgstr "एक मान्य निर्देशिका चुनें"
#: cartridges/preferences.py:397 cartridges/importer/importer.py:318
msgid "Warning"
@@ -571,7 +572,7 @@ msgstr "चेतावनी"
#: cartridges/preferences.py:431
msgid "Invalid Directory"
-msgstr "अवैध डॉयरेक्टरी"
+msgstr "अमान्य निर्देशिका"
#: cartridges/preferences.py:437
msgid "Set Location"
@@ -579,7 +580,7 @@ msgstr "स्थान तय करें"
#: cartridges/utils/create_dialog.py:33 cartridges/importer/importer.py:319
msgid "Dismiss"
-msgstr "खारिज"
+msgstr "खारिज करें"
#: cartridges/importer/importer.py:145
msgid "Importing Games…"
@@ -587,7 +588,7 @@ msgstr "गेम्स आयात किया जा रहा है…"
#: cartridges/importer/importer.py:338
msgid "The following errors occured during import:"
-msgstr "आयात के दौरान निम्नलिखित त्रुटियाँ हुईं:"
+msgstr "आयात के दौरान निम्नलिखित त्रुटियां हुईं:"
#: cartridges/importer/importer.py:367
msgid "No new games found"
@@ -605,22 +606,22 @@ msgstr "{} गेम्स आयातित"
#. A single game removed
#: cartridges/importer/importer.py:387
msgid "1 removed"
-msgstr "1 हटाया"
+msgstr "1 हटाया गया"
#. The variable is the name of the source
#: cartridges/importer/location.py:34
msgid "Select the {} cache directory."
-msgstr "{} कैशे डॉयरेक्टरी का चयन करें।"
+msgstr "{} कैशे निर्देशिका का चयन करें।"
#. The variable is the name of the source
#: cartridges/importer/location.py:36
msgid "Select the {} configuration directory."
-msgstr "{} कॉन्फ़िगरेशन डॉयरेक्टरी का चयन करें।"
+msgstr "{} विन्यास निर्देशिका का चयन करें।"
#. The variable is the name of the source
#: cartridges/importer/location.py:38
msgid "Select the {} data directory."
-msgstr "{} डेटा डॉयरेक्टरी का चयन करें।"
+msgstr "{} डेटा निर्देशिका का चयन करें।"
#: cartridges/importer/retroarch_source.py:129
msgid "No RetroArch Core Selected"
@@ -629,7 +630,7 @@ msgstr "कोई RetroArch कोर चयनित नहीं"
#. The variable is a newline separated list of playlists
#: cartridges/importer/retroarch_source.py:131
msgid "The following playlists have no default core:"
-msgstr "निम्नलिखित प्लेलिस्ट में कोई डिफ़ॉल्ट कोर नहीं है:"
+msgstr "निम्नलिखित प्लेलिस्ट में कोई तयशुदा कोर नहीं है:"
#: cartridges/importer/retroarch_source.py:133
msgid "Games with no core selected were not imported"
diff --git a/po/pl.po b/po/pl.po
index 1b94455..bb7bf0a 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -7,13 +7,14 @@
# Michaks , 2023.
# Igor Popowicz , 2024.
# polswert1 , 2024.
+# Karol , 2024.
msgid ""
msgstr ""
"Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-14 12:48+0200\n"
-"PO-Revision-Date: 2024-04-14 07:01+0000\n"
-"Last-Translator: polswert1 \n"
+"PO-Revision-Date: 2024-05-15 14:01+0000\n"
+"Last-Translator: Karol \n"
"Language-Team: Polish \n"
"Language: pl\n"
@@ -22,7 +23,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
"|| n%100>=20) ? 1 : 2);\n"
-"X-Generator: Weblate 5.5-dev\n"
+"X-Generator: Weblate 5.6-dev\n"
#: data/page.kramo.Cartridges.desktop.in:3
#: data/page.kramo.Cartridges.metainfo.xml.in:9
@@ -98,7 +99,7 @@ msgstr "Plik wykonywalny"
#: data/gtk/details-dialog.blp:109
msgid "Select File"
-msgstr ""
+msgstr "Wybierz Plik"
#: data/gtk/details-dialog.blp:120
msgid "More Info"
@@ -143,8 +144,9 @@ msgid "Quit"
msgstr "Wyjdź"
#: data/gtk/help-overlay.blp:39 data/gtk/window.blp:92 data/gtk/window.blp:185
+#, fuzzy
msgid "Toggle Sidebar"
-msgstr ""
+msgstr "przełącz pasek boczny"
#: data/gtk/help-overlay.blp:44 data/gtk/window.blp:198 data/gtk/window.blp:265
msgid "Main Menu"
@@ -164,14 +166,12 @@ msgid "Import"
msgstr "Importuj"
#: data/gtk/help-overlay.blp:63
-#, fuzzy
msgid "Show Hidden Games"
-msgstr "Pokaż ukryte gry"
+msgstr "Pokaż Ukryte Gry"
#: data/gtk/help-overlay.blp:68
-#, fuzzy
msgid "Remove Game"
-msgstr "Usuń grę"
+msgstr "Usuń Grę"
#: data/gtk/preferences.blp:13 data/gtk/preferences.blp:117
#: data/gtk/preferences.blp:415
@@ -211,9 +211,8 @@ msgid "Remove All Games"
msgstr "Usuń wszystkie gry"
#: data/gtk/preferences.blp:120
-#, fuzzy
msgid "Remove Uninstalled Games"
-msgstr "Usuń wszystkie gry"
+msgstr "Usuń Odinstalowane Gry"
#: data/gtk/preferences.blp:125
msgid "Sources"
@@ -256,9 +255,8 @@ msgid "Import GOG Games"
msgstr "Importuj gry z GOG"
#: data/gtk/preferences.blp:224
-#, fuzzy
msgid "Import Amazon Games"
-msgstr "Importuj gry Steam"
+msgstr "Importuj gry Amazon"
#: data/gtk/preferences.blp:228
msgid "Import Sideloaded Games"
@@ -278,7 +276,7 @@ msgstr "Legendarne"
#: data/gtk/preferences.blp:314 cartridges/importer/retroarch_source.py:142
msgid "RetroArch"
-msgstr ""
+msgstr "RetroArch"
#: data/gtk/preferences.blp:341 cartridges/importer/flatpak_source.py:143
msgid "Flatpak"
diff --git a/po/pt_BR.po b/po/pt_BR.po
index 462e5c6..4c31f7b 100644
--- a/po/pt_BR.po
+++ b/po/pt_BR.po
@@ -11,7 +11,7 @@ msgstr ""
"Project-Id-Version: Cartridges\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-04-14 12:48+0200\n"
-"PO-Revision-Date: 2024-01-04 04:07+0000\n"
+"PO-Revision-Date: 2024-04-20 05:07+0000\n"
"Last-Translator: Filipe Motta \n"
"Language-Team: Portuguese (Brazil) \n"
@@ -20,7 +20,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 5.4-dev\n"
+"X-Generator: Weblate 5.5-dev\n"
#: data/page.kramo.Cartridges.desktop.in:3
#: data/page.kramo.Cartridges.metainfo.xml.in:9
@@ -343,27 +343,24 @@ msgid "No Games Found"
msgstr "Nenhum jogo encontrado"
#: data/gtk/window.blp:7 data/gtk/window.blp:15
-#, fuzzy
msgid "Try a different search"
-msgstr "Tente uma busca diferente."
+msgstr "Tente uma busca diferente"
#: data/gtk/window.blp:21
msgid "No Games"
msgstr "Sem jogos"
#: data/gtk/window.blp:22
-#, fuzzy
msgid "Use the + button to add games"
-msgstr "Use o botão + para adicionar jogos."
+msgstr "Use o botão + para adicionar jogos"
#: data/gtk/window.blp:40
msgid "No Hidden Games"
msgstr "Sem jogos ocultos"
#: data/gtk/window.blp:41
-#, fuzzy
msgid "Games you hide will appear here"
-msgstr "Os jogos ocultos aparecerão aqui."
+msgstr "Os jogos ocultos aparecerão aqui"
#: data/gtk/window.blp:76 data/gtk/window.blp:111 cartridges/main.py:228
msgid "All Games"
diff --git a/pyrightconfig.json b/pyrightconfig.json
new file mode 100644
index 0000000..ae58b54
--- /dev/null
+++ b/pyrightconfig.json
@@ -0,0 +1,4 @@
+{
+ "reportRedeclaration": "none",
+ "reportMissingModuleSource": "none"
+}
diff --git a/search-provider/meson.build b/search-provider/meson.build
index 4e11b93..9bbdb9d 100644
--- a/search-provider/meson.build
+++ b/search-provider/meson.build
@@ -7,19 +7,19 @@ configure_file(
input: 'cartridges-search-provider.in',
output: 'cartridges-search-provider',
configuration: conf,
- install_dir: libexecdir
+ install_dir: libexecdir,
)
configure_file(
input: 'page.kramo.Cartridges.SearchProvider.service.in',
output: app_id + '.SearchProvider.service',
configuration: conf,
- install_dir: service_dir
+ install_dir: service_dir,
)
configure_file(
input: 'page.kramo.Cartridges.SearchProvider.ini',
output: app_id + '.SearchProvider.ini',
configuration: conf,
- install_dir: serarch_provider_dir
+ install_dir: serarch_provider_dir,
)