mirror of
https://github.com/status-im/status-desktop.git
synced 2025-01-09 22:06:25 +00:00
16b2ca5c2c
Fixes #6251 Adds the "Respond to Contact Request" and "Contact Request Pending" options to the MessageContextMenu Also fixes some small issues with contact verification where the state of the incoming request was not correct
466 lines
16 KiB
QML
466 lines
16 KiB
QML
import QtQuick 2.13
|
|
import QtQuick.Controls 2.13
|
|
import QtQuick.Layouts 1.13
|
|
import QtGraphicalEffects 1.13
|
|
|
|
import utils 1.0
|
|
import shared 1.0
|
|
import shared.popups 1.0
|
|
import shared.stores 1.0
|
|
import shared.views.chat 1.0
|
|
import shared.controls.chat 1.0
|
|
import shared.panels 1.0
|
|
|
|
import StatusQ.Core 0.1
|
|
import StatusQ.Core.Theme 0.1
|
|
import StatusQ.Components 0.1
|
|
import StatusQ.Controls 0.1
|
|
import StatusQ.Popups 0.1
|
|
|
|
Rectangle {
|
|
id: root
|
|
|
|
property Popup parentPopup
|
|
|
|
property var profileStore
|
|
property var contactsStore
|
|
|
|
property string userPublicKey: profileStore.pubkey
|
|
property string userDisplayName: profileStore.displayName
|
|
property string userName: profileStore.username
|
|
property string userNickname: profileStore.details.localNickname
|
|
property string userEnsName: profileStore.ensName
|
|
property string userIcon: profileStore.profileLargeImage
|
|
property string text: ""
|
|
|
|
property bool userIsEnsVerified: profileStore.details.ensVerified
|
|
property bool userIsBlocked: profileStore.details.isBlocked
|
|
property bool isCurrentUser: profileStore.pubkey === userPublicKey
|
|
property bool isAddedContact: false
|
|
|
|
property int userTrustStatus: Constants.trustStatus.unknown
|
|
property int outgoingVerificationStatus: Constants.verificationStatus.unverified
|
|
|
|
property string challenge: ""
|
|
property string response: ""
|
|
|
|
property bool userIsUntrustworthy: false
|
|
property bool userTrustIsUnknown: false
|
|
property bool isContact: false
|
|
property bool isVerificationSent: false
|
|
property bool isVerified: false
|
|
property bool isTrusted: false
|
|
property bool hasReceivedVerificationRequest: false
|
|
|
|
property bool showRemoveVerified: false
|
|
property bool showVerifyIdentitySection: false
|
|
property bool showVerificationPendingSection: false
|
|
property bool showIdentityVerified: false
|
|
property bool showIdentityVerifiedUntrustworthy: false
|
|
|
|
property string verificationChallenge: ""
|
|
property string verificationResponse: ""
|
|
property string verificationResponseDisplayName: ""
|
|
property string verificationResponseIcon: ""
|
|
property string verificationRequestedAt: ""
|
|
property string verificationRepliedAt: ""
|
|
|
|
readonly property alias qrCodePopup: qrCodePopup
|
|
readonly property alias unblockContactConfirmationDialog: unblockContactConfirmationDialog
|
|
readonly property alias blockContactConfirmationDialog: blockContactConfirmationDialog
|
|
readonly property alias removeContactConfirmationDialog: removeContactConfirmationDialog
|
|
readonly property alias wizardAnimation: wizardAnimation
|
|
readonly property alias challengeTxt: challengeTxt
|
|
readonly property alias stepsListModel: stepsListModel
|
|
readonly property alias nicknamePopup: nicknamePopup
|
|
|
|
readonly property int animationDuration: 500
|
|
|
|
signal contactUnblocked(publicKey: string)
|
|
signal contactBlocked(publicKey: string)
|
|
signal contactAdded(publicKey: string)
|
|
signal contactRemoved(publicKey: string)
|
|
signal nicknameEdited(publicKey: string)
|
|
|
|
implicitWidth: modalContent.implicitWidth
|
|
implicitHeight: modalContent.implicitHeight
|
|
|
|
color: Theme.palette.statusAppLayout.backgroundColor
|
|
radius: 8
|
|
|
|
QtObject {
|
|
id: d
|
|
readonly property string subTitle: root.userIsEnsVerified ? root.userName : Utils.getElidedCompressedPk(userPublicKey)
|
|
readonly property int subTitleElide: Text.ElideMiddle
|
|
}
|
|
|
|
SequentialAnimation {
|
|
id: wizardAnimation
|
|
ScriptAction {
|
|
id: step1
|
|
property int loadingTime: 0
|
|
Behavior on loadingTime { NumberAnimation { duration: animationDuration }}
|
|
onLoadingTimeChanged: {
|
|
if (isVerificationSent) {
|
|
stepsListModel.setProperty(1, "loadingTime", step1.loadingTime);
|
|
}
|
|
}
|
|
script: {
|
|
step1.loadingTime = animationDuration;
|
|
stepsListModel.setProperty(0, "loadingTime", step1.loadingTime);
|
|
|
|
if (isVerificationSent) {
|
|
stepsListModel.setProperty(0, "stepCompleted", true);
|
|
}
|
|
}
|
|
}
|
|
PauseAnimation {
|
|
duration: animationDuration + 100
|
|
}
|
|
ScriptAction {
|
|
id: step2
|
|
property int loadingTime: 0
|
|
Behavior on loadingTime { NumberAnimation { duration: animationDuration } }
|
|
onLoadingTimeChanged: {
|
|
if (isVerificationSent && !!verificationResponse) {
|
|
stepsListModel.setProperty(2, "loadingTime", step2.loadingTime);
|
|
}
|
|
}
|
|
script: {
|
|
if (isVerificationSent && !!verificationChallenge) {
|
|
step2.loadingTime = animationDuration;
|
|
if (isVerificationSent && !!verificationResponse) {
|
|
stepsListModel.setProperty(1, "stepCompleted", true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
PauseAnimation {
|
|
duration: animationDuration + 100
|
|
}
|
|
ScriptAction {
|
|
script: {
|
|
if (outgoingVerificationStatus === Constants.verificationStatus.trusted) {
|
|
stepsListModel.setProperty(2, "stepCompleted", true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ColumnLayout {
|
|
id: modalContent
|
|
anchors.fill: parent
|
|
|
|
Item {
|
|
Layout.fillWidth: true
|
|
implicitHeight: 32
|
|
}
|
|
|
|
ProfileHeader {
|
|
Layout.fillWidth: true
|
|
|
|
displayName: root.userDisplayName
|
|
pubkey: root.userPublicKey
|
|
icon: root.isCurrentUser ? root.profileStore.profileLargeImage : root.userIcon
|
|
trustStatus: root.userTrustStatus
|
|
isContact: root.isContact
|
|
store: root.profileStore
|
|
isCurrentUser: root.isCurrentUser
|
|
|
|
displayNameVisible: false
|
|
displayNamePlusIconsVisible: true
|
|
pubkeyVisibleWithCopy: true
|
|
pubkeyVisible: false
|
|
imageSize: ProfileHeader.ImageSize.Middle
|
|
editImageButtonVisible: root.isCurrentUser
|
|
onEditClicked: {
|
|
if(!isCurrentUser){
|
|
nicknamePopup.open()
|
|
} else {
|
|
Global.openEditDisplayNamePopup()
|
|
}
|
|
}
|
|
}
|
|
|
|
StatusBanner {
|
|
Layout.fillWidth: true
|
|
visible: root.userIsBlocked
|
|
type: StatusBanner.Type.Danger
|
|
statusText: qsTr("Blocked")
|
|
}
|
|
|
|
StatusDescriptionListItem {
|
|
Layout.fillWidth: true
|
|
visible: !showVerifyIdentitySection && !showVerificationPendingSection && !showIdentityVerified
|
|
title: qsTr("Chat key")
|
|
subTitle: Utils.getCompressedPk(root.userPublicKey)
|
|
subTitleComponent.elide: Text.ElideMiddle
|
|
subTitleComponent.width: 320
|
|
subTitleComponent.font.family: Theme.palette.monoFont.name
|
|
tooltip.text: qsTr("Copied to clipboard")
|
|
tooltip.timeout: 1000
|
|
icon.name: "copy"
|
|
iconButton.onClicked: {
|
|
globalUtils.copyToClipboard(subTitle)
|
|
tooltip.open();
|
|
}
|
|
}
|
|
|
|
StatusDescriptionListItem {
|
|
Layout.fillWidth: true
|
|
visible: !showVerifyIdentitySection && !showVerificationPendingSection && !showIdentityVerified
|
|
title: qsTr("Share Profile URL")
|
|
subTitle: {
|
|
let user = ""
|
|
if (isCurrentUser) {
|
|
user = root.profileStore.ensName !== "" ? root.profileStore.ensName : Utils.elideText(root.profileStore.pubkey, 5)
|
|
} else if (userIsEnsVerified) {
|
|
user = userEnsName
|
|
}
|
|
|
|
if (user === ""){
|
|
user = Utils.elideText(userPublicKey, 5)
|
|
}
|
|
return Constants.userLinkPrefix + user;
|
|
}
|
|
tooltip.text: qsTr("Copied to clipboard")
|
|
tooltip.timeout: 1000
|
|
icon.name: "copy"
|
|
iconButton.onClicked: {
|
|
let user = ""
|
|
if (isCurrentUser) {
|
|
user = root.profileStore.ensName !== "" ? root.profileStore.ensName : root.profileStore.pubkey
|
|
} else {
|
|
user = (userEnsName !== "" ? userEnsName : userPublicKey)
|
|
}
|
|
root.profileStore.copyToClipboard(Constants.userLinkPrefix + user)
|
|
tooltip.open();
|
|
}
|
|
}
|
|
|
|
ListModel {
|
|
id: stepsListModel
|
|
ListElement {description: qsTr("Send Request"); loadingTime: 0; stepCompleted: false}
|
|
ListElement {description: qsTr("Receive Response"); loadingTime: 0; stepCompleted: false}
|
|
ListElement {description: qsTr("Confirm Identity"); loadingTime: 0; stepCompleted: false}
|
|
}
|
|
|
|
StatusWizardStepper {
|
|
id: wizardStepper
|
|
maxDuration: animationDuration
|
|
visible: showVerifyIdentitySection || showVerificationPendingSection || showIdentityVerified || showIdentityVerifiedUntrustworthy
|
|
width: parent.width
|
|
stepsModel: stepsListModel
|
|
}
|
|
|
|
Separator {
|
|
visible: wizardStepper.visible
|
|
implicitHeight: 32
|
|
}
|
|
|
|
StatusBaseText {
|
|
id: confirmLbl
|
|
visible: showIdentityVerified
|
|
text: qsTr("You have confirmed %1's identity. From now on this verification emblem will always be displayed alongside %1's nickname.").arg(userIsEnsVerified ? userEnsName : userDisplayName)
|
|
font.pixelSize: Style.current.additionalTextSize
|
|
horizontalAlignment : Text.AlignHCenter
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.preferredWidth: 363
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.palette.baseColor1
|
|
}
|
|
|
|
StatusBaseText {
|
|
id: confirmUntrustworthyLbl
|
|
visible: showIdentityVerifiedUntrustworthy
|
|
text: qsTr("You have marked %1 as Untrustworthy. From now on this Untrustworthy emblem will always be displayed alongside %1's nickname.").arg(userIsEnsVerified ? userEnsName : userDisplayName)
|
|
font.pixelSize: Style.current.additionalTextSize
|
|
horizontalAlignment : Text.AlignHCenter
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.preferredWidth: 363
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.palette.baseColor1
|
|
}
|
|
|
|
Item {
|
|
visible: checkboxIcon.visible || dangerIcon.visible
|
|
Layout.fillWidth: true
|
|
implicitHeight: visible ? 16 : 0
|
|
}
|
|
|
|
StatusRoundIcon {
|
|
id: checkboxIcon
|
|
visible: confirmLbl.visible
|
|
icon.name: "checkbox"
|
|
icon.width: 16
|
|
icon.height: 16
|
|
icon.color: Theme.palette.white
|
|
Layout.alignment: Qt.AlignHCenter
|
|
color: Theme.palette.primaryColor1
|
|
width: 32
|
|
height: 32
|
|
}
|
|
|
|
StatusDescriptionListItem {
|
|
Layout.fillWidth: true
|
|
visible: !showVerifyIdentitySection && !showVerificationPendingSection && !showIdentityVerified
|
|
title: root.userIsEnsVerified ? qsTr("ENS username") : qsTr("Username")
|
|
subTitle: root.userIsEnsVerified ? root.userEnsName : root.userName
|
|
tooltip.text: qsTr("Copied to clipboard")
|
|
tooltip.timeout: 1000
|
|
icon.name: "copy"
|
|
iconButton.onClicked: {
|
|
globalUtils.copyToClipboard(subTitle)
|
|
tooltip.open();
|
|
}
|
|
}
|
|
|
|
StatusRoundIcon {
|
|
id: dangerIcon
|
|
visible: confirmUntrustworthyLbl.visible
|
|
icon.name: "tiny/subtract"
|
|
icon.width: 5
|
|
icon.height: 21
|
|
icon.color: Theme.palette.white
|
|
Layout.alignment: Qt.AlignHCenter
|
|
color: Theme.palette.dangerColor1
|
|
width: 32
|
|
height: 32
|
|
}
|
|
|
|
Item {
|
|
visible: checkboxIcon.visible || dangerIcon.visible
|
|
height: visible ? 16 : 0
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
StatusInput {
|
|
id: challengeTxt
|
|
visible: showVerifyIdentitySection
|
|
charLimit: 280
|
|
input.text: root.challenge
|
|
Layout.fillWidth: true
|
|
Layout.rightMargin: d.contentMargins
|
|
Layout.leftMargin: d.contentMargins
|
|
input.multiline: true
|
|
minimumHeight: 152
|
|
maximumHeight: 152
|
|
placeholderText: qsTr("Ask a question that only the real %1 will be able to answer e.g. a question about a shared experience, or ask Mark to enter a code or phrase you have sent to them via a different communication channel (phone, post, etc...).").arg(userIsEnsVerified ? userEnsName : userDisplayName)
|
|
}
|
|
|
|
MessageView {
|
|
id: challengeMessage
|
|
visible: root.showVerificationPendingSection
|
|
Layout.fillWidth: true
|
|
isMessage: true
|
|
shouldRepeatHeader: true
|
|
messageTimestamp: root.verificationRequestedAt
|
|
senderDisplayName: userProfile.name
|
|
senderIcon: userProfile.icon
|
|
message: root.verificationChallenge
|
|
messageContentType: Constants.messageContentType.messageType
|
|
placeholderMessage: true
|
|
}
|
|
|
|
MessageView {
|
|
id: responseMessage
|
|
visible: root.showVerificationPendingSection && !!root.verificationResponse
|
|
width: parent.width
|
|
isMessage: true
|
|
shouldRepeatHeader: true
|
|
messageTimestamp: root.verificationRepliedAt
|
|
senderDisplayName: root.verificationResponseDisplayName
|
|
senderIcon: root.verificationResponseIcon
|
|
message: root.verificationResponse
|
|
messageContentType: Constants.messageContentType.messageType
|
|
placeholderMessage: true
|
|
}
|
|
|
|
Item {
|
|
visible: waitingForText.visible
|
|
height: 32
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
StatusBaseText {
|
|
id: waitingForText
|
|
visible: showVerificationPendingSection && !verificationResponse
|
|
text: qsTr("Waiting for %1's response...").arg(userIsEnsVerified ? userEnsName : userDisplayName)
|
|
font.pixelSize: Style.current.additionalTextSize
|
|
horizontalAlignment : Text.AlignHCenter
|
|
Layout.alignment: Qt.AlignHCenter
|
|
Layout.preferredWidth: 363
|
|
wrapMode: Text.WordWrap
|
|
color: Theme.palette.baseColor1
|
|
}
|
|
|
|
Item {
|
|
height: 32
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
|
|
// TODO: replace with StatusModal
|
|
ModalPopup {
|
|
id: qrCodePopup
|
|
width: 320
|
|
height: 320
|
|
Image {
|
|
asynchronous: true
|
|
fillMode: Image.PreserveAspectFit
|
|
source: globalUtils.qrCode(userPublicKey)
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
height: 212
|
|
width: 212
|
|
mipmap: true
|
|
smooth: false
|
|
}
|
|
}
|
|
|
|
UnblockContactConfirmationDialog {
|
|
id: unblockContactConfirmationDialog
|
|
onUnblockButtonClicked: {
|
|
root.contactsStore.unblockContact(userPublicKey)
|
|
unblockContactConfirmationDialog.close();
|
|
root.contactUnblocked(userPublicKey)
|
|
}
|
|
}
|
|
|
|
BlockContactConfirmationDialog {
|
|
id: blockContactConfirmationDialog
|
|
onBlockButtonClicked: {
|
|
root.contactsStore.blockContact(userPublicKey)
|
|
blockContactConfirmationDialog.close();
|
|
root.contactBlocked(userPublicKey)
|
|
}
|
|
}
|
|
|
|
ConfirmationDialog {
|
|
id: removeContactConfirmationDialog
|
|
header.title: qsTr("Remove contact")
|
|
confirmationText: qsTr("Are you sure you want to remove this contact?")
|
|
onConfirmButtonClicked: {
|
|
if (isAddedContact) {
|
|
root.contactsStore.removeContact(userPublicKey);
|
|
}
|
|
removeContactConfirmationDialog.close();
|
|
root.contactRemoved(userPublicKey)
|
|
}
|
|
}
|
|
|
|
NicknamePopup {
|
|
id: nicknamePopup
|
|
nickname: root.userNickname
|
|
header.subTitle: d.subTitle
|
|
header.subTitleElide: d.subTitleElide
|
|
onEditDone: {
|
|
if (root.userNickname !== newNickname)
|
|
{
|
|
root.userNickname = newNickname;
|
|
root.contactsStore.changeContactNickname(userPublicKey, newNickname);
|
|
}
|
|
root.nicknameEdited(userPublicKey)
|
|
}
|
|
}
|
|
}
|