diff options
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; |