1
0
Fork 0
mirror of synced 2024-06-25 17:50:45 +12:00

AccountWidget: Add a Quit button in the widget in case the system tray

is unavailable (for example running in a gamescope session)

* Do not show the launch window while instantiating the application. This
probably was causing numerous issues because it was running outside of
the applications event loop. This also fixes the exit button on the login
dialog requiring `sys.exit()` to quit Rare. Now it goes through the
proper cleanup procedures.

* Make slot and signal names more uniform

* Fix a problem with RareCore connecting RareGames to the same signals
multiple times when the library was refreshed.
This commit is contained in:
loathingKernel 2023-09-13 21:36:11 +03:00
parent 8d46a3e353
commit c3c9b0f059
No known key found for this signature in database
GPG key ID: CE0C72D0B53821FD
7 changed files with 76 additions and 60 deletions

View file

@ -55,14 +55,9 @@ class Rare(RareApp):
self.launch_dialog: Optional[LaunchDialog] = None self.launch_dialog: Optional[LaunchDialog] = None
self.timer: Optional[QTimer] = None self.timer: Optional[QTimer] = None
# launch app # This launches the application after it has been instantiated.
self.launch_dialog = LaunchDialog(parent=None) # The timer's signal will be serviced once we call `exec()` on the application
self.launch_dialog.quit_app.connect(self.launch_dialog.close) QTimer.singleShot(0, self.launch_app)
self.launch_dialog.quit_app.connect(lambda x: sys.exit(x))
self.launch_dialog.start_app.connect(self.start_app)
self.launch_dialog.start_app.connect(self.launch_dialog.close)
self.launch_dialog.login()
def poke_timer(self): def poke_timer(self):
dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1]).replace(tzinfo=timezone.utc) dt_exp = datetime.fromisoformat(self.core.lgd.userdata['expires_at'][:-1]).replace(tzinfo=timezone.utc)
@ -80,13 +75,23 @@ class Rare(RareApp):
return return
self.poke_timer() self.poke_timer()
@pyqtSlot()
def launch_app(self):
self.launch_dialog = LaunchDialog(parent=None)
self.launch_dialog.exit_app.connect(self.launch_dialog.close)
self.launch_dialog.exit_app.connect(self.__on_exit_app)
self.launch_dialog.start_app.connect(self.start_app)
self.launch_dialog.start_app.connect(self.launch_dialog.close)
self.launch_dialog.login()
@pyqtSlot()
def start_app(self): def start_app(self):
self.timer = QTimer() self.timer = QTimer()
self.timer.timeout.connect(self.re_login) self.timer.timeout.connect(self.re_login)
self.poke_timer() self.poke_timer()
self.main_window = MainWindow() self.main_window = MainWindow()
self.main_window.exit_app.connect(self.on_exit_app) self.main_window.exit_app.connect(self.__on_exit_app)
if not self.args.silent: if not self.args.silent:
self.main_window.show() self.main_window.show()
@ -94,11 +99,11 @@ class Rare(RareApp):
if self.args.test_start: if self.args.test_start:
self.main_window.close() self.main_window.close()
self.main_window = None self.main_window = None
self.on_exit_app(0) self.__on_exit_app(0)
@pyqtSlot() @pyqtSlot()
@pyqtSlot(int) @pyqtSlot(int)
def on_exit_app(self, exit_code=0): def __on_exit_app(self, exit_code=0):
threadpool = QThreadPool.globalInstance() threadpool = QThreadPool.globalInstance()
threadpool.waitForDone() threadpool.waitForDone()
if self.timer is not None: if self.timer is not None:
@ -119,9 +124,7 @@ def start(args) -> int:
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
app = Rare(args) app = Rare(args)
exit_code = app.exec_() exit_code = app.exec()
# if not restart
# restart app
del app del app
if exit_code != -133742: if exit_code != -133742:
break break

View file

@ -14,7 +14,7 @@ logger = getLogger("LaunchDialog")
class LaunchDialog(QDialog): class LaunchDialog(QDialog):
quit_app = pyqtSignal(int) exit_app = pyqtSignal(int)
start_app = pyqtSignal() start_app = pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
@ -74,7 +74,7 @@ class LaunchDialog(QDialog):
self.show() self.show()
self.launch() self.launch()
else: else:
self.quit_app.emit(0) self.exit_app.emit(0)
def launch(self): def launch(self):
self.progress_info.setText(self.tr("Preparing Rare")) self.progress_info.setText(self.tr("Preparing Rare"))

View file

@ -1,7 +1,6 @@
from dataclasses import dataclass
from logging import getLogger from logging import getLogger
from PyQt5.QtCore import Qt from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QLayout, QDialog, QMessageBox, QFrame from PyQt5.QtWidgets import QLayout, QDialog, QMessageBox, QFrame
from legendary.core import LegendaryCore from legendary.core import LegendaryCore
@ -15,13 +14,6 @@ from .import_login import ImportLogin
logger = getLogger("LoginDialog") logger = getLogger("LoginDialog")
@dataclass
class LoginPages:
landing: int
browser: int
import_egl: int
class LandingPage(QFrame): class LandingPage(QFrame):
def __init__(self, parent=None): def __init__(self, parent=None):
super(LandingPage, self).__init__(parent=parent) super(LandingPage, self).__init__(parent=parent)
@ -31,8 +23,7 @@ class LandingPage(QFrame):
class LoginDialog(QDialog): class LoginDialog(QDialog):
logged_in: bool = False exit_app: pyqtSignal = pyqtSignal(int)
pages = LoginPages(landing=0, browser=1, import_egl=2)
def __init__(self, core: LegendaryCore, parent=None): def __init__(self, core: LegendaryCore, parent=None):
super(LoginDialog, self).__init__(parent=parent) super(LoginDialog, self).__init__(parent=parent)
@ -51,6 +42,8 @@ class LoginDialog(QDialog):
self.ui = Ui_LoginDialog() self.ui = Ui_LoginDialog()
self.ui.setupUi(self) self.ui.setupUi(self)
self.logged_in: bool = False
self.core = core self.core = core
self.args = ArgumentsSingleton() self.args = ArgumentsSingleton()
@ -59,16 +52,16 @@ class LoginDialog(QDialog):
self.ui.login_stack_layout.addWidget(self.login_stack) self.ui.login_stack_layout.addWidget(self.login_stack)
self.landing_page = LandingPage(self.login_stack) self.landing_page = LandingPage(self.login_stack)
self.login_stack.insertWidget(self.pages.landing, self.landing_page) self.login_stack.insertWidget(0, self.landing_page)
self.browser_page = BrowserLogin(self.core, self.login_stack) self.browser_page = BrowserLogin(self.core, self.login_stack)
self.login_stack.insertWidget(self.pages.browser, self.browser_page) self.login_stack.insertWidget(1, self.browser_page)
self.browser_page.success.connect(self.login_successful) self.browser_page.success.connect(self.login_successful)
self.browser_page.changed.connect( self.browser_page.changed.connect(
lambda: self.ui.next_button.setEnabled(self.browser_page.is_valid()) lambda: self.ui.next_button.setEnabled(self.browser_page.is_valid())
) )
self.import_page = ImportLogin(self.core, self.login_stack) self.import_page = ImportLogin(self.core, self.login_stack)
self.login_stack.insertWidget(self.pages.import_egl, self.import_page) self.login_stack.insertWidget(2, self.import_page)
self.import_page.success.connect(self.login_successful) self.import_page.success.connect(self.login_successful)
self.import_page.changed.connect(lambda: self.ui.next_button.setEnabled(self.import_page.is_valid())) self.import_page.changed.connect(lambda: self.ui.next_button.setEnabled(self.import_page.is_valid()))
@ -84,34 +77,34 @@ class LoginDialog(QDialog):
self.ui.back_button.clicked.connect(self.back_clicked) self.ui.back_button.clicked.connect(self.back_clicked)
self.ui.next_button.clicked.connect(self.next_clicked) self.ui.next_button.clicked.connect(self.next_clicked)
self.login_stack.setCurrentIndex(self.pages.landing) self.login_stack.setCurrentWidget(self.landing_page)
self.layout().setSizeConstraint(QLayout.SetFixedSize) self.layout().setSizeConstraint(QLayout.SetFixedSize)
def back_clicked(self): def back_clicked(self):
self.ui.back_button.setEnabled(False) self.ui.back_button.setEnabled(False)
self.ui.next_button.setEnabled(True) self.ui.next_button.setEnabled(True)
self.login_stack.slideInIndex(self.pages.landing) self.login_stack.slideInWidget(self.landing_page)
def browser_radio_clicked(self): def browser_radio_clicked(self):
self.login_stack.slideInIndex(self.pages.browser) self.login_stack.slideInWidget(self.browser_page)
self.ui.back_button.setEnabled(True) self.ui.back_button.setEnabled(True)
self.ui.next_button.setEnabled(False) self.ui.next_button.setEnabled(False)
def import_radio_clicked(self): def import_radio_clicked(self):
self.login_stack.slideInIndex(self.pages.import_egl) self.login_stack.slideInWidget(self.import_page)
self.ui.back_button.setEnabled(True) self.ui.back_button.setEnabled(True)
self.ui.next_button.setEnabled(self.import_page.is_valid()) self.ui.next_button.setEnabled(self.import_page.is_valid())
def next_clicked(self): def next_clicked(self):
if self.login_stack.currentIndex() == self.pages.landing: if self.login_stack.currentWidget() is self.landing_page:
if self.landing_page.ui.login_browser_radio.isChecked(): if self.landing_page.ui.login_browser_radio.isChecked():
self.browser_radio_clicked() self.browser_radio_clicked()
if self.landing_page.ui.login_import_radio.isChecked(): if self.landing_page.ui.login_import_radio.isChecked():
self.import_radio_clicked() self.import_radio_clicked()
elif self.login_stack.currentIndex() == self.pages.browser: elif self.login_stack.currentWidget() is self.browser_page:
self.browser_page.do_login() self.browser_page.do_login()
elif self.login_stack.currentIndex() == self.pages.import_egl: elif self.login_stack.currentWidget() is self.import_page:
self.import_page.do_login() self.import_page.do_login()
def login(self): def login(self):

View file

@ -44,7 +44,7 @@ class MainWindow(QMainWindow):
self.setWindowTitle("Rare - GUI for legendary") self.setWindowTitle("Rare - GUI for legendary")
self.tab_widget = MainTabWidget(self) self.tab_widget = MainTabWidget(self)
self.tab_widget.exit_app.connect(self.on_exit_app) self.tab_widget.exit_app.connect(self.__on_exit_app)
self.setCentralWidget(self.tab_widget) self.setCentralWidget(self.tab_widget)
# Set up status bar stuff (jumping through a lot of hoops) # Set up status bar stuff (jumping through a lot of hoops)
@ -112,7 +112,7 @@ class MainWindow(QMainWindow):
self.timer.start() self.timer.start()
self.tray_icon: TrayIcon = TrayIcon(self) self.tray_icon: TrayIcon = TrayIcon(self)
self.tray_icon.exit_app.connect(self.on_exit_app) self.tray_icon.exit_app.connect(self.__on_exit_app)
self.tray_icon.show_app.connect(self.show) self.tray_icon.show_app.connect(self.show)
self.tray_icon.activated.connect(lambda r: self.toggle() if r == self.tray_icon.DoubleClick else None) self.tray_icon.activated.connect(lambda r: self.toggle() if r == self.tray_icon.DoubleClick else None)
@ -203,7 +203,7 @@ class MainWindow(QMainWindow):
@pyqtSlot() @pyqtSlot()
@pyqtSlot(int) @pyqtSlot(int)
def on_exit_app(self, exit_code=0) -> None: def __on_exit_app(self, exit_code=0) -> None:
self.__exit_code = exit_code self.__exit_code = exit_code
self.close() self.close()

View file

@ -51,7 +51,7 @@ class MainTabWidget(QTabWidget):
self.setTabEnabled(button_index, False) self.setTabEnabled(button_index, False)
self.account_widget = AccountWidget(self) self.account_widget = AccountWidget(self)
self.account_widget.logout.connect(self.logout) self.account_widget.exit_app.connect(self.__on_exit_app)
account_action = QWidgetAction(self) account_action = QWidgetAction(self)
account_action.setDefaultWidget(self.account_widget) account_action.setDefaultWidget(self.account_widget)
account_button = TabButtonWidget("mdi.account-circle", "Account", fallback_icon="fa.user") account_button = TabButtonWidget("mdi.account-circle", "Account", fallback_icon="fa.user")
@ -93,25 +93,28 @@ class MainTabWidget(QTabWidget):
self.tab_bar.setMinimumWidth(self.width()) self.tab_bar.setMinimumWidth(self.width())
super(MainTabWidget, self).resizeEvent(event) super(MainTabWidget, self).resizeEvent(event)
@pyqtSlot() @pyqtSlot(int)
def logout(self): def __on_exit_app(self, exit_code: int):
# FIXME: Don't allow logging out if there are active downloads # FIXME: Don't allow logging out if there are active downloads
if self.downloads_tab.is_download_active: if self.downloads_tab.is_download_active:
QMessageBox.warning( QMessageBox.warning(
self, self,
self.tr("Logout"), self.tr("Quit") if exit_code == self.account_widget.ExitCodes.EXIT else self.tr("Logout"),
self.tr("There are active downloads. Stop them before logging out."), self.tr("There are active downloads. Stop them before trying to quit."),
) )
return return
# FIXME: End of FIXME # FIXME: End of FIXME
reply = QMessageBox.question( if exit_code == self.account_widget.ExitCodes.LOGOUT:
self, reply = QMessageBox.question(
self.tr("Logout"), self,
self.tr("Do you really want to logout <b>{}</b>?").format(self.core.lgd.userdata.get("display_name")), self.tr("Logout"),
buttons=(QMessageBox.Yes | QMessageBox.No), self.tr("Do you really want to logout <b>{}</b>?").format(self.core.lgd.userdata.get("display_name")),
defaultButton=QMessageBox.No, buttons=(QMessageBox.Yes | QMessageBox.No),
) defaultButton=QMessageBox.No,
)
if reply == QMessageBox.Yes: if reply == QMessageBox.Yes:
self.core.lgd.invalidate_userdata() self.core.lgd.invalidate_userdata()
self.exit_app.emit(-133742) # restart exit code else:
return
self.exit_app.emit(exit_code) # restart exit code

View file

@ -1,15 +1,21 @@
import webbrowser import webbrowser
from enum import IntEnum
from PyQt5.QtCore import pyqtSignal from PyQt5.QtCore import pyqtSignal, pyqtSlot
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QMessageBox, QLabel, QPushButton from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
from rare.utils.misc import icon from rare.utils.misc import icon
class AccountWidget(QWidget): class AccountWidget(QWidget):
exit_app: pyqtSignal = pyqtSignal(int)
logout: pyqtSignal = pyqtSignal() logout: pyqtSignal = pyqtSignal()
class ExitCodes(IntEnum):
EXIT = 0
LOGOUT = -133742
def __init__(self, parent): def __init__(self, parent):
super(AccountWidget, self).__init__(parent=parent) super(AccountWidget, self).__init__(parent=parent)
self.core = LegendaryCoreSingleton() self.core = LegendaryCoreSingleton()
@ -25,11 +31,22 @@ class AccountWidget(QWidget):
"https://www.epicgames.com/account/personal?productName=epicgames" "https://www.epicgames.com/account/personal?productName=epicgames"
) )
) )
self.logout_button = QPushButton(self.tr("Logout")) self.logout_button = QPushButton(self.tr("Logout"), parent=self)
self.logout_button.clicked.connect(self.logout) self.logout_button.clicked.connect(self.__on_logout)
self.quit_button = QPushButton(self.tr("Quit"), parent=self)
self.quit_button.clicked.connect(self.__on_quit)
layout = QVBoxLayout(self) layout = QVBoxLayout(self)
layout.addWidget(QLabel(self.tr("Account"))) layout.addWidget(QLabel(self.tr("Account")))
layout.addWidget(QLabel(self.tr("Logged in as <b>{}</b>").format(username))) layout.addWidget(QLabel(self.tr("Logged in as <b>{}</b>").format(username)))
layout.addWidget(self.open_browser) layout.addWidget(self.open_browser)
layout.addWidget(self.logout_button) layout.addWidget(self.logout_button)
layout.addWidget(self.quit_button)
@pyqtSlot()
def __on_quit(self):
self.exit_app.emit(AccountWidget.ExitCodes.EXIT)
@pyqtSlot()
def __on_logout(self):
self.exit_app.emit(AccountWidget.ExitCodes.LOGOUT)

View file

@ -179,8 +179,8 @@ class RareCore(QObject):
del self.__args del self.__args
self.__args = None self.__args = None
del self.__eos_overlay
RareCore.__instance = None RareCore.__instance = None
super(RareCore, self).deleteLater() super(RareCore, self).deleteLater()
def __validate_install(self, rgame: RareGame): def __validate_install(self, rgame: RareGame):