From 83b8e3091ee500f1c067be394479e79a95ecd0b1 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Sat, 8 Jun 2024 11:15:45 +0300 Subject: [PATCH 1/4] Rare: use zip archive instead of git dev version for Windows --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index c91823c5..a27d034b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ PyQt5 QtAwesome setuptools legendary-gl>=0.20.34; platform_system != "Windows" or platform_system != "Darwin" -legendary-gl @ git+https://github.com/derrod/legendary@96e07ff ; platform_system == "Windows" or platform_system == "Darwin" +legendary-gl @ https://github.com/derrod/legendary/archive/96e07ff453910b8cae89af044e317001ce33ac8b.zip ; platform_system == "Windows" or platform_system == "Darwin" orjson vdf pywin32; platform_system == "Windows" From d58c5a612fdb31f1baa4d911562944801f4c2a56 Mon Sep 17 00:00:00 2001 From: Stelios Tsampas Date: Sat, 8 Jun 2024 11:32:23 +0300 Subject: [PATCH 2/4] ImageManager: Add TODO about threading cover art without remote images --- rare/shared/image_manager.py | 1 + 1 file changed, 1 insertion(+) diff --git a/rare/shared/image_manager.py b/rare/shared/image_manager.py index 98e9d8eb..225276b1 100644 --- a/rare/shared/image_manager.py +++ b/rare/shared/image_manager.py @@ -138,6 +138,7 @@ class ImageManager(QObject): # lk: Find updates or initialize if images are missing. # lk: `updates` will be empty for games without images # lk: so everything below it is skipped + # TODO: Move this into the thread, maybe, concurrency could help here too updates = [] if not all(file.is_file() for file in self.__img_all(game.app_name)): # lk: fast path for games without images, convert Rare's logo From c7436700fd059a4b9e399e36f6ea1de48ea37018 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Sat, 15 Jun 2024 17:46:34 +0300 Subject: [PATCH 3/4] MangoHudSettings: fix label capitalization --- rare/components/tabs/settings/widgets/overlay.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rare/components/tabs/settings/widgets/overlay.py b/rare/components/tabs/settings/widgets/overlay.py index 79f35499..47fbd7be 100644 --- a/rare/components/tabs/settings/widgets/overlay.py +++ b/rare/components/tabs/settings/widgets/overlay.py @@ -305,9 +305,9 @@ class MangoHudSettings(OverlaySettings): OverlayCheckBox("gpu_power", self.tr("GPU power consumption")), ] form = [ - (OverlayNumberInput("fps_limit", 0), self.tr("FPS Limit")), - (OverlaySelectInput("vsync", mangohud_vsync), self.tr("Vulkan VSync")), - (OverlaySelectInput("gl_vsync", mangohud_gl_vsync), self.tr("OpenGL VSync")), + (OverlayNumberInput("fps_limit", 0), self.tr("FPS limit")), + (OverlaySelectInput("vsync", mangohud_vsync), self.tr("Vulkan vsync")), + (OverlaySelectInput("gl_vsync", mangohud_gl_vsync), self.tr("OpenGL vsync")), (OverlayNumberInput("font_size", 24), self.tr("Font size")), (OverlaySelectInput("position", mangohud_position), self.tr("Position")), ] From b5901c5a6dbd0d61201543d99da340a2a07faade Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Sat, 15 Jun 2024 17:50:04 +0300 Subject: [PATCH 4/4] UninstallDialog: add option to keep the game's folder previously, if the game's install directory had remaining untracked data, it would not get deleted. this option force-deletes it it is not checked. --- rare/components/dialogs/uninstall_dialog.py | 27 ++++++++----- rare/components/tabs/downloads/__init__.py | 5 ++- rare/models/game.py | 2 +- rare/models/install.py | 44 ++++++++------------- rare/shared/workers/uninstall.py | 18 +++++++-- 5 files changed, 52 insertions(+), 44 deletions(-) diff --git a/rare/components/dialogs/uninstall_dialog.py b/rare/components/dialogs/uninstall_dialog.py index 337bc1b6..b9ba5606 100644 --- a/rare/components/dialogs/uninstall_dialog.py +++ b/rare/components/dialogs/uninstall_dialog.py @@ -1,4 +1,4 @@ -from PyQt5.QtCore import pyqtSignal +from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import ( QVBoxLayout, QCheckBox, @@ -23,6 +23,10 @@ class UninstallDialog(ButtonDialog): self.keep_files.setChecked(bool(options.keep_files)) self.keep_files.setEnabled(not rgame.is_overlay) + self.keep_folder = QCheckBox(self.tr("Keep game folder")) + self.keep_folder.setChecked(bool(options.keep_folder)) + self.keep_folder.setEnabled(not rgame.is_overlay) + self.keep_config = QCheckBox(self.tr("Keep configuation")) self.keep_config.setChecked(bool(options.keep_config)) self.keep_config.setEnabled(not rgame.is_overlay) @@ -33,6 +37,7 @@ class UninstallDialog(ButtonDialog): layout = QVBoxLayout() layout.addWidget(self.keep_files) + layout.addWidget(self.keep_folder) layout.addWidget(self.keep_config) layout.addWidget(self.keep_overlay_keys) @@ -42,21 +47,25 @@ class UninstallDialog(ButtonDialog): self.accept_button.setIcon(qta_icon("ri.uninstall-line")) self.accept_button.setObjectName("UninstallButton") - if rgame.sdl_name is not None: - self.keep_config.setChecked(True) + self.keep_files.stateChanged.connect(self.__on_keep_files_changed) self.options: UninstallOptionsModel = options + @pyqtSlot(int) + def __on_keep_files_changed(self, state: int): + self.keep_folder.setCheckState(state if state else Qt.Checked) + self.keep_folder.setEnabled(not state) + def done_handler(self) -> None: self.result_ready.emit(self.options) def accept_handler(self): - self.options.values = ( - True, - self.keep_files.isChecked(), - self.keep_config.isChecked(), - self.keep_overlay_keys.isChecked(), + self.options.set_accepted( + keep_files=self.keep_files.isChecked(), + keep_folder=self.keep_folder.isChecked(), + keep_config=self.keep_config.isChecked(), + keep_overlay_keys=self.keep_overlay_keys.isChecked(), ) def reject_handler(self): - self.options.values = (None, None, None, None) + self.options.set_rejected() diff --git a/rare/components/tabs/downloads/__init__.py b/rare/components/tabs/downloads/__init__.py index cf01b03f..e43cac46 100644 --- a/rare/components/tabs/downloads/__init__.py +++ b/rare/components/tabs/downloads/__init__.py @@ -352,7 +352,6 @@ class DownloadsTab(QWidget): def __on_uninstall_dialog_closed(self, options: UninstallOptionsModel): rgame = self.rcore.get_game(options.app_name) if options and options.accepted: - rgame.set_installed(False) worker = UninstallWorker(self.core, rgame, options) worker.signals.result.connect(self.__on_uninstall_worker_result) QThreadPool.globalInstance().start(worker) @@ -361,6 +360,8 @@ class DownloadsTab(QWidget): @pyqtSlot(RareGame, bool, str) def __on_uninstall_worker_result(self, rgame: RareGame, success: bool, message: str): - if not success: + if success: + rgame.set_installed(False) + else: QMessageBox.warning(None, self.tr("Uninstall - {}").format(rgame.app_title), message, QMessageBox.Close) rgame.state = RareGame.State.IDLE diff --git a/rare/models/game.py b/rare/models/game.py index 1756164f..59d6120d 100644 --- a/rare/models/game.py +++ b/rare/models/game.py @@ -555,7 +555,7 @@ class RareGame(RareGameSlim): if not self.is_idle: return False self.signals.game.uninstall.emit( - UninstallOptionsModel(app_name=self.app_name) + UninstallOptionsModel(app_name=self.app_name, keep_config=self.sdl_name is not None) ) return True diff --git a/rare/models/install.py b/rare/models/install.py index 0a4965d6..e17e7939 100644 --- a/rare/models/install.py +++ b/rare/models/install.py @@ -85,41 +85,29 @@ class UninstallOptionsModel: app_name: str accepted: bool = None keep_files: bool = None + keep_folder: bool = True keep_config: bool = None keep_overlay_keys: bool = None - def __bool__(self): - return ( - bool(self.app_name) - and (self.accepted is not None) - and (self.keep_files is not None) - and (self.keep_config is not None) - and (self.keep_overlay_keys is not None) - ) - @property - def values(self) -> Tuple[bool, bool, bool, bool]: - """ - This model's options + def __values(self) -> Tuple[bool, bool, bool, bool, bool]: + return self.accepted, self.keep_config, self.keep_folder, self.keep_files, self.keep_overlay_keys - :return: - Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys` - """ - return self.accepted, self.keep_config, self.keep_files, self.keep_overlay_keys + @__values.setter + def __values(self, values: Tuple[bool, bool, bool, bool, bool]): + self.accepted, self.keep_files, self.keep_folder, self.keep_config, self.keep_overlay_keys = values - @values.setter - def values(self, values: Tuple[bool, bool, bool, bool]): - """ - Set this model's options + def __bool__(self): + return bool(self.app_name) and all(map(lambda x: x is not None, self.__values)) - :param values: - Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys` - :return: - """ - self.accepted = values[0] - self.keep_files = values[1] - self.keep_config = values[2] - self.keep_overlay_keys = values[3] + def __iter__(self): + return iter(self.__values) + + def set_accepted(self, keep_config, keep_folder, keep_files, keep_overlay_keys): + self.__values = True, keep_config, keep_folder, keep_files, keep_overlay_keys + + def set_rejected(self): + self.__values = False, None, None, None, None @dataclass diff --git a/rare/shared/workers/uninstall.py b/rare/shared/workers/uninstall.py index 1a98144c..09a3793c 100644 --- a/rare/shared/workers/uninstall.py +++ b/rare/shared/workers/uninstall.py @@ -1,4 +1,5 @@ import platform +import shutil from logging import getLogger from typing import Tuple @@ -20,7 +21,7 @@ logger = getLogger("UninstallWorker") # TODO: You can use RareGame directly here once this is called inside RareCore and skip metadata fetch def uninstall_game( - core: LegendaryCore, rgame: RareGame, keep_files=False, keep_config=False, keep_overlay_keys=False + core: LegendaryCore, rgame: RareGame, keep_files=False, keep_folder=True, keep_config=False, keep_overlay_keys=False ) -> Tuple[bool, str]: if rgame.is_overlay: logger.info('Deleting overlay installation...') @@ -53,6 +54,8 @@ def uninstall_game( if link_path.exists(): link_path.unlink(missing_ok=True) + install_path = rgame.igame.install_path + status = LgndrIndirectStatus() LegendaryCLI(core).uninstall_game( LgndrUninstallGameArgs( @@ -63,6 +66,12 @@ def uninstall_game( indirect_status=status, ) ) + + keep_folder = keep_files if keep_files else keep_folder + if not keep_folder: + logger.info("Removing game install directory") + shutil.rmtree(install_path, ignore_errors=True) + if not keep_config: logger.info("Removing sections in config file") config.remove_section(rgame.app_name) @@ -89,9 +98,10 @@ class UninstallWorker(Worker): success, message = uninstall_game( self.core, self.rgame, - self.options.keep_files, - self.options.keep_config, - self.options.keep_overlay_keys, + keep_files=self.options.keep_files, + keep_folder=self.options.keep_folder, + keep_config=self.options.keep_config, + keep_overlay_keys=self.options.keep_overlay_keys, ) self.rgame.state = RareGame.State.IDLE self.signals.result.emit(self.rgame, success, message)