Type hints for UI code
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
|
||||
import os
|
||||
from time import time
|
||||
from typing import Any
|
||||
|
||||
from gi.repository import Adw, Gio, GLib, Gtk
|
||||
from PIL import Image
|
||||
@@ -52,16 +53,15 @@ class DetailsWindow(Adw.Window):
|
||||
|
||||
apply_button = Gtk.Template.Child()
|
||||
|
||||
cover_changed = False
|
||||
cover_changed: bool = False
|
||||
|
||||
def __init__(self, game=None, **kwargs):
|
||||
def __init__(self, game: Game | None = None, **kwargs: Any):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.win = shared.win
|
||||
self.game = game
|
||||
self.game_cover = GameCover({self.cover})
|
||||
self.game: Game = game
|
||||
self.game_cover: GameCover = GameCover({self.cover})
|
||||
|
||||
self.set_transient_for(self.win)
|
||||
self.set_transient_for(shared.win)
|
||||
|
||||
if self.game:
|
||||
self.set_title(_("Game Details"))
|
||||
@@ -114,7 +114,7 @@ class DetailsWindow(Adw.Window):
|
||||
|
||||
self.exec_info_label.set_label(exec_info_text)
|
||||
|
||||
def clear_info_selection(*_args):
|
||||
def clear_info_selection(*_args: Any) -> None:
|
||||
self.exec_info_label.select_region(-1, -1)
|
||||
|
||||
self.exec_info_popover.connect("show", clear_info_selection)
|
||||
@@ -130,13 +130,13 @@ class DetailsWindow(Adw.Window):
|
||||
self.set_focus(self.name)
|
||||
self.present()
|
||||
|
||||
def delete_pixbuf(self, *_args):
|
||||
def delete_pixbuf(self, *_args: Any) -> None:
|
||||
self.game_cover.new_cover()
|
||||
|
||||
self.cover_button_delete_revealer.set_reveal_child(False)
|
||||
self.cover_changed = True
|
||||
|
||||
def apply_preferences(self, *_args):
|
||||
def apply_preferences(self, *_args: Any) -> None:
|
||||
final_name = self.name.get_text()
|
||||
final_developer = self.developer.get_text()
|
||||
final_executable = self.executable.get_text()
|
||||
@@ -196,10 +196,10 @@ class DetailsWindow(Adw.Window):
|
||||
self.game.developer = final_developer or None
|
||||
self.game.executable = final_executable
|
||||
|
||||
if self.game.game_id in self.win.game_covers.keys():
|
||||
self.win.game_covers[self.game.game_id].animation = None
|
||||
if self.game.game_id in shared.win.game_covers.keys():
|
||||
shared.win.game_covers[self.game.game_id].animation = None
|
||||
|
||||
self.win.game_covers[self.game.game_id] = self.game_cover
|
||||
shared.win.game_covers[self.game.game_id] = self.game_cover
|
||||
|
||||
if self.cover_changed:
|
||||
save_cover(
|
||||
@@ -222,9 +222,9 @@ class DetailsWindow(Adw.Window):
|
||||
self.game_cover.pictures.remove(self.cover)
|
||||
|
||||
self.close()
|
||||
self.win.show_details_view(self.game)
|
||||
shared.win.show_details_view(self.game)
|
||||
|
||||
def update_cover_callback(self, manager: SGDBManager):
|
||||
def update_cover_callback(self, manager: SGDBManager) -> None:
|
||||
# Set the game as not loading
|
||||
self.game.set_loading(-1)
|
||||
self.game.update()
|
||||
@@ -241,25 +241,25 @@ class DetailsWindow(Adw.Window):
|
||||
_("Preferences"),
|
||||
).connect("response", self.update_cover_error_response)
|
||||
|
||||
def update_cover_error_response(self, _widget, response):
|
||||
def update_cover_error_response(self, _widget: Any, response: str) -> None:
|
||||
if response == "open_preferences":
|
||||
shared.win.get_application().on_preferences_action(page_name="sgdb")
|
||||
|
||||
def focus_executable(self, *_args):
|
||||
def focus_executable(self, *_args: Any) -> None:
|
||||
self.set_focus(self.executable)
|
||||
|
||||
def toggle_loading(self):
|
||||
def toggle_loading(self) -> None:
|
||||
self.apply_button.set_sensitive(not self.apply_button.get_sensitive())
|
||||
self.spinner.set_spinning(not self.spinner.get_spinning())
|
||||
self.cover_overlay.set_opacity(not self.cover_overlay.get_opacity())
|
||||
|
||||
def set_cover(self, _source, result, *_args):
|
||||
def set_cover(self, _source: Any, result: Gio.Task, *_args: Any) -> None:
|
||||
try:
|
||||
path = self.file_dialog.open_finish(result).get_path()
|
||||
except GLib.GError:
|
||||
return
|
||||
|
||||
def resize():
|
||||
def resize() -> None:
|
||||
if cover := resize_cover(path):
|
||||
self.game_cover.new_cover(cover)
|
||||
self.cover_button_delete_revealer.set_reveal_child(True)
|
||||
@@ -269,5 +269,5 @@ class DetailsWindow(Adw.Window):
|
||||
self.toggle_loading()
|
||||
GLib.Thread.new(None, resize)
|
||||
|
||||
def choose_cover(self, *_args):
|
||||
def choose_cover(self, *_args: Any) -> None:
|
||||
self.file_dialog.open(self, None, self.set_cover)
|
||||
|
||||
70
src/game.py
70
src/game.py
@@ -23,10 +23,12 @@ import shlex
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import Any
|
||||
|
||||
from gi.repository import Adw, GLib, GObject, Gtk
|
||||
|
||||
from src import shared
|
||||
from src.game_cover import GameCover
|
||||
|
||||
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
@@ -45,23 +47,23 @@ class Game(Gtk.Box):
|
||||
game_options = Gtk.Template.Child()
|
||||
hidden_game_options = Gtk.Template.Child()
|
||||
|
||||
loading = 0
|
||||
filtered = False
|
||||
loading: int = 0
|
||||
filtered: bool = False
|
||||
|
||||
added = None
|
||||
executable = None
|
||||
game_id = None
|
||||
source = None
|
||||
hidden = False
|
||||
last_played = 0
|
||||
name = None
|
||||
developer = None
|
||||
removed = False
|
||||
blacklisted = False
|
||||
game_cover = None
|
||||
version = 0
|
||||
added: int
|
||||
executable: str
|
||||
game_id: str
|
||||
source: str
|
||||
hidden: bool = False
|
||||
last_played: int = 0
|
||||
name: str
|
||||
developer: str | None = None
|
||||
removed: bool = False
|
||||
blacklisted: bool = False
|
||||
game_cover: GameCover = None
|
||||
version: int = 0
|
||||
|
||||
def __init__(self, data, **kwargs):
|
||||
def __init__(self, data: dict[str, Any], **kwargs: Any) -> None:
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.win = shared.win
|
||||
@@ -82,20 +84,20 @@ class Game(Gtk.Box):
|
||||
|
||||
shared.schema.connect("changed", self.schema_changed)
|
||||
|
||||
def update_values(self, data):
|
||||
def update_values(self, data: dict[str, Any]) -> None:
|
||||
for key, value in data.items():
|
||||
# Convert executables to strings
|
||||
if key == "executable" and isinstance(value, list):
|
||||
value = shlex.join(value)
|
||||
setattr(self, key, value)
|
||||
|
||||
def update(self):
|
||||
def update(self) -> None:
|
||||
self.emit("update-ready", {})
|
||||
|
||||
def save(self):
|
||||
def save(self) -> None:
|
||||
self.emit("save-ready", {})
|
||||
|
||||
def create_toast(self, title, action=None):
|
||||
def create_toast(self, title: str, action: str | None = None) -> None:
|
||||
toast = Adw.Toast.new(title.format(self.name))
|
||||
toast.set_priority(Adw.ToastPriority.HIGH)
|
||||
|
||||
@@ -111,7 +113,7 @@ class Game(Gtk.Box):
|
||||
|
||||
self.win.toast_overlay.add_toast(toast)
|
||||
|
||||
def launch(self):
|
||||
def launch(self) -> None:
|
||||
self.last_played = int(time())
|
||||
self.save()
|
||||
self.update()
|
||||
@@ -129,7 +131,7 @@ class Game(Gtk.Box):
|
||||
cwd=Path.home(),
|
||||
shell=True,
|
||||
start_new_session=True,
|
||||
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == "nt" else 0,
|
||||
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if os.name == "nt" else 0, # type: ignore
|
||||
)
|
||||
|
||||
if shared.schema.get_boolean("exit-after-launch"):
|
||||
@@ -138,7 +140,7 @@ class Game(Gtk.Box):
|
||||
# The variable is the title of the game
|
||||
self.create_toast(_("{} launched"))
|
||||
|
||||
def toggle_hidden(self, toast=True):
|
||||
def toggle_hidden(self, toast: bool = True) -> None:
|
||||
self.hidden = not self.hidden
|
||||
self.save()
|
||||
|
||||
@@ -156,7 +158,7 @@ class Game(Gtk.Box):
|
||||
"hide",
|
||||
)
|
||||
|
||||
def remove_game(self):
|
||||
def remove_game(self) -> None:
|
||||
# Add "removed=True" to the game properties so it can be deleted on next init
|
||||
self.removed = True
|
||||
self.save()
|
||||
@@ -171,50 +173,52 @@ class Game(Gtk.Box):
|
||||
"remove",
|
||||
)
|
||||
|
||||
def set_loading(self, state):
|
||||
def set_loading(self, state: int) -> None:
|
||||
self.loading += state
|
||||
loading = self.loading > 0
|
||||
|
||||
self.cover.set_opacity(int(not loading))
|
||||
self.spinner.set_spinning(loading)
|
||||
|
||||
def get_cover_path(self):
|
||||
def get_cover_path(self) -> Path | None:
|
||||
cover_path = shared.covers_dir / f"{self.game_id}.gif"
|
||||
if cover_path.is_file():
|
||||
return cover_path
|
||||
return cover_path # type: ignore
|
||||
|
||||
cover_path = shared.covers_dir / f"{self.game_id}.tiff"
|
||||
if cover_path.is_file():
|
||||
return cover_path
|
||||
return cover_path # type: ignore
|
||||
|
||||
return None
|
||||
|
||||
def toggle_play(self, _widget, _prop1, _prop2, state=True):
|
||||
def toggle_play(
|
||||
self, _widget: Any, _prop1: Any, _prop2: Any, state: bool = True
|
||||
) -> None:
|
||||
if not self.menu_button.get_active():
|
||||
self.play_revealer.set_reveal_child(not state)
|
||||
self.menu_revealer.set_reveal_child(not state)
|
||||
|
||||
def main_button_clicked(self, _widget, button):
|
||||
def main_button_clicked(self, _widget: Any, button: bool) -> None:
|
||||
if shared.schema.get_boolean("cover-launches-game") ^ button:
|
||||
self.launch()
|
||||
else:
|
||||
self.win.show_details_view(self)
|
||||
|
||||
def set_play_icon(self):
|
||||
def set_play_icon(self) -> None:
|
||||
self.play_button.set_icon_name(
|
||||
"help-about-symbolic"
|
||||
if shared.schema.get_boolean("cover-launches-game")
|
||||
else "media-playback-start-symbolic"
|
||||
)
|
||||
|
||||
def schema_changed(self, _settings, key):
|
||||
def schema_changed(self, _settings: Any, key: str) -> None:
|
||||
if key == "cover-launches-game":
|
||||
self.set_play_icon()
|
||||
|
||||
@GObject.Signal(name="update-ready", arg_types=[object])
|
||||
def update_ready(self, _additional_data) -> None:
|
||||
def update_ready(self, _additional_data): # type: ignore
|
||||
"""Signal emitted when the game needs updating"""
|
||||
|
||||
@GObject.Signal(name="save-ready", arg_types=[object])
|
||||
def save_ready(self, _additional_data) -> None:
|
||||
def save_ready(self, _additional_data): # type: ignore
|
||||
"""Signal emitted when the game needs saving"""
|
||||
|
||||
@@ -17,19 +17,22 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from gi.repository import Gdk, GdkPixbuf, Gio, GLib
|
||||
from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
|
||||
from gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk
|
||||
from PIL import Image, ImageFilter, ImageStat
|
||||
|
||||
from src import shared
|
||||
|
||||
|
||||
class GameCover:
|
||||
texture = None
|
||||
blurred = None
|
||||
luminance = None
|
||||
path = None
|
||||
animation = None
|
||||
anim_iter = None
|
||||
texture: Gdk.Texture | None
|
||||
blurred: Gdk.Texture | None
|
||||
luminance: tuple[float, float] | None
|
||||
path: Path | None
|
||||
animation: GdkPixbuf.PixbufAnimation | None
|
||||
anim_iter: GdkPixbuf.PixbufAnimationIter | None
|
||||
|
||||
placeholder = Gdk.Texture.new_from_resource(
|
||||
shared.PREFIX + "/library_placeholder.svg"
|
||||
@@ -38,21 +41,21 @@ class GameCover:
|
||||
shared.PREFIX + "/library_placeholder_small.svg"
|
||||
)
|
||||
|
||||
def __init__(self, pictures, path=None):
|
||||
def __init__(self, pictures: set[Gtk.Picture], path: Path | None = None) -> None:
|
||||
self.pictures = pictures
|
||||
self.new_cover(path)
|
||||
|
||||
# Wrap the function in another one as Gio.Task.run_in_thread does not allow for passing args
|
||||
def create_func(self, path):
|
||||
def create_func(self, path: Path | None) -> Callable:
|
||||
self.animation = GdkPixbuf.PixbufAnimation.new_from_file(str(path))
|
||||
self.anim_iter = self.animation.get_iter()
|
||||
|
||||
def wrapper(task, *_args):
|
||||
def wrapper(task: Gio.Task, *_args: Any) -> None:
|
||||
self.update_animation((task, self.animation))
|
||||
|
||||
return wrapper
|
||||
|
||||
def new_cover(self, path=None):
|
||||
def new_cover(self, path: Path | None = None) -> None:
|
||||
self.animation = None
|
||||
self.texture = None
|
||||
self.blurred = None
|
||||
@@ -69,14 +72,14 @@ class GameCover:
|
||||
if not self.animation:
|
||||
self.set_texture(self.texture)
|
||||
|
||||
def get_texture(self):
|
||||
def get_texture(self) -> Gdk.Texture:
|
||||
return (
|
||||
Gdk.Texture.new_for_pixbuf(self.animation.get_static_image())
|
||||
if self.animation
|
||||
else self.texture
|
||||
)
|
||||
|
||||
def get_blurred(self):
|
||||
def get_blurred(self) -> Gdk.Texture:
|
||||
if not self.blurred:
|
||||
if self.path:
|
||||
with Image.open(self.path) as image:
|
||||
@@ -94,24 +97,24 @@ class GameCover:
|
||||
stat = ImageStat.Stat(image.convert("L"))
|
||||
|
||||
# Luminance values for light and dark mode
|
||||
self.luminance = [
|
||||
self.luminance = (
|
||||
min((stat.mean[0] + stat.extrema[0][0]) / 510, 0.7),
|
||||
max((stat.mean[0] + stat.extrema[0][1]) / 510, 0.3),
|
||||
]
|
||||
)
|
||||
else:
|
||||
self.blurred = self.placeholder_small
|
||||
self.luminance = (0.3, 0.5)
|
||||
|
||||
return self.blurred
|
||||
|
||||
def add_picture(self, picture):
|
||||
def add_picture(self, picture: Gtk.Picture) -> None:
|
||||
self.pictures.add(picture)
|
||||
if not self.animation:
|
||||
self.set_texture(self.texture)
|
||||
else:
|
||||
self.update_animation((self.task, self.animation))
|
||||
|
||||
def set_texture(self, texture):
|
||||
def set_texture(self, texture: Gdk.Texture) -> None:
|
||||
self.pictures.discard(
|
||||
picture for picture in self.pictures if not picture.is_visible()
|
||||
)
|
||||
@@ -121,13 +124,13 @@ class GameCover:
|
||||
for picture in self.pictures:
|
||||
picture.set_paintable(texture or self.placeholder)
|
||||
|
||||
def update_animation(self, data):
|
||||
def update_animation(self, data: GdkPixbuf.PixbufAnimation) -> None:
|
||||
if self.animation == data[1]:
|
||||
self.anim_iter.advance()
|
||||
self.anim_iter.advance() # type: ignore
|
||||
|
||||
self.set_texture(Gdk.Texture.new_for_pixbuf(self.anim_iter.get_pixbuf()))
|
||||
self.set_texture(Gdk.Texture.new_for_pixbuf(self.anim_iter.get_pixbuf())) # type: ignore
|
||||
|
||||
delay_time = self.anim_iter.get_delay_time()
|
||||
delay_time = self.anim_iter.get_delay_time() # type: ignore
|
||||
GLib.timeout_add(
|
||||
20 if delay_time < 20 else delay_time,
|
||||
self.update_animation,
|
||||
|
||||
51
src/main.py
51
src/main.py
@@ -21,6 +21,7 @@ import json
|
||||
import lzma
|
||||
import os
|
||||
import sys
|
||||
from typing import Any
|
||||
|
||||
import gi
|
||||
|
||||
@@ -55,15 +56,15 @@ from src.window import CartridgesWindow
|
||||
|
||||
|
||||
class CartridgesApplication(Adw.Application):
|
||||
win = None
|
||||
win: CartridgesWindow
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self) -> None:
|
||||
shared.store = Store()
|
||||
super().__init__(
|
||||
application_id=shared.APP_ID, flags=Gio.ApplicationFlags.FLAGS_NONE
|
||||
)
|
||||
|
||||
def do_activate(self): # pylint: disable=arguments-differ
|
||||
def do_activate(self) -> None: # pylint: disable=arguments-differ
|
||||
"""Called on app creation"""
|
||||
|
||||
setup_logging()
|
||||
@@ -141,7 +142,7 @@ class CartridgesApplication(Adw.Application):
|
||||
|
||||
self.win.present()
|
||||
|
||||
def load_games_from_disk(self):
|
||||
def load_games_from_disk(self) -> None:
|
||||
if shared.games_dir.is_dir():
|
||||
for game_file in shared.games_dir.iterdir():
|
||||
try:
|
||||
@@ -151,7 +152,7 @@ class CartridgesApplication(Adw.Application):
|
||||
game = Game(data)
|
||||
shared.store.add_game(game, {"skip_save": True})
|
||||
|
||||
def on_about_action(self, *_args):
|
||||
def on_about_action(self, *_args: Any) -> None:
|
||||
# Get the debug info from the log files
|
||||
debug_str = ""
|
||||
for i, path in enumerate(shared.log_files):
|
||||
@@ -195,8 +196,12 @@ class CartridgesApplication(Adw.Application):
|
||||
about.present()
|
||||
|
||||
def on_preferences_action(
|
||||
self, _action=None, _parameter=None, page_name=None, expander_row=None
|
||||
):
|
||||
self,
|
||||
_action: Any = None,
|
||||
_parameter: Any = None,
|
||||
page_name: (str | None) = None,
|
||||
expander_row: (str | None) = None,
|
||||
) -> CartridgesWindow:
|
||||
win = PreferencesWindow()
|
||||
if page_name:
|
||||
win.set_visible_page_name(page_name)
|
||||
@@ -206,19 +211,19 @@ class CartridgesApplication(Adw.Application):
|
||||
|
||||
return win
|
||||
|
||||
def on_launch_game_action(self, *_args):
|
||||
def on_launch_game_action(self, *_args: Any) -> None:
|
||||
self.win.active_game.launch()
|
||||
|
||||
def on_hide_game_action(self, *_args):
|
||||
def on_hide_game_action(self, *_args: Any) -> None:
|
||||
self.win.active_game.toggle_hidden()
|
||||
|
||||
def on_edit_game_action(self, *_args):
|
||||
def on_edit_game_action(self, *_args: Any) -> None:
|
||||
DetailsWindow(self.win.active_game)
|
||||
|
||||
def on_add_game_action(self, *_args):
|
||||
def on_add_game_action(self, *_args: Any) -> None:
|
||||
DetailsWindow()
|
||||
|
||||
def on_import_action(self, *_args):
|
||||
def on_import_action(self, *_args: Any) -> None:
|
||||
shared.importer = Importer()
|
||||
|
||||
if shared.schema.get_boolean("lutris"):
|
||||
@@ -247,35 +252,35 @@ class CartridgesApplication(Adw.Application):
|
||||
|
||||
shared.importer.run()
|
||||
|
||||
def on_remove_game_action(self, *_args):
|
||||
def on_remove_game_action(self, *_args: Any) -> None:
|
||||
self.win.active_game.remove_game()
|
||||
|
||||
def on_remove_game_details_view_action(self, *_args):
|
||||
def on_remove_game_details_view_action(self, *_args: Any) -> None:
|
||||
if self.win.stack.get_visible_child() == self.win.details_view:
|
||||
self.on_remove_game_action()
|
||||
|
||||
def search(self, uri):
|
||||
def search(self, uri: str) -> None:
|
||||
Gio.AppInfo.launch_default_for_uri(f"{uri}{self.win.active_game.name}")
|
||||
|
||||
def on_igdb_search_action(self, *_args):
|
||||
def on_igdb_search_action(self, *_args: Any) -> None:
|
||||
self.search("https://www.igdb.com/search?type=1&q=")
|
||||
|
||||
def on_sgdb_search_action(self, *_args):
|
||||
def on_sgdb_search_action(self, *_args: Any) -> None:
|
||||
self.search("https://www.steamgriddb.com/search/grids?term=")
|
||||
|
||||
def on_protondb_search_action(self, *_args):
|
||||
def on_protondb_search_action(self, *_args: Any) -> None:
|
||||
self.search("https://www.protondb.com/search?q=")
|
||||
|
||||
def on_lutris_search_action(self, *_args):
|
||||
def on_lutris_search_action(self, *_args: Any) -> None:
|
||||
self.search("https://lutris.net/games?q=")
|
||||
|
||||
def on_hltb_search_action(self, *_args):
|
||||
def on_hltb_search_action(self, *_args: Any) -> None:
|
||||
self.search("https://howlongtobeat.com/?q=")
|
||||
|
||||
def on_quit_action(self, *_args):
|
||||
def on_quit_action(self, *_args: Any) -> None:
|
||||
self.quit()
|
||||
|
||||
def create_actions(self, actions):
|
||||
def create_actions(self, actions: set) -> None:
|
||||
for action in actions:
|
||||
simple_action = Gio.SimpleAction.new(action[0], None)
|
||||
|
||||
@@ -291,7 +296,7 @@ class CartridgesApplication(Adw.Application):
|
||||
scope.add_action(simple_action)
|
||||
|
||||
|
||||
def main(_version):
|
||||
def main(_version: int) -> Any:
|
||||
"""App entry point"""
|
||||
app = CartridgesApplication()
|
||||
return app.run(sys.argv)
|
||||
|
||||
@@ -21,10 +21,12 @@ import logging
|
||||
import re
|
||||
from pathlib import Path
|
||||
from shutil import rmtree
|
||||
from typing import Any, Callable
|
||||
|
||||
from gi.repository import Adw, Gio, GLib, Gtk
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.importer.sources.bottles_source import BottlesSource
|
||||
from src.importer.sources.flatpak_source import FlatpakSource
|
||||
from src.importer.sources.heroic_source import HeroicSource
|
||||
@@ -107,10 +109,10 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
reset_button = Gtk.Template.Child()
|
||||
remove_all_games_button = Gtk.Template.Child()
|
||||
|
||||
removed_games = set()
|
||||
warning_menu_buttons = {}
|
||||
removed_games: set[Game] = set()
|
||||
warning_menu_buttons: dict = {}
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
super().__init__(**kwargs)
|
||||
self.win = shared.win
|
||||
self.file_chooser = Gtk.FileDialog()
|
||||
@@ -157,7 +159,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
self.init_source_row(source)
|
||||
|
||||
# SteamGridDB
|
||||
def sgdb_key_changed(*_args):
|
||||
def sgdb_key_changed(*_args: Any) -> None:
|
||||
shared.schema.set_string("sgdb-key", self.sgdb_key_entry_row.get_text())
|
||||
|
||||
self.sgdb_key_entry_row.set_text(shared.schema.get_string("sgdb-key"))
|
||||
@@ -171,7 +173,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
)
|
||||
)
|
||||
|
||||
def set_sgdb_sensitive(widget):
|
||||
def set_sgdb_sensitive(widget: Adw.EntryRow) -> None:
|
||||
if not widget.get_text():
|
||||
shared.schema.set_boolean("sgdb", False)
|
||||
|
||||
@@ -182,7 +184,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
|
||||
# Switches
|
||||
self.bind_switches(
|
||||
(
|
||||
{
|
||||
"exit-after-launch",
|
||||
"cover-launches-game",
|
||||
"high-quality-images",
|
||||
@@ -197,13 +199,13 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
"sgdb",
|
||||
"sgdb-prefer",
|
||||
"sgdb-animated",
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
def get_switch(self, setting):
|
||||
def get_switch(self, setting: str) -> Any:
|
||||
return getattr(self, f'{setting.replace("-", "_")}_switch')
|
||||
|
||||
def bind_switches(self, settings):
|
||||
def bind_switches(self, settings: set[str]) -> None:
|
||||
for setting in settings:
|
||||
shared.schema.bind(
|
||||
setting,
|
||||
@@ -212,10 +214,12 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
Gio.SettingsBindFlags.DEFAULT,
|
||||
)
|
||||
|
||||
def choose_folder(self, _widget, callback, callback_data=None):
|
||||
def choose_folder(
|
||||
self, _widget: Any, callback: Callable, callback_data: str | None = None
|
||||
) -> None:
|
||||
self.file_chooser.select_folder(self.win, None, callback, callback_data)
|
||||
|
||||
def undo_remove_all(self, *_args):
|
||||
def undo_remove_all(self, *_args: Any) -> None:
|
||||
for game in self.removed_games:
|
||||
game.removed = False
|
||||
game.save()
|
||||
@@ -224,7 +228,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
self.removed_games = set()
|
||||
self.toast.dismiss()
|
||||
|
||||
def remove_all_games(self, *_args):
|
||||
def remove_all_games(self, *_args: Any) -> None:
|
||||
for game in shared.store:
|
||||
if not game.removed:
|
||||
self.removed_games.add(game)
|
||||
@@ -237,7 +241,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
|
||||
self.add_toast(self.toast)
|
||||
|
||||
def reset_app(self, *_args):
|
||||
def reset_app(self, *_args: Any) -> None:
|
||||
rmtree(shared.data_dir / "cartridges", True)
|
||||
rmtree(shared.config_dir / "cartridges", True)
|
||||
rmtree(shared.cache_dir / "cartridges", True)
|
||||
@@ -255,7 +259,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
|
||||
shared.win.get_application().quit()
|
||||
|
||||
def update_source_action_row_paths(self, source: Source):
|
||||
def update_source_action_row_paths(self, source: Source) -> None:
|
||||
"""Set the dir subtitle for a source's action rows"""
|
||||
for location_name, location in source.locations._asdict().items():
|
||||
# Get the action row to subtitle
|
||||
@@ -269,10 +273,10 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
subtitle = re.sub("/run/user/\\d*/doc/.*/", "", str(path))
|
||||
action_row.set_subtitle(subtitle)
|
||||
|
||||
def resolve_locations(self, source: Source):
|
||||
def resolve_locations(self, source: Source) -> None:
|
||||
"""Resolve locations and add a warning if location cannot be found"""
|
||||
|
||||
def clear_warning_selection(_widget, label):
|
||||
def clear_warning_selection(_widget: Any, label: Gtk.Label) -> None:
|
||||
label.select_region(-1, -1)
|
||||
|
||||
for location_name, location in source.locations._asdict().items():
|
||||
@@ -322,12 +326,11 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
action_row.add_prefix(menu_button)
|
||||
self.warning_menu_buttons[source.source_id] = menu_button
|
||||
|
||||
def init_source_row(self, source: Source):
|
||||
def init_source_row(self, source: Source) -> None:
|
||||
"""Initialize a preference row for a source class"""
|
||||
|
||||
def set_dir(_widget, result, location_name):
|
||||
def set_dir(_widget: Any, result: Gio.Task, location_name: str) -> None:
|
||||
"""Callback called when a dir picker button is clicked"""
|
||||
|
||||
try:
|
||||
path = Path(self.file_chooser.select_folder_finish(result).get_path())
|
||||
except GLib.GError:
|
||||
@@ -342,7 +345,9 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
action_row = getattr(
|
||||
self, f"{source.source_id}_{location_name}_action_row", None
|
||||
)
|
||||
action_row.remove(self.warning_menu_buttons[source.source_id])
|
||||
action_row.remove( # type: ignore
|
||||
self.warning_menu_buttons[source.source_id]
|
||||
)
|
||||
self.warning_menu_buttons.pop(source.source_id)
|
||||
logging.debug("User-set value for %s is %s", location.schema_key, path)
|
||||
|
||||
@@ -357,7 +362,7 @@ class PreferencesWindow(Adw.PreferencesWindow):
|
||||
_("Set Location"),
|
||||
)
|
||||
|
||||
def on_response(widget, response):
|
||||
def on_response(widget: Any, response: str) -> None:
|
||||
if response == "choose_folder":
|
||||
self.choose_folder(widget, set_dir, location_name)
|
||||
|
||||
|
||||
@@ -106,5 +106,5 @@ class Pipeline(GObject.Object):
|
||||
self.advance()
|
||||
|
||||
@GObject.Signal(name="advanced")
|
||||
def advanced(self) -> None:
|
||||
def advanced(self): # type: ignore
|
||||
"""Signal emitted when the pipeline has advanced"""
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
#
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from gi.repository import Adw, Gtk
|
||||
from typing import Any
|
||||
|
||||
from gi.repository import Adw, Gio, GLib, Gtk
|
||||
|
||||
from src import shared
|
||||
from src.game import Game
|
||||
from src.game_cover import GameCover
|
||||
from src.utils.relative_date import relative_date
|
||||
|
||||
|
||||
@@ -64,13 +68,13 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
hidden_search_entry = Gtk.Template.Child()
|
||||
hidden_search_button = Gtk.Template.Child()
|
||||
|
||||
game_covers = {}
|
||||
toasts = {}
|
||||
active_game = None
|
||||
details_view_game_cover = None
|
||||
sort_state = "a-z"
|
||||
game_covers: dict = {}
|
||||
toasts: dict = {}
|
||||
active_game: Game
|
||||
details_view_game_cover: GameCover | None = None
|
||||
sort_state: str = "a-z"
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
def __init__(self, **kwargs: Any) -> None:
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.previous_page = self.library_view
|
||||
@@ -110,11 +114,11 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
style_manager.connect("notify::dark", self.set_details_view_opacity)
|
||||
style_manager.connect("notify::high-contrast", self.set_details_view_opacity)
|
||||
|
||||
def search_changed(self, _widget, hidden):
|
||||
def search_changed(self, _widget: Any, hidden: bool) -> None:
|
||||
# Refresh search filter on keystroke in search box
|
||||
(self.hidden_library if hidden else self.library).invalidate_filter()
|
||||
|
||||
def set_library_child(self):
|
||||
def set_library_child(self) -> None:
|
||||
child, hidden_child = self.notice_empty, self.hidden_notice_empty
|
||||
|
||||
for game in shared.store:
|
||||
@@ -134,7 +138,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
self.library_bin.set_child(child)
|
||||
self.hidden_library_bin.set_child(hidden_child)
|
||||
|
||||
def filter_func(self, child):
|
||||
def filter_func(self, child: Gtk.Widget) -> bool:
|
||||
game = child.get_child()
|
||||
text = (
|
||||
(
|
||||
@@ -156,10 +160,10 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
|
||||
return not filtered
|
||||
|
||||
def set_active_game(self, _widget, _pspec, game):
|
||||
def set_active_game(self, _widget: Any, _pspec: Any, game: Game) -> None:
|
||||
self.active_game = game
|
||||
|
||||
def show_details_view(self, game):
|
||||
def show_details_view(self, game: Game) -> None:
|
||||
self.active_game = game
|
||||
|
||||
self.details_view_cover.set_opacity(int(not game.loading))
|
||||
@@ -207,7 +211,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
|
||||
self.set_details_view_opacity()
|
||||
|
||||
def set_details_view_opacity(self, *_args):
|
||||
def set_details_view_opacity(self, *_args: Any) -> None:
|
||||
if self.stack.get_visible_child() != self.details_view:
|
||||
return
|
||||
|
||||
@@ -218,12 +222,12 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
return
|
||||
|
||||
self.details_view_blurred_cover.set_opacity(
|
||||
1 - self.details_view_game_cover.luminance[0]
|
||||
1 - self.details_view_game_cover.luminance[0] # type: ignore
|
||||
if style_manager.get_dark()
|
||||
else self.details_view_game_cover.luminance[1]
|
||||
else self.details_view_game_cover.luminance[1] # type: ignore
|
||||
)
|
||||
|
||||
def sort_func(self, child1, child2):
|
||||
def sort_func(self, child1: Gtk.Widget, child2: Gtk.Widget) -> int:
|
||||
var, order = "name", True
|
||||
|
||||
if self.sort_state in ("newest", "oldest"):
|
||||
@@ -233,7 +237,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
elif self.sort_state == "a-z":
|
||||
order = False
|
||||
|
||||
def get_value(index):
|
||||
def get_value(index: int) -> str:
|
||||
return str(
|
||||
getattr((child1.get_child(), child2.get_child())[index], var)
|
||||
).lower()
|
||||
@@ -243,7 +247,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
|
||||
return ((get_value(0) > get_value(1)) ^ order) * 2 - 1
|
||||
|
||||
def navigate(self, next_page):
|
||||
def navigate(self, next_page: Gtk.Widget) -> None:
|
||||
levels = (self.library_view, self.hidden_library_view, self.details_view)
|
||||
self.stack.set_transition_type(
|
||||
Gtk.StackTransitionType.UNDER_RIGHT
|
||||
@@ -260,13 +264,13 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
|
||||
self.stack.set_visible_child(next_page)
|
||||
|
||||
def on_go_back_action(self, *_args):
|
||||
def on_go_back_action(self, *_args: Any) -> None:
|
||||
if self.stack.get_visible_child() == self.hidden_library_view:
|
||||
self.navigate(self.library_view)
|
||||
elif self.stack.get_visible_child() == self.details_view:
|
||||
self.on_go_to_parent_action()
|
||||
|
||||
def on_go_to_parent_action(self, *_args):
|
||||
def on_go_to_parent_action(self, *_args: Any) -> None:
|
||||
if self.stack.get_visible_child() == self.details_view:
|
||||
self.navigate(
|
||||
self.hidden_library_view
|
||||
@@ -274,20 +278,20 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
else self.library_view
|
||||
)
|
||||
|
||||
def on_go_home_action(self, *_args):
|
||||
def on_go_home_action(self, *_args: Any) -> None:
|
||||
self.navigate(self.library_view)
|
||||
|
||||
def on_show_hidden_action(self, *_args):
|
||||
def on_show_hidden_action(self, *_args: Any) -> None:
|
||||
self.navigate(self.hidden_library_view)
|
||||
|
||||
def on_sort_action(self, action, state):
|
||||
def on_sort_action(self, action: Gio.SimpleAction, state: GLib.Variant) -> None:
|
||||
action.set_state(state)
|
||||
self.sort_state = str(state).strip("'")
|
||||
self.library.invalidate_sort()
|
||||
|
||||
shared.state_schema.set_string("sort-mode", self.sort_state)
|
||||
|
||||
def on_toggle_search_action(self, *_args):
|
||||
def on_toggle_search_action(self, *_args: Any) -> None:
|
||||
if self.stack.get_visible_child() == self.library_view:
|
||||
search_bar = self.search_bar
|
||||
search_entry = self.search_entry
|
||||
@@ -304,7 +308,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
|
||||
search_entry.set_text("")
|
||||
|
||||
def on_escape_action(self, *_args):
|
||||
def on_escape_action(self, *_args: Any) -> None:
|
||||
if (
|
||||
self.get_focus() == self.search_entry.get_focus_child()
|
||||
or self.hidden_search_entry.get_focus_child()
|
||||
@@ -313,7 +317,7 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
else:
|
||||
self.on_go_back_action()
|
||||
|
||||
def show_details_view_search(self, widget):
|
||||
def show_details_view_search(self, widget: Gtk.Widget) -> None:
|
||||
library = (
|
||||
self.hidden_library if widget == self.hidden_search_entry else self.library
|
||||
)
|
||||
@@ -329,39 +333,39 @@ class CartridgesWindow(Adw.ApplicationWindow):
|
||||
|
||||
index += 1
|
||||
|
||||
def on_undo_action(self, _widget, game=None, undo=None):
|
||||
def on_undo_action(
|
||||
self, _widget: Any, game: Game | None = None, undo: str | None = None
|
||||
) -> None:
|
||||
if not game: # If the action was activated via Ctrl + Z
|
||||
if shared.importer and (
|
||||
shared.importer.imported_game_ids or shared.importer.removed_game_ids
|
||||
):
|
||||
undo = "import"
|
||||
else:
|
||||
try:
|
||||
game = tuple(self.toasts.keys())[-1][0]
|
||||
undo = tuple(self.toasts.keys())[-1][1]
|
||||
except IndexError:
|
||||
return
|
||||
shared.importer.undo_import()
|
||||
return
|
||||
|
||||
if undo == "import":
|
||||
shared.importer.undo_import()
|
||||
|
||||
elif undo == "hide":
|
||||
game.toggle_hidden(False)
|
||||
|
||||
elif undo == "remove":
|
||||
game.removed = False
|
||||
game.save()
|
||||
game.update()
|
||||
try:
|
||||
game = tuple(self.toasts.keys())[-1][0]
|
||||
undo = tuple(self.toasts.keys())[-1][1]
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
if game:
|
||||
if undo == "hide":
|
||||
game.toggle_hidden(False)
|
||||
|
||||
elif undo == "remove":
|
||||
game.removed = False
|
||||
game.save()
|
||||
game.update()
|
||||
|
||||
self.toasts[(game, undo)].dismiss()
|
||||
self.toasts.pop((game, undo))
|
||||
|
||||
def on_open_menu_action(self, *_args):
|
||||
def on_open_menu_action(self, *_args: Any) -> None:
|
||||
if self.stack.get_visible_child() == self.library_view:
|
||||
self.primary_menu_button.popup()
|
||||
elif self.stack.get_visible_child() == self.hidden_library_view:
|
||||
self.hidden_primary_menu_button.popup()
|
||||
|
||||
def on_close_action(self, *_args):
|
||||
def on_close_action(self, *_args: Any) -> None:
|
||||
self.close()
|
||||
|
||||
Reference in New Issue
Block a user