diff --git a/CMakeLists.txt b/CMakeLists.txt
index 50940246..de5df88b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -353,8 +353,6 @@ set(SRC_FILES
# Dialogs
src/dialogs/FallbackAuth.cpp
src/dialogs/FallbackAuth.h
- src/dialogs/ReCaptcha.cpp
- src/dialogs/ReCaptcha.h
# Emoji
src/emoji/Provider.cpp
@@ -485,6 +483,8 @@ set(SRC_FILES
src/PowerlevelsEditModels.h
src/ReadReceiptsModel.cpp
src/ReadReceiptsModel.h
+ src/ReCaptcha.cpp
+ src/ReCaptcha.h
src/RegisterPage.cpp
src/RegisterPage.h
src/RoomDirectoryModel.cpp
@@ -776,6 +776,7 @@ set(QML_SOURCES
resources/qml/dialogs/PowerLevelSpacesApplyDialog.qml
resources/qml/dialogs/RawMessageDialog.qml
resources/qml/dialogs/ReadReceipts.qml
+ resources/qml/dialogs/ReCaptchaDialog.qml
resources/qml/dialogs/RoomDirectory.qml
resources/qml/dialogs/RoomMembers.qml
resources/qml/dialogs/AllowedRoomsSettingsDialog.qml
diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml
index e26b386a..1fd0c610 100644
--- a/resources/qml/Root.qml
+++ b/resources/qml/Root.qml
@@ -360,6 +360,7 @@ Pane {
onAccepted: UIA.continue3pidReceived()
}
+
Connections {
function onConfirm3pidToken() {
uiaConfirmationLinkDialog.open();
@@ -381,6 +382,18 @@ Pane {
function onPrompt3pidToken() {
uiaTokenPrompt.show();
}
+ function onReCaptcha(recaptcha) {
+ var component = Qt.createComponent("qrc:/resources/qml/dialogs/ReCaptchaDialog.qml");
+ if (component.status == Component.Ready) {
+ var dialog = component.createObject(timelineRoot, {
+ "recaptcha": recaptcha
+ });
+ dialog.show();
+ destroyOnClose(dialog);
+ } else {
+ console.error("Failed to create component: " + component.errorString());
+ }
+ }
target: UIA
}
diff --git a/resources/qml/dialogs/ReCaptchaDialog.qml b/resources/qml/dialogs/ReCaptchaDialog.qml
new file mode 100644
index 00000000..0da62cbc
--- /dev/null
+++ b/resources/qml/dialogs/ReCaptchaDialog.qml
@@ -0,0 +1,63 @@
+// SPDX-FileCopyrightText: Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick
+import QtQuick.Controls
+import im.nheko
+
+ApplicationWindow {
+ id: recaptchaRoot
+
+ required property ReCaptcha recaptcha
+
+ function accept() {
+ recaptcha.confirm();
+ recaptchaRoot.close();
+ }
+
+ function reject() {
+ recaptcha.cancel();
+ recaptchaRoot.close();
+ }
+
+ color: palette.window
+ title: recaptcha.context
+ flags: Qt.Tool | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
+ height: msg.implicitHeight + footer.implicitHeight
+ width: Math.max(msg.implicitWidth, footer.implicitWidth)
+
+ Shortcut {
+ sequence: StandardKey.Cancel
+ onActivated: recaptchaRoot.reject()
+ }
+
+ Label {
+ id: msg
+
+ anchors.fill: parent
+ padding: 8
+ text: qsTr("Solve the reCAPTCHA and press the confirm button")
+ }
+
+ footer: DialogButtonBox {
+ onAccepted: recaptchaRoot.accept()
+ onRejected: recaptchaRoot.reject()
+
+ Button {
+ text: qsTr("Open reCAPTCHA")
+ onClicked: recaptcha.openReCaptcha()
+ }
+
+ Button {
+ text: qsTr("Cancel")
+ DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
+ }
+
+ Button {
+ text: qsTr("Confirm")
+ DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
+ }
+ }
+
+}
diff --git a/src/ReCaptcha.cpp b/src/ReCaptcha.cpp
new file mode 100644
index 00000000..ffd202f5
--- /dev/null
+++ b/src/ReCaptcha.cpp
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "ReCaptcha.h"
+
+#include <QDesktopServices>
+#include <QUrl>
+
+#include "MatrixClient.h"
+
+ReCaptcha::ReCaptcha(const QString &session, const QString &context, QObject *parent)
+ : QObject{parent},
+ m_session{session},
+ m_context{context}
+{
+}
+
+void ReCaptcha::openReCaptcha()
+{
+ const auto url = QString("https://%1:%2/_matrix/client/r0/auth/m.login.recaptcha/"
+ "fallback/web?session=%3")
+ .arg(QString::fromStdString(http::client()->server()))
+ .arg(http::client()->port())
+ .arg(m_session);
+
+ QDesktopServices::openUrl(url);
+}
diff --git a/src/ReCaptcha.h b/src/ReCaptcha.h
new file mode 100644
index 00000000..84d65478
--- /dev/null
+++ b/src/ReCaptcha.h
@@ -0,0 +1,32 @@
+// SPDX-FileCopyrightText: Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <QQmlEngine>
+
+class ReCaptcha : public QObject
+{
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+
+ Q_PROPERTY(QString context MEMBER m_context CONSTANT)
+ Q_PROPERTY(QString session MEMBER m_session CONSTANT)
+
+public:
+ ReCaptcha(const QString &session, const QString &context, QObject *parent = nullptr);
+
+ Q_INVOKABLE void openReCaptcha();
+ Q_INVOKABLE void confirm() { emit confirmation(); }
+ Q_INVOKABLE void cancel() { emit cancelled(); }
+
+signals:
+ void confirmation();
+ void cancelled();
+
+private:
+ QString m_session;
+ QString m_context;
+};
diff --git a/src/dialogs/ReCaptcha.cpp b/src/dialogs/ReCaptcha.cpp
deleted file mode 100644
index 2abf7c07..00000000
--- a/src/dialogs/ReCaptcha.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-// SPDX-FileCopyrightText: Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <QDesktopServices>
-#include <QLabel>
-#include <QPushButton>
-#include <QUrl>
-#include <QVBoxLayout>
-
-#include "dialogs/ReCaptcha.h"
-
-#include "Config.h"
-#include "MatrixClient.h"
-
-using namespace dialogs;
-
-ReCaptcha::ReCaptcha(const QString &session, QWidget *parent)
- : QWidget(parent)
-{
- setAutoFillBackground(true);
- setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
- setWindowModality(Qt::WindowModal);
- setAttribute(Qt::WA_DeleteOnClose, true);
-
- auto layout = new QVBoxLayout(this);
- layout->setSpacing(conf::modals::WIDGET_SPACING);
- layout->setContentsMargins(conf::modals::WIDGET_MARGIN,
- conf::modals::WIDGET_MARGIN,
- conf::modals::WIDGET_MARGIN,
- conf::modals::WIDGET_MARGIN);
-
- auto buttonLayout = new QHBoxLayout();
- buttonLayout->setContentsMargins(0, 0, 0, 0);
- buttonLayout->setSpacing(8);
-
- openCaptchaBtn_ = new QPushButton(tr("Open reCAPTCHA"), this);
- cancelBtn_ = new QPushButton(tr("Cancel"), this);
- confirmBtn_ = new QPushButton(tr("Confirm"), this);
- confirmBtn_->setDefault(true);
-
- buttonLayout->addStretch(1);
- buttonLayout->addWidget(openCaptchaBtn_);
- buttonLayout->addWidget(cancelBtn_);
- buttonLayout->addWidget(confirmBtn_);
-
- QFont font;
- font.setPointSizeF(font.pointSizeF() * conf::modals::LABEL_MEDIUM_SIZE_RATIO);
-
- auto label = new QLabel(tr("Solve the reCAPTCHA and press the confirm button"), this);
- label->setFont(font);
-
- layout->addWidget(label);
- layout->addLayout(buttonLayout);
-
- connect(openCaptchaBtn_, &QPushButton::clicked, [session]() {
- const auto url = QString("https://%1:%2/_matrix/client/r0/auth/m.login.recaptcha/"
- "fallback/web?session=%3")
- .arg(QString::fromStdString(http::client()->server()))
- .arg(http::client()->port())
- .arg(session);
-
- QDesktopServices::openUrl(url);
- });
-
- connect(confirmBtn_, &QPushButton::clicked, this, [this]() {
- emit confirmation();
- close();
- });
- connect(cancelBtn_, &QPushButton::clicked, this, [this]() {
- emit cancel();
- close();
- });
-}
diff --git a/src/dialogs/ReCaptcha.h b/src/dialogs/ReCaptcha.h
deleted file mode 100644
index 53c7453e..00000000
--- a/src/dialogs/ReCaptcha.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-FileCopyrightText: Nheko Contributors
-//
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <QWidget>
-
-class QPushButton;
-
-namespace dialogs {
-
-class ReCaptcha final : public QWidget
-{
- Q_OBJECT
-
-public:
- ReCaptcha(const QString &session, QWidget *parent = nullptr);
-
-signals:
- void confirmation();
- void cancel();
-
-private:
- QPushButton *openCaptchaBtn_;
- QPushButton *confirmBtn_;
- QPushButton *cancelBtn_;
-};
-} // dialogs
diff --git a/src/ui/UIA.cpp b/src/ui/UIA.cpp
index 2b6b059a..ba35df9b 100644
--- a/src/ui/UIA.cpp
+++ b/src/ui/UIA.cpp
@@ -14,12 +14,12 @@
#include "Logging.h"
#include "MatrixClient.h"
#include "dialogs/FallbackAuth.h"
-#include "dialogs/ReCaptcha.h"
+#include "ReCaptcha.h"
UIA *
UIA::instance()
{
- static UIA uia;
+ static UIA uia{nullptr};
return &uia;
}
@@ -99,24 +99,16 @@ UIA::genericHandler(QString context)
} else if (current_stage == mtx::user_interactive::auth_types::msisdn) {
emit phoneNumber();
} else if (current_stage == mtx::user_interactive::auth_types::recaptcha) {
- auto captchaDialog =
- new dialogs::ReCaptcha(QString::fromStdString(u.session), nullptr);
- captchaDialog->setWindowTitle(context);
-
- connect(
- captchaDialog, &dialogs::ReCaptcha::confirmation, this, [captchaDialog, h, u]() {
- captchaDialog->close();
- captchaDialog->deleteLater();
- h.next(mtx::user_interactive::Auth{u.session,
- mtx::user_interactive::auth::Fallback{}});
- });
-
- connect(captchaDialog, &dialogs::ReCaptcha::cancel, this, [this]() {
+ auto captcha = new ReCaptcha(QString::fromStdString(u.session), context, nullptr);
+ QQmlEngine::setObjectOwnership(captcha, QQmlEngine::JavaScriptOwnership);
+ connect(captcha, &ReCaptcha::confirmation, this, [h, u]() {
+ h.next(mtx::user_interactive::Auth{u.session,
+ mtx::user_interactive::auth::Fallback{}});
+ });
+ connect(captcha, &ReCaptcha::cancelled, this, [this]() {
emit error(tr("Registration aborted"));
});
-
- QTimer::singleShot(0, this, [captchaDialog]() { captchaDialog->show(); });
-
+ emit reCaptcha(captcha);
} else if (current_stage == mtx::user_interactive::auth_types::dummy) {
h.next(
mtx::user_interactive::Auth{u.session, mtx::user_interactive::auth::Dummy{}});
diff --git a/src/ui/UIA.h b/src/ui/UIA.h
index 414cb804..5b5eb9f4 100644
--- a/src/ui/UIA.h
+++ b/src/ui/UIA.h
@@ -9,6 +9,8 @@
#include <mtxclient/http/client.hpp>
+#include "ReCaptcha.h"
+
class UIA final : public QObject
{
Q_OBJECT
@@ -39,7 +41,7 @@ public:
return instance();
}
- UIA(QObject *parent = nullptr)
+ UIA(QObject *parent)
: QObject(parent)
{
}
@@ -59,6 +61,7 @@ signals:
void password();
void email();
void phoneNumber();
+ void reCaptcha(ReCaptcha *recaptcha);
void confirm3pidToken();
void prompt3pidToken();
|