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);