From 2c36ffcd51c82e48be2ba282a12c5ff5350f803f Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Thu, 1 Sep 2022 11:49:42 +0300
Subject: [PATCH 01/15] Lgndr: Adjust for
https://github.com/derrod/legendary/commit/d8af06c936a446b245ae27f3f39baabbf25b946d
---
rare/components/dialogs/install_dialog.py | 22 +++++++++----------
.../tabs/downloads/download_thread.py | 4 ++--
rare/lgndr/api_arguments.py | 2 +-
rare/lgndr/cli.py | 8 +++----
rare/models/install.py | 4 ++--
rare/ui/components/dialogs/install_dialog.py | 20 ++++++++---------
rare/ui/components/dialogs/install_dialog.ui | 4 ++--
.../dialogs/install_dialog_advanced.py | 22 +++++++++----------
.../dialogs/install_dialog_advanced.ui | 6 ++---
9 files changed, 46 insertions(+), 46 deletions(-)
diff --git a/rare/components/dialogs/install_dialog.py b/rare/components/dialogs/install_dialog.py
index c4e2281c..ca58ecb6 100644
--- a/rare/components/dialogs/install_dialog.py
+++ b/rare/components/dialogs/install_dialog.py
@@ -145,9 +145,9 @@ class InstallDialog(QDialog):
self.ui.shortcut_cb.setChecked(False)
self.ui.shortcut_cb.setToolTip(self.tr("Creating a shortcut is not supported on MacOS"))
- self.ui.install_preqs_lbl.setVisible(False)
- self.ui.install_preqs_check.setVisible(False)
- self.ui.install_preqs_check.stateChanged.connect(lambda: self.non_reload_option_changed("install_preqs"))
+ self.ui.install_prereqs_lbl.setVisible(False)
+ self.ui.install_prereqs_check.setVisible(False)
+ self.ui.install_prereqs_check.stateChanged.connect(lambda: self.non_reload_option_changed("install_prereqs"))
self.non_reload_option_changed("shortcut")
@@ -155,7 +155,7 @@ class InstallDialog(QDialog):
self.ui.verify_button.clicked.connect(self.verify_clicked)
self.ui.install_button.clicked.connect(self.install_clicked)
- self.ui.install_preqs_check.setChecked(self.dl_item.options.install_preqs)
+ self.ui.install_prereqs_check.setChecked(self.dl_item.options.install_prereqs)
self.ui.install_dialog_layout.setSizeConstraint(QLayout.SetFixedSize)
@@ -209,7 +209,7 @@ class InstallDialog(QDialog):
self.dl_item.options.ignore_space = self.ui.ignore_space_check.isChecked()
self.dl_item.options.no_install = self.ui.download_only_check.isChecked()
self.dl_item.options.platform = self.ui.platform_combo_box.currentText()
- self.dl_item.options.install_preqs = self.ui.install_preqs_check.isChecked()
+ self.dl_item.options.install_prereqs = self.ui.install_prereqs_check.isChecked()
self.dl_item.options.create_shortcut = self.ui.shortcut_cb.isChecked()
if self.sdl_list_cbs:
self.dl_item.options.install_tag = [""]
@@ -254,8 +254,8 @@ class InstallDialog(QDialog):
elif option == "shortcut":
QSettings().setValue("create_shortcut", self.ui.shortcut_cb.isChecked())
self.dl_item.options.create_shortcut = self.ui.shortcut_cb.isChecked()
- elif option == "install_preqs":
- self.dl_item.options.install_preqs = self.ui.install_preqs_check.isChecked()
+ elif option == "install_prereqs":
+ self.dl_item.options.install_prereqs = self.ui.install_prereqs_check.isChecked()
def cancel_clicked(self):
if self.config_tags:
@@ -289,10 +289,10 @@ class InstallDialog(QDialog):
self.ui.cancel_button.setEnabled(True)
if pf.system() == "Windows" or ArgumentsSingleton().debug:
if dl_item.igame.prereq_info and not dl_item.igame.prereq_info.get("installed", False):
- self.ui.install_preqs_check.setVisible(True)
- self.ui.install_preqs_lbl.setVisible(True)
- self.ui.install_preqs_check.setChecked(True)
- self.ui.install_preqs_check.setText(
+ self.ui.install_prereqs_check.setVisible(True)
+ self.ui.install_prereqs_lbl.setVisible(True)
+ self.ui.install_prereqs_check.setChecked(True)
+ self.ui.install_prereqs_check.setText(
self.tr("Also install: {}").format(dl_item.igame.prereq_info.get("name", ""))
)
if self.silent:
diff --git a/rare/components/tabs/downloads/download_thread.py b/rare/components/tabs/downloads/download_thread.py
index 5f672558..cefc4a94 100644
--- a/rare/components/tabs/downloads/download_thread.py
+++ b/rare/components/tabs/downloads/download_thread.py
@@ -98,7 +98,7 @@ class DownloadThread(QThread):
# postinstall,
# self.item.download.igame,
# False,
- # self.item.options.install_preqs,
+ # self.item.options.install_prereqs,
# )
self._handle_postinstall(postinstall, self.item.download.igame)
@@ -140,7 +140,7 @@ class DownloadThread(QThread):
logger.info("This game lists the following prequisites to be installed:")
logger.info(f'- {postinstall["name"]}: {" ".join((postinstall["path"], postinstall["args"]))}')
if platform.system() == "Windows":
- if not self.item.options.install_preqs:
+ if not self.item.options.install_prereqs:
logger.info("Marking prerequisites as installed...")
self.core.prereq_installed(self.item.download.igame.app_name)
else:
diff --git a/rare/lgndr/api_arguments.py b/rare/lgndr/api_arguments.py
index abbe9bba..03a28942 100644
--- a/rare/lgndr/api_arguments.py
+++ b/rare/lgndr/api_arguments.py
@@ -114,7 +114,7 @@ class LgndrInstallGameRealArgs:
dlm_debug: bool = False
yes: bool = False
# Rare: Extra arguments
- install_preqs: bool = False
+ install_prereqs: bool = False
indirect_status: LgndrIndirectStatus = LgndrIndirectStatus()
ui_update: Callable[[UIUpdate], None] = lambda ui: None
dlm_signals: DLManagerSignals = DLManagerSignals()
diff --git a/rare/lgndr/cli.py b/rare/lgndr/cli.py
index 34622028..667b19a3 100644
--- a/rare/lgndr/cli.py
+++ b/rare/lgndr/cli.py
@@ -248,7 +248,7 @@ class LegendaryCLI(LegendaryCLIReal):
postinstall = self.core.install_game(igame)
if postinstall:
- self._handle_postinstall(postinstall, igame, yes=args.yes, choice=args.install_preqs)
+ self._handle_postinstall(postinstall, igame, skip_prereqs=args.yes, choice=args.install_prereqs)
dlcs = self.core.get_dlc_for_game(game.app_name)
if dlcs and not args.skip_dlcs:
@@ -301,7 +301,7 @@ class LegendaryCLI(LegendaryCLIReal):
self.core.uninstall_tag(old_igame)
self.core.install_game(old_igame)
- def _handle_postinstall(self, postinstall, igame, yes=False, choice=True):
+ def _handle_postinstall(self, postinstall, igame, skip_prereqs=False, choice=True):
# Override logger for the local context to use message as part of the indirect return value
logger = LgndrIndirectLogger(LgndrIndirectStatus(), self.logger)
# noinspection PyShadowingBuiltins
@@ -309,12 +309,12 @@ class LegendaryCLI(LegendaryCLIReal):
# noinspection PyShadowingBuiltins
def input(x): return 'y' if choice else 'i'
- print('\nThis game lists the following prequisites to be installed:')
+ print('\nThis game lists the following prerequisites to be installed:')
print(f'- {postinstall["name"]}: {" ".join((postinstall["path"], postinstall["args"]))}')
print('')
if os.name == 'nt':
- if yes:
+ if skip_prereqs:
c = 'n' # we don't want to launch anything, just silent install.
else:
choice = input('Do you wish to install the prerequisites? ([y]es, [n]o, [i]gnore): ')
diff --git a/rare/models/install.py b/rare/models/install.py
index b4dedef8..d9a487c9 100644
--- a/rare/models/install.py
+++ b/rare/models/install.py
@@ -31,7 +31,7 @@ class InstallOptionsModel:
overlay: bool = False
update: bool = False
silent: bool = False
- install_preqs: bool = pf.system() == "Windows"
+ install_prereqs: bool = pf.system() == "Windows"
def __post_init__(self):
self.sdl_prompt: Callable[[str, str], list] = \
@@ -41,7 +41,7 @@ class InstallOptionsModel:
return {
k: getattr(self, k)
for k in self.__dict__
- if k not in ["update", "silent", "create_shortcut", "overlay", "install_preqs"]
+ if k not in ["update", "silent", "create_shortcut", "overlay", "install_prereqs"]
}
diff --git a/rare/ui/components/dialogs/install_dialog.py b/rare/ui/components/dialogs/install_dialog.py
index df52eea6..41afaa0c 100644
--- a/rare/ui/components/dialogs/install_dialog.py
+++ b/rare/ui/components/dialogs/install_dialog.py
@@ -109,17 +109,17 @@ class Ui_InstallDialog(object):
self.max_memory_info_label.setObjectName("max_memory_info_label")
self.max_memory_layout.addWidget(self.max_memory_info_label)
self.advanced_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.max_memory_layout)
- self.install_preqs_lbl = QtWidgets.QLabel(InstallDialog)
- self.install_preqs_lbl.setObjectName("install_preqs_lbl")
- self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_preqs_lbl)
- self.install_preqs_check = QtWidgets.QCheckBox(InstallDialog)
+ self.install_prereqs_lbl = QtWidgets.QLabel(InstallDialog)
+ self.install_prereqs_lbl.setObjectName("install_prereqs_lbl")
+ self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_lbl)
+ self.install_prereqs_check = QtWidgets.QCheckBox(InstallDialog)
font = QtGui.QFont()
font.setItalic(True)
- self.install_preqs_check.setFont(font)
- self.install_preqs_check.setText("")
- self.install_preqs_check.setChecked(False)
- self.install_preqs_check.setObjectName("install_preqs_check")
- self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.install_preqs_check)
+ self.install_prereqs_check.setFont(font)
+ self.install_prereqs_check.setText("")
+ self.install_prereqs_check.setChecked(False)
+ self.install_prereqs_check.setObjectName("install_prereqs_check")
+ self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.install_prereqs_check)
self.dl_optimizations_label = QtWidgets.QLabel(InstallDialog)
self.dl_optimizations_label.setObjectName("dl_optimizations_label")
self.advanced_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.dl_optimizations_label)
@@ -216,7 +216,7 @@ class Ui_InstallDialog(object):
self.max_memory_label.setText(_translate("InstallDialog", "Max shared memory"))
self.max_memory_spin.setSuffix(_translate("InstallDialog", "MiB"))
self.max_memory_info_label.setText(_translate("InstallDialog", "Less is slower (0: Default)"))
- self.install_preqs_lbl.setText(_translate("InstallDialog", "Install prerequisites"))
+ self.install_prereqs_lbl.setText(_translate("InstallDialog", "Install prerequisites"))
self.dl_optimizations_label.setText(_translate("InstallDialog", "Enable reordering"))
self.force_download_label.setText(_translate("InstallDialog", "Force redownload"))
self.ignore_space_label.setText(_translate("InstallDialog", "Ignore free space"))
diff --git a/rare/ui/components/dialogs/install_dialog.ui b/rare/ui/components/dialogs/install_dialog.ui
index 0e3c9e53..c276cfda 100644
--- a/rare/ui/components/dialogs/install_dialog.ui
+++ b/rare/ui/components/dialogs/install_dialog.ui
@@ -185,14 +185,14 @@
-
-
+
Install prerequisites
-
-
+
true
diff --git a/rare/ui/components/dialogs/install_dialog_advanced.py b/rare/ui/components/dialogs/install_dialog_advanced.py
index 36151d05..c853bb74 100644
--- a/rare/ui/components/dialogs/install_dialog_advanced.py
+++ b/rare/ui/components/dialogs/install_dialog_advanced.py
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_InstallDialogAdvanced(object):
def setupUi(self, InstallDialogAdvanced):
InstallDialogAdvanced.setObjectName("InstallDialogAdvanced")
- InstallDialogAdvanced.resize(359, 208)
+ InstallDialogAdvanced.resize(379, 208)
self.install_dialog_advanced_layout = QtWidgets.QFormLayout(InstallDialogAdvanced)
self.install_dialog_advanced_layout.setObjectName("install_dialog_advanced_layout")
self.max_workers_label = QtWidgets.QLabel(InstallDialogAdvanced)
@@ -63,17 +63,17 @@ class Ui_InstallDialogAdvanced(object):
self.max_memory_info_label.setObjectName("max_memory_info_label")
self.max_memory_layout.addWidget(self.max_memory_info_label)
self.install_dialog_advanced_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.max_memory_layout)
- self.install_preqs_lbl = QtWidgets.QLabel(InstallDialogAdvanced)
- self.install_preqs_lbl.setObjectName("install_preqs_lbl")
- self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_preqs_lbl)
- self.install_preqs_check = QtWidgets.QCheckBox(InstallDialogAdvanced)
+ self.install_prereqs_lbl = QtWidgets.QLabel(InstallDialogAdvanced)
+ self.install_prereqs_lbl.setObjectName("install_prereqs_lbl")
+ self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_lbl)
+ self.install_prereqs_check = QtWidgets.QCheckBox(InstallDialogAdvanced)
font = QtGui.QFont()
font.setItalic(True)
- self.install_preqs_check.setFont(font)
- self.install_preqs_check.setText("")
- self.install_preqs_check.setChecked(False)
- self.install_preqs_check.setObjectName("install_preqs_check")
- self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.install_preqs_check)
+ self.install_prereqs_check.setFont(font)
+ self.install_prereqs_check.setText("")
+ self.install_prereqs_check.setChecked(False)
+ self.install_prereqs_check.setObjectName("install_prereqs_check")
+ self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.install_prereqs_check)
self.dl_optimizations_label = QtWidgets.QLabel(InstallDialogAdvanced)
self.dl_optimizations_label.setObjectName("dl_optimizations_label")
self.install_dialog_advanced_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.dl_optimizations_label)
@@ -119,7 +119,7 @@ class Ui_InstallDialogAdvanced(object):
self.max_memory_label.setText(_translate("InstallDialogAdvanced", "Max shared memory"))
self.max_memory_spin.setSuffix(_translate("InstallDialogAdvanced", "MiB"))
self.max_memory_info_label.setText(_translate("InstallDialogAdvanced", "Less is slower (0: Default)"))
- self.install_preqs_lbl.setText(_translate("InstallDialogAdvanced", "Install prerequisites"))
+ self.install_prereqs_lbl.setText(_translate("InstallDialogAdvanced", "Install prerequisites"))
self.dl_optimizations_label.setText(_translate("InstallDialogAdvanced", "Enable reordering"))
self.force_download_label.setText(_translate("InstallDialogAdvanced", "Force redownload"))
self.ignore_space_label.setText(_translate("InstallDialogAdvanced", "Ignore free space"))
diff --git a/rare/ui/components/dialogs/install_dialog_advanced.ui b/rare/ui/components/dialogs/install_dialog_advanced.ui
index fda1db03..160c386f 100644
--- a/rare/ui/components/dialogs/install_dialog_advanced.ui
+++ b/rare/ui/components/dialogs/install_dialog_advanced.ui
@@ -6,7 +6,7 @@
0
0
- 359
+ 379
208
@@ -102,14 +102,14 @@
-
-
+
Install prerequisites
-
-
+
true
From fb708ce5fd409d455f73860b0c1d1030f604ebba Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Thu, 1 Sep 2022 15:13:58 +0300
Subject: [PATCH 02/15] LoginDialog: Update to legendary 0.20.28
---
rare/app.py | 2 +-
rare/components/dialogs/launch_dialog.py | 11 +++++----
rare/components/dialogs/login/__init__.py | 24 +++++++++++++------
.../components/dialogs/login/browser_login.py | 21 +++++++---------
.../components/dialogs/login/browser_login.py | 9 ++-----
.../components/dialogs/login/browser_login.ui | 6 ++---
rare/widgets/rare_app.py | 2 --
7 files changed, 37 insertions(+), 38 deletions(-)
diff --git a/rare/app.py b/rare/app.py
index 46be17fd..35671637 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -113,7 +113,7 @@ class App(RareApp):
)
# launch app
- self.launch_dialog = LaunchDialog()
+ self.launch_dialog = LaunchDialog(parent=None)
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
self.launch_dialog.quit_app.connect(lambda ec: exit(ec))
self.launch_dialog.start_app.connect(self.start_app)
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index 4a1de3e8..76f58441 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -82,14 +82,13 @@ class ApiRequestWorker(LaunchWorker):
self.signals.result.emit(result, "32bit")
-class LaunchDialog(QDialog, Ui_LaunchDialog):
+class LaunchDialog(QDialog):
quit_app = pyqtSignal(int)
start_app = pyqtSignal()
completed = 0
def __init__(self, parent=None):
super(LaunchDialog, self).__init__(parent=parent)
- self.setupUi(self)
self.setAttribute(Qt.WA_DeleteOnClose, True)
self.setWindowFlags(
Qt.Window
@@ -101,6 +100,8 @@ class LaunchDialog(QDialog, Ui_LaunchDialog):
| Qt.MSWindowsFixedSizeDialogHint
)
self.setWindowModality(Qt.WindowModal)
+ self.ui = Ui_LaunchDialog()
+ self.ui.setupUi(self)
self.core = LegendaryCoreSingleton()
self.args = ArgumentsSingleton()
@@ -143,7 +144,7 @@ class LaunchDialog(QDialog, Ui_LaunchDialog):
def launch(self):
if not self.args.offline:
- self.image_info.setText(self.tr("Downloading Images"))
+ self.ui.image_info.setText(self.tr("Downloading Images"))
image_worker = ImageWorker()
image_worker.signals.result.connect(self.handle_api_worker_result)
image_worker.signals.progress.connect(self.update_image_progbar)
@@ -202,13 +203,13 @@ class LaunchDialog(QDialog, Ui_LaunchDialog):
self.finish()
def update_image_progbar(self, i: int):
- self.image_prog_bar.setValue(i)
+ self.ui.image_prog_bar.setValue(i)
def finish(self):
self.completed += 1
if self.completed == 2:
logger.info("App starting")
- self.image_info.setText(self.tr("Starting..."))
+ self.ui.image_info.setText(self.tr("Starting..."))
ApiResultsSingleton(self.api_results)
self.completed += 1
self.start_app.emit()
diff --git a/rare/components/dialogs/login/__init__.py b/rare/components/dialogs/login/__init__.py
index 2357adcf..eb0399e6 100644
--- a/rare/components/dialogs/login/__init__.py
+++ b/rare/components/dialogs/login/__init__.py
@@ -36,8 +36,6 @@ class LoginDialog(QDialog):
def __init__(self, core: LegendaryCore, parent=None):
super(LoginDialog, self).__init__(parent=parent)
- self.ui = Ui_LoginDialog()
- self.ui.setupUi(self)
self.setAttribute(Qt.WA_DeleteOnClose, True)
self.setWindowFlags(
Qt.Window
@@ -50,6 +48,8 @@ class LoginDialog(QDialog):
| Qt.MSWindowsFixedSizeDialogHint
)
self.setWindowModality(Qt.WindowModal)
+ self.ui = Ui_LoginDialog()
+ self.ui.setupUi(self)
self.core = core
self.args = ArgumentsSingleton()
@@ -76,7 +76,10 @@ class LoginDialog(QDialog):
self.ui.back_button.setEnabled(False)
self.landing_page.ui.login_browser_radio.clicked.connect(lambda: self.ui.next_button.setEnabled(True))
+ self.landing_page.ui.login_browser_radio.clicked.connect(self.browser_radio_clicked)
self.landing_page.ui.login_import_radio.clicked.connect(lambda: self.ui.next_button.setEnabled(True))
+ self.landing_page.ui.login_import_radio.clicked.connect(self.import_radio_clicked)
+
self.ui.exit_button.clicked.connect(self.close)
self.ui.back_button.clicked.connect(self.back_clicked)
self.ui.next_button.clicked.connect(self.next_clicked)
@@ -90,15 +93,22 @@ class LoginDialog(QDialog):
self.ui.next_button.setEnabled(True)
self.login_stack.slideInIndex(self.pages.landing)
+ def browser_radio_clicked(self):
+ self.login_stack.slideInIndex(self.pages.browser)
+ self.ui.back_button.setEnabled(True)
+ self.ui.next_button.setEnabled(False)
+
+ def import_radio_clicked(self):
+ self.login_stack.slideInIndex(self.pages.import_egl)
+ self.ui.back_button.setEnabled(True)
+ self.ui.next_button.setEnabled(self.import_page.is_valid())
+
def next_clicked(self):
if self.login_stack.currentIndex() == self.pages.landing:
if self.landing_page.ui.login_browser_radio.isChecked():
- self.login_stack.slideInIndex(self.pages.browser)
- self.ui.next_button.setEnabled(False)
+ self.browser_radio_clicked()
if self.landing_page.ui.login_import_radio.isChecked():
- self.login_stack.slideInIndex(self.pages.import_egl)
- self.ui.next_button.setEnabled(self.import_page.is_valid())
- self.ui.back_button.setEnabled(True)
+ self.import_radio_clicked()
elif self.login_stack.currentIndex() == self.pages.browser:
self.browser_page.do_login()
elif self.login_stack.currentIndex() == self.pages.import_egl:
diff --git a/rare/components/dialogs/login/browser_login.py b/rare/components/dialogs/login/browser_login.py
index 49c1eb66..6be59419 100644
--- a/rare/components/dialogs/login/browser_login.py
+++ b/rare/components/dialogs/login/browser_login.py
@@ -18,9 +18,6 @@ logger = getLogger("BrowserLogin")
class BrowserLogin(QFrame):
success = pyqtSignal()
changed = pyqtSignal()
- login_url = (
- "https://www.epicgames.com/id/login?redirectUrl=https%3A%2F%2Fwww.epicgames.com%2Fid%2Fapi%2Fredirect"
- )
def __init__(self, core: LegendaryCore, parent=None):
super(BrowserLogin, self).__init__(parent=parent)
@@ -29,9 +26,10 @@ class BrowserLogin(QFrame):
self.ui.setupUi(self)
self.core = core
+ self.login_url = self.core.egs.get_auth_url()
self.sid_edit = IndicatorLineEdit(
- placeholder=self.tr("Insert SID here"), edit_func=self.text_changed, parent=self
+ placeholder=self.tr("Insert authorizationCode here"), edit_func=self.text_changed, parent=self
)
self.ui.link_text.setText(self.login_url)
self.ui.copy_button.setIcon(icon("mdi.content-copy", "fa.copy"))
@@ -56,7 +54,7 @@ class BrowserLogin(QFrame):
text = text.strip()
if text.startswith("{") and text.endswith("}"):
try:
- text = json.loads(text).get("sid")
+ text = json.loads(text).get("authorizationCode")
except json.JSONDecodeError:
return False, text, IndicatorLineEdit.reasons.wrong_format
elif '"' in text:
@@ -67,10 +65,9 @@ class BrowserLogin(QFrame):
def do_login(self):
self.ui.status_label.setText(self.tr("Logging in..."))
- sid = self.sid_edit.text()
+ auth_code = self.sid_edit.text()
try:
- token = self.core.auth_sid(sid)
- if self.core.auth_code(token):
+ if self.core.auth_code(auth_code):
logger.info(f"Successfully logged in as {self.core.lgd.userdata['displayName']}")
self.success.emit()
else:
@@ -80,13 +77,11 @@ class BrowserLogin(QFrame):
logger.warning(e)
def open_browser(self):
- if webview_login.webview_available is False:
- logger.warning("You don't have webengine installed, " "you will need to manually copy the SID.")
+ if not webview_login.webview_available:
+ logger.warning("You don't have webengine installed, you will need to manually copy the authorizationCode.")
QDesktopServices.openUrl(QUrl(self.login_url))
else:
- if webview_login.do_webview_login(
- callback_sid=self.core.auth_sid, callback_code=self.core.auth_code
- ):
+ if webview_login.do_webview_login(callback_code=self.core.auth_ex_token):
logger.info("Successfully logged in as " f"{self.core.lgd.userdata['displayName']}")
self.success.emit()
else:
diff --git a/rare/ui/components/dialogs/login/browser_login.py b/rare/ui/components/dialogs/login/browser_login.py
index 30fadae5..804e41f3 100644
--- a/rare/ui/components/dialogs/login/browser_login.py
+++ b/rare/ui/components/dialogs/login/browser_login.py
@@ -14,12 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_BrowserLogin(object):
def setupUi(self, BrowserLogin):
BrowserLogin.setObjectName("BrowserLogin")
- BrowserLogin.resize(400, 200)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(BrowserLogin.sizePolicy().hasHeightForWidth())
- BrowserLogin.setSizePolicy(sizePolicy)
+ BrowserLogin.resize(182, 210)
BrowserLogin.setWindowTitle("BrowserLogin")
self.browser_layout = QtWidgets.QGridLayout(BrowserLogin)
self.browser_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
@@ -78,7 +73,7 @@ class Ui_BrowserLogin(object):
_translate = QtCore.QCoreApplication.translate
self.open_button.setText(_translate("BrowserLogin", "Open Browser"))
self.title_label.setText(_translate("BrowserLogin", "Login through browser"))
- self.info_label.setText(_translate("BrowserLogin", "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 SID code in the input above."))
+ self.info_label.setText(_translate("BrowserLogin", "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
authorizationCode
in the input above."))
if __name__ == "__main__":
diff --git a/rare/ui/components/dialogs/login/browser_login.ui b/rare/ui/components/dialogs/login/browser_login.ui
index a7712213..98577f99 100644
--- a/rare/ui/components/dialogs/login/browser_login.ui
+++ b/rare/ui/components/dialogs/login/browser_login.ui
@@ -6,8 +6,8 @@
0
0
- 246
- 184
+ 182
+ 210
@@ -94,7 +94,7 @@
- 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 SID code in the input above.
+ 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.
true
diff --git a/rare/widgets/rare_app.py b/rare/widgets/rare_app.py
index a6964350..1b03cabc 100644
--- a/rare/widgets/rare_app.py
+++ b/rare/widgets/rare_app.py
@@ -20,7 +20,6 @@ class RareApp(QApplication):
def __init__(self):
super(RareApp, self).__init__(sys.argv)
self.setQuitOnLastWindowClosed(False)
- self.core = LegendaryCore()
if hasattr(Qt, "AA_UseHighDpiPixmaps"):
self.setAttribute(Qt.AA_UseHighDpiPixmaps)
@@ -36,7 +35,6 @@ class RareApp(QApplication):
# lk: this is a bit silly but serves well until we have a class
# lk: store the default qt style name from the system on startup as a property for later reference
self.setProperty("rareDefaultQtStyle", self.style().objectName())
-
if (
self.settings.value("color_scheme", None) is None
and self.settings.value("style_sheet", None) is None
From 0388d4bf9dc397d0b01106287576c5a364605f52 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Thu, 1 Sep 2022 22:49:09 +0300
Subject: [PATCH 03/15] ImportLogin: Fix failure to login using EGL data
---
rare/components/dialogs/launch_dialog.py | 14 ++++++---
rare/components/dialogs/login/import_login.py | 29 ++++++++++++++-----
.../components/dialogs/login/import_login.py | 10 ++-----
.../components/dialogs/login/import_login.ui | 4 +--
4 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index 76f58441..1ea25720 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -2,7 +2,7 @@ import platform
from logging import getLogger
from PyQt5.QtCore import Qt, pyqtSignal, QRunnable, QObject, QThreadPool, QSettings
-from PyQt5.QtWidgets import QDialog, qApp
+from PyQt5.QtWidgets import QDialog, QApplication
from requests.exceptions import ConnectionError, HTTPError
from rare.components.dialogs.login import LoginDialog
@@ -108,23 +108,29 @@ class LaunchDialog(QDialog):
self.thread_pool = QThreadPool().globalInstance()
self.api_results = ApiResults()
+ self.login_dialog = LoginDialog(core=self.core, parent=self)
+
def login(self):
do_launch = True
try:
if self.args.offline:
pass
else:
- qApp.processEvents()
+ QApplication.instance().processEvents()
if self.core.login():
logger.info("You are logged in")
else:
raise ValueError("You are not logged in. Open Login Window")
except ValueError as e:
logger.info(str(e))
+ # Force an update check and notice in case there are API changes
+ self.core.check_for_updates(force=True)
+ self.core.force_show_update = True
# Do not set parent, because it won't show a task bar icon
# Update: Inherit the same parent as LaunchDialog
- do_launch = LoginDialog(core=self.core, parent=self.parent()).login()
- except ConnectionError as e:
+ do_launch = self.login_dialog.login()
+ self.login_dialog.deleteLater()
+ except (HTTPError, ConnectionError) as e:
logger.warning(e)
self.args.offline = True
finally:
diff --git a/rare/components/dialogs/login/import_login.py b/rare/components/dialogs/login/import_login.py
index b891e685..093f3c44 100644
--- a/rare/components/dialogs/login/import_login.py
+++ b/rare/components/dialogs/login/import_login.py
@@ -5,6 +5,7 @@ from logging import getLogger
from PyQt5.QtCore import pyqtSignal
from PyQt5.QtWidgets import QFrame, QFileDialog
from legendary.core import LegendaryCore
+from legendary.utils.wine_helpers import read_registry, get_shell_folders
from rare.ui.components.dialogs.login.import_login import Ui_ImportLogin
@@ -18,7 +19,7 @@ class ImportLogin(QFrame):
localappdata = os.path.expandvars("%LOCALAPPDATA%")
else:
localappdata = os.path.join("drive_c/users", getuser(), "Local Settings/Application Data")
- appdata_path = os.path.join(localappdata, "EpicGamesLauncher/Saved/Config/Windows")
+ egl_appdata = os.path.join(localappdata, "EpicGamesLauncher", "Saved", "Config", "Windows")
found = False
def __init__(self, core: LegendaryCore, parent=None):
@@ -33,16 +34,18 @@ class ImportLogin(QFrame):
self.text_egl_notfound = self.tr("Could not find EGL Program Data. ")
if os.name == "nt":
- if not self.core.egl.appdata_path and os.path.exists(self.appdata_path):
- self.core.egl.appdata_path = self.appdata_path
+ if not self.core.egl.appdata_path and os.path.exists(self.egl_appdata):
+ self.core.egl.appdata_path = self.egl_appdata
if not self.core.egl.appdata_path:
self.ui.status_label.setText(self.text_egl_notfound)
else:
self.ui.status_label.setText(self.text_egl_found)
self.found = True
else:
+ if wine_pfx := self.core.egl.programdata_path.split("drive_c"):
+ self.ui.prefix_combo.addItems(wine_pfx)
self.ui.info_label.setText(
- self.tr("Please select the Wine prefix" " where Epic Games Launcher is installed. ")
+ self.tr("Please select the Wine prefix where Epic Games Launcher is installed. ")
+ self.ui.info_label.text()
)
prefixes = self.get_wine_prefixes()
@@ -62,7 +65,7 @@ class ImportLogin(QFrame):
]
prefixes = []
for prefix in possible_prefixes:
- if os.path.exists(os.path.join(prefix, self.appdata_path)):
+ if os.path.exists(os.path.join(prefix, self.egl_appdata)):
prefixes.append(prefix)
return prefixes
@@ -73,18 +76,28 @@ class ImportLogin(QFrame):
names = prefix_dialog.selectedFiles()
self.ui.prefix_combo.setCurrentText(names[0])
- def is_valid(self):
+ def is_valid(self) -> bool:
if os.name == "nt":
return self.found
else:
- return os.path.exists(os.path.join(self.ui.prefix_combo.currentText(), self.appdata_path))
+ egl_wine_pfx = self.ui.prefix_combo.currentText()
+ try:
+ wine_folders = get_shell_folders(read_registry(egl_wine_pfx), egl_wine_pfx)
+ self.egl_appdata = os.path.realpath(
+ os.path.join(wine_folders['Local AppData'], 'EpicGamesLauncher', 'Saved', 'Config', 'Windows'))
+ if path_exists := os.path.exists(self.egl_appdata):
+ self.ui.status_label.setText(self.text_egl_found)
+ return path_exists
+ except KeyError:
+ return False
def do_login(self):
self.ui.status_label.setText(self.tr("Loading..."))
if os.name == "nt":
pass
else:
- self.core.egl.appdata_path = os.path.join(self.ui.prefix_combo.currentText(), self.appdata_path)
+ logger.info(f'Using EGL appdata path at "{self.egl_appdata}"')
+ self.core.egl.appdata_path = self.egl_appdata
try:
if self.core.auth_import():
logger.info(f"Logged in as {self.core.lgd.userdata['displayName']}")
diff --git a/rare/ui/components/dialogs/login/import_login.py b/rare/ui/components/dialogs/login/import_login.py
index b4c61533..9c43b0ce 100644
--- a/rare/ui/components/dialogs/login/import_login.py
+++ b/rare/ui/components/dialogs/login/import_login.py
@@ -14,12 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ImportLogin(object):
def setupUi(self, ImportLogin):
ImportLogin.setObjectName("ImportLogin")
- ImportLogin.resize(400, 200)
- sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
- sizePolicy.setHorizontalStretch(0)
- sizePolicy.setVerticalStretch(0)
- sizePolicy.setHeightForWidth(ImportLogin.sizePolicy().hasHeightForWidth())
- ImportLogin.setSizePolicy(sizePolicy)
+ ImportLogin.resize(242, 120)
ImportLogin.setWindowTitle("ImportLogin")
self.import_layout = QtWidgets.QGridLayout(ImportLogin)
self.import_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
@@ -51,6 +46,7 @@ class Ui_ImportLogin(object):
font.setItalic(True)
self.status_label.setFont(font)
self.status_label.setText("")
+ self.status_label.setWordWrap(True)
self.status_label.setObjectName("status_label")
self.import_layout.addWidget(self.status_label, 2, 1, 1, 2)
self.info_label = QtWidgets.QLabel(ImportLogin)
@@ -68,7 +64,7 @@ class Ui_ImportLogin(object):
def retranslateUi(self, ImportLogin):
_translate = QtCore.QCoreApplication.translate
- self.prefix_label.setText(_translate("ImportLogin", "Select path"))
+ self.prefix_label.setText(_translate("ImportLogin", "Select prefix"))
self.title_label.setText(_translate("ImportLogin", "Import existing session from EGL"))
self.prefix_tool.setText(_translate("ImportLogin", "Browse"))
self.info_label.setText(_translate("ImportLogin", "You will get logged out from EGL in the process."))
diff --git a/rare/ui/components/dialogs/login/import_login.ui b/rare/ui/components/dialogs/login/import_login.ui
index 3ef1d2df..d49ca635 100644
--- a/rare/ui/components/dialogs/login/import_login.ui
+++ b/rare/ui/components/dialogs/login/import_login.ui
@@ -6,7 +6,7 @@
0
0
- 235
+ 242
120
@@ -20,7 +20,7 @@
-
- Select path
+ Select prefix
From b3348a1ecad9505746cd6b03420b457f298e0b90 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Thu, 1 Sep 2022 23:48:30 +0300
Subject: [PATCH 04/15] ImportLogin: Check if programdata is set
---
rare/components/dialogs/login/import_login.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/rare/components/dialogs/login/import_login.py b/rare/components/dialogs/login/import_login.py
index 093f3c44..1a7ea4b1 100644
--- a/rare/components/dialogs/login/import_login.py
+++ b/rare/components/dialogs/login/import_login.py
@@ -42,8 +42,9 @@ class ImportLogin(QFrame):
self.ui.status_label.setText(self.text_egl_found)
self.found = True
else:
- if wine_pfx := self.core.egl.programdata_path.split("drive_c"):
- self.ui.prefix_combo.addItems(wine_pfx)
+ if programdata_path := self.core.egl.programdata_path:
+ if wine_pfx := programdata_path.split("drive_c"):
+ self.ui.prefix_combo.addItems(wine_pfx)
self.ui.info_label.setText(
self.tr("Please select the Wine prefix where Epic Games Launcher is installed. ")
+ self.ui.info_label.text()
From 345ee443edc5945dae5b4dcbf41c1c50206f185d Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 00:02:20 +0300
Subject: [PATCH 05/15] ImportLogin: Only add the first part of the split
---
rare/components/dialogs/login/import_login.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rare/components/dialogs/login/import_login.py b/rare/components/dialogs/login/import_login.py
index 1a7ea4b1..a84ce2ad 100644
--- a/rare/components/dialogs/login/import_login.py
+++ b/rare/components/dialogs/login/import_login.py
@@ -43,8 +43,8 @@ class ImportLogin(QFrame):
self.found = True
else:
if programdata_path := self.core.egl.programdata_path:
- if wine_pfx := programdata_path.split("drive_c"):
- self.ui.prefix_combo.addItems(wine_pfx)
+ if wine_pfx := programdata_path.split("drive_c")[0]:
+ self.ui.prefix_combo.addItem(wine_pfx)
self.ui.info_label.setText(
self.tr("Please select the Wine prefix where Epic Games Launcher is installed. ")
+ self.ui.info_label.text()
From 3c5575fda927126f78b9c5bd13d842bc972ebcbf Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 00:04:39 +0300
Subject: [PATCH 06/15] LaunchDialog: Don't explicitly delete LoginDialog
---
rare/components/dialogs/launch_dialog.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index 1ea25720..72243e8c 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -129,7 +129,6 @@ class LaunchDialog(QDialog):
# Do not set parent, because it won't show a task bar icon
# Update: Inherit the same parent as LaunchDialog
do_launch = self.login_dialog.login()
- self.login_dialog.deleteLater()
except (HTTPError, ConnectionError) as e:
logger.warning(e)
self.args.offline = True
From dfb388a9bab2ecfef01bc1ee23a5c5277819523c Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 00:20:04 +0300
Subject: [PATCH 07/15] App: Do a bit more cleanup to avoid crashes
---
rare/app.py | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/rare/app.py b/rare/app.py
index 35671637..06ca7554 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -211,7 +211,7 @@ class App(RareApp):
logger.info("Show App")
def exit_app(self, exit_code=0):
- # FIXME: Fix this with the downlaod tab redesign
+ # FIXME: Fix this with the download tab redesign
if self.mainwindow is not None:
if not self.args.offline and self.mainwindow.tab_widget.downloadTab.is_download_active:
question = QMessageBox.question(
@@ -237,8 +237,15 @@ class App(RareApp):
self.core.exit()
if self.mainwindow is not None:
self.mainwindow.close()
+ self.mainwindow.deleteLater()
+ self.mainwindow = None
if self.tray_icon is not None:
self.tray_icon.deleteLater()
+ self.tray_icon = None
+ if self.timer is not None:
+ self.timer.stop()
+ self.timer.deleteLater()
+ self.timer = None
self.processEvents()
shutil.rmtree(tmp_dir)
os.makedirs(tmp_dir)
From 385291cbfc03ea377a95356586e9563206708467 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 00:23:16 +0300
Subject: [PATCH 08/15] Update pyproject.toml
---
pyproject.toml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pyproject.toml b/pyproject.toml
index a84874f1..96f09ecc 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -30,7 +30,7 @@ pywebview = [
{ version = "^3.6.3", extras = ["cef"], platform = "windows", optional = true },
{ version = "^3.6.3", extras = ["gtk"], platform = "linux", optional = true },
]
-legendary-gl = "^0.20.27"
+legendary-gl = "^0.20.28"
typing-extensions = "^4.3.0"
From 48867a8656ef7b7bbbef55ad5924afcb287964f7 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 00:31:10 +0300
Subject: [PATCH 09/15] DebugSettings: Add restart button, thanks Dummerle!
---
rare/components/tabs/settings/debug.py | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/rare/components/tabs/settings/debug.py b/rare/components/tabs/settings/debug.py
index 66e4cacf..4677d3f5 100644
--- a/rare/components/tabs/settings/debug.py
+++ b/rare/components/tabs/settings/debug.py
@@ -1,5 +1,7 @@
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton
+from rare.shared import GlobalSignalsSingleton
+
class DebugSettings(QWidget):
def __init__(self):
@@ -9,6 +11,9 @@ class DebugSettings(QWidget):
self.raise_runtime_exception_button = QPushButton("Raise Exception")
self.layout().addWidget(self.raise_runtime_exception_button)
self.raise_runtime_exception_button.clicked.connect(self.raise_exception)
+ self.restart_button = QPushButton("Restart")
+ self.layout().addWidget(self.restart_button)
+ self.restart_button.clicked.connect(lambda: GlobalSignalsSingleton().exit_app.emit(-133742))
self.layout().addStretch(1)
From 0a89f0e0b8a7393b983dabc5ce6913398027a1d5 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 13:17:05 +0300
Subject: [PATCH 10/15] Make `launch` and alias for `start`
---
rare/__main__.py | 25 ++++++++-----------------
rare/components/main_window.py | 16 +++-------------
2 files changed, 11 insertions(+), 30 deletions(-)
diff --git a/rare/__main__.py b/rare/__main__.py
index fb84f876..95390609 100644
--- a/rare/__main__.py
+++ b/rare/__main__.py
@@ -45,10 +45,7 @@ def main():
)
subparsers = parser.add_subparsers(title="Commands", dest="subparser")
- launch_parser = subparsers.add_parser("launch")
- launch_parser.add_argument("app_name", help="Name of the app", metavar="")
-
- launch_minimal_parser = subparsers.add_parser("start")
+ launch_minimal_parser = subparsers.add_parser("start", aliases=["launch"])
launch_minimal_parser.add_argument("app_name", help="AppName of the game to launch",
metavar="", action="store")
launch_minimal_parser.add_argument("--offline", help="Launch game offline",
@@ -56,11 +53,11 @@ def main():
launch_minimal_parser.add_argument("--skip_update_check", help="Do not check for updates",
action="store_true")
launch_minimal_parser.add_argument('--wine-bin', dest='wine_bin', action='store', metavar='',
- default=os.environ.get('LGDRY_WINE_BINARY', None),
- help='Set WINE binary to use to launch the app')
+ default=os.environ.get('LGDRY_WINE_BINARY', None),
+ help='Set WINE binary to use to launch the app')
launch_minimal_parser.add_argument('--wine-prefix', dest='wine_pfx', action='store', metavar='',
- default=os.environ.get('LGDRY_WINE_PREFIX', None),
- help='Set WINE prefix to use')
+ default=os.environ.get('LGDRY_WINE_PREFIX', None),
+ help='Set WINE prefix to use')
launch_minimal_parser.add_argument("--ask-alyways-sync", help="Ask for cloud saves",
action="store_true")
@@ -80,10 +77,10 @@ def main():
if args.version:
from rare import __version__, code_name
-
print(f"Rare {__version__} Codename: {code_name}")
return
- if args.subparser == "start":
+
+ if args.subparser == "start" or args.subparser == "launch":
from rare import game_launch_helper as helper
helper.start_game(args)
return
@@ -99,16 +96,10 @@ def main():
from rare.utils.paths import data_dir
with open(os.path.join(data_dir, "lockfile"), "w") as file:
- if args.subparser == "launch":
- file.write(f"launch {args.app_name}")
- else:
- file.write("start")
+ file.write("show")
file.close()
return
- if args.subparser == "launch":
- args.silent = True
-
from rare.app import start
start(args)
diff --git a/rare/components/main_window.py b/rare/components/main_window.py
index 42487a90..7f0c98c9 100644
--- a/rare/components/main_window.py
+++ b/rare/components/main_window.py
@@ -13,8 +13,8 @@ logger = getLogger("Window")
class MainWindow(QMainWindow):
- def __init__(self):
- super(MainWindow, self).__init__()
+ def __init__(self, parent=None):
+ super(MainWindow, self).__init__(parent=parent)
self.setAttribute(Qt.WA_DeleteOnClose)
self.core = LegendaryCoreSingleton()
self.signals = GlobalSignalsSingleton()
@@ -83,17 +83,7 @@ class MainWindow(QMainWindow):
file = open(file_path, "r")
action = file.read()
file.close()
- if action.startswith("launch"):
- game = action.replace("launch ", "").replace("\n", "")
- if game in [
- i.app_name for i in self.tab_widget.games_tab.game_list
- ] and self.core.is_installed(game):
- self.tab_widget.games_tab.game_utils.prepare_launch(
- game, offline=self.args.offline
- )
- else:
- logger.info(f"Could not find {game} in Games")
- elif action.startswith("start"):
+ if action.startswith("show"):
self.show()
os.remove(file_path)
self.timer.start(1000)
From 4951743bbf654a74b93577ff2dfa0d8906b74278 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Fri, 2 Sep 2022 17:53:56 +0300
Subject: [PATCH 11/15] ConfigHelper: Protect name space from globals
---
rare/utils/config_helper.py | 36 ++++++++++++++++++------------------
1 file changed, 18 insertions(+), 18 deletions(-)
diff --git a/rare/utils/config_helper.py b/rare/utils/config_helper.py
index 50a992e9..086e7f1f 100644
--- a/rare/utils/config_helper.py
+++ b/rare/utils/config_helper.py
@@ -1,38 +1,38 @@
-from typing import Callable
+from typing import Callable, Optional
from legendary.core import LegendaryCore
from legendary.utils.config import LGDConf
-config: LGDConf = None
-save_config: Callable[[], None] = None
+_config: Optional[LGDConf] = None
+_save_config: Optional[Callable[[], None]] = None
def init_config_handler(core: LegendaryCore):
- global config, save_config
- config = core.lgd.config
- save_config = core.lgd.save_config
+ global _config, _save_config
+ _config = core.lgd.config
+ _save_config = core.lgd.save_config
def add_option(app_name: str, option: str, value: str):
value = value.replace("%%", "%").replace("%", "%%")
- if not config.has_section(app_name):
- config[app_name] = {}
+ if not _config.has_section(app_name):
+ _config[app_name] = {}
- config.set(app_name, option, value)
- save_config()
+ _config.set(app_name, option, value)
+ _save_config()
def remove_option(app_name, option):
- if config.has_option(app_name, option):
- config.remove_option(app_name, option)
+ if _config.has_option(app_name, option):
+ _config.remove_option(app_name, option)
- if config.has_section(app_name) and not config[app_name]:
- config.remove_section(app_name)
+ if _config.has_section(app_name) and not _config[app_name]:
+ _config.remove_section(app_name)
- save_config()
+ _save_config()
def remove_section(app_name):
- if config.has_section(app_name):
- config.remove_section(app_name)
- save_config()
+ if _config.has_section(app_name):
+ _config.remove_section(app_name)
+ _save_config()
From afcdc1dea1c4f0e544a5ade76fc7b6467543d049 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Sun, 4 Sep 2022 01:14:43 +0300
Subject: [PATCH 12/15] App: Move legendary initialization to the singleton
App: Move tray to MainWindow
Shared: Add destructor for singleton instances
---
rare/app.py | 146 ++++++---------------------------
rare/components/main_window.py | 121 +++++++++++++++++++++------
rare/components/tray_icon.py | 6 +-
rare/shared/__init__.py | 67 +++++++++++++--
rare/utils/extra_widgets.py | 16 ++--
5 files changed, 194 insertions(+), 162 deletions(-)
diff --git a/rare/app.py b/rare/app.py
index 06ca7554..bba47458 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -13,14 +13,19 @@ from typing import Optional
import legendary
import requests.exceptions
from PyQt5.QtCore import QThreadPool, QTimer, QT_VERSION_STR, PYQT_VERSION_STR
-from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMessageBox
+from PyQt5.QtWidgets import QApplication, QMessageBox
from requests import HTTPError
import rare
from rare.components.dialogs.launch_dialog import LaunchDialog
from rare.components.main_window import MainWindow
-from rare.components.tray_icon import TrayIcon
-from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
+from rare.shared import (
+ LegendaryCoreSingleton,
+ GlobalSignalsSingleton,
+ ArgumentsSingleton,
+ ApiResultsSingleton,
+ clear_singleton_instance
+)
from rare.shared.image_manager import ImageManagerSingleton
from rare.utils import legendary_utils, config_helper
from rare.utils.paths import cache_dir, tmp_dir
@@ -54,64 +59,21 @@ def excepthook(exc_type, exc_value, exc_tb):
class App(RareApp):
- mainwindow: Optional[MainWindow] = None
- tray_icon: Optional[QSystemTrayIcon] = None
-
def __init__(self, args: Namespace):
super(App, self).__init__()
+ self.core = LegendaryCoreSingleton()
self.args = ArgumentsSingleton(args) # add some options
- self.window_launched = False
-
- # init Legendary
- try:
- self.core = LegendaryCoreSingleton(init=True)
- except configparser.MissingSectionHeaderError as e:
- logger.warning(f"Config is corrupt: {e}")
- if config_path := os.environ.get("XDG_CONFIG_HOME"):
- path = os.path.join(config_path, "legendary")
- else:
- path = os.path.expanduser("~/.config/legendary")
- with open(os.path.join(path, "config.ini"), "w") as config_file:
- config_file.write("[Legendary]")
- self.core = LegendaryCoreSingleton(init=True)
- if "Legendary" not in self.core.lgd.config.sections():
- self.core.lgd.config.add_section("Legendary")
- self.core.lgd.save_config()
lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang)
- config_helper.init_config_handler(self.core)
-
- # workaround if egl sync enabled, but no programdata_path
- # programdata_path might be unset if logging in through the browser
- if self.core.egl_sync_enabled:
- if self.core.egl.programdata_path is None:
- self.core.lgd.config.remove_option("Legendary", "egl_sync")
- self.core.lgd.save_config()
- else:
- if not os.path.exists(self.core.egl.programdata_path):
- self.core.lgd.config.remove_option("Legendary", "egl_sync")
- self.core.lgd.save_config()
-
# set Application name for settings
- self.launch_dialog = None
+ self.mainwindow: Optional[MainWindow] = None
+ self.launch_dialog: Optional[LaunchDialog] = None
self.signals = GlobalSignalsSingleton(init=True)
self.image_manager = ImageManagerSingleton(init=True)
- self.signals.exit_app.connect(self.exit_app)
- self.signals.send_notification.connect(
- lambda title: self.tray_icon.showMessage(
- self.tr("Download finished"),
- self.tr("Download finished. {} is playable now").format(title),
- QSystemTrayIcon.Information,
- 4000,
- )
- if self.settings.value("notification", True, bool)
- else None
- )
-
# launch app
self.launch_dialog = LaunchDialog(parent=None)
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
@@ -140,12 +102,6 @@ class App(RareApp):
td = abs(dt_exp - dt_now)
self.timer.start(int(td.total_seconds() - 60) * 1000)
- def show_mainwindow(self):
- if self.window_launched:
- self.mainwindow.show()
- else:
- self.mainwindow.show_window_centered()
-
def start_app(self):
for igame in self.core.get_installed_list():
if not os.path.exists(igame.install_path):
@@ -167,85 +123,27 @@ class App(RareApp):
logger.info(f"{igame.title} needs verification")
self.mainwindow = MainWindow()
- self.tray_icon: TrayIcon = TrayIcon(self)
- self.tray_icon.exit_action.triggered.connect(self.exit_app)
- self.tray_icon.start_rare.triggered.connect(self.show_mainwindow)
- self.tray_icon.activated.connect(
- lambda r: self.show_mainwindow()
- if r == QSystemTrayIcon.DoubleClick
- else None
- )
+ self.mainwindow.exit_app.connect(self.exit_app)
if not self.args.silent:
- self.mainwindow.show_window_centered()
- self.window_launched = True
-
- if self.args.subparser == "launch":
- if self.args.app_name in [
- i.app_name for i in self.core.get_installed_list()
- ]:
- logger.info(
- f"Launching {self.core.get_installed_game(self.args.app_name).title}"
- )
- self.mainwindow.tab_widget.games_tab.game_utils.prepare_launch(
- self.args.app_name
- )
- else:
- logger.error(
- f"Could not find {self.args.app_name} in Games or it is not installed"
- )
- QMessageBox.warning(
- self.mainwindow,
- "Warning",
- self.tr(
- "Could not find {} in installed games. Did you modify the shortcut? "
- ).format(self.args.app_name),
- )
+ self.mainwindow.show()
if self.args.test_start:
self.exit_app(0)
- def tray(self, reason):
- if reason == QSystemTrayIcon.DoubleClick:
- self.mainwindow.show()
- logger.info("Show App")
-
def exit_app(self, exit_code=0):
- # FIXME: Fix this with the download tab redesign
- if self.mainwindow is not None:
- if not self.args.offline and self.mainwindow.tab_widget.downloadTab.is_download_active:
- question = QMessageBox.question(
- self.mainwindow,
- self.tr("Close"),
- self.tr(
- "There is a download active. Do you really want to exit app?"
- ),
- QMessageBox.Yes,
- QMessageBox.No,
- )
- if question == QMessageBox.No:
- return
- else:
- # clear queue
- self.mainwindow.tab_widget.downloadTab.queue_widget.update_queue([])
- self.mainwindow.tab_widget.downloadTab.stop_download()
- # FIXME: End of FIXME
- self.mainwindow.timer.stop()
- self.mainwindow.hide()
threadpool = QThreadPool.globalInstance()
threadpool.waitForDone()
- self.core.exit()
- if self.mainwindow is not None:
- self.mainwindow.close()
- self.mainwindow.deleteLater()
- self.mainwindow = None
- if self.tray_icon is not None:
- self.tray_icon.deleteLater()
- self.tray_icon = None
if self.timer is not None:
self.timer.stop()
self.timer.deleteLater()
self.timer = None
+ if self.mainwindow is not None:
+ self.mainwindow.close()
+ self.mainwindow = None
+ clear_singleton_instance(self.signals)
+ clear_singleton_instance(self.args)
+ clear_singleton_instance(ApiResultsSingleton())
self.processEvents()
shutil.rmtree(tmp_dir)
os.makedirs(tmp_dir)
@@ -284,10 +182,16 @@ def start(args):
logger.info(f"Operating System: {platform.system()}")
while True:
+ core = LegendaryCoreSingleton(init=True)
+ config_helper.init_config_handler(core)
app = App(args)
exit_code = app.exec_()
# if not restart
# restart app
del app
+ core.exit()
+ clear_singleton_instance(core)
if exit_code != -133742:
break
+
+
diff --git a/rare/components/main_window.py b/rare/components/main_window.py
index 7f0c98c9..b5e50942 100644
--- a/rare/components/main_window.py
+++ b/rare/components/main_window.py
@@ -1,18 +1,22 @@
import os
from logging import getLogger
-from PyQt5.QtCore import Qt, QSettings, QTimer, QSize
+from PyQt5.QtCore import Qt, QSettings, QTimer, QSize, pyqtSignal, pyqtSlot
from PyQt5.QtGui import QCloseEvent, QCursor
-from PyQt5.QtWidgets import QMainWindow, QApplication, QStatusBar, QScrollArea, QScroller, QComboBox
+from PyQt5.QtWidgets import QMainWindow, QApplication, QStatusBar, QScrollArea, QScroller, QComboBox, QMessageBox
from rare.components.tabs import TabWidget
+from rare.components.tray_icon import TrayIcon
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
from rare.utils.paths import data_dir
-logger = getLogger("Window")
+logger = getLogger("MainWindow")
class MainWindow(QMainWindow):
+ # int: exit code
+ exit_app: pyqtSignal = pyqtSignal(int)
+
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.setAttribute(Qt.WA_DeleteOnClose)
@@ -46,8 +50,42 @@ class MainWindow(QMainWindow):
self.timer.timeout.connect(self.timer_finished)
self.timer.start(1000)
- def show_window_centered(self):
- self.show()
+ self.signals.exit_app.connect(self.on_exit_app)
+ self.exit_code = 0
+ self.accept_close = False
+
+ self.tray_icon: TrayIcon = TrayIcon(self)
+ self.tray_icon.exit_action.triggered.connect(self.on_exit_app)
+ self.tray_icon.start_rare.triggered.connect(self.show)
+ self.tray_icon.activated.connect(
+ lambda r: self.toggle()
+ if r == self.tray_icon.DoubleClick
+ else None
+ )
+
+ self.signals.send_notification.connect(
+ lambda title: self.tray_icon.showMessage(
+ self.tr("Download finished"),
+ self.tr("Download finished. {} is playable now").format(title),
+ self.tray_icon.Information,
+ 4000,
+ )
+ if self.settings.value("notification", True, bool)
+ else None
+ )
+
+ self.window_launched = False
+
+ # enable kinetic scrolling
+ for scroll_area in self.findChildren(QScrollArea):
+ if not scroll_area.property("no_kinetic_scroll"):
+ QScroller.grabGesture(scroll_area.viewport(), QScroller.LeftMouseButtonGesture)
+
+ # fix scrolling
+ for combo_box in scroll_area.findChildren(QComboBox):
+ combo_box.wheelEvent = lambda e: e.ignore()
+
+ def center_window(self):
# get the margins of the decorated window
margins = self.windowHandle().frameMargins()
# get the screen the cursor is on
@@ -68,14 +106,23 @@ class MainWindow(QMainWindow):
- self.rect().adjusted(0, 0, decor_width, decor_height).center()
)
- # enable kinetic scrolling
- for scroll_area in self.findChildren(QScrollArea):
- if not scroll_area.property("no_kinetic_scroll"):
- QScroller.grabGesture(scroll_area.viewport(), QScroller.LeftMouseButtonGesture)
+ def show(self) -> None:
+ super(MainWindow, self).show()
+ if not self.window_launched:
+ self.center_window()
+ self.window_launched = True
- # fix scrolling
- for combo_box in scroll_area.findChildren(QComboBox):
- combo_box.wheelEvent = lambda e: e.ignore()
+ def hide(self) -> None:
+ if self.settings.value("save_size", False, bool):
+ size = self.size().width(), self.size().height()
+ self.settings.setValue("window_size", size)
+ super(MainWindow, self).hide()
+
+ def toggle(self):
+ if self.isHidden():
+ self.show()
+ else:
+ self.hide()
def timer_finished(self):
file_path = os.path.join(data_dir, "lockfile")
@@ -88,15 +135,43 @@ class MainWindow(QMainWindow):
os.remove(file_path)
self.timer.start(1000)
+ @pyqtSlot()
+ @pyqtSlot(int)
+ def on_exit_app(self, exit_code=0) -> None:
+ # FIXME: Fix this with the download tab redesign
+ if not self.args.offline and self.tab_widget.downloadTab.is_download_active:
+ question = QMessageBox.question(
+ self,
+ self.tr("Close"),
+ self.tr(
+ "There is a download active. Do you really want to exit app?"
+ ),
+ QMessageBox.Yes,
+ QMessageBox.No,
+ )
+ if question == QMessageBox.No:
+ return
+ else:
+ # clear queue
+ self.tab_widget.downloadTab.queue_widget.update_queue([])
+ self.tab_widget.downloadTab.stop_download()
+ # FIXME: End of FIXME
+ self.exit_code = exit_code
+ self.close()
+
+ def close(self) -> bool:
+ self.accept_close = True
+ return super(MainWindow, self).close()
+
def closeEvent(self, e: QCloseEvent):
- if self.settings.value("save_size", False, bool):
- size = self.size().width(), self.size().height()
- self.settings.setValue("window_size", size)
- if self.settings.value("sys_tray", True, bool):
- self.hide()
- e.ignore()
- return
- elif self.args.offline:
- pass
- self.signals.exit_app.emit(0)
- e.ignore()
+ if not self.accept_close:
+ if self.settings.value("sys_tray", True, bool):
+ self.hide()
+ e.ignore()
+ return
+ self.timer.stop()
+ self.tray_icon.deleteLater()
+ self.hide()
+ self.exit_app.emit(self.exit_code)
+ super(MainWindow, self).closeEvent(e)
+ e.accept()
diff --git a/rare/components/tray_icon.py b/rare/components/tray_icon.py
index c01ea4fb..8c29e30c 100644
--- a/rare/components/tray_icon.py
+++ b/rare/components/tray_icon.py
@@ -13,7 +13,7 @@ logger = getLogger("TrayIcon")
class TrayIcon(QSystemTrayIcon):
def __init__(self, parent):
- super(TrayIcon, self).__init__(parent)
+ super(TrayIcon, self).__init__(parent=parent)
self.core = LegendaryCoreSingleton()
self.setIcon(QIcon(":/images/Rare.png"))
@@ -33,7 +33,7 @@ class TrayIcon(QSystemTrayIcon):
if len(installed := self.core.get_installed_list()) < 5:
last_played = [GameMeta(i.app_name) for i in sorted(installed, key=lambda x: x.title)]
elif games := sorted(
- parent.mainwindow.tab_widget.games_tab.game_utils.game_meta.get_games(),
+ parent.tab_widget.games_tab.game_utils.game_meta.get_games(),
key=lambda x: x.last_played, reverse=True):
last_played: List[GameMeta] = games[0:5]
else:
@@ -46,7 +46,7 @@ class TrayIcon(QSystemTrayIcon):
a.setProperty("app_name", game.app_name)
self.game_actions.append(a)
a.triggered.connect(
- lambda: parent.mainwindow.tab_widget.games_tab.game_utils.prepare_launch(
+ lambda: parent.tab_widget.games_tab.game_utils.prepare_launch(
self.sender().property("app_name"))
)
diff --git a/rare/shared/__init__.py b/rare/shared/__init__.py
index 6bbbf05a..788e63fc 100644
--- a/rare/shared/__init__.py
+++ b/rare/shared/__init__.py
@@ -5,14 +5,18 @@ Each of the objects in this module should be instantiated ONCE
and only ONCE!
"""
+import configparser
+import logging
+import os
from argparse import Namespace
-from typing import Optional
+from typing import Optional, Union
from rare.lgndr.core import LegendaryCore
-
from rare.models.apiresults import ApiResults
from rare.models.signals import GlobalSignals
+logger = logging.getLogger("Singleton")
+
_legendary_core_singleton: Optional[LegendaryCore] = None
_global_signals_singleton: Optional[GlobalSignals] = None
_arguments_singleton: Optional[Namespace] = None
@@ -23,8 +27,33 @@ def LegendaryCoreSingleton(init: bool = False) -> LegendaryCore:
global _legendary_core_singleton
if _legendary_core_singleton is None and not init:
raise RuntimeError("Uninitialized use of LegendaryCoreSingleton")
- if _legendary_core_singleton is None:
- _legendary_core_singleton = LegendaryCore()
+ if _legendary_core_singleton is not None and init:
+ raise RuntimeError("LegendaryCore already initialized")
+ if init:
+ try:
+ _legendary_core_singleton = LegendaryCore()
+ except configparser.MissingSectionHeaderError as e:
+ logger.warning(f"Config is corrupt: {e}")
+ if config_path := os.environ.get("XDG_CONFIG_HOME"):
+ path = os.path.join(config_path, "legendary")
+ else:
+ path = os.path.expanduser("~/.config/legendary")
+ with open(os.path.join(path, "config.ini"), "w") as config_file:
+ config_file.write("[Legendary]")
+ _legendary_core_singleton = LegendaryCore()
+ if "Legendary" not in _legendary_core_singleton.lgd.config.sections():
+ _legendary_core_singleton.lgd.config.add_section("Legendary")
+ _legendary_core_singleton.lgd.save_config()
+ # workaround if egl sync enabled, but no programdata_path
+ # programdata_path might be unset if logging in through the browser
+ if _legendary_core_singleton.egl_sync_enabled:
+ if _legendary_core_singleton.egl.programdata_path is None:
+ _legendary_core_singleton.lgd.config.remove_option("Legendary", "egl_sync")
+ _legendary_core_singleton.lgd.save_config()
+ else:
+ if not os.path.exists(_legendary_core_singleton.egl.programdata_path):
+ _legendary_core_singleton.lgd.config.remove_option("Legendary", "egl_sync")
+ _legendary_core_singleton.lgd.save_config()
return _legendary_core_singleton
@@ -32,7 +61,9 @@ def GlobalSignalsSingleton(init: bool = False) -> GlobalSignals:
global _global_signals_singleton
if _global_signals_singleton is None and not init:
raise RuntimeError("Uninitialized use of GlobalSignalsSingleton")
- if _global_signals_singleton is None:
+ if _global_signals_singleton is not None and init:
+ raise RuntimeError("GlobalSignals already initialized")
+ if init:
_global_signals_singleton = GlobalSignals()
return _global_signals_singleton
@@ -41,7 +72,9 @@ def ArgumentsSingleton(args: Namespace = None) -> Optional[Namespace]:
global _arguments_singleton
if _arguments_singleton is None and args is None:
raise RuntimeError("Uninitialized use of ArgumentsSingleton")
- if _arguments_singleton is None:
+ if _arguments_singleton is not None and args is not None:
+ raise RuntimeError("Arguments already initialized")
+ if args is not None:
_arguments_singleton = args
return _arguments_singleton
@@ -50,7 +83,27 @@ def ApiResultsSingleton(res: ApiResults = None) -> Optional[ApiResults]:
global _api_results_singleton
if _api_results_singleton is None and res is None:
raise RuntimeError("Uninitialized use of ApiResultsSingleton")
- if _api_results_singleton is None:
+ if _api_results_singleton is not None and res is not None:
+ raise RuntimeError("ApiResults already initialized")
+ if res is not None:
_api_results_singleton = res
return _api_results_singleton
+
+def clear_singleton_instance(instance: Union[LegendaryCore, GlobalSignals, Namespace, ApiResults]):
+ global _legendary_core_singleton, _global_signals_singleton, _arguments_singleton, _api_results_singleton
+ if isinstance(instance, LegendaryCore):
+ del instance
+ _legendary_core_singleton = None
+ elif isinstance(instance, GlobalSignals):
+ instance.deleteLater()
+ del instance
+ _global_signals_singleton = None
+ elif isinstance(instance, Namespace):
+ del instance
+ _arguments_singleton = None
+ elif isinstance(instance, ApiResults):
+ del instance
+ _api_results_singleton = None
+ else:
+ raise RuntimeError(f"Instance is of unknown type \"{type(instance)}\"")
diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py
index bb95e09a..a6ef5db2 100644
--- a/rare/utils/extra_widgets.py
+++ b/rare/utils/extra_widgets.py
@@ -54,7 +54,6 @@ class IndicatorReasons:
class IndicatorLineEdit(QWidget):
textChanged = pyqtSignal(str)
- is_valid = False
reasons = IndicatorReasons()
def __init__(
@@ -97,9 +96,10 @@ class IndicatorLineEdit(QWidget):
layout.addWidget(self.indicator_label)
if not placeholder:
- _translate = QCoreApplication.translate
+ _translate = QCoreApplication.instance().translate
self.line_edit.setPlaceholderText(_translate(self.__class__.__name__, "Default"))
+ self.is_valid = False
self.edit_func = edit_func
self.save_func = save_func
self.line_edit.textChanged.connect(self.__edit)
@@ -107,7 +107,7 @@ class IndicatorLineEdit(QWidget):
self.line_edit.textChanged.connect(self.__save)
# lk: this can be placed here to trigger __edit
- # lk: it going to save the input again if it is valid which
+ # lk: it is going to save the input again if it is valid which
# lk: is ok to do given the checks don't misbehave (they shouldn't)
# lk: however it is going to edit any "understood" bad input to good input
# lk: and we might not want that (but the validity check reports on the edited string)
@@ -185,9 +185,6 @@ class PathEditIconProvider(QFileIconProvider):
class PathEdit(IndicatorLineEdit):
- completer = QCompleter()
- compl_model = QFileSystemModel()
-
def __init__(
self,
path: str = "",
@@ -200,6 +197,9 @@ class PathEdit(IndicatorLineEdit):
horiz_policy: QSizePolicy = QSizePolicy.Expanding,
parent=None,
):
+ self.completer = QCompleter()
+ self.compl_model = QFileSystemModel()
+
try:
self.compl_model.setOptions(
QFileSystemModel.DontWatchForChanges
@@ -230,7 +230,7 @@ class PathEdit(IndicatorLineEdit):
layout = self.layout()
layout.addWidget(self.path_select)
- _translate = QCoreApplication.translate
+ _translate = QCoreApplication.instance().translate
self.path_select.setText(_translate("PathEdit", "Browse..."))
self.type_filter = type_filter
@@ -414,7 +414,7 @@ class SelectViewWidget(QWidget):
class ImageLabel(QLabel):
image = None
img_size = None
- name = str()
+ name = ""
def __init__(self):
super(ImageLabel, self).__init__()
From 70201411480c007a4d945df3be7bc67357135a6d Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Sun, 4 Sep 2022 19:51:23 +0300
Subject: [PATCH 13/15] LaunchDialog: Move update check before login()
---
rare/components/dialogs/launch_dialog.py | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index 72243e8c..458b5591 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -117,15 +117,15 @@ class LaunchDialog(QDialog):
pass
else:
QApplication.instance().processEvents()
+ # Force an update check and notice in case there are API changes
+ self.core.check_for_updates(force=True)
+ self.core.force_show_update = True
if self.core.login():
logger.info("You are logged in")
else:
raise ValueError("You are not logged in. Open Login Window")
except ValueError as e:
logger.info(str(e))
- # Force an update check and notice in case there are API changes
- self.core.check_for_updates(force=True)
- self.core.force_show_update = True
# Do not set parent, because it won't show a task bar icon
# Update: Inherit the same parent as LaunchDialog
do_launch = self.login_dialog.login()
From 1ebd0b18d8829d919cbe6bb80d135b082699d756 Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Sun, 4 Sep 2022 20:38:24 +0300
Subject: [PATCH 14/15] Introduce a very basic RareCore to handle signletons
and their cleanup.
---
rare/app.py | 23 ++-
rare/components/dialogs/launch_dialog.py | 5 +-
rare/components/tabs/games/__init__.py | 2 +-
.../tabs/games/game_info/game_dlc.py | 4 +-
.../tabs/games/game_info/game_info.py | 3 +-
.../tabs/games/game_info/uninstalled_info.py | 3 +-
.../game_widgets/base_installed_widget.py | 4 +-
.../game_widgets/base_uninstalled_widget.py | 3 +-
.../game_widgets/installing_game_widget.py | 4 +-
rare/shared/__init__.py | 101 ++-----------
rare/shared/image_manager.py | 23 +--
rare/shared/rare_core.py | 133 ++++++++++++++++++
12 files changed, 177 insertions(+), 131 deletions(-)
create mode 100644 rare/shared/rare_core.py
diff --git a/rare/app.py b/rare/app.py
index bba47458..efd10a64 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -1,4 +1,3 @@
-import configparser
import logging
import os
import platform
@@ -23,10 +22,8 @@ from rare.shared import (
LegendaryCoreSingleton,
GlobalSignalsSingleton,
ArgumentsSingleton,
- ApiResultsSingleton,
- clear_singleton_instance
)
-from rare.shared.image_manager import ImageManagerSingleton
+from rare.shared.rare_core import RareCore
from rare.utils import legendary_utils, config_helper
from rare.utils.paths import cache_dir, tmp_dir
from rare.widgets.rare_app import RareApp
@@ -61,8 +58,12 @@ def excepthook(exc_type, exc_value, exc_tb):
class App(RareApp):
def __init__(self, args: Namespace):
super(App, self).__init__()
+ self.rare_core = RareCore(args=args)
+ self.args = ArgumentsSingleton()
+ self.signals = GlobalSignalsSingleton()
self.core = LegendaryCoreSingleton()
- self.args = ArgumentsSingleton(args) # add some options
+
+ config_helper.init_config_handler(self.core)
lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang)
@@ -71,9 +72,6 @@ class App(RareApp):
self.mainwindow: Optional[MainWindow] = None
self.launch_dialog: Optional[LaunchDialog] = None
- self.signals = GlobalSignalsSingleton(init=True)
- self.image_manager = ImageManagerSingleton(init=True)
-
# launch app
self.launch_dialog = LaunchDialog(parent=None)
self.launch_dialog.quit_app.connect(self.launch_dialog.close)
@@ -141,9 +139,8 @@ class App(RareApp):
if self.mainwindow is not None:
self.mainwindow.close()
self.mainwindow = None
- clear_singleton_instance(self.signals)
- clear_singleton_instance(self.args)
- clear_singleton_instance(ApiResultsSingleton())
+ self.rare_core.deleteLater()
+ del self.rare_core
self.processEvents()
shutil.rmtree(tmp_dir)
os.makedirs(tmp_dir)
@@ -182,15 +179,11 @@ def start(args):
logger.info(f"Operating System: {platform.system()}")
while True:
- core = LegendaryCoreSingleton(init=True)
- config_helper.init_config_handler(core)
app = App(args)
exit_code = app.exec_()
# if not restart
# restart app
del app
- core.exit()
- clear_singleton_instance(core)
if exit_code != -133742:
break
diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py
index 458b5591..91c507aa 100644
--- a/rare/components/dialogs/launch_dialog.py
+++ b/rare/components/dialogs/launch_dialog.py
@@ -7,12 +7,11 @@ from requests.exceptions import ConnectionError, HTTPError
from rare.components.dialogs.login import LoginDialog
from rare.models.apiresults import ApiResults
-from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSingleton
-from rare.shared.image_manager import ImageManagerSingleton
+from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton, ApiResultsSingleton, ImageManagerSingleton
from rare.ui.components.dialogs.launch_dialog import Ui_LaunchDialog
from rare.utils.misc import CloudWorker
-logger = getLogger("Login")
+logger = getLogger("LoginDialog")
class LaunchWorker(QRunnable):
diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py
index e6db3967..71e319f7 100644
--- a/rare/components/tabs/games/__init__.py
+++ b/rare/components/tabs/games/__init__.py
@@ -11,7 +11,7 @@ from rare.shared import (
ArgumentsSingleton,
ApiResultsSingleton,
)
-from rare.shared.image_manager import ImageManagerSingleton
+from rare.shared import ImageManagerSingleton
from rare.widgets.library_layout import LibraryLayout
from rare.widgets.sliding_stack import SlidingStackedWidget
from .cloud_save_utils import CloudSaveUtils
diff --git a/rare/components/tabs/games/game_info/game_dlc.py b/rare/components/tabs/games/game_info/game_dlc.py
index 192cd28c..82510dea 100644
--- a/rare/components/tabs/games/game_info/game_dlc.py
+++ b/rare/components/tabs/games/game_info/game_dlc.py
@@ -3,8 +3,8 @@ from PyQt5.QtWidgets import QFrame, QWidget, QMessageBox
from legendary.models.game import Game
from rare.components.tabs.games.game_utils import GameUtils
-from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
-from rare.shared.image_manager import ImageManagerSingleton, ImageSize
+from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ImageManagerSingleton
+from rare.shared.image_manager import ImageSize
from rare.ui.components.tabs.games.game_info.game_dlc import Ui_GameDlc
from rare.ui.components.tabs.games.game_info.game_dlc_widget import Ui_GameDlcWidget
from rare.models.install import InstallOptionsModel
diff --git a/rare/components/tabs/games/game_info/game_info.py b/rare/components/tabs/games/game_info/game_info.py
index 4d513b7a..58ffc112 100644
--- a/rare/components/tabs/games/game_info/game_info.py
+++ b/rare/components/tabs/games/game_info/game_info.py
@@ -27,7 +27,8 @@ from rare.shared import (
GlobalSignalsSingleton,
ArgumentsSingleton,
)
-from rare.shared.image_manager import ImageManagerSingleton, ImageSize
+from rare.shared import ImageManagerSingleton
+from rare.shared.image_manager import ImageSize
from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo
from rare.utils.legendary_utils import VerifyWorker
from rare.utils.misc import get_size
diff --git a/rare/components/tabs/games/game_info/uninstalled_info.py b/rare/components/tabs/games/game_info/uninstalled_info.py
index 5c99e648..85f8b188 100644
--- a/rare/components/tabs/games/game_info/uninstalled_info.py
+++ b/rare/components/tabs/games/game_info/uninstalled_info.py
@@ -11,7 +11,8 @@ from rare.shared import (
ArgumentsSingleton,
ApiResultsSingleton,
)
-from rare.shared.image_manager import ImageManagerSingleton, ImageSize
+from rare.shared import ImageManagerSingleton
+from rare.shared.image_manager import ImageSize
from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo
from rare.utils.extra_widgets import SideTabWidget
from rare.utils.json_formatter import QJsonModel
diff --git a/rare/components/tabs/games/game_widgets/base_installed_widget.py b/rare/components/tabs/games/game_widgets/base_installed_widget.py
index 7f1d9837..f493553e 100644
--- a/rare/components/tabs/games/game_widgets/base_installed_widget.py
+++ b/rare/components/tabs/games/game_widgets/base_installed_widget.py
@@ -7,8 +7,8 @@ from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QFrame, QMessageBox, QAction
from rare.components.tabs.games.game_utils import GameUtils
-from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton
-from rare.shared.image_manager import ImageManagerSingleton, ImageSize
+from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton, ImageManagerSingleton
+from rare.shared.image_manager import ImageSize
from rare.utils.misc import create_desktop_link
from rare.widgets.image_widget import ImageWidget
diff --git a/rare/components/tabs/games/game_widgets/base_uninstalled_widget.py b/rare/components/tabs/games/game_widgets/base_uninstalled_widget.py
index 01860985..4ff61cf8 100644
--- a/rare/components/tabs/games/game_widgets/base_uninstalled_widget.py
+++ b/rare/components/tabs/games/game_widgets/base_uninstalled_widget.py
@@ -4,7 +4,8 @@ from PyQt5.QtCore import pyqtSignal, Qt
from PyQt5.QtWidgets import QFrame, QAction
from legendary.models.game import Game
-from rare.shared.image_manager import ImageManagerSingleton, ImageSize
+from rare.shared import ImageManagerSingleton
+from rare.shared.image_manager import ImageSize
from rare.widgets.image_widget import ImageWidget
logger = getLogger("Uninstalled")
diff --git a/rare/components/tabs/games/game_widgets/installing_game_widget.py b/rare/components/tabs/games/game_widgets/installing_game_widget.py
index 4800a757..cc7cf4da 100644
--- a/rare/components/tabs/games/game_widgets/installing_game_widget.py
+++ b/rare/components/tabs/games/game_widgets/installing_game_widget.py
@@ -3,8 +3,8 @@ from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QWidget, QFrame
from legendary.models.game import Game
-from rare.shared import LegendaryCoreSingleton
-from rare.shared.image_manager import ImageManagerSingleton, ImageSize
+from rare.shared import LegendaryCoreSingleton, ImageManagerSingleton
+from rare.shared.image_manager import ImageSize
from rare.widgets.elide_label import ElideLabel
from .library_widget import LibraryWidget
diff --git a/rare/shared/__init__.py b/rare/shared/__init__.py
index 788e63fc..3decb371 100644
--- a/rare/shared/__init__.py
+++ b/rare/shared/__init__.py
@@ -5,105 +5,34 @@ Each of the objects in this module should be instantiated ONCE
and only ONCE!
"""
-import configparser
import logging
-import os
from argparse import Namespace
-from typing import Optional, Union
+from typing import Optional
from rare.lgndr.core import LegendaryCore
from rare.models.apiresults import ApiResults
from rare.models.signals import GlobalSignals
+from .image_manager import ImageManager
+from .rare_core import RareCore
-logger = logging.getLogger("Singleton")
-
-_legendary_core_singleton: Optional[LegendaryCore] = None
-_global_signals_singleton: Optional[GlobalSignals] = None
-_arguments_singleton: Optional[Namespace] = None
-_api_results_singleton: Optional[ApiResults] = None
+logger = logging.getLogger("Shared")
-def LegendaryCoreSingleton(init: bool = False) -> LegendaryCore:
- global _legendary_core_singleton
- if _legendary_core_singleton is None and not init:
- raise RuntimeError("Uninitialized use of LegendaryCoreSingleton")
- if _legendary_core_singleton is not None and init:
- raise RuntimeError("LegendaryCore already initialized")
- if init:
- try:
- _legendary_core_singleton = LegendaryCore()
- except configparser.MissingSectionHeaderError as e:
- logger.warning(f"Config is corrupt: {e}")
- if config_path := os.environ.get("XDG_CONFIG_HOME"):
- path = os.path.join(config_path, "legendary")
- else:
- path = os.path.expanduser("~/.config/legendary")
- with open(os.path.join(path, "config.ini"), "w") as config_file:
- config_file.write("[Legendary]")
- _legendary_core_singleton = LegendaryCore()
- if "Legendary" not in _legendary_core_singleton.lgd.config.sections():
- _legendary_core_singleton.lgd.config.add_section("Legendary")
- _legendary_core_singleton.lgd.save_config()
- # workaround if egl sync enabled, but no programdata_path
- # programdata_path might be unset if logging in through the browser
- if _legendary_core_singleton.egl_sync_enabled:
- if _legendary_core_singleton.egl.programdata_path is None:
- _legendary_core_singleton.lgd.config.remove_option("Legendary", "egl_sync")
- _legendary_core_singleton.lgd.save_config()
- else:
- if not os.path.exists(_legendary_core_singleton.egl.programdata_path):
- _legendary_core_singleton.lgd.config.remove_option("Legendary", "egl_sync")
- _legendary_core_singleton.lgd.save_config()
- return _legendary_core_singleton
+def ArgumentsSingleton() -> Optional[Namespace]:
+ return RareCore.instance().args()
-def GlobalSignalsSingleton(init: bool = False) -> GlobalSignals:
- global _global_signals_singleton
- if _global_signals_singleton is None and not init:
- raise RuntimeError("Uninitialized use of GlobalSignalsSingleton")
- if _global_signals_singleton is not None and init:
- raise RuntimeError("GlobalSignals already initialized")
- if init:
- _global_signals_singleton = GlobalSignals()
- return _global_signals_singleton
+def GlobalSignalsSingleton() -> GlobalSignals:
+ return RareCore.instance().signals()
-def ArgumentsSingleton(args: Namespace = None) -> Optional[Namespace]:
- global _arguments_singleton
- if _arguments_singleton is None and args is None:
- raise RuntimeError("Uninitialized use of ArgumentsSingleton")
- if _arguments_singleton is not None and args is not None:
- raise RuntimeError("Arguments already initialized")
- if args is not None:
- _arguments_singleton = args
- return _arguments_singleton
+def LegendaryCoreSingleton() -> LegendaryCore:
+ return RareCore.instance().core()
+
+
+def ImageManagerSingleton() -> ImageManager:
+ return RareCore.instance().image_manager()
def ApiResultsSingleton(res: ApiResults = None) -> Optional[ApiResults]:
- global _api_results_singleton
- if _api_results_singleton is None and res is None:
- raise RuntimeError("Uninitialized use of ApiResultsSingleton")
- if _api_results_singleton is not None and res is not None:
- raise RuntimeError("ApiResults already initialized")
- if res is not None:
- _api_results_singleton = res
- return _api_results_singleton
-
-
-def clear_singleton_instance(instance: Union[LegendaryCore, GlobalSignals, Namespace, ApiResults]):
- global _legendary_core_singleton, _global_signals_singleton, _arguments_singleton, _api_results_singleton
- if isinstance(instance, LegendaryCore):
- del instance
- _legendary_core_singleton = None
- elif isinstance(instance, GlobalSignals):
- instance.deleteLater()
- del instance
- _global_signals_singleton = None
- elif isinstance(instance, Namespace):
- del instance
- _arguments_singleton = None
- elif isinstance(instance, ApiResults):
- del instance
- _api_results_singleton = None
- else:
- raise RuntimeError(f"Instance is of unknown type \"{type(instance)}\"")
+ return RareCore.instance().api_results(res)
diff --git a/rare/shared/image_manager.py b/rare/shared/image_manager.py
index 9d2791cd..a64cb62f 100644
--- a/rare/shared/image_manager.py
+++ b/rare/shared/image_manager.py
@@ -7,7 +7,7 @@ import zlib
from logging import getLogger
from pathlib import Path
from typing import TYPE_CHECKING
-from typing import Tuple, Dict, Union, Type, List, Callable, Optional
+from typing import Tuple, Dict, Union, Type, List, Callable
import requests
from PyQt5.QtCore import (
@@ -26,7 +26,8 @@ from PyQt5.QtGui import (
from PyQt5.QtWidgets import QApplication
from legendary.models.game import Game
-from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
+from rare.lgndr.core import LegendaryCore
+from rare.models.signals import GlobalSignals
from rare.utils.paths import image_dir, resources_path
if TYPE_CHECKING:
@@ -111,10 +112,10 @@ class ImageManager(QObject):
__dl_retries = 1
__worker_app_names: List[str] = list()
- def __init__(self):
+ def __init__(self, signals: GlobalSignals, core: LegendaryCore):
super(QObject, self).__init__()
- self.core = LegendaryCoreSingleton()
- self.signals = GlobalSignalsSingleton()
+ self.signals = signals
+ self.core = core
self.image_dir = Path(image_dir)
if not self.image_dir.is_dir():
@@ -357,15 +358,3 @@ class ImageManager(QObject):
"""
image: QImage = self.__get_cover(QImage, app_name, color)
return image
-
-
-_image_manager_singleton: Optional[ImageManager] = None
-
-
-def ImageManagerSingleton(init: bool = False) -> ImageManager:
- global _image_manager_singleton
- if _image_manager_singleton is None and not init:
- raise RuntimeError("Uninitialized use of ImageManagerSingleton")
- if _image_manager_singleton is None:
- _image_manager_singleton = ImageManager()
- return _image_manager_singleton
diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py
new file mode 100644
index 00000000..def6af99
--- /dev/null
+++ b/rare/shared/rare_core.py
@@ -0,0 +1,133 @@
+import configparser
+import os
+from argparse import Namespace
+from logging import getLogger
+from typing import Optional
+
+from PyQt5.QtCore import QObject
+
+from rare.lgndr.core import LegendaryCore
+from rare.models.apiresults import ApiResults
+from rare.models.signals import GlobalSignals
+from .image_manager import ImageManager
+
+logger = getLogger("RareCore")
+
+
+class RareCore(QObject):
+ _instance: Optional['RareCore'] = None
+
+ def __init__(self, args: Namespace):
+ if self._instance is not None:
+ raise RuntimeError("RareCore already initialized")
+ super(RareCore, self).__init__()
+ self._args: Optional[Namespace] = None
+ self._signals: Optional[GlobalSignals] = None
+ self._core: Optional[LegendaryCore] = None
+ self._image_manager: Optional[ImageManager] = None
+ self._api_results: Optional[ApiResults] = None
+
+ self.args(args)
+ self.signals(init=True)
+ self.core(init=True)
+ self.image_manager(init=True)
+
+ RareCore._instance = self
+
+ @staticmethod
+ def instance() -> 'RareCore':
+ if RareCore._instance is None:
+ raise RuntimeError("Uninitialized use of RareCore")
+ return RareCore._instance
+
+ def signals(self, init: bool = False) -> GlobalSignals:
+ if self._signals is None and not init:
+ raise RuntimeError("Uninitialized use of GlobalSignalsSingleton")
+ if self._signals is not None and init:
+ raise RuntimeError("GlobalSignals already initialized")
+ if init:
+ self._signals = GlobalSignals()
+ return self._signals
+
+ def args(self, args: Namespace = None) -> Optional[Namespace]:
+ if self._args is None and args is None:
+ raise RuntimeError("Uninitialized use of ArgumentsSingleton")
+ if self._args is not None and args is not None:
+ raise RuntimeError("Arguments already initialized")
+ if args is not None:
+ self._args = args
+ return self._args
+
+ def core(self, init: bool = False) -> LegendaryCore:
+ if self._core is None and not init:
+ raise RuntimeError("Uninitialized use of LegendaryCoreSingleton")
+ if self._core is not None and init:
+ raise RuntimeError("LegendaryCore already initialized")
+ if init:
+ try:
+ self._core = LegendaryCore()
+ except configparser.MissingSectionHeaderError as e:
+ logger.warning(f"Config is corrupt: {e}")
+ if config_path := os.environ.get("XDG_CONFIG_HOME"):
+ path = os.path.join(config_path, "legendary")
+ else:
+ path = os.path.expanduser("~/.config/legendary")
+ with open(os.path.join(path, "config.ini"), "w") as config_file:
+ config_file.write("[Legendary]")
+ self._core = LegendaryCore()
+ if "Legendary" not in self._core.lgd.config.sections():
+ self._core.lgd.config.add_section("Legendary")
+ self._core.lgd.save_config()
+ # workaround if egl sync enabled, but no programdata_path
+ # programdata_path might be unset if logging in through the browser
+ if self._core.egl_sync_enabled:
+ if self._core.egl.programdata_path is None:
+ self._core.lgd.config.remove_option("Legendary", "egl_sync")
+ self._core.lgd.save_config()
+ else:
+ if not os.path.exists(self._core.egl.programdata_path):
+ self._core.lgd.config.remove_option("Legendary", "egl_sync")
+ self._core.lgd.save_config()
+ return self._core
+
+ def image_manager(self, init: bool = False) -> ImageManager:
+ if self._image_manager is None and not init:
+ raise RuntimeError("Uninitialized use of ImageManagerSingleton")
+ if self._image_manager is not None and init:
+ raise RuntimeError("ImageManager already initialized")
+ if self._image_manager is None:
+ self._image_manager = ImageManager(self.signals(), self.core())
+ return self._image_manager
+
+ def api_results(self, res: ApiResults = None) -> Optional[ApiResults]:
+ if self._api_results is None and res is None:
+ raise RuntimeError("Uninitialized use of ApiResultsSingleton")
+ if self._api_results is not None and res is not None:
+ raise RuntimeError("ApiResults already initialized")
+ if res is not None:
+ self._api_results = res
+ return self._api_results
+
+ def deleteLater(self) -> None:
+ del self._api_results
+ self._api_results = None
+
+ self._image_manager.deleteLater()
+ del self._image_manager
+ self._image_manager = None
+
+ self._core.exit()
+ del self._core
+ self._core = None
+
+ self._signals.deleteLater()
+ del self._signals
+ self._signals = None
+
+ del self._args
+ self._args = None
+
+ RareCore._instance = None
+
+ super(RareCore, self).deleteLater()
+
From aa9cf4c5b5fb5ab634e159bcbd8fe58d60a841fc Mon Sep 17 00:00:00 2001
From: loathingKernel <142770+loathingKernel@users.noreply.github.com>
Date: Sun, 4 Sep 2022 21:40:41 +0300
Subject: [PATCH 15/15] GameLaunchHelper: Remove LegendaryCoreSingleton usage
---
rare/game_launch_helper/__init__.py | 12 ++++++------
rare/game_launch_helper/lgd_helper.py | 4 +++-
2 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/rare/game_launch_helper/__init__.py b/rare/game_launch_helper/__init__.py
index 6773b866..35a13e3f 100644
--- a/rare/game_launch_helper/__init__.py
+++ b/rare/game_launch_helper/__init__.py
@@ -11,11 +11,11 @@ from PyQt5.QtCore import QObject, QProcess, pyqtSignal, QUrl, QRunnable, QThread
from PyQt5.QtGui import QDesktopServices
from PyQt5.QtNetwork import QLocalServer, QLocalSocket
+from rare.lgndr.core import LegendaryCore
+from rare.widgets.rare_app import RareApp
from .console import Console
from .lgd_helper import get_launch_args, InitArgs, get_configured_process, LaunchArgs, GameArgsError
from .message_models import ErrorModel, Actions, FinishedModel, BaseModel, StateChangedModel
-from ..shared import LegendaryCoreSingleton
-from ..widgets.rare_app import RareApp
class PreLaunchThread(QRunnable):
@@ -25,9 +25,9 @@ class PreLaunchThread(QRunnable):
pre_launch_command_finished = pyqtSignal(int) # exit_code
error_occurred = pyqtSignal(str)
- def __init__(self, args: InitArgs):
+ def __init__(self, core: LegendaryCore, args: InitArgs):
super(PreLaunchThread, self).__init__()
- self.core = LegendaryCoreSingleton()
+ self.core = core
self.app_name = args.app_name
self.signals = self.Signals()
@@ -69,7 +69,7 @@ class GameProcessApp(RareApp):
self.game_process = QProcess()
self.app_name = app_name
self.logger = getLogger(self.app_name)
- self.core = LegendaryCoreSingleton(init=True)
+ self.core = LegendaryCore()
lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang)
@@ -187,7 +187,7 @@ class GameProcessApp(RareApp):
self.logger.error("Not logged in. Try to launch game offline")
args.offline = True
- worker = PreLaunchThread(args)
+ worker = PreLaunchThread(self.core, args)
worker.signals.ready_to_launch.connect(self.launch_game)
worker.signals.error_occurred.connect(self.error_occurred)
# worker.signals.started_pre_launch_command(None)
diff --git a/rare/game_launch_helper/lgd_helper.py b/rare/game_launch_helper/lgd_helper.py
index 00d3cc74..7e82960c 100644
--- a/rare/game_launch_helper/lgd_helper.py
+++ b/rare/game_launch_helper/lgd_helper.py
@@ -6,9 +6,11 @@ from logging import getLogger
from typing import List
from PyQt5.QtCore import QProcess, QProcessEnvironment
-from legendary.core import LegendaryCore
from legendary.models.game import InstalledGame, LaunchParameters
+from rare.lgndr.core import LegendaryCore
+
+
logger = getLogger("Helper")