summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--resources/qml/UserProfile.qml4
-rw-r--r--resources/qml/device-verification/AcceptNewVerificationRequest.qml65
-rw-r--r--resources/qml/device-verification/AwaitingVerificationConfirmation.qml48
-rw-r--r--resources/qml/device-verification/AwaitingVerificationRequest.qml48
-rw-r--r--resources/qml/device-verification/DeviceVerification.qml621
-rw-r--r--resources/qml/device-verification/DigitVerification.qml80
-rw-r--r--resources/qml/device-verification/EmojiElement.qml1
-rw-r--r--resources/qml/device-verification/EmojiVerification.qml160
-rw-r--r--resources/qml/device-verification/NewVerificationRequest.qml71
-rw-r--r--resources/qml/device-verification/PartnerAborted.qml42
-rw-r--r--resources/qml/device-verification/TimedOut.qml44
-rw-r--r--resources/qml/device-verification/VerificationSuccess.qml43
-rw-r--r--resources/res.qrc9
-rw-r--r--src/Cache.cpp38
-rw-r--r--src/ChatPage.cpp11
-rw-r--r--src/emoji/EmojiSearchModel.h1
-rw-r--r--src/timeline/EventStore.cpp148
-rw-r--r--src/timeline/TimelineModel.cpp33
18 files changed, 757 insertions, 710 deletions
diff --git a/resources/qml/UserProfile.qml b/resources/qml/UserProfile.qml
index 9d59184d..1ca9dcc8 100644
--- a/resources/qml/UserProfile.qml
+++ b/resources/qml/UserProfile.qml
@@ -70,8 +70,8 @@ ApplicationWindow{
 			id: verifyUserButton
 			text: "Verify"
 			Layout.alignment: Qt.AlignHCenter
-			enabled: profile.isUserVerified
-			visible: profile.isUserVerified
+			enabled: !profile.isUserVerified
+			visible: !profile.isUserVerified
 
 			onClicked: {
 				var newFlow = profile.createFlow(true);
diff --git a/resources/qml/device-verification/AcceptNewVerificationRequest.qml b/resources/qml/device-verification/AcceptNewVerificationRequest.qml
new file mode 100644
index 00000000..872fabe1
--- /dev/null
+++ b/resources/qml/device-verification/AcceptNewVerificationRequest.qml
@@ -0,0 +1,65 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+import im.nheko 1.0
+
+Pane {
+	property string title: qsTr("Recieving Device Verification Request")
+	Component {
+		id: awaitingVerificationRequestAccept
+		AwaitingVerificationRequest {}
+	}
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			text: qsTr("The device was requested to be verified")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("Deny")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { 
+					flow.cancelVerification(DeviceVerificationFlow.User);
+					deviceVerificationList.remove(tran_id);
+					dialog.destroy();
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("Accept")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { 
+					stack.replace(awaitingVerificationRequestAccept); 
+					isRequest?flow.sendVerificationReady():flow.acceptVerificationRequest(); 
+				}
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/AwaitingVerificationConfirmation.qml b/resources/qml/device-verification/AwaitingVerificationConfirmation.qml
new file mode 100644
index 00000000..e0786343
--- /dev/null
+++ b/resources/qml/device-verification/AwaitingVerificationConfirmation.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+import im.nheko 1.0
+
+Pane {
+	property string title: qsTr("Awaiting Confirmation")
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: qsTr("Waiting for other side to complete verification.")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		BusyIndicator {
+			Layout.alignment: Qt.AlignHCenter
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("Cancel")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { 
+					flow.cancelVerification(DeviceVerificationFlow.User); 
+					deviceVerificationList.remove(tran_id);
+					dialog.destroy();
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/AwaitingVerificationRequest.qml b/resources/qml/device-verification/AwaitingVerificationRequest.qml
new file mode 100644
index 00000000..22a504c2
--- /dev/null
+++ b/resources/qml/device-verification/AwaitingVerificationRequest.qml
@@ -0,0 +1,48 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+import im.nheko 1.0
+
+Pane {
+	property string title: qsTr("Waiting for other party")
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: qsTr("Waiting for other side to accept the verification request.")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		BusyIndicator {
+			Layout.alignment: Qt.AlignHCenter
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("Cancel")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { 
+					flow.cancelVerification(DeviceVerificationFlow.User);
+					deviceVerificationList.remove(tran_id);
+					dialog.destroy();
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index 6e4b4621..e409b0fe 100644
--- a/resources/qml/device-verification/DeviceVerification.qml
+++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -1,11 +1,14 @@
 import QtQuick 2.3
 import QtQuick.Controls 2.10
 import QtQuick.Window 2.2
-import QtQuick.Layouts 1.10
 
 import im.nheko 1.0
 
 ApplicationWindow {
+	property var flow
+	property bool isRequest
+	property var tran_id
+
 	title: stack.currentItem.title
 	id: dialog
 
@@ -15,6 +18,17 @@ ApplicationWindow {
 
 	height: stack.implicitHeight
 	width: stack.implicitWidth
+
+	Component{
+		id: newVerificationRequest
+		NewVerificationRequest {}
+	}
+
+	Component{
+		id: acceptNewVerificationRequest
+		AcceptNewVerificationRequest {}
+	}
+
 	StackView {
 		id: stack
 		initialItem: flow.sender == true?newVerificationRequest:acceptNewVerificationRequest
@@ -22,613 +36,44 @@ ApplicationWindow {
 		implicitHeight: currentItem.implicitHeight
 	}
 
-	property var flow
-	property bool isRequest
-	property var tran_id
-
-	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;
-		}
-
-		onRefreshProfile: {
-			deviceVerificationList.updateProfile(flow.userId);
-		}
-	}
-
 	Component {
-		id: newVerificationRequest
-		Pane {
-			property string title: qsTr("Sending Device Verification Request")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					text: qsTr("A new device was added.")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					text: qsTr("The device may have been added by you signing in from another client or physical device. To ensure that no malicious user can eavesdrop on your encrypted communications, you should verify the new device.")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				RowLayout {
-					Button {
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("Cancel")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { 
-							deviceVerificationList.remove(tran_id);
-							flow.deleteFlow();
-							dialog.destroy();  
-						}
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("Start verification")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { 
-							stack.replace(awaitingVerificationRequestAccept); 
-							isRequest?flow.sendVerificationRequest():flow.startVerificationRequest(); }
-					}
-				}
-			}
-		}
+		id: partnerAborted
+		PartnerAborted {}
 	}
 
 	Component {
-		id: acceptNewVerificationRequest
-		Pane {
-			property string title: qsTr("Recieving Device Verification Request")
-			ColumnLayout {
-				spacing: 16
-
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					text: qsTr("The device was requested to be verified")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-				RowLayout {
-					Button {
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("Deny")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { 
-							flow.cancelVerification(DeviceVerificationFlow.User);
-							deviceVerificationList.remove(tran_id);
-							dialog.destroy();
-						}
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("Accept")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { 
-							stack.replace(awaitingVerificationRequestAccept); 
-							isRequest?flow.sendVerificationReady():flow.acceptVerificationRequest(); 
-						}
-					}
-				}
-			}
-		}
+		id: timedout
+		TimedOut {}
 	}
 
 	Component {
-		id: awaitingVerificationRequestAccept
-		Pane {
-			property string title: qsTr("Waiting for other party")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					id: content
-					text: qsTr("Waiting for other side to accept the verification request.")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				BusyIndicator {
-					Layout.alignment: Qt.AlignHCenter
-				}
-				RowLayout {
-					Button {
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("Cancel")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { 
-							flow.cancelVerification(DeviceVerificationFlow.User);
-							deviceVerificationList.remove(tran_id);
-							dialog.destroy();
-						}
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-				}
-			}
-		}
+		id: verificationSuccess
+		VerificationSuccess {}
 	}
 
 	Component {
 		id: digitVerification
-		Pane {
-			property string title: qsTr("Verification Code")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					text: qsTr("Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				RowLayout {
-					Layout.alignment: Qt.AlignHCenter
-					Label {
-						font.pixelSize: Qt.application.font.pixelSize * 2
-						text: flow.sasList[0]
-						color:colors.text
-					}
-					Label {
-						font.pixelSize: Qt.application.font.pixelSize * 2
-						text: flow.sasList[1]
-						color:colors.text
-					}
-					Label {
-						font.pixelSize: Qt.application.font.pixelSize * 2
-						text: flow.sasList[2]
-						color:colors.text
-					}
-				}
-
-				RowLayout {
-					Button {
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("They do not match!")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: {
-							flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
-							deviceVerificationList.remove(tran_id);
-							dialog.destroy();
-						}
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("They match!")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
-					}
-				}
-			}
-		}
+		DigitVerification {}
 	}
 
 	Component {
 		id: emojiVerification
-		Pane {
-			property string title: qsTr("Verification Code")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					text: qsTr("Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification!")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				RowLayout {
-					Layout.alignment: Qt.AlignHCenter
-
-					id: emojis
-
-					property var mapping: [
-						{"number": 0, "emoji": "🐶", "description": "Dog", "unicode": "U+1F436"},
-						{"number": 1, "emoji": "🐱", "description": "Cat", "unicode": "U+1F431"},
-						{"number": 2, "emoji": "🦁", "description": "Lion", "unicode": "U+1F981"},
-						{"number": 3, "emoji": "🐎", "description": "Horse", "unicode": "U+1F40E"},
-						{"number": 4, "emoji": "🦄", "description": "Unicorn", "unicode": "U+1F984"},
-						{"number": 5, "emoji": "🐷", "description": "Pig", "unicode": "U+1F437"},
-						{"number": 6, "emoji": "🐘", "description": "Elephant", "unicode": "U+1F418"},
-						{"number": 7, "emoji": "🐰", "description": "Rabbit", "unicode": "U+1F430"},
-						{"number": 8, "emoji": "🐼", "description": "Panda", "unicode": "U+1F43C"},
-						{"number": 9, "emoji": "🐓", "description": "Rooster", "unicode": "U+1F413"},
-						{"number": 10, "emoji": "🐧", "description": "Penguin", "unicode": "U+1F427"},
-						{"number": 11, "emoji": "🐢", "description": "Turtle", "unicode": "U+1F422"},
-						{"number": 12, "emoji": "🐟", "description": "Fish", "unicode": "U+1F41F"},
-						{"number": 13, "emoji": "🐙", "description": "Octopus", "unicode": "U+1F419"},
-						{"number": 14, "emoji": "🦋", "description": "Butterfly", "unicode": "U+1F98B"},
-						{"number": 15, "emoji": "🌷", "description": "Flower", "unicode": "U+1F337"},
-						{"number": 16, "emoji": "🌳", "description": "Tree", "unicode": "U+1F333"},
-						{"number": 17, "emoji": "🌵", "description": "Cactus", "unicode": "U+1F335"},
-						{"number": 18, "emoji": "🍄", "description": "Mushroom", "unicode": "U+1F344"},
-						{"number": 19, "emoji": "🌏", "description": "Globe", "unicode": "U+1F30F"},
-						{"number": 20, "emoji": "🌙", "description": "Moon", "unicode": "U+1F319"},
-						{"number": 21, "emoji": "☁️", "description": "Cloud", "unicode": "U+2601U+FE0F"},
-						{"number": 22, "emoji": "🔥", "description": "Fire", "unicode": "U+1F525"},
-						{"number": 23, "emoji": "🍌", "description": "Banana", "unicode": "U+1F34C"},
-						{"number": 24, "emoji": "🍎", "description": "Apple", "unicode": "U+1F34E"},
-						{"number": 25, "emoji": "🍓", "description": "Strawberry", "unicode": "U+1F353"},
-						{"number": 26, "emoji": "🌽", "description": "Corn", "unicode": "U+1F33D"},
-						{"number": 27, "emoji": "🍕", "description": "Pizza", "unicode": "U+1F355"},
-						{"number": 28, "emoji": "🎂", "description": "Cake", "unicode": "U+1F382"},
-						{"number": 29, "emoji": "❤️", "description": "Heart", "unicode": "U+2764U+FE0F"},
-						{"number": 30, "emoji": "😀", "description": "Smiley", "unicode": "U+1F600"},
-						{"number": 31, "emoji": "🤖", "description": "Robot", "unicode": "U+1F916"},
-						{"number": 32, "emoji": "🎩", "description": "Hat", "unicode": "U+1F3A9"},
-						{"number": 33, "emoji": "👓", "description": "Glasses", "unicode": "U+1F453"},
-						{"number": 34, "emoji": "🔧", "description": "Spanner", "unicode": "U+1F527"},
-						{"number": 35, "emoji": "🎅", "description": "Santa", "unicode": "U+1F385"},
-						{"number": 36, "emoji": "👍", "description": "Thumbs Up", "unicode": "U+1F44D"},
-						{"number": 37, "emoji": "☂️", "description": "Umbrella", "unicode": "U+2602U+FE0F"},
-						{"number": 38, "emoji": "⌛", "description": "Hourglass", "unicode": "U+231B"},
-						{"number": 39, "emoji": "⏰", "description": "Clock", "unicode": "U+23F0"},
-						{"number": 40, "emoji": "🎁", "description": "Gift", "unicode": "U+1F381"},
-						{"number": 41, "emoji": "💡", "description": "Light Bulb", "unicode": "U+1F4A1"},
-						{"number": 42, "emoji": "📕", "description": "Book", "unicode": "U+1F4D5"},
-						{"number": 43, "emoji": "✏️", "description": "Pencil", "unicode": "U+270FU+FE0F"},
-						{"number": 44, "emoji": "📎", "description": "Paperclip", "unicode": "U+1F4CE"},
-						{"number": 45, "emoji": "✂️", "description": "Scissors", "unicode": "U+2702U+FE0F"},
-						{"number": 46, "emoji": "🔒", "description": "Lock", "unicode": "U+1F512"},
-						{"number": 47, "emoji": "🔑", "description": "Key", "unicode": "U+1F511"},
-						{"number": 48, "emoji": "🔨", "description": "Hammer", "unicode": "U+1F528"},
-						{"number": 49, "emoji": "☎️", "description": "Telephone", "unicode": "U+260EU+FE0F"},
-						{"number": 50, "emoji": "🏁", "description": "Flag", "unicode": "U+1F3C1"},
-						{"number": 51, "emoji": "🚂", "description": "Train", "unicode": "U+1F682"},
-						{"number": 52, "emoji": "🚲", "description": "Bicycle", "unicode": "U+1F6B2"},
-						{"number": 53, "emoji": "✈️", "description": "Aeroplane", "unicode": "U+2708U+FE0F"},
-						{"number": 54, "emoji": "🚀", "description": "Rocket", "unicode": "U+1F680"},
-						{"number": 55, "emoji": "🏆", "description": "Trophy", "unicode": "U+1F3C6"},
-						{"number": 56, "emoji": "⚽", "description": "Ball", "unicode": "U+26BD"},
-						{"number": 57, "emoji": "🎸", "description": "Guitar", "unicode": "U+1F3B8"},
-						{"number": 58, "emoji": "🎺", "description": "Trumpet", "unicode": "U+1F3BA"},
-						{"number": 59, "emoji": "🔔", "description": "Bell", "unicode": "U+1F514"},
-						{"number": 60, "emoji": "⚓", "description": "Anchor", "unicode": "U+2693"},
-						{"number": 61, "emoji": "🎧", "description": "Headphones", "unicode": "U+1F3A7"},
-						{"number": 62, "emoji": "📁", "description": "Folder", "unicode": "U+1F4C1"},
-						{"number": 63, "emoji": "📌", "description": "Pin", "unicode": "U+1F4CC"}
-					]
-
-					Repeater {
-						id: repeater
-						model: 7
-						delegate: Rectangle {
-							color: "transparent"
-							implicitHeight: Qt.application.font.pixelSize * 8
-							implicitWidth: col.width
-							ColumnLayout {
-								id: col
-								Layout.fillWidth: true
-								anchors.bottom: parent.bottom
-								property var emoji: emojis.mapping[flow.sasList[index]]
-								Label {
-									//height: font.pixelSize * 2
-									Layout.alignment: Qt.AlignHCenter
-									text: col.emoji.emoji
-									font.pixelSize: Qt.application.font.pixelSize * 2
-									font.family: Settings.emojiFont
-									color:colors.text
-								}
-								Label {
-									Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
-									text: col.emoji.description
-									color:colors.text
-								}
-							}
-						}
-					}
-				}
-
-				RowLayout {
-					Button {
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("They do not match!")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: {  
-							flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
-							deviceVerificationList.remove(tran_id);
-							dialog.destroy();
-						}
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("They match!")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
-					}
-				}
-			}
-		}
-	}
-
-	Component {
-		id: awaitingVerificationConfirmation
-		Pane {
-			property string title: qsTr("Awaiting Confirmation")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					id: content
-					text: qsTr("Waiting for other side to complete verification.")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				BusyIndicator {
-					Layout.alignment: Qt.AlignHCenter
-				}
-				RowLayout {
-					Button {
-						Layout.alignment: Qt.AlignLeft
-						text: qsTr("Cancel")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: { 
-							flow.cancelVerification(DeviceVerificationFlow.User); 
-							deviceVerificationList.remove(tran_id);
-							dialog.destroy();
-						}
-					}
-					Item {
-						Layout.fillWidth: true
-					}
-				}
-			}
-		}
+		EmojiVerification {}
 	}
 
-	Component {
-		id: verificationSuccess
-		Pane {
-			property string title: qsTr("Successful Verification")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					id: content
-					text: qsTr("Verification successful! Both sides verified their devices!")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				RowLayout {
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("Close")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: {
-							deviceVerificationList.remove(tran_id);
-							flow.deleteFlow();
-							dialog.destroy();
-						}
-					}
-				}
-			}
-		}
-	}
-
-	Component {
-		id: partnerAborted
-		Pane {
-			property string title: qsTr("Verification aborted!")
-			ColumnLayout {
-				spacing: 16
-				Label {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					id: content
-					text: qsTr("Verification canceled by the other party!")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
+	Connections {
+		target: flow
+		onVerificationCanceled: stack.replace(partnerAborted)
+		onTimedout: stack.replace(timedout)
+		onDeviceVerified: stack.replace(verificationSuccess)
 
-				RowLayout {
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						Layout.alignment: Qt.AlignRight
-						text: qsTr("Close")
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						onClicked: {
-							deviceVerificationList.remove(tran_id);
-							dialog.destroy();
-						}
-					}
-				}
-			}
+		onVerificationRequestAccepted: switch(method) {
+			case DeviceVerificationFlow.Decimal: stack.replace(digitVerification); break;
+			case DeviceVerificationFlow.Emoji: stack.replace(emojiVerification); break;
 		}
-	}
 
-	Component {
-		id: timedout
-		Pane {
-			property string title: qsTr("Verification timed out")
-			ColumnLayout {
-				spacing: 16
-				Text {
-					Layout.maximumWidth: 400
-					Layout.fillHeight: true
-					Layout.fillWidth: true
-					wrapMode: Text.Wrap
-					id: content
-					text: qsTr("Device verification timed out.")
-					color:colors.text
-					verticalAlignment: Text.AlignVCenter
-				}
-
-				RowLayout {
-					Item {
-						Layout.fillWidth: true
-					}
-					Button {
-						id: timedOutCancel
-						Layout.alignment: Qt.AlignRight
-						palette {
-                            button: "white"
-                        }
-						contentItem: Text {
-                            text: parent.text
-                            color: "black"
-                            horizontalAlignment: Text.AlignHCenter
-                            verticalAlignment: Text.AlignVCenter
-                        }
-						text: qsTr("Close")
-						onClicked: {
-							deviceVerificationList.remove(tran_id);
-							flow.deleteFlow();
-							dialog.destroy()
-						}
-					}
-				}
-			}
+		onRefreshProfile: {
+			deviceVerificationList.updateProfile(flow.userId);
 		}
 	}
 }
diff --git a/resources/qml/device-verification/DigitVerification.qml b/resources/qml/device-verification/DigitVerification.qml
new file mode 100644
index 00000000..241ccbd0
--- /dev/null
+++ b/resources/qml/device-verification/DigitVerification.qml
@@ -0,0 +1,80 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+import im.nheko 1.0
+
+Pane {
+	property string title: qsTr("Verification Code")
+	Component {
+		id: awaitingVerificationConfirmation
+		AwaitingVerificationConfirmation {}
+	}
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			text: qsTr("Please verify the following digits. You should see the same numbers on both sides. If they differ, please press 'They do not match!' to abort verification!")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Layout.alignment: Qt.AlignHCenter
+			Label {
+				font.pixelSize: Qt.application.font.pixelSize * 2
+				text: flow.sasList[0]
+				color:colors.text
+			}
+			Label {
+				font.pixelSize: Qt.application.font.pixelSize * 2
+				text: flow.sasList[1]
+				color:colors.text
+			}
+			Label {
+				font.pixelSize: Qt.application.font.pixelSize * 2
+				text: flow.sasList[2]
+				color:colors.text
+			}
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("They do not match!")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: {
+					flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
+					deviceVerificationList.remove(tran_id);
+					dialog.destroy();
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("They match!")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/resources/qml/device-verification/EmojiElement.qml b/resources/qml/device-verification/EmojiElement.qml
index 22f9e414..7e364594 100644
--- a/resources/qml/device-verification/EmojiElement.qml
+++ b/resources/qml/device-verification/EmojiElement.qml
@@ -1,4 +1,5 @@
 import QtQuick 2.3
+import QtQuick.Controls 2.10
 import QtQuick.Layouts 1.10
 
 Rectangle {
diff --git a/resources/qml/device-verification/EmojiVerification.qml b/resources/qml/device-verification/EmojiVerification.qml
new file mode 100644
index 00000000..fae08f25
--- /dev/null
+++ b/resources/qml/device-verification/EmojiVerification.qml
@@ -0,0 +1,160 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+import im.nheko 1.0
+
+Pane {
+	property string title: qsTr("Verification Code")
+	Component {
+		id: awaitingVerificationConfirmation
+		AwaitingVerificationConfirmation{}
+	}
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			text: qsTr("Please verify the following emoji. You should see the same emoji on both sides. If they differ, please press 'They do not match!' to abort verification!")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Layout.alignment: Qt.AlignHCenter
+			id: emojis
+			property var mapping: [
+				{"number": 0, "emoji": "🐶", "description": "Dog", "unicode": "U+1F436"},
+				{"number": 1, "emoji": "🐱", "description": "Cat", "unicode": "U+1F431"},
+				{"number": 2, "emoji": "🦁", "description": "Lion", "unicode": "U+1F981"},
+				{"number": 3, "emoji": "🐎", "description": "Horse", "unicode": "U+1F40E"},
+				{"number": 4, "emoji": "🦄", "description": "Unicorn", "unicode": "U+1F984"},
+				{"number": 5, "emoji": "🐷", "description": "Pig", "unicode": "U+1F437"},
+				{"number": 6, "emoji": "🐘", "description": "Elephant", "unicode": "U+1F418"},
+				{"number": 7, "emoji": "🐰", "description": "Rabbit", "unicode": "U+1F430"},
+				{"number": 8, "emoji": "🐼", "description": "Panda", "unicode": "U+1F43C"},
+				{"number": 9, "emoji": "🐓", "description": "Rooster", "unicode": "U+1F413"},
+				{"number": 10, "emoji": "🐧", "description": "Penguin", "unicode": "U+1F427"},
+				{"number": 11, "emoji": "🐢", "description": "Turtle", "unicode": "U+1F422"},
+				{"number": 12, "emoji": "🐟", "description": "Fish", "unicode": "U+1F41F"},
+				{"number": 13, "emoji": "🐙", "description": "Octopus", "unicode": "U+1F419"},
+				{"number": 14, "emoji": "🦋", "description": "Butterfly", "unicode": "U+1F98B"},
+				{"number": 15, "emoji": "🌷", "description": "Flower", "unicode": "U+1F337"},
+				{"number": 16, "emoji": "🌳", "description": "Tree", "unicode": "U+1F333"},
+				{"number": 17, "emoji": "🌵", "description": "Cactus", "unicode": "U+1F335"},
+				{"number": 18, "emoji": "🍄", "description": "Mushroom", "unicode": "U+1F344"},
+				{"number": 19, "emoji": "🌏", "description": "Globe", "unicode": "U+1F30F"},
+				{"number": 20, "emoji": "🌙", "description": "Moon", "unicode": "U+1F319"},
+				{"number": 21, "emoji": "☁️", "description": "Cloud", "unicode": "U+2601U+FE0F"},
+				{"number": 22, "emoji": "🔥", "description": "Fire", "unicode": "U+1F525"},
+				{"number": 23, "emoji": "🍌", "description": "Banana", "unicode": "U+1F34C"},
+				{"number": 24, "emoji": "🍎", "description": "Apple", "unicode": "U+1F34E"},
+				{"number": 25, "emoji": "🍓", "description": "Strawberry", "unicode": "U+1F353"},
+				{"number": 26, "emoji": "🌽", "description": "Corn", "unicode": "U+1F33D"},
+				{"number": 27, "emoji": "🍕", "description": "Pizza", "unicode": "U+1F355"},
+				{"number": 28, "emoji": "🎂", "description": "Cake", "unicode": "U+1F382"},
+				{"number": 29, "emoji": "❤️", "description": "Heart", "unicode": "U+2764U+FE0F"},
+				{"number": 30, "emoji": "😀", "description": "Smiley", "unicode": "U+1F600"},
+				{"number": 31, "emoji": "🤖", "description": "Robot", "unicode": "U+1F916"},
+				{"number": 32, "emoji": "🎩", "description": "Hat", "unicode": "U+1F3A9"},
+				{"number": 33, "emoji": "👓", "description": "Glasses", "unicode": "U+1F453"},
+				{"number": 34, "emoji": "🔧", "description": "Spanner", "unicode": "U+1F527"},
+				{"number": 35, "emoji": "🎅", "description": "Santa", "unicode": "U+1F385"},
+				{"number": 36, "emoji": "👍", "description": "Thumbs Up", "unicode": "U+1F44D"},
+				{"number": 37, "emoji": "☂️", "description": "Umbrella", "unicode": "U+2602U+FE0F"},
+				{"number": 38, "emoji": "⌛", "description": "Hourglass", "unicode": "U+231B"},
+				{"number": 39, "emoji": "⏰", "description": "Clock", "unicode": "U+23F0"},
+				{"number": 40, "emoji": "🎁", "description": "Gift", "unicode": "U+1F381"},
+				{"number": 41, "emoji": "💡", "description": "Light Bulb", "unicode": "U+1F4A1"},
+				{"number": 42, "emoji": "📕", "description": "Book", "unicode": "U+1F4D5"},
+				{"number": 43, "emoji": "✏️", "description": "Pencil", "unicode": "U+270FU+FE0F"},
+				{"number": 44, "emoji": "📎", "description": "Paperclip", "unicode": "U+1F4CE"},
+				{"number": 45, "emoji": "✂️", "description": "Scissors", "unicode": "U+2702U+FE0F"},
+				{"number": 46, "emoji": "🔒", "description": "Lock", "unicode": "U+1F512"},
+				{"number": 47, "emoji": "🔑", "description": "Key", "unicode": "U+1F511"},
+				{"number": 48, "emoji": "🔨", "description": "Hammer", "unicode": "U+1F528"},
+				{"number": 49, "emoji": "☎️", "description": "Telephone", "unicode": "U+260EU+FE0F"},
+				{"number": 50, "emoji": "🏁", "description": "Flag", "unicode": "U+1F3C1"},
+				{"number": 51, "emoji": "🚂", "description": "Train", "unicode": "U+1F682"},
+				{"number": 52, "emoji": "🚲", "description": "Bicycle", "unicode": "U+1F6B2"},
+				{"number": 53, "emoji": "✈️", "description": "Aeroplane", "unicode": "U+2708U+FE0F"},
+				{"number": 54, "emoji": "🚀", "description": "Rocket", "unicode": "U+1F680"},
+				{"number": 55, "emoji": "🏆", "description": "Trophy", "unicode": "U+1F3C6"},
+				{"number": 56, "emoji": "⚽", "description": "Ball", "unicode": "U+26BD"},
+				{"number": 57, "emoji": "🎸", "description": "Guitar", "unicode": "U+1F3B8"},
+				{"number": 58, "emoji": "🎺", "description": "Trumpet", "unicode": "U+1F3BA"},
+				{"number": 59, "emoji": "🔔", "description": "Bell", "unicode": "U+1F514"},
+				{"number": 60, "emoji": "⚓", "description": "Anchor", "unicode": "U+2693"},
+				{"number": 61, "emoji": "🎧", "description": "Headphones", "unicode": "U+1F3A7"},
+				{"number": 62, "emoji": "📁", "description": "Folder", "unicode": "U+1F4C1"},
+				{"number": 63, "emoji": "📌", "description": "Pin", "unicode": "U+1F4CC"}
+			]
+			Repeater {
+				id: repeater
+				model: 7
+				delegate: Rectangle {
+					color: "transparent"
+					implicitHeight: Qt.application.font.pixelSize * 8
+					implicitWidth: col.width
+					ColumnLayout {
+						id: col
+						Layout.fillWidth: true
+						anchors.bottom: parent.bottom
+						property var emoji: emojis.mapping[flow.sasList[index]]
+						Label {
+							//height: font.pixelSize * 2
+							Layout.alignment: Qt.AlignHCenter
+							text: col.emoji.emoji
+							font.pixelSize: Qt.application.font.pixelSize * 2
+							font.family: Settings.emojiFont
+							color:colors.text
+						}
+						Label {
+							Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
+							text: col.emoji.description
+							color:colors.text
+						}
+					}
+				}
+			}
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("They do not match!")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: {  
+					flow.cancelVerification(DeviceVerificationFlow.MismatchedSAS);
+					deviceVerificationList.remove(tran_id);
+					dialog.destroy();
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("They match!")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { stack.replace(awaitingVerificationConfirmation); flow.sendVerificationMac(); }
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/NewVerificationRequest.qml b/resources/qml/device-verification/NewVerificationRequest.qml
new file mode 100644
index 00000000..d8fc65a0
--- /dev/null
+++ b/resources/qml/device-verification/NewVerificationRequest.qml
@@ -0,0 +1,71 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+Pane {
+	property string title: qsTr("Sending Device Verification Request")
+	Component {
+		id: awaitingVerificationRequestAccept
+		AwaitingVerificationRequest {}
+	}
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			text: qsTr("A new device was added.")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			text: qsTr("The device may have been added by you signing in from another client or physical device. To ensure that no malicious user can eavesdrop on your encrypted communications, you should verify the new device.")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Button {
+				Layout.alignment: Qt.AlignLeft
+				text: qsTr("Cancel")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { 
+					deviceVerificationList.remove(tran_id);
+					flow.deleteFlow();
+					dialog.destroy();  
+				}
+			}
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("Start verification")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: { 
+					stack.replace(awaitingVerificationRequestAccept); 
+					isRequest?flow.sendVerificationRequest():flow.startVerificationRequest(); }
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/PartnerAborted.qml b/resources/qml/device-verification/PartnerAborted.qml
new file mode 100644
index 00000000..62787b18
--- /dev/null
+++ b/resources/qml/device-verification/PartnerAborted.qml
@@ -0,0 +1,42 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+Pane {
+	property string title: qsTr("Verification aborted!")
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: qsTr("Verification canceled by the other party!")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("Close")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: {
+					deviceVerificationList.remove(tran_id);
+					dialog.destroy();
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/resources/qml/device-verification/TimedOut.qml b/resources/qml/device-verification/TimedOut.qml
new file mode 100644
index 00000000..40528693
--- /dev/null
+++ b/resources/qml/device-verification/TimedOut.qml
@@ -0,0 +1,44 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+Pane {
+	property string title: qsTr("Verification timed out")
+	ColumnLayout {
+		spacing: 16
+		Text {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: qsTr("Device verification timed out.")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				id: timedOutCancel
+				Layout.alignment: Qt.AlignRight
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				text: qsTr("Close")
+				onClicked: {
+					deviceVerificationList.remove(tran_id);
+					flow.deleteFlow();
+					dialog.destroy()
+				}
+			}
+		}
+	}
+}
diff --git a/resources/qml/device-verification/VerificationSuccess.qml b/resources/qml/device-verification/VerificationSuccess.qml
new file mode 100644
index 00000000..c87488da
--- /dev/null
+++ b/resources/qml/device-verification/VerificationSuccess.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.3
+import QtQuick.Controls 2.10
+import QtQuick.Layouts 1.10
+
+Pane {
+	property string title: qsTr("Successful Verification")
+	ColumnLayout {
+		spacing: 16
+		Label {
+			Layout.maximumWidth: 400
+			Layout.fillHeight: true
+			Layout.fillWidth: true
+			wrapMode: Text.Wrap
+			id: content
+			text: qsTr("Verification successful! Both sides verified their devices!")
+			color:colors.text
+			verticalAlignment: Text.AlignVCenter
+		}
+		RowLayout {
+			Item {
+				Layout.fillWidth: true
+			}
+			Button {
+				Layout.alignment: Qt.AlignRight
+				text: qsTr("Close")
+				palette {
+                    button: "white"
+                }
+				contentItem: Text {
+                    text: parent.text
+                    color: "black"
+                    horizontalAlignment: Text.AlignHCenter
+                    verticalAlignment: Text.AlignVCenter
+                }
+				onClicked: {
+					deviceVerificationList.remove(tran_id);
+					if(flow) flow.deleteFlow();
+					dialog.destroy();
+				}
+			}
+		}
+	}
+}
diff --git a/resources/res.qrc b/resources/res.qrc
index e8f1f7be..7ef7ecf9 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -141,7 +141,16 @@
         <file>qml/delegates/Pill.qml</file>
         <file>qml/delegates/Placeholder.qml</file>
         <file>qml/delegates/Reply.qml</file>
+        <file>qml/device-verification/AcceptNewVerificationRequest.qml</file>
+        <file>qml/device-verification/AwaitingVerificationConfirmation.qml</file>
+        <file>qml/device-verification/AwaitingVerificationRequest.qml</file>
         <file>qml/device-verification/DeviceVerification.qml</file>
+        <file>qml/device-verification/DigitVerification.qml</file>
+        <file>qml/device-verification/EmojiVerification.qml</file>
+        <file>qml/device-verification/NewVerificationRequest.qml</file>
+        <file>qml/device-verification/PartnerAborted.qml</file>
+        <file>qml/device-verification/TimedOut.qml</file>
+        <file>qml/device-verification/VerificationSuccess.qml</file>
     </qresource>
     <qresource prefix="/media">
         <file>media/ring.ogg</file>
diff --git a/src/Cache.cpp b/src/Cache.cpp
index 07d01819..5302218a 100644
--- a/src/Cache.cpp
+++ b/src/Cache.cpp
@@ -139,26 +139,24 @@ Cache::Cache(const QString &userId, QObject *parent)
   , localUserId_{userId}
 {
         setup();
-        connect(
-          this,
-          &Cache::updateUserCacheFlag,
-          this,
-          [this](const std::string &user_id) {
-                  std::optional<UserCache> cache_ = getUserCache(user_id);
-                  if (cache_.has_value()) {
-                          cache_.value().isUpdated = false;
-                          setUserCache(user_id, cache_.value());
-                  } else {
-                          setUserCache(user_id, UserCache{});
-                  }
-          },
-          Qt::QueuedConnection);
-        connect(
-          this,
-          &Cache::deleteLeftUsers,
-          this,
-          [this](const std::string &user_id) { deleteUserCache(user_id); },
-          Qt::QueuedConnection);
+        connect(this,
+                &Cache::updateUserCacheFlag,
+                this,
+                [this](const std::string &user_id) {
+                        std::optional<UserCache> cache_ = getUserCache(user_id);
+                        if (cache_.has_value()) {
+                                cache_.value().isUpdated = false;
+                                setUserCache(user_id, cache_.value());
+                        } else {
+                                setUserCache(user_id, UserCache{});
+                        }
+                },
+                Qt::QueuedConnection);
+        connect(this,
+                &Cache::deleteLeftUsers,
+                this,
+                [this](const std::string &user_id) { deleteUserCache(user_id); },
+                Qt::QueuedConnection);
 }
 
 void
diff --git a/src/ChatPage.cpp b/src/ChatPage.cpp
index 704543b5..31ba38d7 100644
--- a/src/ChatPage.cpp
+++ b/src/ChatPage.cpp
@@ -606,12 +606,11 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
         connect(
           this, &ChatPage::tryInitialSyncCb, this, &ChatPage::tryInitialSync, Qt::QueuedConnection);
         connect(this, &ChatPage::trySyncCb, this, &ChatPage::trySync, Qt::QueuedConnection);
-        connect(
-          this,
-          &ChatPage::tryDelayedSyncCb,
-          this,
-          [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
-          Qt::QueuedConnection);
+        connect(this,
+                &ChatPage::tryDelayedSyncCb,
+                this,
+                [this]() { QTimer::singleShot(RETRY_TIMEOUT, this, &ChatPage::trySync); },
+                Qt::QueuedConnection);
 
         connect(this,
                 &ChatPage::newSyncResponse,
diff --git a/src/emoji/EmojiSearchModel.h b/src/emoji/EmojiSearchModel.h
index 1ff5f4e9..13a03934 100644
--- a/src/emoji/EmojiSearchModel.h
+++ b/src/emoji/EmojiSearchModel.h
@@ -33,5 +33,4 @@ private:
                 return shortname.replace(" ", "-").replace(":", "-").replace("--", "-").toLower();
         }
 };
-
 }
diff --git a/src/timeline/EventStore.cpp b/src/timeline/EventStore.cpp
index af1f7b23..66a6d799 100644
--- a/src/timeline/EventStore.cpp
+++ b/src/timeline/EventStore.cpp
@@ -32,40 +32,38 @@ EventStore::EventStore(std::string room_id, QObject *)
                 this->last  = range->last;
         }
 
-        connect(
-          this,
-          &EventStore::eventFetched,
-          this,
-          [this](std::string id,
-                 std::string relatedTo,
-                 mtx::events::collections::TimelineEvents timeline) {
-                  cache::client()->storeEvent(room_id_, id, {timeline});
-
-                  if (!relatedTo.empty()) {
-                          auto idx = idToIndex(relatedTo);
-                          if (idx)
-                                  emit dataChanged(*idx, *idx);
-                  }
-          },
-          Qt::QueuedConnection);
-
-        connect(
-          this,
-          &EventStore::oldMessagesRetrieved,
-          this,
-          [this](const mtx::responses::Messages &res) {
-                  uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res);
-                  if (newFirst == first)
-                          fetchMore();
-                  else {
-                          emit beginInsertRows(toExternalIdx(newFirst),
-                                               toExternalIdx(this->first - 1));
-                          this->first = newFirst;
-                          emit endInsertRows();
-                          emit fetchedMore();
-                  }
-          },
-          Qt::QueuedConnection);
+        connect(this,
+                &EventStore::eventFetched,
+                this,
+                [this](std::string id,
+                       std::string relatedTo,
+                       mtx::events::collections::TimelineEvents timeline) {
+                        cache::client()->storeEvent(room_id_, id, {timeline});
+
+                        if (!relatedTo.empty()) {
+                                auto idx = idToIndex(relatedTo);
+                                if (idx)
+                                        emit dataChanged(*idx, *idx);
+                        }
+                },
+                Qt::QueuedConnection);
+
+        connect(this,
+                &EventStore::oldMessagesRetrieved,
+                this,
+                [this](const mtx::responses::Messages &res) {
+                        uint64_t newFirst = cache::client()->saveOldMessages(room_id_, res);
+                        if (newFirst == first)
+                                fetchMore();
+                        else {
+                                emit beginInsertRows(toExternalIdx(newFirst),
+                                                     toExternalIdx(this->first - 1));
+                                this->first = newFirst;
+                                emit endInsertRows();
+                                emit fetchedMore();
+                        }
+                },
+                Qt::QueuedConnection);
 
         connect(this, &EventStore::processPending, this, [this]() {
                 if (!current_txn.empty()) {
@@ -130,48 +128,46 @@ EventStore::EventStore(std::string room_id, QObject *)
                   event->data);
         });
 
-        connect(
-          this,
-          &EventStore::messageFailed,
-          this,
-          [this](std::string txn_id) {
-                  if (current_txn == txn_id) {
-                          current_txn_error_count++;
-                          if (current_txn_error_count > 10) {
-                                  nhlog::ui()->debug("failing txn id '{}'", txn_id);
-                                  cache::client()->removePendingStatus(room_id_, txn_id);
-                                  current_txn_error_count = 0;
-                          }
-                  }
-                  QTimer::singleShot(1000, this, [this]() {
-                          nhlog::ui()->debug("timeout");
-                          this->current_txn = "";
-                          emit processPending();
-                  });
-          },
-          Qt::QueuedConnection);
-
-        connect(
-          this,
-          &EventStore::messageSent,
-          this,
-          [this](std::string txn_id, std::string event_id) {
-                  nhlog::ui()->debug("sent {}", txn_id);
-
-                  http::client()->read_event(
-                    room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
-                            if (err) {
-                                    nhlog::net()->warn(
-                                      "failed to read_event ({}, {})", room_id_, event_id);
-                            }
-                    });
-
-                  cache::client()->removePendingStatus(room_id_, txn_id);
-                  this->current_txn             = "";
-                  this->current_txn_error_count = 0;
-                  emit processPending();
-          },
-          Qt::QueuedConnection);
+        connect(this,
+                &EventStore::messageFailed,
+                this,
+                [this](std::string txn_id) {
+                        if (current_txn == txn_id) {
+                                current_txn_error_count++;
+                                if (current_txn_error_count > 10) {
+                                        nhlog::ui()->debug("failing txn id '{}'", txn_id);
+                                        cache::client()->removePendingStatus(room_id_, txn_id);
+                                        current_txn_error_count = 0;
+                                }
+                        }
+                        QTimer::singleShot(1000, this, [this]() {
+                                nhlog::ui()->debug("timeout");
+                                this->current_txn = "";
+                                emit processPending();
+                        });
+                },
+                Qt::QueuedConnection);
+
+        connect(this,
+                &EventStore::messageSent,
+                this,
+                [this](std::string txn_id, std::string event_id) {
+                        nhlog::ui()->debug("sent {}", txn_id);
+
+                        http::client()->read_event(
+                          room_id_, event_id, [this, event_id](mtx::http::RequestErr err) {
+                                  if (err) {
+                                          nhlog::net()->warn(
+                                            "failed to read_event ({}, {})", room_id_, event_id);
+                                  }
+                          });
+
+                        cache::client()->removePendingStatus(room_id_, txn_id);
+                        this->current_txn             = "";
+                        this->current_txn_error_count = 0;
+                        emit processPending();
+                },
+                Qt::QueuedConnection);
 }
 
 void
diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp
index 570186a5..8f0e470e 100644
--- a/src/timeline/TimelineModel.cpp
+++ b/src/timeline/TimelineModel.cpp
@@ -204,12 +204,11 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
   , room_id_(room_id)
   , manager_(manager)
 {
-        connect(
-          this,
-          &TimelineModel::redactionFailed,
-          this,
-          [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
-          Qt::QueuedConnection);
+        connect(this,
+                &TimelineModel::redactionFailed,
+                this,
+                [](const QString &msg) { emit ChatPage::instance()->showNotification(msg); },
+                Qt::QueuedConnection);
 
         connect(this,
                 &TimelineModel::newMessageToSend,
@@ -218,17 +217,17 @@ TimelineModel::TimelineModel(TimelineViewManager *manager, QString room_id, QObj
                 Qt::QueuedConnection);
         connect(this, &TimelineModel::addPendingMessageToStore, &events, &EventStore::addPending);
 
-        connect(
-          &events,
-          &EventStore::dataChanged,
-          this,
-          [this](int from, int to) {
-                  nhlog::ui()->debug(
-                    "data changed {} to {}", events.size() - to - 1, events.size() - from - 1);
-                  emit dataChanged(index(events.size() - to - 1, 0),
-                                   index(events.size() - from - 1, 0));
-          },
-          Qt::QueuedConnection);
+        connect(&events,
+                &EventStore::dataChanged,
+                this,
+                [this](int from, int to) {
+                        nhlog::ui()->debug("data changed {} to {}",
+                                           events.size() - to - 1,
+                                           events.size() - from - 1);
+                        emit dataChanged(index(events.size() - to - 1, 0),
+                                         index(events.size() - from - 1, 0));
+                },
+                Qt::QueuedConnection);
 
         connect(&events, &EventStore::beginInsertRows, this, [this](int from, int to) {
                 int first = events.size() - to;