From c1bf278fd77d05425d99284d46728c2afeffb95b Mon Sep 17 00:00:00 2001 From: Robert Honz Date: Thu, 1 Feb 2024 07:38:01 +0100 Subject: ✨ Implemented login dialog for PKCE login method. Fixes #22. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tidal_dl_ng/ui/dialog_login.py | 110 ++++++++++++++++++++++ tidal_dl_ng/ui/dialog_login.ui | 194 +++++++++++++++++++++++++++++++++++++++ tidal_dl_ng/ui/dummy_register.py | 33 +++++++ tidal_dl_ng/ui/dummy_wiggly.py | 68 ++++++++++++++ 4 files changed, 405 insertions(+) create mode 100644 tidal_dl_ng/ui/dialog_login.py create mode 100644 tidal_dl_ng/ui/dialog_login.ui create mode 100644 tidal_dl_ng/ui/dummy_register.py create mode 100644 tidal_dl_ng/ui/dummy_wiggly.py (limited to 'tidal_dl_ng/ui') diff --git a/tidal_dl_ng/ui/dialog_login.py b/tidal_dl_ng/ui/dialog_login.py new file mode 100644 index 0000000..ffb8e76 --- /dev/null +++ b/tidal_dl_ng/ui/dialog_login.py @@ -0,0 +1,110 @@ +################################################################################ +## Form generated from reading UI file 'dialog_login.ui' +## +## Created by: Qt User Interface Compiler version 6.6.1 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import QCoreApplication, QMetaObject, QRect, QSize, Qt +from PySide6.QtGui import QFont +from PySide6.QtWidgets import QDialogButtonBox, QLabel, QSizePolicy, QTextEdit, QVBoxLayout, QWidget + + +class Ui_DialogLogin: + def setupUi(self, DialogLogin): + if not DialogLogin.objectName(): + DialogLogin.setObjectName("DialogLogin") + DialogLogin.resize(451, 400) + sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(DialogLogin.sizePolicy().hasHeightForWidth()) + DialogLogin.setSizePolicy(sizePolicy) + self.bb_dialog = QDialogButtonBox(DialogLogin) + self.bb_dialog.setObjectName("bb_dialog") + self.bb_dialog.setGeometry(QRect(20, 350, 411, 32)) + sizePolicy.setHeightForWidth(self.bb_dialog.sizePolicy().hasHeightForWidth()) + self.bb_dialog.setSizePolicy(sizePolicy) + self.bb_dialog.setStyleSheet("") + self.bb_dialog.setOrientation(Qt.Horizontal) + self.bb_dialog.setStandardButtons(QDialogButtonBox.Cancel | QDialogButtonBox.Ok) + self.verticalLayoutWidget = QWidget(DialogLogin) + self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") + self.verticalLayoutWidget.setGeometry(QRect(20, 20, 411, 321)) + self.lv_main = QVBoxLayout(self.verticalLayoutWidget) + self.lv_main.setObjectName("lv_main") + self.lv_main.setContentsMargins(0, 0, 0, 0) + self.l_header = QLabel(self.verticalLayoutWidget) + self.l_header.setObjectName("l_header") + sizePolicy.setHeightForWidth(self.l_header.sizePolicy().hasHeightForWidth()) + self.l_header.setSizePolicy(sizePolicy) + font = QFont() + font.setPointSize(23) + font.setBold(True) + self.l_header.setFont(font) + + self.lv_main.addWidget(self.l_header) + + self.l_description = QLabel(self.verticalLayoutWidget) + self.l_description.setObjectName("l_description") + sizePolicy.setHeightForWidth(self.l_description.sizePolicy().hasHeightForWidth()) + self.l_description.setSizePolicy(sizePolicy) + font1 = QFont() + font1.setItalic(True) + self.l_description.setFont(font1) + self.l_description.setWordWrap(True) + + self.lv_main.addWidget(self.l_description) + + self.l_url_login = QLabel(self.verticalLayoutWidget) + self.l_url_login.setObjectName("l_url_login") + sizePolicy.setHeightForWidth(self.l_url_login.sizePolicy().hasHeightForWidth()) + self.l_url_login.setSizePolicy(sizePolicy) + self.l_url_login.setMinimumSize(QSize(0, 50)) + self.l_url_login.setBaseSize(QSize(0, 0)) + self.l_url_login.setStyleSheet("border: 2px solid red; padding: 6px") + self.l_url_login.setWordWrap(True) + self.l_url_login.setOpenExternalLinks(True) + + self.lv_main.addWidget(self.l_url_login) + + self.te_url_redirect = QTextEdit(self.verticalLayoutWidget) + self.te_url_redirect.setObjectName("te_url_redirect") + + self.lv_main.addWidget(self.te_url_redirect) + + self.l_hint = QLabel(self.verticalLayoutWidget) + self.l_hint.setObjectName("l_hint") + sizePolicy.setHeightForWidth(self.l_hint.sizePolicy().hasHeightForWidth()) + self.l_hint.setSizePolicy(sizePolicy) + self.l_hint.setFont(font1) + + self.lv_main.addWidget(self.l_hint) + + self.retranslateUi(DialogLogin) + self.bb_dialog.accepted.connect(DialogLogin.accept) + self.bb_dialog.rejected.connect(DialogLogin.reject) + + QMetaObject.connectSlotsByName(DialogLogin) + + # setupUi + + def retranslateUi(self, DialogLogin): + DialogLogin.setWindowTitle(QCoreApplication.translate("DialogLogin", "Dialog", None)) + self.l_header.setText(QCoreApplication.translate("DialogLogin", "TIDAL PKCE Login", None)) + self.l_description.setText( + QCoreApplication.translate( + "DialogLogin", + 'Click the link below and login with your TIDAL credentials. You will be redirected to an "Ooops" page' + ' after a successful login. Copy the URL of this "Ooops" page and post it in the box below.', + None, + ) + ) + self.l_url_login.setText(QCoreApplication.translate("DialogLogin", "PLACEHOLDER URL...", None)) + self.te_url_redirect.setPlaceholderText( + QCoreApplication.translate("DialogLogin", "Copy and paste the redirect URL after login here...", None) + ) + self.l_hint.setText(QCoreApplication.translate("DialogLogin", "Waiting...", None)) + + # retranslateUi diff --git a/tidal_dl_ng/ui/dialog_login.ui b/tidal_dl_ng/ui/dialog_login.ui new file mode 100644 index 0000000..ae0a25a --- /dev/null +++ b/tidal_dl_ng/ui/dialog_login.ui @@ -0,0 +1,194 @@ + + + DialogLogin + + + + 0 + 0 + 451 + 400 + + + + + 0 + 0 + + + + Dialog + + + + + 20 + 350 + 411 + 32 + + + + + 0 + 0 + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + 20 + 20 + 411 + 321 + + + + + + + + 0 + 0 + + + + + 23 + true + + + + TIDAL PKCE Login + + + + + + + + 0 + 0 + + + + + true + + + + Click the link below and login with your TIDAL credentials. You will be redirected to an "Ooops" page after a successful login. Copy the URL of this "Ooops" page and post it in the box below. + + + true + + + + + + + + 0 + 0 + + + + + 0 + 50 + + + + + 0 + 0 + + + + border: 2px solid red; padding: 6px + + + PLACEHOLDER URL... + + + true + + + true + + + + + + + Copy and paste the redirect URL after login here... + + + + + + + + 0 + 0 + + + + + true + + + + Waiting... + + + + + + + + + + bb_dialog + accepted() + DialogLogin + accept() + + + 248 + 254 + + + 157 + 274 + + + + + bb_dialog + rejected() + DialogLogin + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/tidal_dl_ng/ui/dummy_register.py b/tidal_dl_ng/ui/dummy_register.py new file mode 100644 index 0000000..dfffdc2 --- /dev/null +++ b/tidal_dl_ng/ui/dummy_register.py @@ -0,0 +1,33 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection + +from .dummy_wiggly import WigglyWidget + +# Set PYSIDE_DESIGNER_PLUGINS to point to this directory and load the plugin + + +TOOLTIP = "A cool wiggly widget (Python)" +DOM_XML = """ + + + + + 0 + 0 + 400 + 200 + + + + Hello, world + + + +""" + +if __name__ == "__main__": + QPyDesignerCustomWidgetCollection.registerCustomWidget( + WigglyWidget, module="wigglywidget", tool_tip=TOOLTIP, xml=DOM_XML + ) diff --git a/tidal_dl_ng/ui/dummy_wiggly.py b/tidal_dl_ng/ui/dummy_wiggly.py new file mode 100644 index 0000000..e6eb3d3 --- /dev/null +++ b/tidal_dl_ng/ui/dummy_wiggly.py @@ -0,0 +1,68 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +from PySide6.QtCore import Property, QBasicTimer +from PySide6.QtGui import QColor, QFontMetrics, QPainter, QPalette +from PySide6.QtWidgets import QWidget + + +class WigglyWidget(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self._step = 0 + self._text = "" + self.setBackgroundRole(QPalette.Midlight) + self.setAutoFillBackground(True) + + new_font = self.font() + new_font.setPointSize(new_font.pointSize() + 20) + self.setFont(new_font) + self._timer = QBasicTimer() + + def isRunning(self): + return self._timer.isActive() + + def setRunning(self, r): + if r == self.isRunning(): + return + if r: + self._timer.start(60, self) + else: + self._timer.stop() + + def paintEvent(self, event): + if not self._text: + return + + sineTable = [0, 38, 71, 92, 100, 92, 71, 38, 0, -38, -71, -92, -100, -92, -71, -38] + + metrics = QFontMetrics(self.font()) + x = (self.width() - metrics.horizontalAdvance(self.text)) / 2 + y = (self.height() + metrics.ascent() - metrics.descent()) / 2 + color = QColor() + + with QPainter(self) as painter: + for i in range(len(self.text)): + index = (self._step + i) % 16 + color.setHsv((15 - index) * 16, 255, 191) + painter.setPen(color) + dy = (sineTable[index] * metrics.height()) / 400 + c = self._text[i] + painter.drawText(x, y - dy, str(c)) + x += metrics.horizontalAdvance(c) + + def timerEvent(self, event): + if event.timerId() == self._timer.timerId(): + self._step += 1 + self.update() + else: + QWidget.timerEvent(event) + + def text(self): + return self._text + + def setText(self, text): + self._text = text + + running = Property(bool, isRunning, setRunning) + text = Property(str, text, setText) -- cgit v1.3.1