Compare commits

...

6 Commits
v2.9 ... v2.9.1

Author SHA1 Message Date
kramo
bdcded93f3 v2.9.1 2024-07-11 01:22:08 +02:00
kramo
b3a65c3d23 Move ApplicationDelegate to separate module 2024-07-11 01:18:26 +02:00
kramo
06730248a9 Build without WebP TIFF compression in macOS CI 2024-07-10 22:34:42 +02:00
kramo
b46faa951f Improve macOS menu bar 2024-07-10 22:17:59 +02:00
kramo
43a04e7d44 Quote game names in search URLs 2024-07-10 22:00:40 +02:00
kramo
d74c8aba1a Use menu bar on macOS 2024-07-10 21:56:02 +02:00
8 changed files with 166 additions and 14 deletions

View File

@@ -73,11 +73,11 @@ jobs:
- name: Install Dependencies - name: Install Dependencies
run: | run: |
brew install meson pygobject3 libadwaita adwaita-icon-theme desktop-file-utils pyinstaller pillow brew install meson pygobject3 libadwaita adwaita-icon-theme desktop-file-utils pyinstaller pillow
pip3 install --break-system-packages requests PyYAML pip3 install --break-system-packages requests PyYAML pyobjc
- name: Meson Build - name: Meson Build
run: | run: |
meson setup _build meson setup _build -Dtiff_compression=jpeg
ninja install -C _build ninja install -C _build
- name: PyInstaller - name: PyInstaller

View File

@@ -0,0 +1,120 @@
# 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 <https://www.gnu.org/licenses/>.
#
# SPDX-License-Identifier: GPL-3.0-or-later
"""A set of methods that manage your apps 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 showtime import shared
class ApplicationDelegate(NSObject): # type: ignore
"""A set of methods that manage your apps 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()

View File

@@ -59,8 +59,15 @@ class DetailsDialog(Adw.Dialog):
cover_changed: bool = False cover_changed: bool = False
is_open = False
def __init__(self, game: Optional[Game] = None, **kwargs: Any): def __init__(self, game: Optional[Game] = None, **kwargs: Any):
super().__init__(**kwargs) super().__init__(**kwargs)
# 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: Game = game self.game: Game = game
self.game_cover: GameCover = GameCover({self.cover}) self.game_cover: GameCover = GameCover({self.cover})
@@ -325,3 +332,6 @@ class DetailsDialog(Adw.Dialog):
def choose_cover(self, *_args: Any) -> None: def choose_cover(self, *_args: Any) -> None:
self.image_file_dialog.open(self.get_root(), None, self.set_cover) 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

View File

@@ -24,6 +24,7 @@ import shlex
import sys import sys
from time import time from time import time
from typing import Any, Optional from typing import Any, Optional
from urllib.parse import quote
import gi import gi
@@ -57,6 +58,12 @@ from cartridges.store.store import Store
from cartridges.utils.run_executable import run_executable from cartridges.utils.run_executable import run_executable
from cartridges.window import CartridgesWindow 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): class CartridgesApplication(Adw.Application):
state = shared.AppState.DEFAULT state = shared.AppState.DEFAULT
@@ -87,8 +94,15 @@ class CartridgesApplication(Adw.Application):
self.add_main_option_entries((search, launch)) self.add_main_option_entries((search, launch))
if sys.platform == "darwin" and (settings := Gtk.Settings.get_default()): if sys.platform == "darwin":
settings.props.gtk_decoration_layout = "close,minimize,maximize:" 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 def do_activate(self) -> None: # pylint: disable=arguments-differ
"""Called on app creation""" """Called on app creation"""
@@ -287,7 +301,7 @@ class CartridgesApplication(Adw.Application):
_parameter: Any = None, _parameter: Any = None,
page_name: Optional[str] = None, page_name: Optional[str] = None,
expander_row: Optional[str] = None, expander_row: Optional[str] = None,
) -> CartridgesWindow: ) -> Optional[CartridgesPreferences]:
if CartridgesPreferences.is_open: if CartridgesPreferences.is_open:
return return
@@ -310,6 +324,9 @@ class CartridgesApplication(Adw.Application):
DetailsDialog(shared.win.active_game).present(shared.win) DetailsDialog(shared.win.active_game).present(shared.win)
def on_add_game_action(self, *_args: Any) -> None: def on_add_game_action(self, *_args: Any) -> None:
if DetailsDialog.is_open:
return
DetailsDialog().present(shared.win) DetailsDialog().present(shared.win)
def on_import_action(self, *_args: Any) -> None: def on_import_action(self, *_args: Any) -> None:
@@ -352,7 +369,7 @@ class CartridgesApplication(Adw.Application):
self.on_remove_game_action() self.on_remove_game_action()
def search(self, uri: str) -> None: 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: def on_igdb_search_action(self, *_args: Any) -> None:
self.search("https://www.igdb.com/search?type=1&q=") self.search("https://www.igdb.com/search?type=1&q=")

View File

@@ -15,6 +15,7 @@ install_subdir('logging', install_dir: moduledir)
install_subdir('errors', install_dir: moduledir) install_subdir('errors', install_dir: moduledir)
install_data( install_data(
[ [
'application_delegate.py',
'main.py', 'main.py',
'window.py', 'window.py',
'preferences.py', 'preferences.py',

View File

@@ -450,6 +450,9 @@ class CartridgesWindow(Adw.ApplicationWindow):
self.navigation_view.pop_to_page(self.library_page) self.navigation_view.pop_to_page(self.library_page)
def on_show_hidden_action(self, *_args: Any) -> None: 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) self.navigation_view.push(self.hidden_library_page)
def on_sort_action(self, action: Gio.SimpleAction, state: GLib.Variant) -> None: def on_sort_action(self, action: Gio.SimpleAction, state: GLib.Variant) -> None:

View File

@@ -54,6 +54,14 @@
</screenshots> </screenshots>
<content_rating type="oars-1.1" /> <content_rating type="oars-1.1" />
<releases> <releases>
<release version="2.9.1" date="2024-07-11">
<description translate="no">
<ul>
<li>Cartridges now utilizes the menu bar on macOS</li>
<li>Various bug fixes</li>
</ul>
</description>
</release>
<release version="2.9" date="2024-07-10"> <release version="2.9" date="2024-07-10">
<description translate="no"> <description translate="no">
<ul> <ul>
@@ -62,13 +70,6 @@
</ul> </ul>
</description> </description>
</release> </release>
<release version="2.8.5" date="2024-05-25">
<description translate="no">
<ul>
<li>Steam runtimes and Proton should stop being imported again</li>
</ul>
</description>
</release>
<release version="2.8" date="2024-03-20"> <release version="2.8" date="2024-03-20">
<description translate="no"> <description translate="no">
<ul> <ul>

View File

@@ -1,6 +1,6 @@
project( project(
'cartridges', 'cartridges',
version: '2.9', version: '2.9.1',
meson_version: '>= 0.59.0', meson_version: '>= 0.59.0',
default_options: [ default_options: [
'warning_level=2', 'warning_level=2',