From 2088053d26fc124058fafb434d41b7c9516f0da0 Mon Sep 17 00:00:00 2001 From: Nicolas Werner Date: Fri, 13 Mar 2020 21:05:18 +0100 Subject: [PATCH] Add DeviceVerificationFlow dummy and verification test button --- CMakeLists.txt | 2 + resources/qml/TimelineView.qml | 19 +++++ .../DeviceVerification.qml | 77 ++++++++++++++----- .../DeviceVerificationTest.qml | 13 ---- resources/res.qrc | 1 + src/DeviceVerificationFlow.cpp | 36 +++++++++ src/DeviceVerificationFlow.h | 38 +++++++++ src/timeline/TimelineViewManager.cpp | 7 ++ src/timeline/TimelineViewManager.h | 3 + 9 files changed, 163 insertions(+), 33 deletions(-) delete mode 100644 resources/qml/device-verification/DeviceVerificationTest.qml create mode 100644 src/DeviceVerificationFlow.cpp create mode 100644 src/DeviceVerificationFlow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 69261046..69a46bde 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -284,6 +284,7 @@ set(SRC_FILES src/ColorImageProvider.cpp src/CommunitiesList.cpp src/CommunitiesListItem.cpp + src/DeviceVerificationFlow.cpp src/EventAccessors.cpp src/InviteeItem.cpp src/Logging.cpp @@ -488,6 +489,7 @@ qt5_wrap_cpp(MOC_HEADERS src/ChatPage.h src/CommunitiesList.h src/CommunitiesListItem.h + src/DeviceVerificationFlow.h src/InviteeItem.h src/LoginPage.h src/MainWindow.h diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 8a5612d2..dd35473c 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -9,6 +9,7 @@ import im.nheko.EmojiModel 1.0 import "./delegates" import "./emoji" +import "./device-verification" Page { id: timelineRoot @@ -98,6 +99,24 @@ Page { anchors.fill: parent color: colors.window + Component { + id: deviceVerificationDialog + DeviceVerification {} + } + Connections { + target: timelineManager + onDeviceVerificationRequest: { + var dialog = deviceVerificationDialog.createObject(timelineRoot, {flow: deviceVerificationFlow}); + dialog.show(); + } + } + + Button { + text: "test device verification" + onClicked: timelineManager.startDummyVerification() + z: 5 + } + Label { visible: !timelineManager.timeline && !timelineManager.isInitialSync anchors.centerIn: parent diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml index c32e3414..d8752316 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml @@ -3,12 +3,15 @@ import QtQuick.Controls 2.10 import QtQuick.Window 2.2 import QtQuick.Layouts 1.10 -Window { +import im.nheko 1.0 + +ApplicationWindow { title: stack.currentItem.title id: dialog flags: Qt.Dialog + palette: colors height: stack.implicitHeight width: stack.implicitWidth @@ -21,6 +24,19 @@ Window { onClosing: stack.replace(newVerificationRequest) + property var flow + Connections { + target: flow + onVerificationCanceled: stack.replace(partnerAborted) + onTimedout: stack.replace(timedout) + onDeviceVerified: stack.replace(verificationSuccess) + + onVerificationRequestAccepted: switch(method) { + case DeviceVerificationFlow.Decimal: stack.replace(digitVerification); break; + case DeviceVerificationFlow.Emoji: stack.replace(emojiVerification); break; + } + } + Component { id: newVerificationRequest Pane { @@ -51,7 +67,7 @@ Window { Button { Layout.alignment: Qt.AlignLeft text: "Cancel" - onClicked: dialog.close() + onClicked: { dialog.close(); flow.cancelVerification(); } } Item { Layout.fillWidth: true @@ -59,7 +75,7 @@ Window { Button { Layout.alignment: Qt.AlignRight text: "Start verification" - onClicked: stack.replace(awaitingVerificationRequestAccept) + onClicked: { stack.replace(awaitingVerificationRequestAccept); flow.acceptVerificationRequest(); } } } } @@ -90,17 +106,12 @@ Window { Button { Layout.alignment: Qt.AlignLeft text: "Cancel" - onClicked: dialog.close() + onClicked: { dialog.close(); flow.cancelVerification(); } } Item { Layout.fillWidth: true } } - Timer { - // temporary, until it is bound to a backend - interval: 5000; running: true; - onTriggered: if (Math.random() > 0.5) stack.replace(emojiVerification); else stack.replace(digitVerification); - } } } } @@ -141,7 +152,7 @@ Window { Button { Layout.alignment: Qt.AlignLeft text: "They do not match!" - onClicked: dialog.close() + onClicked: { dialog.close(); flow.cancelVerification(); } } Item { Layout.fillWidth: true @@ -149,7 +160,7 @@ Window { Button { Layout.alignment: Qt.AlignRight text: "They match." - onClicked: stack.replace(awaitingVerificationConfirmation) + onClicked: { stack.replace(awaitingVerificationConfirmation); flow.acceptDevice(); } } } } @@ -248,7 +259,7 @@ Window { id: repeater model: 7 delegate: Rectangle { - color: "red" + color: "transparent" implicitHeight: Qt.application.font.pixelSize * 8 implicitWidth: col.width ColumnLayout { @@ -274,7 +285,7 @@ Window { Button { Layout.alignment: Qt.AlignLeft text: "They do not match!" - onClicked: dialog.close() + onClicked: { dialog.close(); flow.cancelVerification(); } } Item { Layout.fillWidth: true @@ -282,7 +293,7 @@ Window { Button { Layout.alignment: Qt.AlignRight text: "They match." - onClicked: stack.replace(awaitingVerificationConfirmation) + onClicked: { stack.replace(awaitingVerificationConfirmation); flow.acceptDevice(); } } } } @@ -313,17 +324,12 @@ Window { Button { Layout.alignment: Qt.AlignLeft text: "Cancel" - onClicked: dialog.close() + onClicked: { dialog.close(); flow.cancelVerification(); } } Item { Layout.fillWidth: true } } - Timer { - // temporary, until it is bound to a backend - interval: 5000; running: true; - onTriggered: Math.random() > 0.5 ? stack.replace(verificationSuccess) : stack.replace(partnerAborted) - } } } } @@ -389,4 +395,35 @@ Window { } } } + + Component { + id: timedout + Pane { + property string title: "Verification timed out" + ColumnLayout { + spacing: 16 + Text { + Layout.maximumWidth: 400 + Layout.fillHeight: true + Layout.fillWidth: true + wrapMode: Text.Wrap + id: content + text: "Device verification timed out." + + verticalAlignment: Text.AlignVCenter + } + + RowLayout { + Item { + Layout.fillWidth: true + } + Button { + Layout.alignment: Qt.AlignRight + text: "Close" + onClicked: dialog.close() + } + } + } + } + } } diff --git a/resources/qml/device-verification/DeviceVerificationTest.qml b/resources/qml/device-verification/DeviceVerificationTest.qml deleted file mode 100644 index 6682e7ec..00000000 --- a/resources/qml/device-verification/DeviceVerificationTest.qml +++ /dev/null @@ -1,13 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 - -Item { - DeviceVerification { - id: deviceVerification - } - - Button { - text: "Test DeviceVerification" - onClicked: deviceVerification.show() - } -} diff --git a/resources/res.qrc b/resources/res.qrc index 439ed97b..ec086b3a 100644 --- a/resources/res.qrc +++ b/resources/res.qrc @@ -135,5 +135,6 @@ qml/delegates/Pill.qml qml/delegates/Placeholder.qml qml/delegates/Reply.qml + qml/device-verification/DeviceVerification.qml diff --git a/src/DeviceVerificationFlow.cpp b/src/DeviceVerificationFlow.cpp new file mode 100644 index 00000000..69d6ab9c --- /dev/null +++ b/src/DeviceVerificationFlow.cpp @@ -0,0 +1,36 @@ +#include "DeviceVerificationFlow.h" + +#include + +static constexpr int TIMEOUT = 2 * 60 * 1000; // 2 minutes + +DeviceVerificationFlow::DeviceVerificationFlow(QObject *) +{ + timeout = new QTimer(this); + timeout->setSingleShot(true); + connect(timeout, &QTimer::timeout, this, [this]() { + emit timedout(); + this->deleteLater(); + }); + timeout->start(TIMEOUT); +} + +//! accepts a verification and starts the verification flow +void +DeviceVerificationFlow::acceptVerificationRequest() +{ + emit verificationRequestAccepted(rand() % 2 ? Emoji : Decimal); +} +//! cancels a verification flow +void +DeviceVerificationFlow::cancelVerification() +{ + this->deleteLater(); +} +//! Completes the verification flow +void +DeviceVerificationFlow::acceptDevice() +{ + emit deviceVerified(); + this->deleteLater(); +} diff --git a/src/DeviceVerificationFlow.h b/src/DeviceVerificationFlow.h new file mode 100644 index 00000000..038f1e13 --- /dev/null +++ b/src/DeviceVerificationFlow.h @@ -0,0 +1,38 @@ +#pragma once + +#include + +class QTimer; + +class DeviceVerificationFlow : public QObject +{ + Q_OBJECT + // Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") + +public: + enum Method + { + Decimal, + Emoji + }; + Q_ENUM(Method) + + DeviceVerificationFlow(QObject *parent = nullptr); + +public slots: + //! accepts a verification and starts the verification flow + void acceptVerificationRequest(); + //! cancels a verification flow + void cancelVerification(); + //! Completes the verification flow + void acceptDevice(); + +signals: + void verificationRequestAccepted(Method method); + void deviceVerified(); + void timedout(); + void verificationCanceled(); + +private: + QTimer *timeout = nullptr; +}; diff --git a/src/timeline/TimelineViewManager.cpp b/src/timeline/TimelineViewManager.cpp index 975dd5fb..8447619a 100644 --- a/src/timeline/TimelineViewManager.cpp +++ b/src/timeline/TimelineViewManager.cpp @@ -85,6 +85,7 @@ TimelineViewManager::TimelineViewManager(QSharedPointer userSettin "Can't instantiate enum!"); qmlRegisterType("im.nheko", 1, 0, "DelegateChoice"); qmlRegisterType("im.nheko", 1, 0, "DelegateChooser"); + qmlRegisterType("im.nheko", 1, 0, "DeviceVerificationFlow"); qRegisterMetaType(); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiModel"); qmlRegisterType("im.nheko.EmojiModel", 1, 0, "EmojiProxyModel"); @@ -460,3 +461,9 @@ TimelineViewManager::queueVideoMessage(const QString &roomid, model->sendMessage(video); } + +void +TimelineViewManager::startDummyVerification() +{ + emit deviceVerificationRequest(new DeviceVerificationFlow(this)); +} diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index 63106916..583a9e4c 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -10,6 +10,7 @@ #include #include "Cache.h" +#include "DeviceVerificationFlow.h" #include "Logging.h" #include "TimelineModel.h" #include "Utils.h" @@ -43,6 +44,7 @@ public: Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const; Q_INVOKABLE QColor userColor(QString id, QColor background); + Q_INVOKABLE void startDummyVerification(); Q_INVOKABLE QString userPresence(QString id) const; Q_INVOKABLE QString userStatus(QString id) const; @@ -54,6 +56,7 @@ signals: void initialSyncChanged(bool isInitialSync); void replyingEventChanged(QString replyingEvent); void replyClosed(); + void deviceVerificationRequest(DeviceVerificationFlow *deviceVerificationFlow); public slots: void updateReadReceipts(const QString &room_id, const std::vector &event_ids);