From a566e836e55a0cb48c55e9c2e90aeeff722ec6cc Mon Sep 17 00:00:00 2001 From: Dummerle Date: Wed, 17 Feb 2021 13:58:29 +0100 Subject: [PATCH] Added Login, In Gamelist filter and installed only --- Rare/Components/Tabs/Games/GameList.py | 21 ++++- .../Tabs/Games/GameWidgetInstalled.py | 10 +- .../Tabs/Games/GameWidgetUninstalled.py | 6 ++ Rare/Components/Tabs/Games/Games.py | 34 ++++++- Rare/Main.py | 20 ++-- Rare/Styles/RareStyle.qss | 19 +++- Rare/utils/Dialogs/Login/BrowserLogin.py | 52 +++++++++++ Rare/utils/Dialogs/Login/ImportWidget.py | 6 ++ Rare/utils/Dialogs/Login/LoginDialog.py | 93 +++++++++++++++++++ Rare/utils/Dialogs/Login/__init__.py | 0 10 files changed, 239 insertions(+), 22 deletions(-) create mode 100644 Rare/utils/Dialogs/Login/BrowserLogin.py create mode 100644 Rare/utils/Dialogs/Login/ImportWidget.py create mode 100644 Rare/utils/Dialogs/Login/LoginDialog.py create mode 100644 Rare/utils/Dialogs/Login/__init__.py diff --git a/Rare/Components/Tabs/Games/GameList.py b/Rare/Components/Tabs/Games/GameList.py index 864faaf3..e45f3799 100644 --- a/Rare/Components/Tabs/Games/GameList.py +++ b/Rare/Components/Tabs/Games/GameList.py @@ -12,6 +12,7 @@ class GameList(QScrollArea): super(GameList, self).__init__() self.core = core self.widget = QWidget() + self .setObjectName("list_widget") self.setWidgetResizable(True) self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) @@ -27,10 +28,24 @@ class GameList(QScrollArea): for game in sorted(core.get_game_list(), key=lambda x: x.app_title): if not game.app_name in installed: uninstalled_games.append(game) + self.widgets = [] for i in uninstalled_games: - self.layout.addWidget(GameWidgetUninstalled(core, i)) - + widget = GameWidgetUninstalled(core, i) + self.layout.addWidget(widget) + self.widgets.append(widget) self.widget.setLayout(self.layout) - self.setWidget(self.widget) \ No newline at end of file + self.setWidget(self.widget) + + def filter(self, text: str): + for w in self.widgets: + if text.lower() in w.game.app_title.lower() + w.game.app_name.lower(): + w.setVisible(True) + else: + w.setVisible(False) + + def installed_only(self, i_o: bool): + # TODO save state + for w in self.widgets: + w.setVisible(not i_o) \ No newline at end of file diff --git a/Rare/Components/Tabs/Games/GameWidgetInstalled.py b/Rare/Components/Tabs/Games/GameWidgetInstalled.py index 46aeae18..e187d0e0 100644 --- a/Rare/Components/Tabs/Games/GameWidgetInstalled.py +++ b/Rare/Components/Tabs/Games/GameWidgetInstalled.py @@ -12,7 +12,7 @@ from Rare.utils import LegendaryApi from Rare.utils.QtExtensions import ClickableLabel from Rare.utils.RareConfig import IMAGE_DIR -logger = getLogger("FlowWidget") +logger = getLogger("GameWidgetInstalled") class GameWidgetInstalled(QWidget): @@ -24,7 +24,9 @@ class GameWidgetInstalled(QWidget): self.game = game self.running = False - Qt.WA_MouseTracking = Qt.WA_Hover + self.update_available = self.core.get_asset(self.game.app_name, True).build_version != game.version + if self.update_available: + logger.info("Update available for game: "+ self.game.app_name) if os.path.exists(f"{IMAGE_DIR}/{game.app_name}/FinalArt.png"): pixmap = QPixmap(f"{IMAGE_DIR}/{game.app_name}/FinalArt.png") @@ -73,10 +75,6 @@ class GameWidgetInstalled(QWidget): def leaveEvent(self, a0: QEvent) -> None: self.info_label.setText("") - - - #return QWidget.mouseMoveEvent(self, mouseEvent) - def mousePressEvent(self, a0) -> None: self.launch() diff --git a/Rare/Components/Tabs/Games/GameWidgetUninstalled.py b/Rare/Components/Tabs/Games/GameWidgetUninstalled.py index 0f27df91..47a3c420 100644 --- a/Rare/Components/Tabs/Games/GameWidgetUninstalled.py +++ b/Rare/Components/Tabs/Games/GameWidgetUninstalled.py @@ -49,6 +49,12 @@ class GameWidgetUninstalled(QWidget): def mousePressEvent(self, a0) -> None: self.install() + def enterEvent(self, QEvent): + self.info_label.setText("Install Game") + + def leaveEvent(self, QEvent): + self.info_label.setText("") + def install(self): logger.info("Install " + self.game.app_title) infos = InstallDialog().get_information() diff --git a/Rare/Components/Tabs/Games/Games.py b/Rare/Components/Tabs/Games/Games.py index 460946c4..0721f5c4 100644 --- a/Rare/Components/Tabs/Games/Games.py +++ b/Rare/Components/Tabs/Games/Games.py @@ -1,4 +1,4 @@ -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QCheckBox, QLineEdit, QLabel from Rare.Components.Tabs.Games.GameList import GameList @@ -9,16 +9,40 @@ class Games(QWidget): self.layout = QVBoxLayout() self.head_bar = GameListHeadBar() + self.head_bar.setObjectName("head_bar") self.game_list = GameList(core) - self.layout.addLayout(self.head_bar) + + self.head_bar.search_bar.textChanged.connect( + lambda: self.game_list.filter(self.head_bar.search_bar.text())) + + self.head_bar.installed_only.stateChanged.connect(lambda : + self.game_list.installed_only(self.head_bar.installed_only.isChecked())) + + self.layout.addWidget(self.head_bar) self.layout.addWidget(self.game_list) - #self.layout.addStretch(1) + # self.layout.addStretch(1) self.setLayout(self.layout) -class GameListHeadBar(QHBoxLayout): +class GameListHeadBar(QWidget): def __init__(self): super(GameListHeadBar, self).__init__() + self.layout = QHBoxLayout() + self.installed_only = QCheckBox("Installed only") - self.addWidget(self.installed_only) + self.layout.addWidget(self.installed_only) + + self.layout.addStretch() + + self.search_bar = QLineEdit() + self.search_bar.setPlaceholderText("Search Game") + self.layout.addWidget(self.search_bar) + + self.layout.addStretch() + self.list_view = QLabel("List view") + self.layout.addWidget(self.list_view) + self.view = QCheckBox("Icon view") + self.layout.addWidget(self.view) + + self.setLayout(self.layout) diff --git a/Rare/Main.py b/Rare/Main.py index 8790cdaa..6a875cf0 100644 --- a/Rare/Main.py +++ b/Rare/Main.py @@ -3,8 +3,9 @@ import os import sys import requests -from PyQt5.QtCore import QTranslator +from PyQt5.QtCore import QTranslator, pyqtSignal from PyQt5.QtWidgets import QApplication, QMessageBox + from legendary.core import LegendaryCore from Rare import style_path, lang_path @@ -13,6 +14,8 @@ from Rare.Components.MainWindow import MainWindow # from Rare.Start.Launch import LaunchDialog # from Rare.Start.Login import LoginWindow # from Rare.utils.RareUtils import get_lang +from Rare.utils.Dialogs.Login.LoginDialog import LoginDialog +from Rare.utils.utils import download_images, get_lang logging.basicConfig( format='[%(name)s] %(levelname)s: %(message)s', @@ -24,19 +27,21 @@ core = LegendaryCore() def main(): app = QApplication(sys.argv) + + # Translator translator = QTranslator() - # lang = get_lang() - lang = "de" + lang = get_lang() if os.path.exists(lang_path + lang + ".qm"): translator.load(lang_path + lang + ".qm") - else: + elif not lang == "en": logger.info("Your language is not supported") app.installTranslator(translator) - + # Style app.setStyleSheet(open(style_path + "RareStyle.qss").read()) + # Offline mode (not completed) offline = True - + # Login logger.info("Try if you are logged in") try: if core.login(): @@ -47,8 +52,9 @@ def main(): main() except ValueError: + # If not Logged in: Start Login window logger.info("You are not logged in. Open Login Window") - login_window = LoginWindow(core) + login_window = LoginDialog(core) if not login_window.login(): return diff --git a/Rare/Styles/RareStyle.qss b/Rare/Styles/RareStyle.qss index 0a907c1a..7b5d2739 100644 --- a/Rare/Styles/RareStyle.qss +++ b/Rare/Styles/RareStyle.qss @@ -19,7 +19,6 @@ QTabBar::tab:disabled { } - QToolButton { padding: 5px; } @@ -42,3 +41,21 @@ QPushButton#menu { margin: 0px; border-style: none; } + +QLineEdit { + border: 1px solid white; +} + +QCheckBox::indicator { + border: 1px solid white; + border-radius: 2px; +} +QCheckBox::indicator:checked { + background-color: white; +} +#head_bar{ + border-bottom: 2px solid white; +} +#list_widget{ + border-top: 2px solid white; +} \ No newline at end of file diff --git a/Rare/utils/Dialogs/Login/BrowserLogin.py b/Rare/utils/Dialogs/Login/BrowserLogin.py new file mode 100644 index 00000000..ee1f140d --- /dev/null +++ b/Rare/utils/Dialogs/Login/BrowserLogin.py @@ -0,0 +1,52 @@ +import json +import webbrowser +from logging import getLogger + +from PyQt5.QtCore import pyqtSignal +from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLabel, QLineEdit +from legendary.core import LegendaryCore + +logger = getLogger("BrowserLogin") +class BrowserLogin(QWidget): + + success = pyqtSignal() + url: str = "https://www.epicgames.com/id/login?redirectUrl=https%3A%2F%2Fwww.epicgames.com%2Fid%2Fapi%2Fredirect" + def __init__(self, core: LegendaryCore): + super(BrowserLogin, self).__init__() + self.layout = QVBoxLayout() + self.core = core + + self.back = QPushButton("Back") # TODO Icon + self.back.clicked.connect(lambda: self.success.emit("back")) + self.layout.addWidget(self.back) + + self.info_text = QLabel(f"Opens a browser. You login and copy the json code in the field below. Click here to open Browser") + self.info_text.setWordWrap(True) + self.info_text.setOpenExternalLinks(True) + self.layout.addWidget(self.info_text) + + self.input_field = QLineEdit() + self.input_field.setPlaceholderText("Insert SID here") + self.layout.addWidget(self.input_field) + + self.mini_info = QLabel("") + + self.login_btn = QPushButton("Login") + self.login_btn.clicked.connect(self.login) + self.layout.addWidget(self.login_btn) + + self.setLayout(self.layout) + + + def login(self): + self.mini_info.setText("Loading...") + sid = self.input_field.text() + # when the text copied + if sid.startswith("{") and sid.endswith("}"): + sid = json.loads(sid)["sid"] + token = self.core.auth_sid(sid) + if self.core.auth_code(token): + logger.info(f"Successfully logged in as {self.core.lgd.userdata['displayName']}") + self.success.emit() + else: + self.mini_info.setText("Login failed") \ No newline at end of file diff --git a/Rare/utils/Dialogs/Login/ImportWidget.py b/Rare/utils/Dialogs/Login/ImportWidget.py new file mode 100644 index 00000000..86f4719b --- /dev/null +++ b/Rare/utils/Dialogs/Login/ImportWidget.py @@ -0,0 +1,6 @@ +from PyQt5.QtWidgets import QWidget + + +class ImportWidget(QWidget): + def __init__(self): + super(ImportWidget, self).__init__() \ No newline at end of file diff --git a/Rare/utils/Dialogs/Login/LoginDialog.py b/Rare/utils/Dialogs/Login/LoginDialog.py new file mode 100644 index 00000000..98eb3b60 --- /dev/null +++ b/Rare/utils/Dialogs/Login/LoginDialog.py @@ -0,0 +1,93 @@ +import time + +from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel, QStackedLayout, QWidget, QPushButton +from legendary.core import LegendaryCore + +from Rare.utils.Dialogs.Login.BrowserLogin import BrowserLogin +from Rare.utils.Dialogs.Login.ImportWidget import ImportWidget + + +# Login Opportunities: Browser, Import + + +class LoginDialog(QDialog): + logged_in: bool = False + + def __init__(self, core: LegendaryCore): + super(LoginDialog, self).__init__() + + self.core = core + self.setWindowTitle("Rare - Login") + self.setGeometry(0, 0, 400, 600) + self.init_ui() + + def init_ui(self): + self.layout = QStackedLayout() + + self.landing_widget = QWidget() + self.landing_layout = QVBoxLayout() + + self.title = QLabel(f"

{self.tr('Welcome to Rare')}

") + self.landing_layout.addWidget(self.title) + self.info_text = QLabel(self.tr("Select one option to Login")) + self.landing_layout.addWidget(self.info_text) + + self.browser_login = OptionWidget("Use Browser", "This opens your default webbrowser. Login and copy the text") + self.landing_layout.addWidget(self.browser_login) + self.browser_login.button.clicked.connect(lambda: self.layout.setCurrentIndex(1)) + + self.import_login = OptionWidget("Import from existing installation", + "Import an existing login session from an Epic Games Launcher installation. You will get logged out there") + self.import_login.button.clicked.connect(lambda: self.layout.setCurrentIndex(2)) + self.landing_layout.addWidget(self.import_login) + + self.close_button = QPushButton("Exit App") + self.close_button.clicked.connect(self.close) + self.landing_layout.addWidget(self.close_button) + + self.landing_widget.setLayout(self.landing_layout) + self.layout.addWidget(self.landing_widget) + + self.browser_widget = BrowserLogin(self.core) + self.browser_widget.success.connect(lambda: self.layout.setCurrentIndex(0)) + self.browser_widget.success.connect(self.success) + self.layout.addWidget(self.browser_widget) + + self.import_widget = ImportWidget() + self.layout.addWidget(self.import_widget) + + self.layout.addWidget(LoginSuccessfulWidget()) + + self.setLayout(self.layout) + + def login(self): + self.exec_() + return self.logged_in + + def success(self): + if self.core.login(): + self.logged_in = True + self.layout.setCurrentIndex(3) + time.sleep(1) + self.close() + + +class OptionWidget(QWidget): + def __init__(self, btn_text: str, info_text: str): + super(OptionWidget, self).__init__() + self.layout = QVBoxLayout() + self.text = QLabel(info_text) + self.text.setWordWrap(True) + self.button = QPushButton(btn_text) + + self.layout.addWidget(self.button) + self.layout.addWidget(self.text) + + self.setLayout(self.layout) + +class LoginSuccessfulWidget(QWidget): + def __init__(self): + super(LoginSuccessfulWidget, self).__init__() + self.layout = QVBoxLayout() + self.layout.addWidget(QLabel("Login Successful")) + self.setLayout(self.layout) \ No newline at end of file diff --git a/Rare/utils/Dialogs/Login/__init__.py b/Rare/utils/Dialogs/Login/__init__.py new file mode 100644 index 00000000..e69de29b