From 08ba75237f341ee71432817d20ec0412e5c93f2a Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Mon, 30 Sep 2024 08:50:14 -0400 Subject: [PATCH] refactor: refactor several popups to make them functional and add them to storybook --- .../ContactVerificationRequestPopupPage.qml | 138 ++++++++++++++++++ ...ingContactVerificationRequestPopupPage.qml | 36 ++++- .../pages/SendContactRequestModalPage.qml | 136 +++++++++++++++++ ui/app/mainui/Popups.qml | 54 +++++-- .../popups/BlockContactConfirmationDialog.qml | 1 - .../ContactVerificationRequestPopup.qml | 59 ++------ .../shared/popups/MarkAsUntrustedPopup.qml | 1 - ...utgoingContactVerificationRequestPopup.qml | 16 +- .../shared/popups/SendContactRequestModal.qml | 42 +----- 9 files changed, 379 insertions(+), 104 deletions(-) create mode 100644 storybook/pages/ContactVerificationRequestPopupPage.qml create mode 100644 storybook/pages/SendContactRequestModalPage.qml diff --git a/storybook/pages/ContactVerificationRequestPopupPage.qml b/storybook/pages/ContactVerificationRequestPopupPage.qml new file mode 100644 index 0000000000..b9a18ac43c --- /dev/null +++ b/storybook/pages/ContactVerificationRequestPopupPage.qml @@ -0,0 +1,138 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import StatusQ 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Popups 0.1 + +import shared.popups 1.0 +import Models 1.0 + +import utils 1.0 +import shared.status 1.0 + +SplitView { + id: root + + Pane { + SplitView.fillWidth: true + SplitView.fillHeight: true + + ColumnLayout { + anchors.fill: parent + spacing: 20 + + Item { + Layout.preferredHeight: 50 + } + + Button { + text: "Open Contact Verification Request Popup" + Layout.alignment: Qt.AlignHCenter + onClicked: contactVerificationRequestPopup.open() + } + + Item { + Layout.preferredWidth: contactVerificationRequestPopup.implicitWidth + Layout.preferredHeight: contactVerificationRequestPopup.implicitHeight + Layout.alignment: Qt.AlignHCenter + + ContactVerificationRequestPopup { + id: contactVerificationRequestPopup + visible: false + senderPublicKey: senderPublicKeyInput.text + challengeText: challengeTextInput.text + messageTimestamp: messageTimestampInput.value + onVerificationRefused: { + log("Verification request declined") + } + onResponseSent: { + log("Response sent: " + response) + } + } + } + } + } + + Pane { + SplitView.minimumWidth: 300 + SplitView.preferredWidth: 400 + SplitView.fillHeight: true + + ColumnLayout { + anchors.fill: parent + spacing: 16 + + Label { + text: "Contact Verification Request Popup Settings" + font.bold: true + font.pixelSize: 16 + } + + Label { text: "Sender Public Key" } + TextField { + id: senderPublicKeyInput + Layout.fillWidth: true + placeholderText: "Enter sender's public key" + } + + Label { text: "Challenge Text" } + TextArea { + id: challengeTextInput + Layout.fillWidth: true + placeholderText: "Enter challenge text" + } + + Label { text: "Message Timestamp" } + SpinBox { + id: messageTimestampInput + Layout.fillWidth: true + from: 0 + to: 2147483647 // Max 32-bit integer + value: Date.now() + } + + Item { + Layout.fillHeight: true + } + + // Add logs section + ColumnLayout { + Layout.fillWidth: true + spacing: 8 + + Label { + text: "Logs" + font.bold: true + font.pixelSize: 16 + } + + ScrollView { + Layout.fillWidth: true + Layout.preferredHeight: 150 + clip: true + + TextArea { + id: logsTextArea + readOnly: true + wrapMode: TextEdit.Wrap + selectByMouse: true + } + } + + Button { + text: "Clear Logs" + onClicked: logsTextArea.clear() + } + } + } + } + + // Add log function + function log(message) { + var timestamp = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss") + logsTextArea.append(timestamp + ": " + message) + } +} diff --git a/storybook/pages/OutgoingContactVerificationRequestPopupPage.qml b/storybook/pages/OutgoingContactVerificationRequestPopupPage.qml index d69c0fbfd8..c9d3b3bde3 100644 --- a/storybook/pages/OutgoingContactVerificationRequestPopupPage.qml +++ b/storybook/pages/OutgoingContactVerificationRequestPopupPage.qml @@ -45,11 +45,15 @@ SplitView { verificationStatus: verificationStatusSelector.currentValue verificationChallenge: challengeInput.text verificationResponse: responseInput.text - verificationResponseDisplayName: nameInput.text - verificationResponseIcon: iconInput.text + verificationResponseDisplayName: verificationResponseNameInput.text + verificationResponseIcon: verificationResponseIconInput.text verificationRequestedAt: requestedAtInput.text verificationRepliedAt: repliedAtInput.text ensVerified: ensVerifiedCheckBox.checked + pubKey: pubKeyInput.text + preferredName: preferredNameInput.text + name: nameInput.text + icon: iconInput.text onVerificationRequestCanceled: { log("Verification request canceled") } @@ -122,6 +126,20 @@ SplitView { placeholderText: "Enter response" } + Label { text: "Verification Response Display Name" } + TextField { + id: verificationResponseNameInput + Layout.fillWidth: true + placeholderText: "Enter verification response display name" + } + + Label { text: "Verification Response Icon" } + TextField { + id: verificationResponseIconInput + Layout.fillWidth: true + placeholderText: "Enter verification response icon" + } + Label { text: "Requested At" } TextField { id: requestedAtInput @@ -136,6 +154,20 @@ SplitView { placeholderText: "Enter replied time" } + Label { text: "Public Key" } + TextField { + id: pubKeyInput + Layout.fillWidth: true + placeholderText: "Enter public key" + } + + Label { text: "Preferred Name" } + TextField { + id: preferredNameInput + Layout.fillWidth: true + placeholderText: "Enter preferred name" + } + CheckBox { id: ensVerifiedCheckBox text: "ENS Verified" diff --git a/storybook/pages/SendContactRequestModalPage.qml b/storybook/pages/SendContactRequestModalPage.qml new file mode 100644 index 0000000000..887d2ad1ba --- /dev/null +++ b/storybook/pages/SendContactRequestModalPage.qml @@ -0,0 +1,136 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import StatusQ 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Popups 0.1 + +import shared.popups 1.0 +import Models 1.0 + +import utils 1.0 +import shared.status 1.0 + +SplitView { + id: root + + Pane { + SplitView.fillWidth: true + SplitView.fillHeight: true + + ColumnLayout { + anchors.fill: parent + spacing: 20 + + Item { + Layout.preferredHeight: 50 + } + + Button { + text: "Open Send Contact Request Modal" + Layout.alignment: Qt.AlignHCenter + onClicked: sendContactRequestModal.open() + } + + Item { + Layout.preferredWidth: sendContactRequestModal.implicitWidth + Layout.preferredHeight: sendContactRequestModal.implicitHeight + Layout.alignment: Qt.AlignHCenter + + SendContactRequestModal { + id: sendContactRequestModal + visible: false + labelText: labelTextInput.text + challengeText: challengeTextInput.text + buttonText: buttonTextInput.text + onAccepted: function(message) { + log("Contact request sent with message: " + message) + } + } + } + } + } + + Pane { + SplitView.minimumWidth: 300 + SplitView.preferredWidth: 400 + SplitView.fillHeight: true + + ColumnLayout { + anchors.fill: parent + spacing: 16 + + Label { + text: "Send Contact Request Modal Settings" + font.bold: true + font.pixelSize: 16 + } + + Label { text: "Label Text" } + TextField { + id: labelTextInput + Layout.fillWidth: true + text: qsTr("Why should they accept your contact request?") + placeholderText: "Enter label text" + } + + Label { text: "Challenge Text" } + TextField { + id: challengeTextInput + Layout.fillWidth: true + text: qsTr("Write a short message telling them who you are...") + placeholderText: "Enter challenge text" + } + + Label { text: "Button Text" } + TextField { + id: buttonTextInput + Layout.fillWidth: true + text: qsTr("Send contact request") + placeholderText: "Enter button text" + } + + Item { + Layout.fillHeight: true + } + + // Add logs section + ColumnLayout { + Layout.fillWidth: true + spacing: 8 + + Label { + text: "Logs" + font.bold: true + font.pixelSize: 16 + } + + ScrollView { + Layout.fillWidth: true + Layout.preferredHeight: 150 + clip: true + + TextArea { + id: logsTextArea + readOnly: true + wrapMode: TextEdit.Wrap + selectByMouse: true + } + } + + Button { + text: "Clear Logs" + onClicked: logsTextArea.clear() + } + } + } + } + + // Add log function + function log(message) { + var timestamp = new Date().toLocaleTimeString(Qt.locale(), "HH:mm:ss") + logsTextArea.append(timestamp + ": " + message) + } +} diff --git a/ui/app/mainui/Popups.qml b/ui/app/mainui/Popups.qml index c310565450..aad0de38ff 100644 --- a/ui/app/mainui/Popups.qml +++ b/ui/app/mainui/Popups.qml @@ -281,7 +281,11 @@ QtObject { largeImage: contactDetails.largeImage, isContact: contactDetails.isContact, trustStatus: contactDetails.trustStatus, - isBlocked: contactDetails.isBlocked + isBlocked: contactDetails.isBlocked, + pubKey: Global.userProfile.pubKey, + preferredName: Global.userProfile.preferredName, + name: Global.userProfile.name, + icon: Global.userProfile.icon } openPopup(contactOutgoingVerificationRequestPopupComponent, popupProperties, cb) } catch (e) { @@ -291,7 +295,15 @@ QtObject { function openIncomingIDRequestPopup(publicKey, contactDetails, cb) { let details = contactDetails ?? Utils.getContactDetailsAsJson(publicKey) - openPopup(contactVerificationRequestPopupComponent, {publicKey, contactDetails: details}) + + openPopup(contactVerificationRequestPopupComponent, { + publicKey: publicKey, + senderPublicKey: request.from, + challengeText: request.challenge, + responseText: request.response, + messageTimestamp: request.requestedAt, + requestStatus: request.requestStatus + }) } function openInviteFriendsToCommunityPopup(community, communitySectionModule, cb) { @@ -310,7 +322,16 @@ QtObject { let details = contactDetails ?? Utils.getContactDetailsAsJson(publicKey, false) const popupProperties = { publicKey: publicKey, - contactDetails: details + // contactDetails: details + localNickname: details.localNickname, + name: details.name, + displayName: details.displayName, + alias: details.alias, + ensVerified: details.ensVerified, + onlineStatus: details.onlineStatus, + largeImage: details.largeImage, + isContact: details.isContact, + trustStatus: details.trustStatus, } openPopup(sendContactRequestPopupComponent, popupProperties, cb) } @@ -322,7 +343,14 @@ QtObject { console.warn("Popups.openReviewContactRequestPopup: not matching publicKey:", publicKey) return } - openPopup(reviewContactRequestPopupComponent, {publicKey, contactDetails, ...crDetails}, cb) + openPopup(reviewContactRequestPopupComponent, { + publicKey, + contactRequestId: crDetails.id, + fromAddress: crDetails.from, + clock: crDetails.requestedAt, + text: crDetails.challenge, + contactRequestState: crDetails.requestStatus + }, cb) } catch (e) { console.error("Popups.openReviewContactRequestPopup: error getting or parsing contact request data", e) } @@ -512,13 +540,13 @@ QtObject { Component { id: contactVerificationRequestPopupComponent ContactVerificationRequestPopup { - contactsStore: rootStore.contactStore - onResponseSent: (senderPublicKey, response) => { - contactsStore.acceptVerificationRequest(senderPublicKey, response) + id: contactVerificationRequestPopup + onResponseSent: (response) => { + contactsStore.acceptVerificationRequest(contactVerificationRequestPopup.senderPublicKey, response) Global.displaySuccessToastMessage(qsTr("ID verification reply sent")) } - onVerificationRefused: (senderPublicKey) => { - contactsStore.declineVerificationRequest(senderPublicKey) + onVerificationRefused: () => { + contactsStore.declineVerificationRequest(contactVerificationRequestPopup.senderPublicKey) Global.displaySuccessToastMessage(qsTr("ID verification request declined")) } onClosed: destroy() @@ -551,8 +579,8 @@ QtObject { Component { id: sendIDRequestPopupComponent SendContactRequestModal { - rootStore: root.rootStore - onAccepted: rootStore.contactStore.sendVerificationRequest(publicKey, message) + id: sendIDRequestPopup + onAccepted: rootStore.contactStore.sendVerificationRequest(sendIDRequestPopup.publicKey, sendIDRequestPopup.message) onClosed: destroy() } }, @@ -609,8 +637,8 @@ QtObject { id: sendContactRequestPopupComponent SendContactRequestModal { - rootStore: root.rootStore - onAccepted: rootStore.contactStore.sendContactRequest(publicKey, message) + id: sendContactRequestPopup + onAccepted: rootStore.contactStore.sendContactRequest(sendContactRequestPopup.publicKey, sendContactRequestPopup.message) onClosed: destroy() } }, diff --git a/ui/imports/shared/popups/BlockContactConfirmationDialog.qml b/ui/imports/shared/popups/BlockContactConfirmationDialog.qml index 155666196c..c20a2e0afe 100644 --- a/ui/imports/shared/popups/BlockContactConfirmationDialog.qml +++ b/ui/imports/shared/popups/BlockContactConfirmationDialog.qml @@ -15,7 +15,6 @@ CommonContactDialog { readonly property bool removeIDVerification: ctrlRemoveIDVerification.checked readonly property bool removeContact: ctrlRemoveContact.checked - // New properties to replace contactDetails property bool isContact: false property int outgoingVerificationStatus: Constants.verificationStatus.untrustworthy property int incomingVerificationStatus: Constants.verificationStatus.untrustworthy diff --git a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml index 433bb24fa6..898758ecd5 100644 --- a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml +++ b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml @@ -15,51 +15,18 @@ import AppLayouts.Profile.stores 1.0 as ProfileStores CommonContactDialog { id: root - required property ProfileStores.ContactsStore contactsStore + property string senderPublicKey: "" + property string challengeText: "" + property string responseText: "" + property double messageTimestamp: 0 + property double responseTimestamp: 0 - signal verificationRefused(string senderPublicKey) - signal responseSent(string senderPublicKey, string response) - - function updateVerificationDetails() { - try { - const request = root.contactsStore.getVerificationDetailsFromAsJson(root.publicKey) - - if (request.requestStatus === Constants.verificationStatus.canceled) { - root.close() - } - - d.senderPublicKey = request.from - d.challengeText = request.challenge - d.responseText = request.response - d.messageTimestamp = request.requestedAt - } catch (e) { - console.error("Error getting or parsing verification data", e) - } - } - - readonly property var _con: Connections { - target: root.contactsStore.receivedContactRequestsModel ?? null - - function onItemChanged(pubKey) { - if (pubKey === root.publicKey) - root.updateVerificationDetails() - } - } - - readonly property var d: QtObject { - id: d - - property string senderPublicKey - property string challengeText - property string responseText - property double messageTimestamp - property double responseTimestamp - } + signal verificationRefused() + signal responseSent(string response) title: qsTr("Reply to ID verification request") onAboutToShow: { - root.updateVerificationDetails() verificationResponse.input.edit.forceActiveFocus() } @@ -78,12 +45,12 @@ CommonContactDialog { StatusTimeStampLabel { Layout.fillWidth: true - timestamp: d.messageTimestamp + timestamp: root.messageTimestamp } StatusBaseText { Layout.fillWidth: true wrapMode: Text.WordWrap - text: d.challengeText + text: root.challengeText } } } @@ -107,7 +74,7 @@ CommonContactDialog { type: StatusBaseButton.Type.Danger objectName: "refuseVerificationButton" onClicked: { - root.verificationRefused(d.senderPublicKey) + root.verificationRefused() root.close() } } @@ -117,9 +84,9 @@ CommonContactDialog { objectName: "sendAnswerButton" enabled: verificationResponse.text !== "" onClicked: { - root.responseSent(d.senderPublicKey, SQUtils.StringUtils.escapeHtml(verificationResponse.text)) - d.responseText = verificationResponse.text - d.responseTimestamp = Date.now() + root.responseSent(SQUtils.StringUtils.escapeHtml(verificationResponse.text)) + root.responseText = verificationResponse.text + root.responseTimestamp = Date.now() root.close() } } diff --git a/ui/imports/shared/popups/MarkAsUntrustedPopup.qml b/ui/imports/shared/popups/MarkAsUntrustedPopup.qml index feb9ef8b96..e46cbb91f6 100644 --- a/ui/imports/shared/popups/MarkAsUntrustedPopup.qml +++ b/ui/imports/shared/popups/MarkAsUntrustedPopup.qml @@ -12,7 +12,6 @@ import utils 1.0 CommonContactDialog { id: root - // New properties to replace contactDetails, with default values property int verificationStatus: Constants.verificationStatus.unverified property int incomingVerificationStatus: Constants.verificationStatus.unverified property bool isContact: false diff --git a/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml b/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml index 91dfb219a2..50a5c3a18b 100644 --- a/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml +++ b/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml @@ -21,13 +21,17 @@ CommonContactDialog { property string verificationRequestedAt property string verificationRepliedAt property bool ensVerified + property string pubKey + property string preferredName + property string name + property string icon readonly property bool hasReply: root.verificationResponse !== "" signal verificationRequestCanceled() signal untrustworthyVerified() signal trustedVerified() - signal onLinkActivated() + signal linkActivated() title: !hasReply ? qsTr("ID verification pending") : qsTr("Review ID verification reply") @@ -72,11 +76,11 @@ CommonContactDialog { id: challengeMessage timestamp: root.verificationRequestedAt messageDetails.messageText: root.verificationChallenge - messageDetails.sender.id: Global.userProfile.pubKey - messageDetails.sender.displayName: Global.userProfile.name - messageDetails.sender.profileImage.name: Global.userProfile.icon + messageDetails.sender.id: root.pubKey + messageDetails.sender.displayName: root.name + messageDetails.sender.profileImage.name: root.icon messageDetails.sender.profileImage.assetSettings.isImage: true - messageDetails.sender.profileImage.colorId: Utils.colorIdForPubkey(Global.userProfile.pubKey) + messageDetails.sender.profileImage.colorId: Utils.colorIdForPubkey(root.pubKey) messageDetails.sender.profileImage.colorHash: Utils.getColorHashAsJson(Global.userProfile.pubKey, !!Global.userProfile.preferredName) messageDetails.sender.isEnsVerified: !!Global.userProfile.preferredName Layout.fillWidth: true @@ -107,6 +111,6 @@ CommonContactDialog { wrapMode: Text.WordWrap textFormat: Text.RichText color: root.hasReply ? Theme.palette.directColor1 : Theme.palette.baseColor1 - onLinkActivated: root.onLinkActivated() + onLinkActivated: root.linkActivated() } } diff --git a/ui/imports/shared/popups/SendContactRequestModal.qml b/ui/imports/shared/popups/SendContactRequestModal.qml index 302ee0eca1..72ddd2ec79 100644 --- a/ui/imports/shared/popups/SendContactRequestModal.qml +++ b/ui/imports/shared/popups/SendContactRequestModal.qml @@ -15,8 +15,6 @@ import AppLayouts.stores 1.0 as AppLayoutStores CommonContactDialog { id: root - property AppLayoutStores.RootStore rootStore - property string labelText: qsTr("Why should they accept your contact request?") property string challengeText: qsTr("Write a short message telling them who you are...") property string buttonText: qsTr("Send contact request") @@ -25,49 +23,23 @@ CommonContactDialog { title: qsTr("Send contact request") - onAboutToShow: { - messageInput.input.edit.forceActiveFocus() - - // (request) update from mailserver - if (d.userDisplayName === "") { - root.rootStore.contactStore.requestContactInfo(root.publicKey) - root.loadingContactDetails = true - } - } - - readonly property var d: QtObject { - id: d - - readonly property int maxMsgLength: 280 - readonly property int minMsgLength: 1 - readonly property int msgHeight: 152 - } - - readonly property var _conn: Connections { - target: root.rootStore.contactStore.contactsModule - - function onContactInfoRequestFinished(publicKey, ok) { - if (publicKey !== root.publicKey) - return - if (ok) - root.contactDetails = Utils.getContactDetailsAsJson(root.publicKey, false) - root.loadingContactDetails = false - } - } + readonly property int maxMsgLength: 280 + readonly property int minMsgLength: 1 + readonly property int msgHeight: 152 StatusInput { id: messageInput input.edit.objectName: "ProfileSendContactRequestModal_sayWhoYouAreInput" Layout.fillWidth: true label: root.labelText - charLimit: d.maxMsgLength + charLimit: root.maxMsgLength placeholderText: root.challengeText input.multiline: true - minimumHeight: d.msgHeight - maximumHeight: d.msgHeight + minimumHeight: root.msgHeight + maximumHeight: root.msgHeight input.verticalAlignment: TextEdit.AlignTop validators: StatusMinLengthValidator { - minLength: d.minMsgLength + minLength: root.minMsgLength errorMessage: Utils.getErrorMessage(messageInput.errors, qsTr("who are you")) } }