diff --git a/src/details_window.py b/src/details_window.py index c437d53..e3cff21 100644 --- a/src/details_window.py +++ b/src/details_window.py @@ -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) diff --git a/src/game.py b/src/game.py index 3063633..edeaad4 100644 --- a/src/game.py +++ b/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""" diff --git a/src/game_cover.py b/src/game_cover.py index 073f0c9..24ebf09 100644 --- a/src/game_cover.py +++ b/src/game_cover.py @@ -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, diff --git a/src/main.py b/src/main.py index 96fa420..a1e3fdf 100644 --- a/src/main.py +++ b/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) diff --git a/src/preferences.py b/src/preferences.py index 6b3d766..c2f2596 100644 --- a/src/preferences.py +++ b/src/preferences.py @@ -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) diff --git a/src/store/pipeline.py b/src/store/pipeline.py index f3f2883..559ee7f 100644 --- a/src/store/pipeline.py +++ b/src/store/pipeline.py @@ -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""" diff --git a/src/window.py b/src/window.py index ac2ab42..6b485d8 100644 --- a/src/window.py +++ b/src/window.py @@ -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()