Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 15 additions & 9 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,41 +8,47 @@ assignees: ''
---

**Describe the bug**

<!---
A clear and concise description of what the bug is.
-->

**To Reproduce**

**Steps to Reproduce**
<!---
Steps to reproduce the behavior:
-->
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error

**Expected behavior**

<!---
A clear and concise description of what you expected to happen.
-->

**Screenshots**

<!---
If applicable, add screenshots to help explain your problem.
-->

**System information**

<!---
Please complete the following information
-->
- Operating system: [e.g. Manjaro/Windows 10]
- Version: [e.g. 1.6.2]
- Installation method: [e.g. pip/msi/AppImage]
- Python version: (if installed through `pip` or your package manager)

**Additional context**

<!---
Add any other context about the problem here.
-->

**Error message**

<!---
You can find logs in these locations

-->
| OS | Path |
|---------|----------------------------------------------------------|
| Windows | `C:\Users\<username>\AppData\Local\Rare\Rare\cache\logs` |
Expand Down
12 changes: 8 additions & 4 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@ assignees: ''
---

**Is your feature request related to a problem? Please describe.**

<!---
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
-->

**Describe the solution you'd like**

<!---
A clear and concise description of what you want to happen.
-->

**Describe alternatives you've considered**

<!---
A clear and concise description of any alternative solutions or features you've considered.
-->

**Additional context**

<!---
Add any other context or screenshots about the feature request here.
-->
2 changes: 1 addition & 1 deletion rare/commands/launcher/console_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ class ConsoleEdit(QPlainTextEdit):
def __init__(self, parent=None):
super(ConsoleEdit, self).__init__(parent=parent)
self.setReadOnly(True)
font = QFont("Monospace")
font = self.font()
font.setStyleHint(QFont.StyleHint.Monospace)
self.setFont(font)

Expand Down
55 changes: 31 additions & 24 deletions rare/components/dialogs/login/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,40 +45,44 @@ def __init__(self, args: Namespace, core: LegendaryCore, parent=None):
self.core = core

self.login_stack = SlidingStackedWidget(parent=self)
self.login_stack.setMinimumWidth(480)
self.ui.login_stack_layout.addWidget(self.login_stack)
self.ui.main_layout.insertWidget(3, self.login_stack, stretch=1)

self.landing_page = LandingPage(self.login_stack)
self.login_stack.insertWidget(0, self.landing_page)
self.landing_index = self.login_stack.insertWidget(0, self.landing_page)

self.browser_page = BrowserLogin(self.core, self.login_stack)
self.login_stack.insertWidget(1, self.browser_page)
self.browser_index = self.login_stack.insertWidget(1, self.browser_page)
self.browser_page.success.connect(self.login_successful)
self.browser_page.isValid.connect(lambda x: self.ui.next_button.setEnabled(x))
self.import_page = ImportLogin(self.core, self.login_stack)
self.login_stack.insertWidget(2, self.import_page)
self.import_index = self.login_stack.insertWidget(2, self.import_page)
self.import_page.success.connect(self.login_successful)
self.import_page.isValid.connect(lambda x: self.ui.next_button.setEnabled(x))

# # NOTE: The real problem is that the BrowserLogin page has a huge QLabel with word-wrapping enabled.
# # That forces the whole form to vertically expand instead of horizontally. Since the form is not shown
# # on the first page, the internal Qt calculation for the size of that form calculates it by expanding it
# # vertically. Once the form becomes visible, the correct calculation takes place and that is why the
# # dialog reduces in height. To avoid that, calculate the bounding size of all forms and set it as the
# # minumum size
# self.login_stack.setMinimumSize(
# self.landing_page.sizeHint().expandedTo(
# self.browser_page.sizeHint().expandedTo(self.import_page.sizeHint())
# )
# )

self.login_stack.setFixedHeight(
max(
self.landing_page.heightForWidth(self.login_stack.minimumWidth()),
self.browser_page.heightForWidth(self.login_stack.minimumWidth()),
self.import_page.heightForWidth(self.login_stack.minimumWidth()),
)
)
self.info_message = {
self.landing_index: self.tr(
"<i>Select log-in method.</i>"
),
self.browser_index: self.tr(
"<i>Click the <strong>Open Browser</strong> button to open the "
"login page in your web browser or copy the link and paste it "
"in any web browser. After logging in using the browser, copy "
"the text in the quotes after </i><code><b>authorizationCode</b></code><i> "
"in the same line into the empty input above."
"<br><br><strong>DO NOT SHARE THE INFORMATION IN THE BROWSER PAGE WITH "
"ANYONE IN ANY FORM (TEXT OR SCREENSHOT)!</strong></i>"
),
self.import_index: self.tr(
"<i>Select the Wine prefix where Epic Games Launcher is installed. "
"You will get logged out from EGL in the process.</i>"
),
}
self.ui.info_label.setText(self.info_message[self.landing_index])

self.login_stack.setMinimumWidth(640)
self.login_stack.setMinimumHeight(180)
self.ui.info_label.setMinimumWidth(640)
self.ui.info_label.setMinimumHeight(40)

self.ui.next_button.setEnabled(False)
self.ui.back_button.setEnabled(False)
Expand Down Expand Up @@ -108,19 +112,22 @@ def __init__(self, args: Namespace, core: LegendaryCore, parent=None):
@Slot()
def browser_radio_clicked(self):
self.login_stack.slideInWidget(self.browser_page)
self.ui.info_label.setText(self.info_message[self.browser_index])
self.ui.back_button.setEnabled(True)
self.ui.next_button.setEnabled(False)

@Slot()
def import_radio_clicked(self):
self.login_stack.slideInWidget(self.import_page)
self.ui.info_label.setText(self.info_message[self.import_index])
self.ui.back_button.setEnabled(True)
self.ui.next_button.setEnabled(self.import_page.is_valid())

@Slot()
def back_clicked(self):
self.ui.back_button.setEnabled(False)
self.ui.next_button.setEnabled(True)
self.ui.info_label.setText(self.info_message[self.landing_index])
self.login_stack.slideInWidget(self.landing_page)

@Slot()
Expand Down
41 changes: 25 additions & 16 deletions rare/components/dialogs/login/browser_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from PySide6.QtWidgets import QApplication, QFormLayout, QFrame, QLineEdit

from rare.lgndr.core import LegendaryCore
from rare.lgndr.glue.exception import LgndrException
from rare.ui.components.dialogs.login.browser_login import Ui_BrowserLogin
from rare.utils.misc import qta_icon
from rare.utils.paths import get_rare_executable
Expand All @@ -29,28 +30,30 @@ def __init__(self, core: LegendaryCore, parent=None):
self.core = core
self.login_url = self.core.egs.get_auth_url()

self.sid_edit = IndicatorLineEdit(
self.auth_edit = IndicatorLineEdit(
placeholder=self.tr("Insert authorizationCode here"), edit_func=self.sid_edit_callback, parent=self
)
self.sid_edit.line_edit.setEchoMode(QLineEdit.EchoMode.Password)
self.auth_edit.line_edit.setEchoMode(QLineEdit.EchoMode.Password)
self.ui.link_text.setText(self.login_url)
self.ui.copy_button.setIcon(qta_icon("mdi.content-copy", "fa5.copy"))
self.ui.copy_button.clicked.connect(self.copy_link)
self.ui.form_layout.setWidget(
self.ui.form_layout.getWidgetPosition(self.ui.sid_label)[0], QFormLayout.ItemRole.FieldRole, self.sid_edit
self.ui.form_layout.getWidgetPosition(self.ui.sid_label)[0],
QFormLayout.ItemRole.FieldRole,
self.auth_edit
)

self.ui.open_button.clicked.connect(self.open_browser)
self.sid_edit.textChanged.connect(lambda _: self.isValid.emit(self.is_valid()))
self.auth_edit.textChanged.connect(lambda _: self.isValid.emit(self.is_valid()))

@Slot()
def copy_link(self):
clipboard = QApplication.instance().clipboard()
clipboard.setText(self.login_url)
self.ui.status_label.setText(self.tr("Copied to clipboard"))
self.ui.status_field.setText(self.tr("Copied to clipboard"))

def is_valid(self):
return self.sid_edit.is_valid
return self.auth_edit.is_valid

@staticmethod
def sid_edit_callback(text) -> Tuple[bool, str, int]:
Expand All @@ -68,17 +71,17 @@ def sid_edit_callback(text) -> Tuple[bool, str, int]:
return False, text, IndicatorReasonsCommon.VALID

def do_login(self):
self.ui.status_label.setText(self.tr("Logging in..."))
auth_code = self.sid_edit.text()
self.ui.status_field.setText(self.tr("Logging in..."))
auth_code = self.auth_edit.text()
try:
if self.core.auth_code(auth_code):
self.logger.info("Successfully logged in as %s", self.core.lgd.userdata["displayName"])
self.success.emit()
else:
self.ui.status_label.setText(self.tr("Login failed."))
self.logger.warning("Failed to login through browser")
except Exception as e:
self.logger.warning(e)
msg = e.message if isinstance(e, LgndrException) else str(e)
self.ui.status_field.setText(self.tr("Login failed: {}").format(msg))
self.logger.error("Failed to login through browser")
self.logger.error(e)

@Slot()
def open_browser(self):
Expand All @@ -97,8 +100,14 @@ def open_browser(self):
proc.deleteLater()

if out:
self.core.auth_ex_token(out)
self.logger.info("Successfully logged in as %s", {self.core.lgd.userdata["displayName"]})
self.success.emit()
try:
self.core.auth_ex_token(out)
self.logger.info("Successfully logged in as %s", {self.core.lgd.userdata["displayName"]})
self.success.emit()
except Exception as e:
msg = e.message if isinstance(e, LgndrException) else str(e)
self.ui.status_field.setText(self.tr("Login failed: {}").format(msg))
self.logger.error("Failed to login through browser")
self.logger.error(e)
else:
self.logger.warning("Failed to login through browser.")
self.logger.error("Failed to login through browser")
22 changes: 11 additions & 11 deletions rare/components/dialogs/login/import_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from PySide6.QtWidgets import QFileDialog, QFrame

from rare.lgndr.core import LegendaryCore
from rare.lgndr.glue.exception import LgndrException
from rare.ui.components.dialogs.login.import_login import Ui_ImportLogin


Expand Down Expand Up @@ -40,9 +41,9 @@ def __init__(self, core: LegendaryCore, parent=None):
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)
self.ui.status_field.setText(self.text_egl_notfound)
else:
self.ui.status_label.setText(self.text_egl_found)
self.ui.status_field.setText(self.text_egl_found)
self.found = True
self.ui.prefix_combo.setCurrentText(self.egl_appdata)
else:
Expand All @@ -52,9 +53,9 @@ def __init__(self, core: LegendaryCore, parent=None):
prefixes = self.get_wine_prefixes()
if len(prefixes):
self.ui.prefix_combo.addItems(prefixes)
self.ui.status_label.setText(self.tr("Select the Wine prefix you want to import."))
self.ui.status_field.setText(self.tr("Select the Wine prefix you want to import."))
else:
self.ui.status_label.setText(self.text_egl_notfound)
self.ui.status_field.setText(self.text_egl_notfound)

self.ui.prefix_button.clicked.connect(self.prefix_path)
self.ui.prefix_combo.editTextChanged.connect(lambda _: self.isValid.emit(self.is_valid()))
Expand Down Expand Up @@ -90,23 +91,22 @@ def is_valid(self) -> bool:
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)
self.ui.status_field.setText(self.text_egl_found)
return path_exists
except KeyError:
return False

def do_login(self):
self.ui.status_label.setText(self.tr("Loading..."))
self.ui.status_field.setText(self.tr("Loading..."))
if os.name != "nt":
self.logger.info("Using EGL appdata path at %s", {self.egl_appdata})
self.core.egl.appdata_path = self.egl_appdata
try:
if self.core.auth_import():
self.logger.info("Logged in as %s", {self.core.lgd.userdata["displayName"]})
self.success.emit()
else:
self.ui.status_label.setText(self.tr("Login failed."))
self.logger.warning("Failed to import existing session.")
except Exception as e:
self.ui.status_label.setText(self.tr("Login failed. {}").format(str(e)))
self.logger.warning("Failed to import existing session: %s", e)
msg = e.message if isinstance(e, LgndrException) else str(e)
self.ui.status_field.setText(self.tr("Login failed: {}").format(msg))
self.logger.warning("Failed to import existing session")
self.logger.error(e)
4 changes: 2 additions & 2 deletions rare/components/dialogs/move.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Optional, Tuple, Union

from PySide6.QtCore import QSignalBlocker, QThreadPool, Signal, Slot
from PySide6.QtGui import QShowEvent, Qt
from PySide6.QtGui import QFont, QShowEvent, Qt
from PySide6.QtWidgets import QFileDialog, QFormLayout, QLabel, QWidget

from rare.models.game import RareGame
Expand Down Expand Up @@ -62,7 +62,7 @@ def __init__(self, rcore: RareCore, rgame: RareGame, parent=None):

self.full_path_info = ElideLabel(parent=self)
font = self.font()
font.setItalic(True)
font.setStyleHint(QFont.StyleHint.Monospace)
self.full_path_info.setFont(font)
self.ui.main_layout.setWidget(
self.ui.main_layout.getWidgetPosition(self.ui.full_path_label)[0],
Expand Down
33 changes: 33 additions & 0 deletions rare/lgndr/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,39 @@ def default_platform(self) -> str:
usr_platform = self.lgd.config.get("Legendary", "default_platform", fallback=os_default)
return usr_platform if usr_platform in ("Windows", "Win32", "Mac") else os_default

def auth_code(self, code) -> bool:
handler = LgndrLogHandler(logging.ERROR)
self.log.addHandler(handler)
try:
ret = super().auth_code(code)
except LgndrException as ret:
raise ret
finally:
self.log.removeHandler(handler)
return ret

def auth_ex_token(self, code) -> bool:
handler = LgndrLogHandler(logging.ERROR)
self.log.addHandler(handler)
try:
ret = super().auth_ex_token(code)
except LgndrException as ret:
raise ret
finally:
self.log.removeHandler(handler)
return ret

def auth_import(self) -> bool:
handler = LgndrLogHandler(logging.ERROR)
self.log.addHandler(handler)
try:
ret = super().auth_import()
except LgndrException as ret:
raise ret
finally:
self.log.removeHandler(handler)
return ret

def update_check_enabled(self):
return True

Expand Down
Loading