From d3ec79378e6452b81e4a74228c1a092a098e82d0 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 2 Jan 2024 22:31:25 +0200 Subject: [PATCH 1/4] UninstallDialog: Refactor to use ButtonDialog as base --- rare/components/dialogs/uninstall_dialog.py | 74 +++++++-------------- rare/components/tabs/downloads/__init__.py | 2 +- 2 files changed, 26 insertions(+), 50 deletions(-) diff --git a/rare/components/dialogs/uninstall_dialog.py b/rare/components/dialogs/uninstall_dialog.py index f87f2f00..c6f24cae 100644 --- a/rare/components/dialogs/uninstall_dialog.py +++ b/rare/components/dialogs/uninstall_dialog.py @@ -1,81 +1,57 @@ -from PyQt5.QtCore import Qt, pyqtSignal, QCoreApplication -from PyQt5.QtGui import QCloseEvent, QKeyEvent +from PyQt5.QtCore import pyqtSignal from PyQt5.QtWidgets import ( - QDialog, QLabel, QVBoxLayout, QCheckBox, - QHBoxLayout, - QPushButton, QLayout, ) -from legendary.utils.selective_dl import get_sdl_appname from rare.models.game import RareGame from rare.models.install import UninstallOptionsModel from rare.utils.misc import icon +from rare.widgets.dialogs import ButtonDialog, dialog_title_game -class UninstallDialog(QDialog): +class UninstallDialog(ButtonDialog): result_ready = pyqtSignal(UninstallOptionsModel) def __init__(self, rgame: RareGame, options: UninstallOptionsModel, parent=None): super(UninstallDialog, self).__init__(parent=parent) - self.setAttribute(Qt.WA_DeleteOnClose, True) - self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint) header = self.tr("Uninstall") - self.setWindowTitle(f'{header} "{rgame.app_title}" - {QCoreApplication.instance().applicationName()}') - self.title_label = QLabel( - self.tr("

Do you really want to uninstall {}?

").format(rgame.app_title) - ) + self.setWindowTitle(dialog_title_game(header, rgame.app_title)) - self.keep_files = QCheckBox(self.tr("Keep game files.")) + title_label = QLabel(f"

{dialog_title_game(header, rgame.app_title)}

", self) + + self.keep_files = QCheckBox(self.tr("Keep files")) self.keep_files.setChecked(bool(options.keep_files)) - self.keep_config = QCheckBox(self.tr("Keep game configuation.")) + + self.keep_config = QCheckBox(self.tr("Keep configuation")) self.keep_config.setChecked(bool(options.keep_config)) - self.uninstall_button = QPushButton( - icon("ei.remove-circle", color="red"), self.tr("Uninstall") - ) - self.uninstall_button.setObjectName("UninstallButton") - self.uninstall_button.clicked.connect(self.__on_uninstall) + layout = QVBoxLayout() + layout.addWidget(title_label) + layout.addWidget(self.keep_files) + layout.addWidget(self.keep_config) - self.cancel_button = QPushButton(self.tr("Cancel")) - self.cancel_button.clicked.connect(self.__on_cancel) + self.setCentralLayout(layout) - form_layout = QVBoxLayout() - form_layout.setContentsMargins(-1, -1, 0, -1) - form_layout.addWidget(self.keep_files) - form_layout.addWidget(self.keep_config) - - button_layout = QHBoxLayout() - button_layout.addWidget(self.cancel_button) - button_layout.addStretch(1) - button_layout.addWidget(self.uninstall_button) - - layout = QVBoxLayout(self) - layout.setSizeConstraint(QLayout.SetFixedSize) - layout.addWidget(self.title_label) - layout.addLayout(form_layout) - layout.addLayout(button_layout) + self.accept_button.setText(self.tr("Uninstall")) + self.accept_button.setIcon(icon("ri.uninstall-line")) + self.accept_button.setObjectName("UninstallButton") if rgame.sdl_name is not None: self.keep_config.setChecked(True) self.options: UninstallOptionsModel = options - def closeEvent(self, a0: QCloseEvent) -> None: + def done_handler(self) -> None: self.result_ready.emit(self.options) - super(UninstallDialog, self).closeEvent(a0) - def __on_uninstall(self): - self.options.values = (True, self.keep_files.isChecked(), self.keep_config.isChecked()) - self.close() + def accept_handler(self): + self.options.values = ( + True, + self.keep_files.isChecked(), + self.keep_config.isChecked(), + ) - def __on_cancel(self): + def reject_handler(self): self.options.values = (None, None, None) - self.close() - - def keyPressEvent(self, e: QKeyEvent) -> None: - if e.key() == Qt.Key_Escape: - e.accept() - self.__on_cancel() diff --git a/rare/components/tabs/downloads/__init__.py b/rare/components/tabs/downloads/__init__.py index dfff5865..9166f724 100644 --- a/rare/components/tabs/downloads/__init__.py +++ b/rare/components/tabs/downloads/__init__.py @@ -330,7 +330,7 @@ class DownloadsTab(QWidget): parent=self, ) uninstall_dialog.result_ready.connect(self.__on_uninstall_dialog_closed) - uninstall_dialog.exec() + uninstall_dialog.open() @pyqtSlot(UninstallOptionsModel) def __on_uninstall_dialog_closed(self, options: UninstallOptionsModel): From 17a5562b4c7ae453c2575d0692fd54f27aaccb0c Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 2 Jan 2024 23:00:29 +0200 Subject: [PATCH 2/4] ImportGroup: Update some strings --- .../ui/components/tabs/games/integrations/import_group.py | 8 ++++---- .../ui/components/tabs/games/integrations/import_group.ui | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rare/ui/components/tabs/games/integrations/import_group.py b/rare/ui/components/tabs/games/integrations/import_group.py index ccd97153..6b4a2a93 100644 --- a/rare/ui/components/tabs/games/integrations/import_group.py +++ b/rare/ui/components/tabs/games/integrations/import_group.py @@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_ImportGroup(object): def setupUi(self, ImportGroup): ImportGroup.setObjectName("ImportGroup") - ImportGroup.resize(651, 218) + ImportGroup.resize(651, 232) ImportGroup.setWindowTitle("ImportGroup") ImportGroup.setWindowFilePath("") self.import_layout = QtWidgets.QFormLayout(ImportGroup) @@ -54,7 +54,7 @@ class Ui_ImportGroup(object): self.import_force_check.setObjectName("import_force_check") self.import_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.import_force_check) self.import_button_label = QtWidgets.QLabel(ImportGroup) - self.import_button_label.setText("Error") + self.import_button_label.setText("error") self.import_button_label.setObjectName("import_button_label") self.import_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.import_button_label) self.button_info_layout = QtWidgets.QHBoxLayout() @@ -96,13 +96,13 @@ class Ui_ImportGroup(object): ImportGroup.setTitle(_translate("ImportGroup", "Import EGL game from a directory")) self.path_edit_label.setText(_translate("ImportGroup", "Installation path")) self.app_name_label.setText(_translate("ImportGroup", "Override app name")) - self.import_folder_label.setText(_translate("ImportGroup", "Import all folders")) + self.import_folder_label.setText(_translate("ImportGroup", "Import all games")) self.import_folder_check.setText(_translate("ImportGroup", "Scan the installation path for game folders and import them")) self.import_dlcs_label.setText(_translate("ImportGroup", "Import DLCs")) self.import_dlcs_check.setText(_translate("ImportGroup", "If a game has DLCs, try to import them too")) self.import_force_label.setText(_translate("ImportGroup", "Force import")) self.import_force_check.setText(_translate("ImportGroup", "Import game despite missing files")) - self.import_button.setText(_translate("ImportGroup", "Import Game")) + self.import_button.setText(_translate("ImportGroup", "Import game(s)")) self.platform_label.setText(_translate("ImportGroup", "Platform")) self.platform_tooltip.setText(_translate("ImportGroup", "Select the native platform of the game")) diff --git a/rare/ui/components/tabs/games/integrations/import_group.ui b/rare/ui/components/tabs/games/integrations/import_group.ui index 60dbd349..1ee4f1f2 100644 --- a/rare/ui/components/tabs/games/integrations/import_group.ui +++ b/rare/ui/components/tabs/games/integrations/import_group.ui @@ -7,7 +7,7 @@ 0 0 651 - 218 + 232 @@ -40,7 +40,7 @@ - Import all folders + Import all games @@ -97,7 +97,7 @@ - Error + error @@ -112,7 +112,7 @@ - Import Game + Import game(s) From 0fb1526d67f714b59fbb30458cd8d5dcd6586cd3 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Tue, 2 Jan 2024 23:11:47 +0200 Subject: [PATCH 3/4] MoveDialog: Refactor MovePopup into a dialog using ActionDialog as base --- .../move_game.py => dialogs/move_dialog.py} | 79 ++++++++++++------- .../tabs/games/game_info/game_info.py | 39 ++++----- rare/models/install.py | 17 +++- .../tabs/games/game_info/game_info.py | 5 +- .../tabs/games/game_info/game_info.ui | 11 +-- 5 files changed, 82 insertions(+), 69 deletions(-) rename rare/components/{tabs/games/game_info/move_game.py => dialogs/move_dialog.py} (76%) diff --git a/rare/components/tabs/games/game_info/move_game.py b/rare/components/dialogs/move_dialog.py similarity index 76% rename from rare/components/tabs/games/game_info/move_game.py rename to rare/components/dialogs/move_dialog.py index 37ebebac..cab68049 100644 --- a/rare/components/tabs/games/game_info/move_game.py +++ b/rare/components/dialogs/move_dialog.py @@ -4,12 +4,14 @@ from enum import auto from logging import getLogger from typing import Tuple, Optional -from PyQt5.QtCore import pyqtSignal, Qt, pyqtSlot -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFileDialog +from PyQt5.QtCore import pyqtSignal, pyqtSlot +from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QLabel, QFileDialog, QLayout +from rare.models.install import MoveGameModel from rare.models.game import RareGame from rare.shared import RareCore -from rare.utils.misc import path_size, format_size +from rare.utils.misc import path_size, format_size, icon +from rare.widgets.dialogs import ActionDialog, dialog_title_game from rare.widgets.elide_label import ElideLabel from rare.widgets.indicator_edit import PathEdit, IndicatorReasons, IndicatorReasonsCommon @@ -25,12 +27,16 @@ class MovePathEditReasons(IndicatorReasons): NO_SPACE = auto() -class MoveGamePopUp(QWidget): - move_clicked = pyqtSignal(str) - browse_done = pyqtSignal() +class MoveDialog(ActionDialog): + result_ready = pyqtSignal(RareGame, MoveGameModel) + + def __init__(self, rgame: RareGame, parent=None): + super(MoveDialog, self).__init__(parent=parent) + header = self.tr("Move") + self.setWindowTitle(dialog_title_game(header, rgame.app_title)) + + title_label = QLabel(f"

{dialog_title_game(header, rgame.app_title)}

", self) - def __init__(self, parent=None): - super(MoveGamePopUp, self).__init__(parent=parent) self.rcore = RareCore.instance() self.core = RareCore.instance().core() self.rgame: Optional[RareGame] = None @@ -44,19 +50,9 @@ class MoveGamePopUp(QWidget): MovePathEditReasons.NESTED_DIR: self.tr("Game install directories cannot be nested."), MovePathEditReasons.NO_SPACE: self.tr("Not enough space available on drive."), }) - self.path_edit.path_select.clicked.connect(self.browse_done) - - self.button = QPushButton(self.tr("Move")) - self.button.setFixedSize(self.path_edit.path_select.sizeHint()) - self.button.clicked.connect(lambda p: self.move_clicked.emit(self.path_edit.text())) self.warn_label = ElideLabel("", parent=self) - middle_layout = QHBoxLayout() - middle_layout.setAlignment(Qt.AlignRight) - middle_layout.addWidget(self.warn_label, stretch=1) - middle_layout.addWidget(self.button) - font = self.font() font.setBold(True) self.req_space_label = QLabel(self.tr("Required:"), self) @@ -72,11 +68,38 @@ class MoveGamePopUp(QWidget): bottom_layout.addWidget(self.avail_space_label) bottom_layout.addWidget(self.avail_space, stretch=1) - layout: QVBoxLayout = QVBoxLayout(self) + layout = QVBoxLayout() + layout.setSizeConstraint(QLayout.SetFixedSize) + layout.addWidget(title_label) layout.addWidget(self.path_edit) - layout.addLayout(middle_layout) + layout.addWidget(self.warn_label) layout.addLayout(bottom_layout) + self.setCentralLayout(layout) + + self.accept_button.setText(self.tr("Move")) + self.accept_button.setIcon(icon("mdi.folder-move-outline")) + + self.action_button.setHidden(True) + + self.update_game(rgame) + + self.options: MoveGameModel = MoveGameModel(rgame.app_name) + + def action_handler(self): + pass + + def done_handler(self): + self.result_ready.emit(self.rgame, self.options) + + def accept_handler(self): + self.options.accepted = True + self.options.target_path = self.path_edit.text() + + def reject_handler(self): + self.options.accepted = False + self.options.target_path = "" + def refresh_indicator(self): # needed so the edit_func gets run again text = self.path_edit.text() @@ -84,13 +107,13 @@ class MoveGamePopUp(QWidget): self.path_edit.setText(text) def path_edit_callback(self, path: str) -> Tuple[bool, str, int]: - self.button.setEnabled(True) + self.accept_button.setEnabled(True) self.warn_label.setHidden(False) self.req_space.setText("...") self.avail_space.setText("...") def helper_func(reason: int) -> Tuple[bool, str, int]: - self.button.setEnabled(False) + self.accept_button.setEnabled(False) return False, path, reason if not self.rgame.install_path or not path: @@ -141,7 +164,7 @@ class MoveGamePopUp(QWidget): return helper_func(MovePathEditReasons.NO_SPACE) # Fallback - self.button.setEnabled(True) + self.accept_button.setEnabled(True) return True, path, IndicatorReasonsCommon.VALID @pyqtSlot() @@ -151,20 +174,18 @@ class MoveGamePopUp(QWidget): self.setDisabled(True) return # FIXME: Make edit_func lighter instead of blocking signals - self.path_edit.line_edit.blockSignals(True) + # self.path_edit.line_edit.blockSignals(True) + self.setActive(True) self.path_edit.setText(self.rgame.install_path) # FIXME: Make edit_func lighter instead of blocking signals - self.path_edit.line_edit.blockSignals(False) + # self.path_edit.line_edit.blockSignals(False) + self.setActive(False) self.warn_label.setText( self.tr("Moving here will overwrite {}").format(os.path.basename(self.rgame.install_path)) ) self.refresh_indicator() def update_game(self, rgame: RareGame): - if self.rgame is not None: - self.rgame.signals.widget.update.disconnect(self.__update_widget) - self.rgame = None - rgame.signals.widget.update.connect(self.__update_widget) self.rgame = rgame self.__update_widget() diff --git a/rare/components/tabs/games/game_info/game_info.py b/rare/components/tabs/games/game_info/game_info.py index aed40fea..16030470 100644 --- a/rare/components/tabs/games/game_info/game_info.py +++ b/rare/components/tabs/games/game_info/game_info.py @@ -10,13 +10,11 @@ from PyQt5.QtCore import ( pyqtSignal, ) from PyQt5.QtWidgets import ( - QMenu, QWidget, QMessageBox, - QWidgetAction, ) -from rare.models.install import SelectiveDownloadsModel +from rare.models.install import SelectiveDownloadsModel, MoveGameModel from rare.components.dialogs.selective_dialog import SelectiveDialog from rare.models.game import RareGame from rare.shared import RareCore @@ -25,7 +23,7 @@ from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo from rare.utils.misc import format_size, icon from rare.widgets.image_widget import ImageWidget, ImageSize from rare.widgets.side_tab import SideTabContents -from .move_game import MoveGamePopUp, is_game_dir +from rare.components.dialogs.move_dialog import MoveDialog, is_game_dir logger = getLogger("GameInfo") @@ -68,18 +66,9 @@ class GameInfo(QWidget, SideTabContents): self.ui.modify_button.clicked.connect(self.__on_modify) self.ui.verify_button.clicked.connect(self.__on_verify) self.ui.repair_button.clicked.connect(self.__on_repair) + self.ui.move_button.clicked.connect(self.__on_move) self.ui.uninstall_button.clicked.connect(self.__on_uninstall) - self.move_game_pop_up = MoveGamePopUp(self) - move_action = QWidgetAction(self) - move_action.setDefaultWidget(self.move_game_pop_up) - self.ui.move_button.setMenu(QMenu(self.ui.move_button)) - self.ui.move_button.menu().addAction(move_action) - - self.move_game_pop_up.browse_done.connect(self.ui.move_button.showMenu) - self.move_game_pop_up.move_clicked.connect(self.ui.move_button.menu().close) - self.move_game_pop_up.move_clicked.connect(self.__on_move) - self.steam_grade_ratings = { "platinum": self.tr("Platinum"), "gold": self.tr("Gold"), @@ -217,17 +206,24 @@ class GameInfo(QWidget, SideTabContents): if ans == QMessageBox.Yes: self.repair_game(rgame) - @pyqtSlot(str) - def __on_move(self, dst_path: str): + @pyqtSlot() + def __on_move(self): """ This method is to be called from the button only """ - new_install_path = os.path.join(dst_path, os.path.basename(self.rgame.install_path)) + move_dialog = MoveDialog(self.rgame, parent=self) + move_dialog.result_ready.connect(self.move_game) + move_dialog.open() + def move_game(self, rgame: RareGame, model: MoveGameModel): + if not model.accepted: + return + + new_install_path = os.path.join(model.target_path, os.path.basename(self.rgame.install_path)) dir_exists = False if os.path.isdir(new_install_path): dir_exists = is_game_dir(self.rgame.install_path, new_install_path) if not dir_exists: - for item in os.listdir(dst_path): + for item in os.listdir(model.target_path): if os.path.basename(self.rgame.install_path) in os.path.basename(item): ans = QMessageBox.question( self, @@ -248,11 +244,8 @@ class GameInfo(QWidget, SideTabContents): else: return - self.move_game(self.rgame, new_install_path, dir_exists) - - def move_game(self, rgame: RareGame, dst_path, dst_exists): worker = MoveWorker( - self.core, rgame=rgame, dst_path=dst_path, dst_exists=dst_exists + self.core, rgame=rgame, dst_path=model.target_path, dst_exists=dir_exists ) worker.signals.progress.connect(self.__on_move_progress) worker.signals.result.connect(self.__on_move_result) @@ -395,7 +388,5 @@ class GameInfo(QWidget, SideTabContents): else: self.ui.install_button.setText(self.tr("Install")) - self.move_game_pop_up.update_game(rgame) - self.rgame = rgame self.__update_widget() diff --git a/rare/models/install.py b/rare/models/install.py index 05ef39ef..69123d0b 100644 --- a/rare/models/install.py +++ b/rare/models/install.py @@ -101,7 +101,7 @@ class UninstallOptionsModel: This model's options :return: - Tuple of `accepted` `keep_files` `keep_config` + Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys` """ return self.accepted, self.keep_config, self.keep_files @@ -111,7 +111,7 @@ class UninstallOptionsModel: Set this model's options :param values: - Tuple of `accepted` `keep_files` `keep_config` + Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys` :return: """ self.accepted = values[0] @@ -132,3 +132,16 @@ class SelectiveDownloadsModel: and (self.install_tag is not None) ) + +@dataclass +class MoveGameModel: + app_name: str + accepted: bool = None + target_path: Optional[str] = None + + def __bool__(self): + return ( + bool(self.app_name) + and (self.accepted is not None) + and (self.target_path is not None) + ) diff --git a/rare/ui/components/tabs/games/game_info/game_info.py b/rare/ui/components/tabs/games/game_info/game_info.py index bce4a9d5..3457e942 100644 --- a/rare/ui/components/tabs/games/game_info/game_info.py +++ b/rare/ui/components/tabs/games/game_info/game_info.py @@ -255,15 +255,12 @@ class Ui_GameInfo(object): self.move_button_layout.setContentsMargins(0, 0, 0, 0) self.move_button_layout.setSpacing(0) self.move_button_layout.setObjectName("move_button_layout") - self.move_button = QtWidgets.QToolButton(self.move_button_page) + self.move_button = QtWidgets.QPushButton(self.move_button_page) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.move_button.sizePolicy().hasHeightForWidth()) self.move_button.setSizePolicy(sizePolicy) - self.move_button.setPopupMode(QtWidgets.QToolButton.InstantPopup) - self.move_button.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly) - self.move_button.setArrowType(QtCore.Qt.DownArrow) self.move_button.setObjectName("move_button") self.move_button_layout.addWidget(self.move_button) self.move_stack.addWidget(self.move_button_page) diff --git a/rare/ui/components/tabs/games/game_info/game_info.ui b/rare/ui/components/tabs/games/game_info/game_info.ui index 64796002..89115667 100644 --- a/rare/ui/components/tabs/games/game_info/game_info.ui +++ b/rare/ui/components/tabs/games/game_info/game_info.ui @@ -488,7 +488,7 @@ 0 - + 0 @@ -498,15 +498,6 @@ Move - - QToolButton::InstantPopup - - - Qt::ToolButtonTextOnly - - - Qt::DownArrow - From 9ad47ba75ba3b85576ec4a95d21eab75108fcdd7 Mon Sep 17 00:00:00 2001 From: loathingKernel <142770+loathingKernel@users.noreply.github.com> Date: Sat, 6 Jan 2024 14:08:27 +0200 Subject: [PATCH 4/4] Translations: Update source file --- .../resources/languages/translation_source.ts | 1400 +++++++++-------- 1 file changed, 773 insertions(+), 627 deletions(-) diff --git a/rare/resources/languages/translation_source.ts b/rare/resources/languages/translation_source.ts index 5a381708..be0d8d00 100644 --- a/rare/resources/languages/translation_source.ts +++ b/rare/resources/languages/translation_source.ts @@ -4,93 +4,103 @@ About - + About - + Version - - Update available - - - - + Download latest release - - Rare Developer - - - - + Github - + Legendary Developer - + License - + GNU General Public License v3.0 - - Update available: {} -> {} + + You have the latest version + + + + + Update + + + + + Rare Developers + + + + + Rare Contributors AccountWidget - + Account settings - + Logout - + Account - + Logged in as <b>{}</b> + + + Quit + + AvailableGameDlcWidget - + Install DLC - + Error - + Base Game is not installed. Please install {} first @@ -98,46 +108,46 @@ BrowserLogin - + Open Browser - + Login through browser - + Logging in... - + Login failed. - + Copied to clipboard - - - Click the button to open the login page in a browser or copy the link and paste it in a browser. After logging in, copy the <b><code>authorizationCode</code></b> in the input above. - - Insert authorizationCode here + + + <i>Click the <strong>Open Browser</strong> button to open the login page in your web browser or copy the link and paste it in any web browser. After logging in using the browser, copy the text in the quotes after </i><code><b>authorizationCode</b></code><i> in the same line into the empty input above.<br><br><strong>DO NOT SHARE THE INFORMATION IN THE BROWSER PAGE WITH ANYONE IN ANY FORM (TEXT OR SCREENSHOT)!</strong></i> + + - CloudSaveDialog + ButtonDialog - - Newer + + Cancel @@ -154,46 +164,87 @@ - - Save path - - - - + Calculate path - + Loading... - + Error - {} - - Error while calculating path for <b>{}</b>. Insufficient permisions to create <b>{}</b> + + Newer - + + Error while calculating path for <b>{}</b>. Insufficient permissions to create <b>{}</b> + + + + + CloudSettingsWidget + + + Settings + + + + + Enable sync + + + + + Saves path + + + + + CloudSyncDialog + + + Cloud saves for + + + + + Skip + + + + Newer - CloudWidget + CloudSyncWidget - - Options + + Local - - Sync with cloud + + Upload + + + + + Cloud + + + + + Download @@ -212,29 +263,39 @@ - Console + ConsoleDialog - + Show environment - + Save output to file - + Clear console - + + Terminate + + + + + Kill + + + + Saved - + Application "{}" finished with "{}" @@ -243,17 +304,17 @@ ConsoleEnv - + Rare - Console Environment - + Variable - + Value @@ -261,112 +322,112 @@ Constants - + Action - + Adventure - + Puzzle - + Open world - + Racing - + RPG - + Shooter - + Strategy - + Survival - + First Person - + Indie - + Simulation - + Sport - + Single player - + Multiplayer - + Controller - + Co-op - + Editor - + Game - + Bundle - + Add-on - + Apps @@ -407,22 +468,22 @@ DownloadsTab - + No active download - + Error - + Download error: {} - + Uninstall - {} @@ -435,7 +496,7 @@ - + DXVK Settings @@ -445,12 +506,12 @@ - + DXVK Version - + FPS @@ -535,30 +596,35 @@ - + Custom options + + + Compiler activity + + EGLSyncExportGroup - + Exportable games - + No games to export to EGL - + Export - + The following errors occurred while exporting. @@ -566,65 +632,70 @@ EGLSyncGroup - + Sync with Epic Games Launcher - + Prefix/Manifest path - + Estimated path - + Enable automatic sync - + Updating... - + Path to the Wine prefix where EGL is installed, or the Manifests folder - + Default Wine prefix is unset, or path does not exist. Create it or configure it in Settings -> Linux. - + Default Wine prefix is set but EGL manifests path does not exist. Your configured default Wine prefix might not be where EGL is installed. + + + This will immediately synchronize with EGL + + EGLSyncImportGroup - + Importable games - + No games to import from EGL - + Import - + The following errors occurred while importing. @@ -645,42 +716,42 @@ EOSGroup - + No update available - + Something went wrong, when installing overlay - + Failed to disable Overlay. Probably it is installed by Epic Games Launcher - + Disabled - + Failed to enable EOS overlay. Maybe it is already installed by Epic Games Launcher - + Enabled - + Overlay is not installed. Could not update - + Do you want to uninstall overlay? @@ -696,22 +767,22 @@ EnvVarsTableModel - + Key - + Value - + Disabled, please set the variable name first. - + Readonly, please edit this via setting the appropriate setting. @@ -719,47 +790,47 @@ EosWidget - + Activated - + Uninstall - + Update - + Install - + Epic Overlay - + Version - + Location - + Check for update - + Epic Overlay Services is not installed @@ -808,180 +879,210 @@ GameInfo - + Game Info - + Developer - + Installation Path - + Installation Size - + Version - + Application Name - + Actions - + ProtonDB Grade - - Verify Installation - - - - - Uninstall Game - - - - - Install Game - - - - + Repair file does not exist or game does not need a repair. Please verify game first - + Platform - - Repair Installation - - - - - Move Installation - - - - + Error - {} - + Installation path for <b>{}</b> does not exist. Cannot continue. - + Summary - {} - + <b>{}</b> has been verified successfully. No missing or corrupt files found - - Import Game - - - - + Platinum - + Gold - + Silver - + Bronze - + Borked - + Failed to get rating - + Loading... - + Not applicable - + Repair and update? - {} - + There is an update for <b>{}</b> from <b>{}</b> to <b>{}</b>. Do you want to update the game while repairing it? - + <b>{}</b> failed verification, <b>{}</b> file(s) corrupted, <b>{}</b> file(s) are missing. Do you want to repair them? - + Move game? - {} - + Destination <b>{}</b> already exists. Are you sure you want to overwrite it? - + <b>{}</b> successfully moved to <b>{}<b>. - + Link/Launch + + + Install + + + + + Tags + + + + + Completed + + + + + Hidden + + + + + Favorites + + + + + Backlog + + + + + Modify + + + + + Verify + + + + + Repair + + + + + Move + + + + + Uninstall + + + + + Import + + GameInfoTabs @@ -1019,75 +1120,75 @@ GameListHeadBar - - Installed only - - - - - Offline Games - - - - - 32 Bit Games - - - - + Exclude Origin - + Import Game - + Search Game - + Sync with EGL - - Mac games - - - - - Include Unreal Engine - - - - + All games - + Installed games - + Available games - + Epic Overlay and Ubisoft - + Integrations + + + Installed + + + + + Offline + + + + + 32bit games + + + + + macOS games + + + + + Include Unreal + + GameSettings @@ -1155,137 +1256,137 @@ GameWidget - + Free - + Launch - + Install - + Reload Image - + Uninstall - + Running... - + Downloading... - + Verifying... - + Moving... - + Uninstalling... - + Syncing saves... - + Update available - + Needs verification - + Can't launch - + Save is not up-to-date - + Show information - + Install game - + Launch game - + Launch offline - + Launch without version check - + Launch/Link - + Remove Desktop link - + Create Desktop link - + Remove Start Menu link - + Create Start Menu link - + Warning - + Creating shortcuts is currently unsupported on {} @@ -1293,223 +1394,238 @@ ImportGroup - + Import EGL game from a directory - + Installation path - + Override app name - - Import Game - - - - + Use in case the app name was not found automatically - - Import all folders - - - - + Scan the installation path for game folders and import them - + Import DLCs - + If a game has DLCs, try to import them too - + Success: <b>{}</b> imported - + Failed: <b>{}</b> - {} - + Error: Could not find AppName for <b>{}</b> - + Import summary - + Success: {} imported - + Failed: {} - {} - + Error: Could not find AppName for {} - - Importing games - - - - + Tried to import {} folders. Successfully imported {} games, failed to import {} games and {} errors occurred - + Force import - + Import game despite missing files + + + When importing multiple games, the current OS will be used at the platform for the games that support it, otherwise the Windows version will be imported. + + + + + Status: Importing games + + + + + Status: Finished importing games + + + + + Import all games + + + + + Import game(s) + + + + + Platform + + + + + Select the native platform of the game + + ImportLogin - - You will get logged out from EGL in the process. - - - - + Import existing session from EGL - + Browse - + Found EGL Program Data. Click 'Next' to import them. - + Select the Wine prefix you want to import. - + Choose path - + Loading... - + Login failed. - + Login failed. {} - + Could not find EGL Program Data. - - Please select the Wine prefix where Epic Games Launcher is installed. + + Select prefix - - Select prefix + + <i>Please select the Wine prefix where Epic Games Launcher is installed. You will get logged out from EGL in the process.</i> IndicatorLineEdit - - Default + + Use global/default setting IndicatorReasonsStrings - + Ok! - + Unknown error occurred - + Value can not be empty - + Wrong format - + Wrong file or directory - + Directory is not empty - + Directory does not exist - + File does not exist - + Game is not installed or does not exist @@ -1517,120 +1633,120 @@ Successfully imported {} games, failed to import {} games and {} errors occurred InstallDialog - + error - - Install directory - - - - + Download size - + Click verify... - + Total install size - + None - - Cancel - - - - + Verify - + Install - + Update - + Updating... - + Game already installed - + Error - + Platform - + Create shortcut - - Creating a shortcut is not supported on MacOS - - - - + Warning - + You will not be able to run the game if you select <b>{}</b> as platform - + Also install: {} - + Optional downloads - + Repair - + Repair and update - + Available space + + + Modify + + + + + Creating a shortcut is not supported on macOS + + + + + Install folder + + InstallDialogAdvanced @@ -1698,7 +1814,7 @@ Successfully imported {} games, failed to import {} games and {} errors occurred InstalledGameDlcWidget - + Uninstall DLC @@ -1734,38 +1850,33 @@ Successfully imported {} games, failed to import {} games and {} errors occurred LandingPage - + Select login method - + Browser - + Login using a browser. - + Import - + Import from Epic Games Launcher LaunchDialog - - - Launching Rare - - <h2>Launching Rare</h2> @@ -1776,102 +1887,122 @@ Successfully imported {} games, failed to import {} games and {} errors occurred Preparing Rare + + + Launching + + LegendarySettings - - Default Installation Directory - - - - - Download Settings - - - - - Max Workers - - - - + Less is slower (0: Default) - + MiB - + Preferred CDN - + Default - + Disable HTTPS - + Locale - + Cleanup - + Clean, but keep manifests - + Remove everything - + Cleanup complete! Successfully removed {} - - Refresh game meta + + Default installation folder for macOS games - - Loading + + Default installation folder for Windows games - - Game metadata + + Default installation folder - - Load 32bit data + + Download settings - - Load MacOS data + + Max sorkers - - Max Shared Memory + + Max shared memory + + + + + Platforms + + + + + Include Win32 games + + + + + Include macOS games + + + + + Include Unreal engine + + + + + Restart Rare to apply + + + + + Refresh metadata @@ -1934,13 +2065,13 @@ Successfully imported {} games, failed to import {} games and {} errors occurred - - Rare Login + + Login error - - Login error + + Login @@ -1962,18 +2093,23 @@ Successfully imported {} games, failed to import {} games and {} errors occurred - + Logout - - There are active downloads. Stop them before logging out. + + Do you really want to logout <b>{}</b>? - - Do you really want to logout <b>{}</b>? + + Quit + + + + + There are active downloads. Stop them before trying to quit. @@ -1990,19 +2126,19 @@ Successfully imported {} games, failed to import {} games and {} errors occurred - + Quit {}? - + There are currently running operations. Rare cannot exit until they are completed. Do you want to clear the queue? - + There is an active download. Quitting Rare now will stop the download. Are you sure you want to quit? @@ -2116,54 +2252,54 @@ Are you sure you want to quit? - MoveGamePopUp + MoveDialog - + Move - + You need to provide the destination directory. - + No write permission on destination. - + Same directory or subdirectory selected. - + Destination is inside source directory - + Game install directories cannot be nested. - + Not enough space available on drive. - + Required: - + Available: - + Moving here will overwrite <b>{}</b> @@ -2199,12 +2335,12 @@ Are you sure you want to quit? - + Browse... - + Choose path @@ -2212,7 +2348,7 @@ Are you sure you want to quit? PathInputDialog - + Cancel @@ -2253,7 +2389,7 @@ Are you sure you want to quit? - + Please select path for proton prefix @@ -2368,30 +2504,25 @@ Are you sure you want to quit? RareCore - + Loaded <b>{}</b> - - Prepared games - - - - - Prepared games without assets - - - - + Launching Rare + + + Preparing library + + RareException - + Failed to login @@ -2408,26 +2539,11 @@ Are you sure you want to quit? Language - - - Color Scheme - - None - - - Style Sheet - - - - - Restart Rare to apply. - - Behavior @@ -2438,115 +2554,153 @@ Are you sure you want to quit? Restore window size on application startup - - - Show notification on download completion - - - - - Show console for game debug - - - - - Exit to System tray - - - - - Update games on application startup - - - - - Confirm game launch - - - - - Automatically sync with cloud - - Logs - - - Open Log directory - - - - - Clean Log directory - - Shortcuts - - Create Desktop link - - - - + Create start menu link - + Remove desktop link - + Remove start menu link - + Remove Desktop link - + Create desktop link - + Not supported - + Error - + Permission error, cannot remove {} + + + Color scheme + + + + + Style sheet + + + + + Restart Rare to apply changes. + + + + + Show notifications when downloads complete + + + + + Show console windows when launching games + + + + + Exit to system tray + + + + + Queue game updates on application startup + + + + + Confirm before launching games + + + + + Automatically upload/download cloud saves + + + + + Open log folder + + + + + Clean log folder + + + + + Create on desktop + + + + + Create in menu + + SearchResults - + Back - + No results found + + SelectiveDialog + + + Optional downloads for + + + + + Optional downloads + + + + + Verify + + + SettingsTab @@ -2558,12 +2712,12 @@ Are you sure you want to quit? Shop - + Games - + Wishlist @@ -2571,47 +2725,47 @@ Are you sure you want to quit? ShopGameInfo - + Remove from Wishlist - + Show Game on Epic Page - + Buy Game in Epic Games Store - + Loading - + Free - + Minimum - + Recommend - + Could not get requirements - + Social Links @@ -2704,42 +2858,42 @@ Are you sure you want to quit? - + Now Free - + Free Games next week - + Search Games - + Could not get games matching the filter - + Reload - + Could not find current free game - + Failed to get wishlist: {} - + Failed to fetch free games: {} @@ -2747,52 +2901,11 @@ Are you sure you want to quit? SideTabWidget - + Back - - SyncSaveDialog - - - Sync saves with cloud - - - - - Cancel - - - - - Select save, you want to use for - - - - - SyncWidget - - - Local - - - - - Upload - - - - - Cloud - - - - - Download - - - TrayIcon @@ -2814,79 +2927,79 @@ Are you sure you want to quit? UbiLinkWidget - - Redeem to Ubisoft - - - - + Already activated - + Try again + + + Redeem in Ubisoft + + UbisoftGroup - + Link Ubisoft Games - - - Your account is not linked with Ubisoft. Please link your account first - - - - - Open link page - - - An error occurred + Getting information about your redeemable Ubisoft games. - - All your Ubisoft games have already been activated + + Link Ubisoft acccount - - You don't own any Ubisoft games + + Your account is not linked with Ubisoft. Please link your account and try again. + + + + + An error has occurred while requesting your account's Ubisoft information. + + + + + You don't own any Ubisoft games. + + + + + All your Ubisoft games have already been activated. + + + + + You have <b>{}</b> games available to redeem. UninstallDialog - + Uninstall - - Cancel + + Keep files - Do you really want to uninstall <b>{}</b>? - - - - - Keep game files. - - - - - Keep game configuation. + Keep configuation @@ -2956,7 +3069,7 @@ Are you sure you want to quit? - + Could not remove game from wishlist @@ -2964,7 +3077,7 @@ Are you sure you want to quit? WishlistWidget - + Free @@ -2977,47 +3090,80 @@ Are you sure you want to quit? - - Wrapper is already in the list - - - - - Wrapper is not in $PATH. Ignore? - - - - - Do not insert proton manually. Add it in proton settings - - - - + Add wrapper - - Insert wrapper executable + + Enter wrapper command + + + + + Warning + + + + + Wrapper <b>{0}</b> is already in the list + + + + + Wrapper <b>{0}</b> is not in $PATH. Add it anyway? + + + + + Do not insert <b>proton</b> manually. Add it through Proton settings WrapperWidget - - Disable it in settings + + Manage through settings + + + + + Manage + + + + + Edit wrapper command _SearchResultItem - + Free + + self.signals + + + Updating game metadata for Windows + + + + + Updating game metadata for macOS + + + + + Updating non-asset game metadata + + + shop_info @@ -3054,7 +3200,7 @@ Are you sure you want to quit? widget - + Advanced options