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. -Download on Flathub +Download 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, )