feat(Profile flow): Respond to/review an incoming CR

- implement the new "Reviewing contact request" popup & flow
- adjust storybook

Fixes #13519
This commit is contained in:
Lukáš Tinkl 2024-02-29 22:01:33 +01:00 committed by Lukáš Tinkl
parent babedf4272
commit d12490ab18
8 changed files with 126 additions and 26 deletions

View File

@ -148,6 +148,22 @@ SplitView {
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Sent) ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Sent)
} }
function acceptContactRequest(publicKey, contactRequestId) {
logs.logEvent("rootStore::contactStore::acceptContactRequest", ["publicKey, contactRequestId"], arguments)
ctrlContactRequestState.currentIndex = ctrlContactRequestState.indexOfValue(Constants.ContactRequestState.Mutual)
}
function getLatestContactRequestForContactAsJson(pubKey) {
logs.logEvent("rootStore::contactStore::getLatestContactRequestForContactAsJson", ["pubKey"], arguments)
return {
id: "123456789",
from: pubKey,
clock: Date.now(),
text: "Hey Jo, its Alex here, we met at devcon last week!",
contactRequestState: Constants.ContactRequestState.Received
}
}
function sendVerificationRequest(publicKey, challenge) { function sendVerificationRequest(publicKey, challenge) {
logs.logEvent("rootStore::contactStore::sendVerificationRequest", ["publicKey", "challenge"], arguments) logs.logEvent("rootStore::contactStore::sendVerificationRequest", ["publicKey", "challenge"], arguments)
ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.verifying) ctrlVerificationStatus.currentIndex = ctrlVerificationStatus.indexOfValue(Constants.verificationStatus.verifying)

View File

@ -53,6 +53,7 @@ QtObject {
Global.openIncomingIDRequestPopup.connect(openIncomingIDRequestPopup) Global.openIncomingIDRequestPopup.connect(openIncomingIDRequestPopup)
Global.openInviteFriendsToCommunityPopup.connect(openInviteFriendsToCommunityPopup) Global.openInviteFriendsToCommunityPopup.connect(openInviteFriendsToCommunityPopup)
Global.openContactRequestPopup.connect(openContactRequestPopup) Global.openContactRequestPopup.connect(openContactRequestPopup)
Global.openReviewContactRequestPopup.connect(openReviewContactRequestPopup)
Global.openChooseBrowserPopup.connect(openChooseBrowserPopup) Global.openChooseBrowserPopup.connect(openChooseBrowserPopup)
Global.openDownloadModalRequested.connect(openDownloadModal) Global.openDownloadModalRequested.connect(openDownloadModal)
Global.openImagePopup.connect(openImagePopup) Global.openImagePopup.connect(openImagePopup)
@ -222,6 +223,19 @@ QtObject {
openPopup(sendContactRequestPopupComponent, popupProperties, cb) openPopup(sendContactRequestPopupComponent, popupProperties, cb)
} }
function openReviewContactRequestPopup(publicKey, contactDetails, cb) {
try {
const crDetails = rootStore.contactStore.getLatestContactRequestForContactAsJson(publicKey)
if (crDetails.from !== publicKey) {
console.warn("Popups.openReviewContactRequestPopup: not matching publicKey:", publicKey)
return
}
openPopup(reviewContactRequestPopupComponent, {publicKey, contactDetails, crDetails}, cb)
} catch (e) {
console.error("Popups.openReviewContactRequestPopup: error getting or parsing contact request data", e)
}
}
function openPinnedMessagesPopup(store, messageStore, pinnedMessagesModel, messageToPin, chatId) { function openPinnedMessagesPopup(store, messageStore, pinnedMessagesModel, messageToPin, chatId) {
openPopup(pinnedMessagesPopup, { openPopup(pinnedMessagesPopup, {
store: store, store: store,
@ -467,6 +481,23 @@ QtObject {
} }
}, },
Component {
id: reviewContactRequestPopupComponent
ReviewContactRequestPopup {
onAccepted: {
rootStore.contactStore.acceptContactRequest(publicKey, contactRequestId)
Global.displaySuccessToastMessage(qsTr("Contact request accepted"))
close()
}
onDiscarded: {
rootStore.contactStore.dismissContactRequest(publicKey, contactRequestId)
Global.displaySuccessToastMessage(qsTr("Contact request ignored"))
close()
}
onClosed: destroy()
}
},
Component { Component {
id: backupSeedModalComponent id: backupSeedModalComponent
BackupSeedModal { BackupSeedModal {

View File

@ -8,8 +8,6 @@ import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
import StatusQ.Core.Utils 0.1 as SQUtils import StatusQ.Core.Utils 0.1 as SQUtils
import shared.views.chat 1.0
import utils 1.0 import utils 1.0
CommonContactDialog { CommonContactDialog {

View File

@ -0,0 +1,61 @@
import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Core.Theme 0.1
import utils 1.0
CommonContactDialog {
id: root
// expected roles: id, from, clock, text, contactRequestState
required property var crDetails
signal accepted(string contactRequestId)
signal discarded(string contactRequestId)
title: qsTr("Review contact request")
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: msgColumn.implicitHeight + msgColumn.anchors.topMargin + msgColumn.anchors.bottomMargin
color: "transparent"
border.width: 1
border.color: Theme.palette.baseColor2
radius: Style.current.radius
ColumnLayout {
id: msgColumn
anchors.fill: parent
anchors.margins: Style.current.padding
StatusTimeStampLabel {
Layout.maximumWidth: parent.width
timestamp: crDetails.clock
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: crDetails.text
}
}
}
rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Ignore")
objectName: "ignoreButton"
onClicked: root.discarded(crDetails.id ?? "")
}
StatusButton {
text: qsTr("Accept")
type: StatusBaseButton.Type.Success
objectName: "acceptButton"
onClicked: root.accepted(crDetails.id ?? "")
}
}
}

View File

@ -31,3 +31,4 @@ MarkAsUntrustedPopup 1.0 MarkAsUntrustedPopup.qml
RemoveContactPopup 1.0 RemoveContactPopup.qml RemoveContactPopup 1.0 RemoveContactPopup.qml
MarkAsIDVerifiedDialog 1.0 MarkAsIDVerifiedDialog.qml MarkAsIDVerifiedDialog 1.0 MarkAsIDVerifiedDialog.qml
RemoveIDVerificationDialog 1.0 RemoveIDVerificationDialog.qml RemoveIDVerificationDialog 1.0 RemoveIDVerificationDialog.qml
ReviewContactRequestPopup 1.0 ReviewContactRequestPopup.qml

View File

@ -143,29 +143,14 @@ Pane {
} }
} }
// TODO a popup here instead of buttons
Component { Component {
id: btnAcceptContactRequestComponent id: btnAcceptContactRequestComponent
ColumnLayout { StatusButton {
spacing: Style.current.halfPadding objectName: "profileDialog_reviewContactRequestButton"
size: StatusButton.Size.Small
StatusBaseText { text: qsTr("Review contact request")
color: Theme.palette.baseColor1 onClicked: Global.openReviewContactRequestPopup(root.publicKey, d.contactDetails,
font.pixelSize: 13 popup => popup.closed.connect(d.reload))
text: qsTr("Review contact request")
}
AcceptRejectOptionsButtonsPanel {
menuButton.visible: false
onAcceptClicked: {
root.contactsStore.acceptContactRequest(root.publicKey, "")
d.reload()
}
onDeclineClicked: {
root.contactsStore.dismissContactRequest(root.publicKey)
d.reload()
}
}
} }
} }
@ -175,7 +160,8 @@ Pane {
objectName: "profileDialog_sendContactRequestButton" objectName: "profileDialog_sendContactRequestButton"
size: StatusButton.Size.Small size: StatusButton.Size.Small
text: qsTr("Send contact request") text: qsTr("Send contact request")
onClicked: Global.openContactRequestPopup(root.publicKey, d.contactDetails, null) onClicked: Global.openContactRequestPopup(root.publicKey, d.contactDetails,
popup => popup.closed.connect(d.reload))
} }
} }

View File

@ -52,7 +52,7 @@ StatusMenu {
} }
readonly property bool hasPendingContactRequest: { readonly property bool hasPendingContactRequest: {
return !root.isMe && root.selectedUserPublicKey !== "" && return !root.isMe && root.selectedUserPublicKey !== "" &&
root.store.contactsStore.hasPendingContactRequest(root.selectedUserPublicKey); contactDetails.contactRequestState === Constants.ContactRequestState.Received
} }
readonly property bool hasActiveReceivedVerificationRequestFrom: { readonly property bool hasActiveReceivedVerificationRequestFrom: {
if (!root.selectedUserPublicKey || root.isMe || !root.isContact) { if (!root.selectedUserPublicKey || root.isMe || !root.isContact) {
@ -127,7 +127,13 @@ StatusMenu {
} }
} }
// TODO Review contact request popup StatusAction {
text: qsTr("Review contact request")
objectName: "reviewContactRequest_StatusItem"
icon.name: "add-contact"
enabled: !root.isMe && !root.isContact && !root.isBridgedAccount && !root.isBlockedContact && root.hasPendingContactRequest
onTriggered: Global.openReviewContactRequestPopup(root.selectedUserPublicKey, root.contactDetails, null)
}
SendMessageMenuItem { SendMessageMenuItem {
id: sendMessageMenuItem id: sendMessageMenuItem

View File

@ -42,6 +42,7 @@ QtObject {
signal openMarkAsIDVerifiedPopup(string publicKey, var contactDetails, var cb) signal openMarkAsIDVerifiedPopup(string publicKey, var contactDetails, var cb)
signal openRemoveIDVerificationDialog(string publicKey, var contactDetails, var cb) signal openRemoveIDVerificationDialog(string publicKey, var contactDetails, var cb)
signal openContactRequestPopup(string publicKey, var contactDetails, var cb) signal openContactRequestPopup(string publicKey, var contactDetails, var cb)
signal openReviewContactRequestPopup(string publicKey, var contactDetails, var cb)
signal markAsUntrustedRequested(string publicKey, var contactDetails) signal markAsUntrustedRequested(string publicKey, var contactDetails)
signal removeContactRequested(string publicKey, var contactDetails) signal removeContactRequested(string publicKey, var contactDetails)
signal openInviteFriendsToCommunityPopup(var community, var communitySectionModule, var cb) signal openInviteFriendsToCommunityPopup(var community, var communitySectionModule, var cb)