feat: New Profile Modal

Fixes: #7360
This commit is contained in:
Lukáš Tinkl 2022-09-27 23:26:26 +02:00 committed by Lukáš Tinkl
parent 1652681897
commit 7a407662e2
74 changed files with 1222 additions and 1306 deletions

View File

@ -760,6 +760,7 @@ method getContactDetailsAsJson*[T](self: Module[T], publicKey: string, getVerifi
requestStatus = self.getVerificationRequestFrom(publicKey).status.int requestStatus = self.getVerificationRequestFrom(publicKey).status.int
let jsonObj = %* { let jsonObj = %* {
"displayName": name, "displayName": name,
"optionalName": self.controller.getContactDetails(contact.id).optionalName, # original display name, if renamed
"displayIcon": contact.image.thumbnail, "displayIcon": contact.image.thumbnail,
"publicKey": contact.id, "publicKey": contact.id,
"name": contact.name, "name": contact.name,
@ -982,4 +983,4 @@ method runAuthenticationPopup*[T](self: Module[T], keyUid: string, bip44Path: st
self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.Authentication, keyUid, bip44Path, txHash) self.keycardSharedModule.runFlow(keycard_shared_module.FlowType.Authentication, keyUid, bip44Path, txHash)
method onDisplayKeycardSharedModuleFlow*[T](self: Module[T]) = method onDisplayKeycardSharedModuleFlow*[T](self: Module[T]) =
self.view.emitDisplayKeycardSharedModuleFlow() self.view.emitDisplayKeycardSharedModuleFlow()

View File

@ -229,6 +229,7 @@ QtObject:
self.items[ind].ensName = ensName self.items[ind].ensName = ensName
self.items[ind].localNickname = localNickname self.items[ind].localNickname = localNickname
self.items[ind].alias = alias self.items[ind].alias = alias
self.items[ind].icon = icon
self.items[ind].isUntrustworthy = isUntrustworthy self.items[ind].isUntrustworthy = isUntrustworthy
let index = self.createIndex(ind, 0, nil) let index = self.createIndex(ind, 0, nil)
@ -310,4 +311,4 @@ QtObject:
return self.items.map(i => i.pubKey) return self.items.map(i => i.pubKey)
proc containsItemWithPubKey*(self: Model, pubKey: string): bool = proc containsItemWithPubKey*(self: Model, pubKey: string): bool =
return self.findIndexByPubKey(pubKey) != -1 return self.findIndexByPubKey(pubKey) != -1

View File

@ -1,21 +1,23 @@
import QtQuick 2.0 import QtQuick 2.14
import StatusQ.Core 0.1 import StatusQ.Core 0.1
import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1 import StatusQ.Core.Theme 0.1
Row { Row {
id: root id: root
property bool isContact: false property bool isContact: false
property var trustIndicator: StatusContactVerificationIcons.TrustedType.None property int trustIndicator: StatusContactVerificationIcons.TrustedType.None
property bool tiny: true
property StatusAssetSettings mutualConnectionIcon: StatusAssetSettings { property StatusAssetSettings mutualConnectionIcon: StatusAssetSettings {
name: "tiny/tiny-contact" name: root.tiny ? "tiny/tiny-contact" : "tiny/contact"
color: Theme.palette.indirectColor1 color: Theme.palette.indirectColor1
width: dummyImage.width width: Math.min(bgWidth, dummyImage.width)
height: dummyImage.height height: Math.min(bgHeight, dummyImage.height)
bgWidth: 10 bgWidth: root.tiny ? 10 : 16.5
bgHeight: 10 bgHeight: root.tiny ? 10 : 16.5
bgColor: Theme.palette.primaryColor1 bgColor: Theme.palette.primaryColor1
// Only used to get implicit width and height from the actual image // Only used to get implicit width and height from the actual image
property Image dummyImage: Image { property Image dummyImage: Image {
@ -26,12 +28,13 @@ Row {
property StatusAssetSettings trustContactIcon: StatusAssetSettings { property StatusAssetSettings trustContactIcon: StatusAssetSettings {
// None and Untrustworthy types, same aspect (Icon will not be visible in case of None type): // None and Untrustworthy types, same aspect (Icon will not be visible in case of None type):
name: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? "tiny/tiny-checkmark" : "tiny/subtract" name: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? root.tiny ? "tiny/tiny-checkmark" : "tiny/checkmark"
: root.tiny ? "tiny/tiny-exclamation" : "tiny/exclamation"
color: Theme.palette.indirectColor1 color: Theme.palette.indirectColor1
width: dummyImage.width width: Math.min(bgWidth, dummyImage.width)
height: dummyImage.height height: Math.min(bgHeight, dummyImage.height)
bgWidth: 10 bgWidth: root.tiny ? 10 : 16
bgHeight: 10 bgHeight: root.tiny ? 10 : 16
bgColor: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1 bgColor: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
// Only used to get implicit width and height from the actual image // Only used to get implicit width and height from the actual image
property Image dummyImage: Image { property Image dummyImage: Image {
@ -49,27 +52,34 @@ Row {
spacing: 4 spacing: 4
visible: root.isContact || (root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None) visible: root.isContact || (root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None)
HoverHandler {
id: hoverHandler
}
StatusToolTip {
text: {
if (root.isContact) {
if (root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified)
return qsTr("Verified contact")
if (root.trustIndicator === StatusContactVerificationIcons.TrustedType.Untrustworthy)
return qsTr("Untrustworthy contact")
return qsTr("Contact")
}
if (root.trustIndicator === StatusContactVerificationIcons.TrustedType.Untrustworthy)
return qsTr("Untrustworthy")
return ""
}
visible: hoverHandler.hovered && text
}
StatusRoundIcon { StatusRoundIcon {
visible: root.isContact visible: root.isContact && root.trustIndicator !== StatusContactVerificationIcons.TrustedType.Verified
asset.name: root.mutualConnectionIcon.name asset: root.mutualConnectionIcon
asset.width: root.mutualConnectionIcon.width
asset.height: root.mutualConnectionIcon.height
asset.rotation: root.mutualConnectionIcon.rotation
asset.color: root.mutualConnectionIcon.color
asset.bgColor: root.mutualConnectionIcon.bgColor
asset.bgWidth: root.mutualConnectionIcon.bgWidth
asset.bgHeight: root.mutualConnectionIcon.bgHeight
} }
StatusRoundIcon { StatusRoundIcon {
visible: root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None visible: root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None
asset.name: root.trustContactIcon.name asset: root.trustContactIcon
asset.width: root.trustContactIcon.width
asset.height: root.trustContactIcon.height
asset.rotation: root.trustContactIcon.rotation
asset.color: root.trustContactIcon.color
asset.bgColor: root.trustContactIcon.bgColor
asset.bgWidth: root.trustContactIcon.bgWidth
asset.bgHeight: root.trustContactIcon.bgHeight
} }
} }

View File

@ -70,6 +70,7 @@ Button {
icon.height: 24 icon.height: 24
icon.width: 24 icon.width: 24
icon.color: d.textColor
background: Rectangle { background: Rectangle {
radius: root.radius radius: root.radius
@ -90,7 +91,7 @@ Button {
rotation: root.asset.rotation rotation: root.asset.rotation
opacity: !loading && root.icon.name !== "" opacity: !loading && root.icon.name !== ""
visible: root.icon.name !== "" visible: root.icon.name !== ""
color: d.textColor color: root.icon.color
} }
StatusEmoji { StatusEmoji {
Layout.preferredWidth: visible ? root.icon.width : 0 Layout.preferredWidth: visible ? root.icon.width : 0

View File

@ -14,7 +14,7 @@ Button {
property var type: StatusPickerButton.Type.Next property var type: StatusPickerButton.Type.Next
/*! /*!
\qmlproperty StatusAssetSettings StatusPickerButton::image \qmlproperty StatusAssetSettings StatusPickerButton::asset
This property holds the image settings information. This property holds the image settings information.
*/ */
property StatusAssetSettings asset: StatusAssetSettings { property StatusAssetSettings asset: StatusAssetSettings {

View File

@ -57,10 +57,14 @@ Item {
onCenteredChanged: flow.onPositioningComplete() onCenteredChanged: flow.onPositioningComplete()
implicitHeight: flow.implicitHeight
Flow { Flow {
id: flow id: flow
anchors.fill: parent anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
onPositioningComplete: { onPositioningComplete: {
if (!root.centered || children.length === 0) if (!root.centered || children.length === 0)

View File

@ -14,7 +14,7 @@ QtObject {
FontSizeXXL FontSizeXXL
} }
property QtObject palette: StatusLightTheme {} property ThemePalette palette: StatusLightTheme {}
property int primaryTextFontSize: 15 property int primaryTextFontSize: 15
property int secondaryTextFontSize: 14 property int secondaryTextFontSize: 14

View File

@ -10,6 +10,8 @@ import StatusQ.Core.Theme 0.1
Dialog { Dialog {
id: root id: root
property string subtitle
anchors.centerIn: Overlay.overlay anchors.centerIn: Overlay.overlay
padding: 16 padding: 16
@ -25,8 +27,9 @@ Dialog {
background: StatusDialogBackground {} background: StatusDialogBackground {}
header: StatusDialogHeader { header: StatusDialogHeader {
visible: root.title visible: root.title || root.subtitle
headline.title: root.title headline.title: root.title
headline.subtitle: root.subtitle
actions.closeButton.onClicked: root.close() actions.closeButton.onClicked: root.close()
} }

View File

@ -77,7 +77,7 @@ StatusModal {
validators: [ validators: [
StatusRegularExpressionValidator { StatusRegularExpressionValidator {
regularExpression: /^#(?:[0-9a-fA-F]{3}){1,2}$/ regularExpression: /^#(?:[0-9a-fA-F]{3}){1,2}$/
errorMessage: qsTr("This is not a valid color") errorMessage: qsTr("This is not a valid colour")
} }
] ]
validationMode: StatusInput.ValidationMode.Always validationMode: StatusInput.ValidationMode.Always
@ -115,7 +115,7 @@ StatusModal {
} }
StatusBaseText { StatusBaseText {
text: qsTr("Standart colours") text: qsTr("Standard colours")
font.pixelSize: 15 font.pixelSize: 15
} }

View File

@ -1,4 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.624 8.41603C16.8538 8.07138 16.7607 7.60573 16.416 7.37596C16.0714 7.1462 15.6057 7.23933 15.376 7.58397L9.88343 15.8228L7.53033 13.4697C7.23744 13.1768 6.76256 13.1768 6.46967 13.4697C6.17678 13.7626 6.17678 14.2374 6.46967 14.5303L9.46967 17.5303C9.62855 17.6892 9.8503 17.7685 10.0739 17.7464C10.2975 17.7242 10.4994 17.603 10.624 17.416L16.624 8.41603Z" fill="black"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M20.5 12C20.5 16.6944 16.6944 20.5 12 20.5C7.30558 20.5 3.5 16.6944 3.5 12C3.5 7.30558 7.30558 3.5 12 3.5C16.6944 3.5 20.5 7.30558 20.5 12ZM22 12C22 17.5228 17.5228 22 12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12ZM16.7728 10.1161C17.0657 9.82318 17.0657 9.34831 16.7728 9.05541C16.4799 8.76252 16.0051 8.76252 15.7122 9.05541L10.5856 14.1819L8.28754 11.8838C7.99465 11.5909 7.51977 11.5909 7.22688 11.8838C6.93398 12.1767 6.93399 12.6516 7.22688 12.9445L10.0553 15.7729C10.3482 16.0658 10.8231 16.0658 11.116 15.7729L16.7728 10.1161Z" fill="#0D1625"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 22C6.47715 22 2 17.5228 2 12C2 6.47715 6.47715 2 12 2C17.5228 2 22 6.47715 22 12C22 17.5228 17.5228 22 12 22ZM12 20.5C7.30558 20.5 3.5 16.6944 3.5 12C3.5 7.30558 7.30558 3.5 12 3.5C16.6944 3.5 20.5 7.30558 20.5 12C20.5 16.6944 16.6944 20.5 12 20.5Z" fill="black"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 807 B

After

Width:  |  Height:  |  Size: 743 B

View File

@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 2C7.30964 2 6.75 2.55964 6.75 3.25V7.75C6.75 8.44036 7.30964 9 8 9C8.69036 9 9.25 8.44036 9.25 7.75V3.25C9.25 2.55964 8.69036 2 8 2ZM8 13.5C8.69036 13.5 9.25 12.9404 9.25 12.25C9.25 11.5596 8.69036 11 8 11C7.30964 11 6.75 11.5596 6.75 12.25C6.75 12.9404 7.30964 13.5 8 13.5Z" fill="#0D1625"/>
</svg>

After

Width:  |  Height:  |  Size: 448 B

View File

Before

Width:  |  Height:  |  Size: 531 B

After

Width:  |  Height:  |  Size: 531 B

View File

@ -1,5 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 6.25C12.4142 6.25 12.75 6.58579 12.75 7V14C12.75 14.4142 12.4142 14.75 12 14.75C11.5858 14.75 11.25 14.4142 11.25 14V7C11.25 6.58579 11.5858 6.25 12 6.25Z" fill="black"/> <path fill-rule="evenodd" clip-rule="evenodd" d="M12 3.75C7.44365 3.75 3.75 7.44365 3.75 12C3.75 16.5563 7.44365 20.25 12 20.25C16.5563 20.25 20.25 16.5563 20.25 12C20.25 7.44365 16.5563 3.75 12 3.75ZM2.25 12C2.25 6.61522 6.61522 2.25 12 2.25C17.3848 2.25 21.75 6.61522 21.75 12C21.75 17.3848 17.3848 21.75 12 21.75C6.61522 21.75 2.25 17.3848 2.25 12ZM12 6.25C12.4142 6.25 12.75 6.58579 12.75 7V13C12.75 13.4142 12.4142 13.75 12 13.75C11.5858 13.75 11.25 13.4142 11.25 13V7C11.25 6.58579 11.5858 6.25 12 6.25ZM13 17C13 17.5523 12.5523 18 12 18C11.4477 18 11 17.5523 11 17C11 16.4477 11.4477 16 12 16C12.5523 16 13 16.4477 13 17Z" fill="#0D1625"/>
<path d="M12 18.75C12.6904 18.75 13.25 18.1904 13.25 17.5C13.25 16.8096 12.6904 16.25 12 16.25C11.3096 16.25 10.75 16.8096 10.75 17.5C10.75 18.1904 11.3096 18.75 12 18.75Z" fill="black"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 12C2 17.5228 6.47715 22 12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12ZM3.5 12C3.5 16.6944 7.30558 20.5 12 20.5C16.6944 20.5 20.5 16.6944 20.5 12C20.5 7.30558 16.6944 3.5 12 3.5C7.30558 3.5 3.5 7.30558 3.5 12Z" fill="black"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 791 B

After

Width:  |  Height:  |  Size: 750 B

View File

@ -37,9 +37,7 @@ ModalPopup {
Global.openProfilePopup(model.pubKey) Global.openProfilePopup(model.pubKey)
} }
onBlockContactActionTriggered: { onBlockContactActionTriggered: {
blockContactConfirmationDialog.contactName = model.displayName Global.blockContactRequested(model.pubKey, model.displayName)
blockContactConfirmationDialog.contactAddress = model.pubKey
blockContactConfirmationDialog.open()
} }
onAcceptClicked: { onAcceptClicked: {
popup.store.acceptContactRequest(model.pubKey) popup.store.acceptContactRequest(model.pubKey)
@ -54,14 +52,6 @@ ModalPopup {
width: parent.width width: parent.width
height: children[0].height height: children[0].height
BlockContactConfirmationDialog {
id: blockContactConfirmationDialog
onBlockButtonClicked: {
popup.store.blockContact(blockContactConfirmationDialog.contactAddress)
blockContactConfirmationDialog.close()
}
}
ConfirmationDialog { ConfirmationDialog {
id: declineAllDialog id: declineAllDialog
header.title: qsTr("Decline all contacts") header.title: qsTr("Decline all contacts")

View File

@ -23,7 +23,6 @@ StatusDialog {
signal updateGroupChatDetails(string groupName, string groupColor, string groupImage) signal updateGroupChatDetails(string groupName, string groupColor, string groupImage)
anchors.centerIn: parent
title: qsTr("Edit group name and image") title: qsTr("Edit group name and image")
width: 480 width: 480
height: 610 height: 610
@ -34,7 +33,7 @@ StatusDialog {
} }
onOpened: { onOpened: {
groupName.forceActiveFocus(Qt.MouseFocusReason) groupName.input.edit.forceActiveFocus()
groupName.text = root.activeGroupName.substring(0, d.nameCharLimit) groupName.text = root.activeGroupName.substring(0, d.nameCharLimit)
colorSelectionGrid.selectedColor = activeGroupColor colorSelectionGrid.selectedColor = activeGroupColor

View File

@ -81,7 +81,7 @@ StatusModal {
} }
StatusBaseText { StatusBaseText {
text: qsTr("%1 members").arg(nbMembers) text: qsTr("%n member(s)", "", nbMembers)
font.pixelSize: 15 font.pixelSize: 15
font.weight: Font.Medium font.weight: Font.Medium
color: Theme.palette.directColor1 color: Theme.palette.directColor1

View File

@ -34,7 +34,7 @@ StatusModal {
root.channels = [] root.channels = []
root.store.prepareEditCategoryModel(categoryId); root.store.prepareEditCategoryModel(categoryId);
} }
root.contentItem.categoryName.input.forceActiveFocus(Qt.MouseFocusReason) root.contentItem.categoryName.input.edit.forceActiveFocus()
} }
onClosed: destroy() onClosed: destroy()
@ -42,9 +42,7 @@ StatusModal {
return contentItem.categoryName.valid return contentItem.categoryName.valid
} }
header.title: isEdit ? header.title: isEdit ? qsTr("Edit category") : qsTr("New category")
qsTr("Edit category") :
qsTr("New category")
contentItem: Column { contentItem: Column {
property alias categoryName: nameInput property alias categoryName: nameInput
@ -59,6 +57,7 @@ StatusModal {
anchors.leftMargin: 16 anchors.leftMargin: 16
input.edit.objectName: "createOrEditCommunityCategoryNameInput" input.edit.objectName: "createOrEditCommunityCategoryNameInput"
input.clearable: true
label: qsTr("Category title") label: qsTr("Category title")
charLimit: maxCategoryNameLength charLimit: maxCategoryNameLength
placeholderText: qsTr("Name the category") placeholderText: qsTr("Name the category")
@ -123,6 +122,8 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
title: "#" + model.name title: "#" + model.name
asset.width: 30
asset.height: 30
asset.emoji: model.emoji asset.emoji: model.emoji
asset.color: model.color asset.color: model.color
asset.imgIsIdenticon: false asset.imgIsIdenticon: false

View File

@ -1,8 +1,6 @@
import QtQuick 2.13 import QtQuick 2.14
import utils 1.0 import utils 1.0
import StatusQ.Core.Utils 0.1 as StatusQUtils
QtObject { QtObject {
id: root id: root
@ -172,7 +170,7 @@ QtObject {
function interpretMessage(msg) { function interpretMessage(msg) {
if (msg.startsWith("/shrug")) { if (msg.startsWith("/shrug")) {
return msg.replace("/shrug", "") + " ¯\\\\\\_(ツ)\\_/¯" return msg.replace("/shrug", "") + " ¯\\\\\\_(ツ)\\_/¯"
} }
if (msg.startsWith("/tableflip")) { if (msg.startsWith("/tableflip")) {
return msg.replace("/tableflip", "") + " (╯°□°)╯︵ ┻━┻" return msg.replace("/tableflip", "") + " (╯°□°)╯︵ ┻━┻"

View File

@ -401,9 +401,9 @@ QtObject {
if (index > -1) { if (index > -1) {
const pk = link.substring(index + 3) const pk = link.substring(index + 3)
result.title = qsTr("Start a 1-on-1 chat with %1") result.title = qsTr("Start a 1-on-1 chat with %1")
.arg(isChatKey(pk) ? globalUtils.generateAlias(pk) : ("@" + removeStatusEns(pk))) .arg(Utils.isChatKey(pk) ? globalUtils.generateAlias(pk) : ("@" + Utils.removeStatusEns(pk)))
result.callback = function () { result.callback = function () {
if (isChatKey(pk)) { if (Utils.isChatKey(pk)) {
chatCommunitySectionModule.createOneToOneChat("", pk, "") chatCommunitySectionModule.createOneToOneChat("", pk, "")
} else { } else {
// Not Refactored Yet // Not Refactored Yet

View File

@ -1,8 +1,4 @@
import QtQuick 2.3 import QtQml.Models 2.14
import QtQuick.Controls 2.3
import QtQuick.Controls 2.12 as QQC2
import QtQuick.Layouts 1.3
import Qt.labs.platform 1.1
ListModel { ListModel {
ListElement { ListElement {
@ -58,9 +54,3 @@ ListModel {
url: "QmY4QULmzFQ2AAbEuMvnd3Nd7qD8eWtyxiLD9CAf3kFZWU" url: "QmY4QULmzFQ2AAbEuMvnd3Nd7qD8eWtyxiLD9CAf3kFZWU"
} }
} }
/*##^##
Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

View File

@ -1,5 +1,4 @@
import QtQuick 2.13 import QtQml.Models 2.14
import QtQuick.Controls 2.13
ListModel { ListModel {
ListElement { ListElement {
@ -24,9 +23,3 @@ ListModel {
thumbnail: "QmZdTTRiMvupRUWq6ctVbuPfEmc8Js53TmBKyjSYNHmGdi" thumbnail: "QmZdTTRiMvupRUWq6ctVbuPfEmc8Js53TmBKyjSYNHmGdi"
} }
} }
/*##^##
Designer {
D{i:0;autoSize:true;height:480;width:640}
}
##^##*/

View File

@ -108,7 +108,7 @@ ColumnLayout {
} }
onOpenProfileClicked: { onOpenProfileClicked: {
Global.openProfilePopup(publicKey, null, state) Global.openProfilePopup(publicKey, null)
} }
onDeleteMessage: { onDeleteMessage: {

View File

@ -185,9 +185,6 @@ StatusPopupMenu {
Global.openPopup(deleteChatConfirmationDialogComponent) Global.openPopup(deleteChatConfirmationDialogComponent)
close() close()
} }
onClosed: {
destroy()
}
} }
} }

View File

@ -173,26 +173,12 @@ StatusSectionLayout {
} }
} }
ConfirmationDialog {
id: removeContactConfirmationDialog
header.title: qsTr("Remove contact")
confirmationText: qsTr("Are you sure you want to remove this contact?")
onConfirmButtonClicked: {
let pk = chatColumn.contactToRemove
if (Utils.getContactDetailsAsJson(pk).isAdded) {
root.contactsStore.removeContact(pk)
}
removeContactConfirmationDialog.parentPopup.close();
removeContactConfirmationDialog.close();
}
}
MessageContextMenuView { MessageContextMenuView {
id: quickActionMessageOptionsMenu id: quickActionMessageOptionsMenu
store: root.rootStore store: root.rootStore
onOpenProfileClicked: { onOpenProfileClicked: {
Global.openProfilePopup(publicKey, null, state) Global.openProfilePopup(publicKey, null)
} }
onCreateOneToOneChat: { onCreateOneToOneChat: {
Global.changeAppSectionBySectionType(Constants.appSection.chat) Global.changeAppSectionBySectionType(Constants.appSection.chat)

View File

@ -14,7 +14,6 @@ StatusDialog {
id: root id: root
width: 480 width: 480
anchors.centerIn: parent
closePolicy: Popup.NoAutoClose closePolicy: Popup.NoAutoClose
header: StatusDialogHeader { header: StatusDialogHeader {

View File

@ -38,10 +38,6 @@ StatusSectionLayout {
} }
} }
Component.onCompleted: {
Global.privacyModuleInst = store.privacyStore.privacyModule
}
QtObject { QtObject {
id: d id: d
@ -106,6 +102,7 @@ StatusSectionLayout {
walletStore: root.store.walletStore walletStore: root.store.walletStore
profileStore: root.store.profileStore profileStore: root.store.profileStore
privacyStore: root.store.privacyStore privacyStore: root.store.privacyStore
contactsStore: root.store.contactsStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile) sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile)
contentWidth: d.contentWidth contentWidth: d.contentWidth
} }

View File

@ -20,6 +20,8 @@ StatusListItem {
asset.letterSize: 14 asset.letterSize: 14
asset.isLetterIdenticon: !!account.emoji asset.isLetterIdenticon: !!account.emoji
asset.bgColor: Theme.palette.primaryColor3 asset.bgColor: Theme.palette.primaryColor3
asset.width: 40
asset.height: 40
width: parent.width width: parent.width
components: !showShevronIcon ? [] : [ shevronIcon ] components: !showShevronIcon ? [] : [ shevronIcon ]

View File

@ -70,7 +70,7 @@ StatusListItem {
asset.isImage: asset.name.includes("data") asset.isImage: asset.name.includes("data")
asset.isLetterIdenticon: root.iconSource.toString() === "" asset.isLetterIdenticon: root.iconSource.toString() === ""
ringSettings { ringSettings {
ringSpecModel: Utils.getColorHashAsJson(root.publicKey) ringSpecModel: d.ensVerified ? undefined : Utils.getColorHashAsJson(root.publicKey, true)
ringPxSize: Math.max(asset.width / 24.0) ringPxSize: Math.max(asset.width / 24.0)
} }

View File

@ -16,7 +16,7 @@ QtObject {
property var profileSectionModuleInst: profileSectionModule property var profileSectionModuleInst: profileSectionModule
property bool fetchingUpdate: aboutModule.fetching readonly property bool fetchingUpdate: aboutModuleInst.fetching
property ContactsStore contactsStore: ContactsStore { property ContactsStore contactsStore: ContactsStore {
contactsModule: profileSectionModuleInst.contactsModule contactsModule: profileSectionModuleInst.contactsModule

View File

@ -27,8 +27,6 @@ SettingsContentBase {
headerComponents: [ headerComponents: [
StatusButton { StatusButton {
implicitHeight: 38
size: StatusBaseButton.Size.Normal
text: qsTr("Send contact request to chat key") text: qsTr("Send contact request to chat key")
onClicked: { onClicked: {
sendContactRequest.open() sendContactRequest.open()
@ -54,8 +52,8 @@ SettingsContentBase {
store: ({contactsStore: root.contactsStore}) store: ({contactsStore: root.contactsStore})
isProfile: true isProfile: true
onOpenProfileClicked: function (pubkey, state) { onOpenProfileClicked: function (pubkey) {
Global.openProfilePopup(pubkey, null, state) Global.openProfilePopup(pubkey, null)
} }
onCreateOneToOneChat: function (communityId, chatId, ensName) { onCreateOneToOneChat: function (communityId, chatId, ensName) {
@ -196,6 +194,10 @@ SettingsContentBase {
contactsModel: root.contactsStore.receivedContactRequestsModel contactsModel: root.contactsStore.receivedContactRequestsModel
panelUsage: Constants.contactsPanelUsage.receivedContactRequest panelUsage: Constants.contactsPanelUsage.receivedContactRequest
onSendMessageActionTriggered: {
root.contactsStore.joinPrivateChat(publicKey)
}
onContactRequestAccepted: { onContactRequestAccepted: {
root.contactsStore.acceptContactRequest(publicKey) root.contactsStore.acceptContactRequest(publicKey)
} }
@ -205,20 +207,7 @@ SettingsContentBase {
} }
onShowVerificationRequest: { onShowVerificationRequest: {
try { Global.openIncomingIDRequestPopup(publicKey)
let request = root.contactsStore.getVerificationDetailsFromAsJson(publicKey)
Global.openPopup(contactVerificationRequestPopupComponent, {
senderPublicKey: request.from,
senderDisplayName: request.displayName,
senderIcon: request.icon,
challengeText: request.challenge,
responseText: request.response,
messageTimestamp: request.requestedAt,
responseTimestamp: request.repliedAt
})
} catch (e) {
console.error("Error getting or parsing verification data", e)
}
} }
} }
@ -311,41 +300,6 @@ SettingsContentBase {
} }
} }
// TODO: Make BlockContactConfirmationDialog a dynamic component on a future refactor
BlockContactConfirmationDialog {
id: blockContactConfirmationDialog
onBlockButtonClicked: {
root.contactsStore.blockContact(blockContactConfirmationDialog.contactAddress)
blockContactConfirmationDialog.close()
}
}
// TODO: Make ConfirmationDialog a dynamic component on a future refactor
ConfirmationDialog {
id: removeContactConfirmationDialog
header.title: qsTr("Remove contact")
confirmationText: qsTr("Are you sure you want to remove this contact?")
onConfirmButtonClicked: {
if (Utils.getContactDetailsAsJson(removeContactConfirmationDialog.value).isAdded) {
root.contactsStore.removeContact(removeContactConfirmationDialog.value);
}
removeContactConfirmationDialog.close()
}
}
Component {
id: contactVerificationRequestPopupComponent
ContactVerificationRequestPopup {
onResponseSent: {
root.contactsStore.acceptVerificationRequest(senderPublicKey, response)
}
onVerificationRefused: {
root.contactsStore.declineVerificationRequest(senderPublicKey)
}
}
}
Loader { Loader {
id: sendContactRequest id: sendContactRequest
width: parent.width width: parent.width

View File

@ -64,7 +64,7 @@ Item {
gasPrice, gasPrice,
tipLimit, tipLimit,
overallLimit, overallLimit,
password, password,
eip1559Enabled, eip1559Enabled,
) )
} }

View File

@ -200,7 +200,7 @@ SettingsContentBase {
Connections { Connections {
target: Global target: Global
onSettingsLoaded: { function onSettingsLoaded() {
generalColumn.populatePreviewableSites() generalColumn.populatePreviewableSites()
} }
} }

View File

@ -24,6 +24,7 @@ SettingsContentBase {
property WalletStore walletStore property WalletStore walletStore
property ProfileStore profileStore property ProfileStore profileStore
property PrivacyStore privacyStore property PrivacyStore privacyStore
property ContactsStore contactsStore
titleRowComponentLoader.sourceComponent: StatusButton { titleRowComponentLoader.sourceComponent: StatusButton {
objectName: "profileSettingsChangePasswordButton" objectName: "profileSettingsChangePasswordButton"
@ -35,8 +36,14 @@ SettingsContentBase {
dirty: settingsView.dirty dirty: settingsView.dirty
saveChangesButtonEnabled: settingsView.valid saveChangesButtonEnabled: settingsView.valid
onResetChangesClicked: settingsView.reset() onResetChangesClicked: {
onSaveChangesClicked: settingsView.save() settingsView.reset()
profilePreview.reload()
}
onSaveChangesClicked: {
settingsView.save()
profilePreview.reload()
}
ColumnLayout { ColumnLayout {
id: layout id: layout
@ -73,6 +80,7 @@ SettingsContentBase {
id: profilePreview id: profilePreview
Layout.fillWidth: true Layout.fillWidth: true
profileStore: root.profileStore profileStore: root.profileStore
contactsStore: root.contactsStore
} }
} }

View File

@ -58,7 +58,7 @@ SettingsContentBase {
StatusListItem { StatusListItem {
property string lowerCaseSearchString: searchBox.text.toLowerCase() property string lowerCaseSearchString: searchBox.text.toLowerCase()
width: parent.width width: ListView.view.width
height: visible ? implicitHeight : 0 height: visible ? implicitHeight : 0
visible: lowerCaseSearchString === "" || visible: lowerCaseSearchString === "" ||
model.itemId.toLowerCase().includes(lowerCaseSearchString) || model.itemId.toLowerCase().includes(lowerCaseSearchString) ||

View File

@ -1,4 +1,4 @@
import QtQuick 2.13 import QtQuick 2.14
import QtGraphicalEffects 1.14 import QtGraphicalEffects 1.14
import shared.views 1.0 as SharedViews import shared.views 1.0 as SharedViews
@ -7,6 +7,7 @@ import StatusQ.Core.Theme 0.1
Item { Item {
property alias profileStore: profilePreview.profileStore property alias profileStore: profilePreview.profileStore
property alias contactsStore: profilePreview.contactsStore
implicitHeight: profilePreview.implicitHeight implicitHeight: profilePreview.implicitHeight
+ profilePreview.anchors.topMargin + profilePreview.anchors.topMargin
@ -16,10 +17,15 @@ Item {
+ profilePreview.anchors.leftMargin + profilePreview.anchors.leftMargin
+ profilePreview.anchors.rightMargin + profilePreview.anchors.rightMargin
SharedViews.ProfileView { function reload() {
profilePreview.reload()
}
SharedViews.ProfileDialogView {
id: profilePreview id: profilePreview
anchors.fill: parent anchors.fill: parent
anchors.margins: 24 anchors.margins: 24
readOnly: true
} }
DropShadow { DropShadow {
@ -32,4 +38,4 @@ Item {
color: "#40000000" color: "#40000000"
source: profilePreview source: profilePreview
} }
} }

View File

@ -181,7 +181,6 @@ ColumnLayout {
visible: communitiesRepeater.count == 0 visible: communitiesRepeater.count == 0
width: parent.width width: parent.width
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.pixelSize: 15
color: Theme.palette.directColor1 color: Theme.palette.directColor1
text: qsTr("You haven't joined any communities yet") text: qsTr("You haven't joined any communities yet")
} }
@ -204,7 +203,6 @@ ColumnLayout {
visible: accountsRepeater.count == 0 visible: accountsRepeater.count == 0
width: parent.width width: parent.width
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
font.pixelSize: 15
color: Theme.palette.directColor1 color: Theme.palette.directColor1
text: qsTr("You don't have any wallet accounts yet") text: qsTr("You don't have any wallet accounts yet")
} }
@ -233,5 +231,4 @@ ColumnLayout {
} }
} }
} }
} }

View File

@ -52,7 +52,6 @@ Item {
} }
ColumnLayout { ColumnLayout {
anchors.fill: parent
WalletHeader { WalletHeader {
Layout.fillWidth: true Layout.fillWidth: true
locale: RootStore.locale locale: RootStore.locale

View File

@ -84,13 +84,19 @@ Item {
}) })
return downloadPage return downloadPage
} }
onOpenProfilePopupRequested: { onOpenProfilePopupRequested: {
var popup = profilePopupComponent.createObject(appMain); Global.openPopup(profilePopupComponent, {publicKey: publicKey, parentPopup: parentPopup})
if (parentPopup) { Global.profilePopupOpened = true
popup.parentPopup = parentPopup; }
} onOpenNicknamePopupRequested: {
popup.openPopup(publicKey, state); Global.openPopup(nicknamePopupComponent, {publicKey: publicKey, nickname: nickname, "header.subTitle": subtitle})
Global.profilePopupOpened = true; }
onBlockContactRequested: {
Global.openPopup(blockContactConfirmationComponent, {contactName: contactName, contactAddress: publicKey})
}
onUnblockContactRequested: {
Global.openPopup(unblockContactConfirmationComponent, {contactName: contactName, contactAddress: publicKey})
} }
onOpenActivityCenterPopupRequested: { onOpenActivityCenterPopupRequested: {
@ -106,28 +112,30 @@ Item {
onDisplayToastMessage: { onDisplayToastMessage: {
appMain.rootStore.mainModuleInst.displayEphemeralNotification(title, subTitle, icon, loading, ephNotifType, url); appMain.rootStore.mainModuleInst.displayEphemeralNotification(title, subTitle, icon, loading, ephNotifType, url);
} }
onOpenEditDisplayNamePopup: { onOpenEditDisplayNamePopup: Global.openPopup(displayNamePopupComponent)
var popup = displayNamePopupComponent.createObject(appMain)
popup.open()
}
} }
function changeAppSectionBySectionId(sectionId) { function changeAppSectionBySectionId(sectionId) {
mainModule.setActiveSectionById(sectionId) mainModule.setActiveSectionById(sectionId)
} }
property Component backupSeedModalComponent: BackupSeedModal { Component {
id: backupSeedModal id: backupSeedModalComponent
anchors.centerIn: parent BackupSeedModal {
privacyStore: appMain.rootStore.profileSectionStore.privacyStore anchors.centerIn: parent
onClosed: destroy() privacyStore: appMain.rootStore.profileSectionStore.privacyStore
onClosed: destroy()
}
} }
property Component displayNamePopupComponent: DisplayNamePopup { Component {
anchors.centerIn: parent id: displayNamePopupComponent
profileStore: appMain.rootStore.profileSectionStore.profileStore DisplayNamePopup {
onClosed: { anchors.centerIn: parent
destroy() profileStore: appMain.rootStore.profileSectionStore.profileStore
onClosed: {
destroy()
}
} }
} }
@ -164,21 +172,24 @@ Item {
} }
} }
property Component profilePopupComponent: ProfilePopup { Component {
id: profilePopup id: profilePopupComponent
anchors.centerIn: parent ProfileDialog {
profileStore: appMain.rootStore.profileSectionStore.profileStore id: profilePopup
contactsStore: appMain.rootStore.profileSectionStore.contactsStore profileStore: appMain.rootStore.profileSectionStore.profileStore
onClosed: { contactsStore: appMain.rootStore.profileSectionStore.contactsStore
if (profilePopup.parentPopup) { onClosed: {
profilePopup.parentPopup.close(); if (profilePopup.parentPopup) {
profilePopup.parentPopup.close()
}
Global.profilePopupOpened = false
destroy()
} }
Global.profilePopupOpened = false;
destroy();
} }
} }
property Component changeProfilePicComponent: Component { Component {
id: changeProfilePicComponent
ImageCropWorkflow { ImageCropWorkflow {
title: qsTr("Profile Picture") title: qsTr("Profile Picture")
acceptButtonText: qsTr("Make this my Profile Pic") acceptButtonText: qsTr("Make this my Profile Pic")
@ -636,7 +647,6 @@ Item {
} }
} }
} }
} }
Item { Item {
@ -711,8 +721,6 @@ Item {
ChatLayout { ChatLayout {
id: chatLayoutContainer id: chatLayoutContainer
Layout.fillWidth: true
Layout.fillHeight: true
chatView.emojiPopup: statusEmojiPopup chatView.emojiPopup: statusEmojiPopup
@ -955,6 +963,44 @@ Item {
} }
} }
Component {
id: nicknamePopupComponent
NicknamePopup {
onEditDone: {
if (nickname !== newNickname) {
appMain.rootStore.contactStore.changeContactNickname(publicKey, newNickname)
Global.nickNameChanged(publicKey, newNickname)
}
close()
}
onClosed: destroy()
}
}
Component {
id: unblockContactConfirmationComponent
UnblockContactConfirmationDialog {
onUnblockButtonClicked: {
appMain.rootStore.contactStore.unblockContact(contactAddress)
Global.contactUnblocked(contactAddress)
close()
}
onClosed: destroy()
}
}
Component {
id: blockContactConfirmationComponent
BlockContactConfirmationDialog {
onBlockButtonClicked: {
appMain.rootStore.contactStore.blockContact(contactAddress)
Global.contactBlocked(contactAddress)
close()
}
onClosed: destroy()
}
}
// Add SendModal here as it is used by the Wallet as well as the Browser // Add SendModal here as it is used by the Wallet as well as the Browser
Loader { Loader {
id: sendModal id: sendModal
@ -1183,8 +1229,8 @@ Item {
} catch (e) { } catch (e) {
console.error('Could not parse the whitelist for sites', e) console.error('Could not parse the whitelist for sites', e)
} }
Global.privacyModuleInst = appMain.rootStore.profileSectionStore.privacyStore.privacyModule
Global.settingsHasLoaded(); Global.settingsHasLoaded();
Global.errorSound = errorSound;
} }
Loader { Loader {

View File

@ -44,6 +44,7 @@ Item {
onItemClicked: { onItemClicked: {
appSearch.store.setSearchLocation(firstLevelItemValue, secondLevelItemValue) appSearch.store.setSearchLocation(firstLevelItemValue, secondLevelItemValue)
searchPopup.forceActiveFocus()
if(searchPopup.searchText !== "") if(searchPopup.searchText !== "")
searchMessages(searchPopup.searchText) searchMessages(searchPopup.searchText)
} }

View File

@ -15,7 +15,7 @@ Item {
property string ensAsyncValidationError: qsTr("ENS Username not found") property string ensAsyncValidationError: qsTr("ENS Username not found")
property alias input: contactFieldAndList.chatKey property alias input: contactFieldAndList.chatKey
property string selectedAddress property string selectedAddress
property var isValid: false property bool isValid: false
property alias isPending: contactFieldAndList.loading property alias isPending: contactFieldAndList.loading
property bool isResolvedAddress: false property bool isResolvedAddress: false
property int parentWidth property int parentWidth

View File

@ -2,8 +2,6 @@ import QtQuick 2.13
import StatusQ.Controls 0.1 import StatusQ.Controls 0.1
import shared.stores 1.0
import utils 1.0 import utils 1.0
StatusRoundButton { StatusRoundButton {
@ -32,16 +30,6 @@ StatusRoundButton {
id: toolTip id: toolTip
text: qsTr("Copied!") text: qsTr("Copied!")
orientation: tooltipUnder ? StatusToolTip.Orientation.Bottom: StatusToolTip.Orientation.Top orientation: tooltipUnder ? StatusToolTip.Orientation.Bottom: StatusToolTip.Orientation.Top
} timeout: 2000
Timer {
id: hideTimer
interval: 2000
running: toolTip.visible
onTriggered: {
toolTip.visible = false;
}
} }
} }

View File

@ -4,12 +4,12 @@ import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import utils 1.0 import utils 1.0
import shared.panels 1.0
Item { Item {
id: root id: root
property bool compact: false property bool compact: false
property bool oneRow
property string publicKey property string publicKey
readonly property real size: compact ? 10 : 15 readonly property real size: compact ? 10 : 15
@ -20,8 +20,8 @@ Item {
Grid { Grid {
id: positioner id: positioner
rows: 2 rows: root.oneRow ? 1 : 2
columnSpacing: 0.2 columnSpacing: root.oneRow ? 4 : 2
rowSpacing: root.compact ? 4 : 6 rowSpacing: root.compact ? 4 : 6
Repeater { Repeater {

View File

@ -140,24 +140,11 @@ Item {
} }
} }
Loader { StatusContactVerificationIcons {
sourceComponent: SVGImage { Layout.alignment: Qt.AlignVCenter
height: compact ? 10 : 16 visible: !root.isCurrentUser
width: compact ? 10 : 16 isContact: root.isContact
source: Style.svg("contact") trustIndicator: root.trustStatus
}
active: isContact && !root.isCurrentUser
visible: active
}
Loader {
sourceComponent: VerificationLabel {
trustStatus: root.trustStatus
height: compact ? 10 : 16
width: compact ? 10 : 16
}
active: root.trustStatus !== Constants.trustStatus.unknown && !root.isCurrentUser
visible: active
} }
Loader { Loader {

View File

@ -5,6 +5,6 @@ import StatusQ.Popups 0.1
StatusMenuItem { StatusMenuItem {
property bool muted: false property bool muted: false
text: !muted ? qsTr("Mute chat") : qsTr("Unmute chat") text: muted ? qsTr("Unmute Chat") : qsTr("Mute Chat")
icon.name: "notification" icon.name: "notification"
} }

View File

@ -3,6 +3,6 @@ import QtQuick 2.14
import StatusQ.Popups 0.1 import StatusQ.Popups 0.1
StatusMenuItem { StatusMenuItem {
text: qsTr("Send message") text: qsTr("Send Message")
icon.name: "chat" icon.name: "chat"
} }

View File

@ -10,26 +10,16 @@ import shared.controls.chat.menuItems 1.0
Row { Row {
id: root id: root
height: declineBtn.height
spacing: Style.current.halfPadding
property alias menuButton: menuButton
signal acceptClicked() signal acceptClicked()
signal declineClicked() signal declineClicked()
signal blockClicked() signal blockClicked()
signal profileClicked() signal profileClicked()
height: acceptBtn.height
spacing: Style.current.halfPadding
StatusFlatRoundButton {
id: acceptBtn
width: 32
height: 32
anchors.verticalCenter: parent.verticalCenter
icon.name: "checkmark-circle"
icon.color: Style.current.success
backgroundHoverColor: Utils.setColorAlpha(Style.current.success, 0.1)
onClicked: root.acceptClicked()
}
StatusFlatRoundButton { StatusFlatRoundButton {
id: declineBtn id: declineBtn
width: 32 width: 32
@ -41,6 +31,16 @@ Row {
onClicked: root.declineClicked() onClicked: root.declineClicked()
} }
StatusFlatRoundButton {
id: acceptBtn
width: 32
height: 32
anchors.verticalCenter: parent.verticalCenter
icon.name: "checkmark-circle"
icon.color: Style.current.success
backgroundHoverColor: Utils.setColorAlpha(Style.current.success, 0.1)
onClicked: root.acceptClicked()
}
StatusFlatRoundButton { StatusFlatRoundButton {
id: menuButton id: menuButton

View File

@ -55,7 +55,7 @@ Rectangle {
Connections { Connections {
enabled: !!mainModule enabled: !!mainModule
target: enabled ? mainModule : undefined target: enabled ? mainModule : undefined
onOnlineStatusChanged: { function onOnlineStatusChanged(connected) {
if (connected && root.state !== "ready" && if (connected && root.state !== "ready" &&
root.visible && root.visible &&
root.source && root.source &&

View File

@ -8,9 +8,6 @@ import StatusQ.Core.Theme 0.1
import utils 1.0 import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
Item { Item {
id: root id: root
@ -29,7 +26,7 @@ Item {
signal clicked() signal clicked()
signal closeClicked() signal closeClicked()
signal showStarted() signal showStarted()
signal showFinihsed() signal showFinished()
signal hideStarted() signal hideStarted()
signal hideFinished() signal hideFinished()
@ -73,7 +70,7 @@ Item {
root.showStarted() root.showStarted()
} }
onFinished: { onFinished: {
root.showFinihsed() root.showFinished()
} }
} }
@ -134,7 +131,6 @@ Item {
text: root.text text: root.text
font.pixelSize: 13 font.pixelSize: 13
font.weight: Font.Medium font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter
color: Theme.palette.indirectColor1 color: Theme.palette.indirectColor1
linkColor: color linkColor: color
onLinkActivated: root.linkActivated(link) onLinkActivated: root.linkActivated(link)

View File

@ -1,4 +1,5 @@
import QtQuick 2.14 import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14 import QtQuick.Layouts 1.14
import QtQml.Models 2.14 import QtQml.Models 2.14
@ -10,7 +11,7 @@ import "../controls"
import SortFilterProxyModel 0.2 import SortFilterProxyModel 0.2
Item { Control {
id: root id: root
property string bio property string bio
@ -18,9 +19,6 @@ Item {
onUserSocialLinksJsonChanged: d.buildSocialLinksModel() onUserSocialLinksJsonChanged: d.buildSocialLinksModel()
implicitWidth: layout.implicitWidth
implicitHeight: layout.implicitHeight
QtObject { QtObject {
id: d id: d
@ -83,11 +81,7 @@ Item {
] ]
} }
ColumnLayout { contentItem: ColumnLayout {
id: layout
anchors.fill: parent
spacing: 20 spacing: 20
StatusBaseText { StatusBaseText {
@ -95,15 +89,15 @@ Item {
visible: text !== "" visible: text !== ""
text: root.bio text: root.bio
wrapMode: Text.Wrap wrapMode: Text.Wrap
font.weight: Font.Medium
lineHeight: 1.2
} }
Flow { StatusCenteredFlow {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: 10
Layout.rightMargin: 10
spacing: 16 spacing: Style.current.halfPadding
visible: repeater.count > 0 visible: repeater.count > 0
Repeater { Repeater {

View File

@ -10,10 +10,10 @@ Item {
height: root.visible ? implicitHeight : 0 height: root.visible ? implicitHeight : 0
anchors.topMargin: Style.current.padding anchors.topMargin: Style.current.padding
Rectangle { Rectangle {
id: separator id: separator
width: parent.width width: parent.width
height: 1 height: 1
color: root.color color: root.color
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }

View File

@ -15,7 +15,6 @@ ModalPopup {
height: 237 height: 237
width: 400 width: 400
property Popup parentPopup
property string contactAddress: "" property string contactAddress: ""
property string contactName: "" property string contactName: ""

View File

@ -1,6 +1,5 @@
import QtQuick 2.13 import QtQuick 2.13
import QtQuick.Controls 2.13 import QtQuick.Controls 2.13
import QtQuick.Dialogs 1.3
import utils 1.0 import utils 1.0
@ -37,9 +36,6 @@ StatusModal {
onOpened: { onOpened: {
verificationResponse.input.edit.forceActiveFocus(Qt.MouseFocusReason) verificationResponse.input.edit.forceActiveFocus(Qt.MouseFocusReason)
} }
onClosed: {
root.destroy();
}
contentItem: Item { contentItem: Item {
anchors.left: parent.left anchors.left: parent.left
@ -69,6 +65,7 @@ StatusModal {
messageTimestamp: root.messageTimestamp messageTimestamp: root.messageTimestamp
senderId: root.senderPublicKey senderId: root.senderPublicKey
senderDisplayName: root.senderDisplayName senderDisplayName: root.senderDisplayName
senderIsEnsVerified: Utils.isEnsVerified(root.senderPublicKey)
senderIcon: root.senderIcon senderIcon: root.senderIcon
messageText: root.challengeText messageText: root.challengeText
messageContentType: Constants.messageContentType.messageType messageContentType: Constants.messageContentType.messageType
@ -100,7 +97,8 @@ StatusModal {
shouldRepeatHeader: true shouldRepeatHeader: true
messageTimestamp: root.responseTimestamp messageTimestamp: root.responseTimestamp
senderId: userProfile.pubKey senderId: userProfile.pubKey
senderDisplayName: userProfile.name senderDisplayName: userProfile.displayName
senderIsEnsVerified: !!userProfile.ensName
senderIcon: userProfile.icon senderIcon: userProfile.icon
messageText: root.responseText messageText: root.responseText
messageContentType: Constants.messageContentType.messageType messageContentType: Constants.messageContentType.messageType
@ -115,9 +113,9 @@ StatusModal {
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
anchors.top: responseMessage.bottom anchors.top: responseMessage.bottom
anchors.topMargin: 58 anchors.topMargin: 58
text: qsTr("You're answer has been sent to %1.").arg(root.senderDisplayName) text: qsTr("Your answer has been sent to %1.").arg(root.senderDisplayName)
font.pixelSize: 13 font.pixelSize: 13
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
} }

View File

@ -47,6 +47,6 @@ StatusModal {
} }
] ]
onOpened: { displayNameInput.input.forceActiveFocus(Qt.MouseFocusReason) } onOpened: { displayNameInput.input.edit.forceActiveFocus() }
} }

View File

@ -18,15 +18,18 @@ StatusModal {
anchors.centerIn: parent anchors.centerIn: parent
header.title: qsTr("Nickname") header.title: qsTr("Nickname")
header.subTitleElide: Text.ElideMiddle
/*required*/ property string publicKey
property string nickname
property alias nickname: nicknameInput.text
readonly property int nicknameLength: nicknameInput.text.length readonly property int nicknameLength: nicknameInput.text.length
readonly property int maxNicknameLength: 32 readonly property int maxNicknameLength: 32
signal editDone(string newNickname) signal editDone(string newNickname)
onOpened: { onOpened: {
nicknameInput.forceActiveFocus(Qt.MouseFocusReason); nicknameInput.input.edit.forceActiveFocus()
} }
contentItem: Item { contentItem: Item {
@ -51,9 +54,9 @@ StatusModal {
StatusInput { StatusInput {
id: nicknameInput id: nicknameInput
placeholderText: qsTr("Nickname") placeholderText: qsTr("Nickname")
input.clearable: true
width: parent.width width: parent.width
text: popup.nickname
charLimit: maxNicknameLength charLimit: maxNicknameLength
validationMode: StatusInput.ValidationMode.IgnoreInvalidInput validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
validators: [ validators: [

View File

@ -0,0 +1,110 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQml.Models 2.14
import utils 1.0
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups.Dialog 0.1
import shared.views.chat 1.0
StatusDialog {
id: root
/* required*/ property string userPublicKey
property int verificationStatus
property string verificationChallenge
property string verificationResponse
property string verificationResponseDisplayName
property string verificationResponseIcon
property string verificationRequestedAt
property string verificationRepliedAt
signal verificationRequestCanceled(string userPublicKey)
signal untrustworthyVerified(string userPublicKey)
signal trustedVerified(string userPublicKey)
title: qsTr("Verify %1's Identity").arg(root.verificationResponseDisplayName)
footer: StatusDialogFooter {
leftButtons: ObjectModel {
StatusButton {
text: qsTr("Cancel verification")
type: StatusBaseButton.Type.Danger
visible: root.verificationStatus !== Constants.verificationStatus.verified
onClicked: {
root.verificationRequestCanceled(root.userPublicKey)
root.close()
}
}
}
rightButtons: ObjectModel {
StatusButton {
text: qsTr("Mark Untrustworthy")
enabled: root.verificationResponse !== ""
type: StatusBaseButton.Type.Danger
onClicked: {
root.untrustworthyVerified(root.userPublicKey)
root.close()
}
}
StatusButton {
text: qsTr("Confirm Identity")
enabled: root.verificationResponse !== ""
type: StatusBaseButton.Type.Primary
onClicked: {
root.trustedVerified(root.userPublicKey)
root.close()
}
}
}
}
contentItem: ColumnLayout {
MessageView {
id: challengeMessage
Layout.fillWidth: true
isMessage: true
shouldRepeatHeader: true
messageTimestamp: root.verificationRequestedAt
senderId: userProfile.pubKey
senderDisplayName: userProfile.name
senderIcon: userProfile.icon
senderIsEnsVerified: !!userProfile.ensName
messageText: root.verificationChallenge
messageContentType: Constants.messageContentType.messageType
placeholderMessage: true
}
MessageView {
id: responseMessage
visible: root.verificationResponse !== ""
Layout.fillWidth: true
isMessage: true
shouldRepeatHeader: true
messageTimestamp: root.verificationRepliedAt
senderId: root.userPublicKey
senderDisplayName: root.verificationResponseDisplayName
senderIcon: root.verificationResponseIcon
senderIsEnsVerified: Utils.isEnsVerified(root.userPublicKey)
messageText: root.verificationResponse
messageContentType: Constants.messageContentType.messageType
placeholderMessage: true
}
StatusBaseText {
id: waitingForText
visible: !root.verificationResponse
text: qsTr("Waiting for %1's response...").arg(root.verificationResponseDisplayName)
font.pixelSize: Style.current.additionalTextSize
horizontalAlignment : Text.AlignHCenter
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
wrapMode: Text.WordWrap
color: Theme.palette.baseColor1
}
}
}

View File

@ -0,0 +1,29 @@
import QtQuick 2.14
import StatusQ.Popups.Dialog 0.1
import shared.views 1.0
StatusDialog {
id: root
property var parentPopup
property string publicKey
property var profileStore
property var contactsStore
width: 640
padding: 0
header: null
footer: null
contentItem: ProfileDialogView {
publicKey: root.publicKey
profileStore: root.profileStore
contactsStore: root.contactsStore
onCloseRequested: root.close()
}
}

View File

@ -1,474 +0,0 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.13
import QtQml.Models 2.14
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 1.0 as SharedViews
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.Dialog 0.1
StatusDialog {
id: popup
property Popup parentPopup
property var profileStore
property var contactsStore
property string userPublicKey: ""
property string userDisplayName: ""
property string userName: ""
property string userNickname: ""
property string userEnsName: ""
property string userIcon: ""
property string userBio: ""
property string userSocialLinks: ""
property int userTrustStatus: Constants.trustStatus.unknown
property int outgoingVerificationStatus: Constants.verificationStatus.unverified
property int incomingVerificationStatus: Constants.verificationStatus.unverified
property string text: ""
property string challenge: ""
property string response: ""
property bool userIsEnsVerified: false
property bool userIsBlocked: false
property bool userIsUntrustworthy: false
property bool userTrustIsUnknown: false
property bool isCurrentUser: false
property bool isAddedContact: 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: ""
signal blockButtonClicked(name: string, address: string)
signal unblockButtonClicked(name: string, address: string)
signal removeButtonClicked(address: string)
signal contactUnblocked(publicKey: string)
signal contactBlocked(publicKey: string)
function openPopup(publicKey, state = "") {
// All this should be improved more, but for now we leave it like this.
const contactDetails = Utils.getContactDetailsAsJson(publicKey);
isCurrentUser = popup.profileStore.pubkey === publicKey;
userPublicKey = publicKey;
userDisplayName = isCurrentUser ? Qt.binding(() => { return popup.profileStore.displayName }) : contactDetails.displayName;
userName = contactDetails.alias;
userNickname = contactDetails.localNickname;
userEnsName = contactDetails.name;
userIcon = contactDetails.largeImage;
userBio = contactDetails.bio;
userSocialLinks = contactDetails.socialLinks;
userIsEnsVerified = contactDetails.ensVerified;
userIsBlocked = contactDetails.isBlocked;
isAddedContact = contactDetails.isAdded;
isContact = contactDetails.isContact
userTrustStatus = contactDetails.trustStatus
userTrustIsUnknown = contactDetails.trustStatus === Constants.trustStatus.unknown
userIsUntrustworthy = contactDetails.trustStatus === Constants.trustStatus.untrustworthy
outgoingVerificationStatus = contactDetails.verificationStatus
incomingVerificationStatus = contactDetails.incomingVerificationStatus
isVerificationSent = outgoingVerificationStatus !== Constants.verificationStatus.unverified
if (isContact && popup.contactsStore.hasReceivedVerificationRequestFrom(publicKey)) {
popup.hasReceivedVerificationRequest = true
}
if(isContact && isVerificationSent) {
let verificationDetails = popup.contactsStore.getSentVerificationDetailsAsJson(publicKey);
outgoingVerificationStatus = verificationDetails.requestStatus;
verificationChallenge = verificationDetails.challenge;
verificationResponse = verificationDetails.response;
verificationResponseDisplayName = verificationDetails.displayName;
verificationResponseIcon = verificationDetails.icon;
verificationRequestedAt = verificationDetails.requestedAt;
verificationRepliedAt = verificationDetails.repliedAt;
}
isTrusted = outgoingVerificationStatus === Constants.verificationStatus.trusted
|| incomingVerificationStatus === Constants.verificationStatus.trusted
isVerified = outgoingVerificationStatus === Constants.verificationStatus.verified
text = ""; // this is most likely unneeded
popup.open();
if (state === Constants.profilePopupStates.openNickname) {
profileView.nicknamePopup.open();
} else if (state === Constants.profilePopupStates.contactRequest) {
d.openContactRequestPopup()
} else if (state === Constants.profilePopupStates.blockUser) {
blockUser();
} else if (state === Constants.profilePopupStates.unblockUser) {
unblockUser();
} else if (state === Constants.profilePopupStates.verifyIdentity) {
showVerifyIdentitySection = true;
} else if (state === Constants.profilePopupStates.respondToPendingRequest) {
popup.openPendingRequestPopup()
} else if (state === Constants.profilePopupStates.showVerificationPendingSection) {
popup.showVerificationPendingSection = true
profileView.wizardAnimation.running = true
}
}
function blockUser() {
profileView.blockContactConfirmationDialog.contactName = userDisplayName;
profileView.blockContactConfirmationDialog.contactAddress = userPublicKey;
profileView.blockContactConfirmationDialog.open();
}
function unblockUser() {
profileView.unblockContactConfirmationDialog.contactName = userDisplayName;
profileView.unblockContactConfirmationDialog.contactAddress = userPublicKey;
profileView.unblockContactConfirmationDialog.open();
}
function openPendingRequestPopup() {
try {
let request = popup.contactsStore.getVerificationDetailsFromAsJson(popup.userPublicKey)
Global.openPopup(contactVerificationRequestPopupComponent, {
senderPublicKey: request.from,
senderDisplayName: request.displayName,
senderIcon: request.icon,
challengeText: request.challenge,
responseText: request.response,
messageTimestamp: request.requestedAt,
responseTimestamp: request.repliedAt
})
} catch (e) {
console.error("Error getting or parsing verification data", e)
}
}
QtObject {
id: d
function openContactRequestPopup() {
let contactRequestPopup = Global.openContactRequestPopup(popup.userPublicKey)
contactRequestPopup.closed.connect(popup.close)
}
}
width: 700
padding: 8
header: StatusDialogHeader {
id: dialogHeader
headline.title: {
if(showVerifyIdentitySection || showVerificationPendingSection){
return qsTr("Verify %1's Identity").arg(userDisplayName)
}
return popup.isCurrentUser ? qsTr("My Profile") :
qsTr("%1's Profile").arg(userDisplayName)
}
headline.subtitle: popup.isCurrentUser ? "" : Utils.getElidedCompressedPk(userPublicKey)
actions {
customButtons: ObjectModel {
StatusFlatRoundButton {
type: StatusFlatRoundButton.Type.Secondary
width: 32
height: 32
icon.width: 20
icon.height: 20
icon.name: "qr"
onClicked: profileView.qrCodePopup.open()
}
}
closeButton.onClicked: popup.close()
}
}
footer: StatusDialogFooter {
visible: !popup.isCurrentUser
leftButtons: ObjectModel {
StatusButton {
text: qsTr("Cancel verification")
visible: !isVerified && isContact && isVerificationSent && showVerificationPendingSection
onClicked: {
popup.contactsStore.cancelVerificationRequest(userPublicKey);
popup.close()
}
}
}
rightButtons: ObjectModel {
StatusFlatButton {
text: userIsBlocked ?
qsTr("Unblock User") :
qsTr("Block User")
type: StatusBaseButton.Type.Danger
visible: !isAddedContact
onClicked: userIsBlocked ? unblockUser() : blockUser()
}
StatusFlatButton {
visible: !showRemoveVerified && !showIdentityVerified && !showVerifyIdentitySection && !showVerificationPendingSection && !userIsBlocked && isAddedContact
type: StatusBaseButton.Type.Danger
text: qsTr('Remove Contact')
onClicked: {
profileView.removeContactConfirmationDialog.parentPopup = popup;
profileView.removeContactConfirmationDialog.open();
}
}
StatusButton {
text: qsTr("Send Contact Request")
visible: !userIsBlocked && !isAddedContact
onClicked: d.openContactRequestPopup()
}
StatusButton {
text: qsTr("Mark Untrustworthy")
visible: !showIdentityVerifiedUntrustworthy && !showIdentityVerified && !showVerifyIdentitySection && userTrustIsUnknown
enabled: !showVerificationPendingSection || verificationResponse !== ""
type: StatusBaseButton.Type.Danger
onClicked: {
if (showVerificationPendingSection) {
popup.showIdentityVerified = false;
popup.showIdentityVerifiedUntrustworthy = true;
popup.showVerificationPendingSection = false;
popup.showVerifyIdentitySection = false;
profileView.stepsListModel.setProperty(2, "stepCompleted", true);
popup.contactsStore.verifiedUntrustworthy(userPublicKey);
} else {
popup.contactsStore.markUntrustworthy(userPublicKey);
popup.close();
}
}
}
StatusButton {
text: qsTr("Remove 'Identity Verified' status")
visible: isTrusted && !showIdentityVerified && !showRemoveVerified
type: StatusBaseButton.Type.Danger
onClicked: {
showRemoveVerified = true
}
}
StatusButton {
text: qsTr("No")
visible: showRemoveVerified
type: StatusBaseButton.Type.Danger
onClicked: {
showRemoveVerified = false
}
}
StatusButton {
text: qsTr("Yes")
visible: showRemoveVerified
onClicked: {
popup.contactsStore.removeTrustStatus(userPublicKey);
popup.close();
}
}
StatusButton {
text: qsTr("Remove Untrustworthy Mark")
visible: userIsUntrustworthy
onClicked: {
popup.contactsStore.removeTrustStatus(userPublicKey);
popup.close();
}
}
StatusButton {
text: qsTr("Verify Identity")
visible: !showIdentityVerifiedUntrustworthy && !showIdentityVerified &&
!showVerifyIdentitySection && isContact && !isVerificationSent
&& !hasReceivedVerificationRequest
onClicked: {
popup.showVerifyIdentitySection = true
}
}
StatusButton {
text: qsTr("Verify Identity pending...")
visible: (!showIdentityVerifiedUntrustworthy && !showIdentityVerified && !isTrusted
&& isContact && isVerificationSent && !showVerificationPendingSection) ||
(hasReceivedVerificationRequest && !isTrusted)
onClicked: {
if (hasReceivedVerificationRequest) {
popup.openPendingRequestPopup()
} else {
popup.showVerificationPendingSection = true
profileView.wizardAnimation.running = true
}
}
}
StatusButton {
text: qsTr("Send verification request")
visible: showVerifyIdentitySection && isContact && !isVerificationSent
onClicked: {
popup.contactsStore.sendVerificationRequest(userPublicKey, Utils.escapeHtml(profileView.challengeTxt.input.text));
profileView.stepsListModel.setProperty(1, "stepCompleted", true);
Global.displayToastMessage(qsTr("Verification request sent"),
"",
"checkmark-circle",
false,
Constants.ephemeralNotificationType.normal,
"");
popup.close();
}
}
StatusButton {
text: qsTr("Confirm Identity")
visible: isContact && isVerificationSent && !isTrusted && showVerificationPendingSection
enabled: verificationChallenge !== "" && verificationResponse !== ""
onClicked: {
popup.showIdentityVerified = true;
popup.showIdentityVerifiedUntrustworthy = false;
popup.showVerificationPendingSection = false;
popup.showVerifyIdentitySection = false;
profileView.stepsListModel.setProperty(2, "stepCompleted", true);
popup.contactsStore.verifiedTrusted(userPublicKey);
popup.isTrusted = true
}
}
StatusButton {
visible: showIdentityVerified || showIdentityVerifiedUntrustworthy
text: qsTr("Rename")
onClicked: {
profileView.nicknamePopup.open()
}
}
StatusButton {
visible: showIdentityVerified || showIdentityVerifiedUntrustworthy
text: qsTr("Close")
onClicked: {
popup.close();
}
}
}
}
StatusScrollView {
id: scrollView
anchors.fill: parent
padding: 0
SharedViews.ProfileView {
id: profileView
width: scrollView.availableWidth
profileStore: popup.profileStore
contactsStore: popup.contactsStore
userPublicKey: popup.userPublicKey
userDisplayName: popup.userDisplayName
userName: popup.userName
userNickname: popup.userNickname
userEnsName: popup.userEnsName
userIcon: popup.userIcon
userBio: popup.userBio
userSocialLinks: popup.userSocialLinks
userIsEnsVerified: popup.userIsEnsVerified
userIsBlocked: popup.userIsBlocked
isAddedContact: popup.isAddedContact
isCurrentUser: popup.isCurrentUser
isContact: popup.isContact
isVerificationSent: popup.isVerificationSent
isVerified: popup.isVerified
isTrusted: popup.isTrusted
hasReceivedVerificationRequest: popup.hasReceivedVerificationRequest
userTrustStatus: popup.userTrustStatus
outgoingVerificationStatus: popup.outgoingVerificationStatus
showVerifyIdentitySection: popup.showVerifyIdentitySection
showVerificationPendingSection: popup.showVerificationPendingSection
showIdentityVerified: popup.showIdentityVerified
showIdentityVerifiedUntrustworthy: popup.showIdentityVerifiedUntrustworthy
challenge: popup.challenge
response: popup.response
userIsUntrustworthy: popup.userIsUntrustworthy
userTrustIsUnknown: popup.userTrustIsUnknown
verificationChallenge: popup.verificationChallenge
verificationResponse: popup.verificationResponse
verificationResponseDisplayName: popup.verificationResponseDisplayName
verificationResponseIcon: popup.verificationResponseIcon
verificationRequestedAt: popup.verificationRequestedAt
verificationRepliedAt: popup.verificationRepliedAt
onContactUnblocked: {
popup.close()
popup.contactUnblocked(publicKey)
}
onContactBlocked: {
popup.close()
popup.contactBlocked(publicKey)
}
onContactAdded: {
popup.close()
popup.contactAdded(publicKey)
}
onContactRemoved: {
popup.close()
}
onNicknameEdited: {
popup.close()
}
}
}
Component {
id: contactVerificationRequestPopupComponent
ContactVerificationRequestPopup {
onResponseSent: {
popup.contactsStore.acceptVerificationRequest(senderPublicKey, response)
}
onVerificationRefused: {
popup.contactsStore.declineVerificationRequest(senderPublicKey)
}
}
}
}

View File

@ -19,9 +19,12 @@ StatusModal {
property string userIcon: "" property string userIcon: ""
property bool userIsEnsVerified property bool userIsEnsVerified
property string challengeText: qsTr("Say who you are / why you want to become a contact...")
property string buttonText: qsTr("Send Contact Request")
signal accepted(string message) signal accepted(string message)
padding: 16 padding: Style.current.padding
header.title: qsTr("Send Contact Request to %1").arg(userDisplayName) header.title: qsTr("Send Contact Request to %1").arg(userDisplayName)
QtObject { QtObject {
@ -33,6 +36,10 @@ StatusModal {
readonly property int contentSpacing: 5 readonly property int contentSpacing: 5
} }
onAboutToShow: {
messageInput.input.edit.forceActiveFocus()
}
ColumnLayout { ColumnLayout {
id: content id: content
anchors.fill: parent anchors.fill: parent
@ -55,7 +62,7 @@ StatusModal {
id: messageInput id: messageInput
charLimit: d.maxMsgLength charLimit: d.maxMsgLength
placeholderText: qsTr("Say who you are / why you want to become a contact...") placeholderText: root.challengeText
input.multiline: true input.multiline: true
minimumHeight: d.msgHeight minimumHeight: d.msgHeight
maximumHeight: d.msgHeight maximumHeight: d.msgHeight
@ -71,7 +78,7 @@ StatusModal {
rightButtons: StatusButton { rightButtons: StatusButton {
enabled: messageInput.valid enabled: messageInput.valid
text: qsTr("Send Contact Request") text: root.buttonText
onClicked: { onClicked: {
root.accepted(Utils.escapeHtml(messageInput.text)); root.accepted(Utils.escapeHtml(messageInput.text));
root.close(); root.close();

View File

@ -15,7 +15,6 @@ ModalPopup {
height: 237 height: 237
width: 400 width: 400
property Popup parentPopup
property string contactAddress: "" property string contactAddress: ""
property string contactName: "" property string contactName: ""

View File

@ -4,6 +4,7 @@ SettingsDirtyToastMessage 1.0 SettingsDirtyToastMessage.qml
ConfirmationDialog 1.0 ConfirmationDialog.qml ConfirmationDialog 1.0 ConfirmationDialog.qml
CommunityIntroDialog 1.0 CommunityIntroDialog.qml CommunityIntroDialog 1.0 CommunityIntroDialog.qml
ContactVerificationRequestPopup 1.0 ContactVerificationRequestPopup.qml ContactVerificationRequestPopup 1.0 ContactVerificationRequestPopup.qml
OutgoingContactVerificationRequestPopup 1.0 OutgoingContactVerificationRequestPopup.qml
DownloadModal 1.0 DownloadModal.qml DownloadModal 1.0 DownloadModal.qml
DownloadPage 1.0 DownloadPage.qml DownloadPage 1.0 DownloadPage.qml
InviteFriendsPopup 1.0 InviteFriendsPopup.qml InviteFriendsPopup 1.0 InviteFriendsPopup.qml
@ -17,7 +18,7 @@ UnblockContactConfirmationDialog 1.0 UnblockContactConfirmationDialog.qml
UserStatusContextMenu 1.0 UserStatusContextMenu.qml UserStatusContextMenu 1.0 UserStatusContextMenu.qml
SignTransactionModal 1.0 SignTransactionModal.qml SignTransactionModal 1.0 SignTransactionModal.qml
SelectAccountModal 1.0 SelectAccountModal.qml SelectAccountModal 1.0 SelectAccountModal.qml
ProfilePopup 1.0 ProfilePopup.qml ProfileDialog 1.0 ProfileDialog.qml
ImageCropWorkflow 1.0 ImageCropWorkflow.qml ImageCropWorkflow 1.0 ImageCropWorkflow.qml
ImportCommunityPopup 1.0 ImportCommunityPopup.qml ImportCommunityPopup 1.0 ImportCommunityPopup.qml
DisplayNamePopup 1.0 DisplayNamePopup.qml DisplayNamePopup 1.0 DisplayNamePopup.qml

View File

@ -8,7 +8,7 @@ import ".."
StatusChatImageValidator { StatusChatImageValidator {
id: root id: root
errorMessage: qsTr("You can only upload %1 images at a time").arg(Constants.maxUploadFiles) errorMessage: qsTr("You can only upload %n image(s) at a time", "", Constants.maxUploadFiles)
onImagesChanged: { onImagesChanged: {
root.isValid = images.length <= Constants.maxUploadFiles root.isValid = images.length <= Constants.maxUploadFiles

View File

@ -57,7 +57,7 @@ ModalPopup {
root.close(); root.close();
} catch (e) { } catch (e) {
console.error('Error sending the transaction', e) console.error('Error sending the transaction', e)
sendingError.text = "Error sending the transaction: " + e.message; sendingError.text = qsTr("Error sending the transaction: %1").arg(e.message);
return sendingError.open() return sendingError.open()
} }
} }

View File

@ -63,8 +63,6 @@ Popup {
searchBox.input.edit.forceActiveFocus() searchBox.input.edit.forceActiveFocus()
if (RootStore.isTenorWarningAccepted) { if (RootStore.isTenorWarningAccepted) {
RootStore.getTrendingsGifs() RootStore.getTrendingsGifs()
} else {
confirmationPopupLoader.active = true
} }
} }
@ -202,7 +200,7 @@ Popup {
sourceComponent: ConfirmationPopup { sourceComponent: ConfirmationPopup {
visible: true visible: true
} }
active: false active: !RootStore.isTenorWarningAccepted
} }
Component { Component {

View File

@ -45,7 +45,7 @@ Popup {
} }
Connections { Connections {
target: mainModule target: mainModule
onOnlineStatusChanged: { function onOnlineStatusChanged() {
root.close() root.close()
} }
} }

View File

@ -179,7 +179,6 @@ QtObject {
function findTokenSymbolByAddress(address) { function findTokenSymbolByAddress(address) {
return walletSectionAllTokens.findTokenSymbolByAddress(address) return walletSectionAllTokens.findTokenSymbolByAddress(address)
} }
function getNameForSavedWalletAddress(address) { function getNameForSavedWalletAddress(address) {

View File

@ -44,7 +44,7 @@ Item {
delegate: StatusListItem { delegate: StatusListItem {
readonly property string balance: enabledNetworkBalance // Needed for the tests readonly property string balance: enabledNetworkBalance // Needed for the tests
objectName: "AssetView_TokenListItem_" + symbol objectName: "AssetView_TokenListItem_" + symbol
width: parent.width width: ListView.view.width
title: name title: name
subTitle: `${enabledNetworkBalance} ${symbol}` subTitle: `${enabledNetworkBalance} ${symbol}`
asset.name: symbol ? Style.png("tokens/" + symbol) : "" asset.name: symbol ? Style.png("tokens/" + symbol) : ""

View File

@ -35,7 +35,7 @@ ColumnLayout {
target: RootStore.history target: RootStore.history
onLoadingTrxHistoryChanged: function(isLoading, address) { onLoadingTrxHistoryChanged: function(isLoading, address) {
if (historyView.account.address.toLowerCase() === address.toLowerCase()) { if (historyView.account.address.toLowerCase() === address.toLowerCase()) {
root.isLoading = isLoading historyView.isLoading = isLoading
} }
} }
} }

View File

@ -0,0 +1,704 @@
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtGraphicalEffects 1.14
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Controls 0.1
import StatusQ.Components 0.1
import StatusQ.Popups 0.1
import StatusQ.Popups.Dialog 0.1
import StatusQ.Core.Utils 0.1 as SQUtils
import utils 1.0
import shared.controls 1.0
import shared.panels 1.0
import shared.popups 1.0
import shared.controls.chat 1.0
import shared.controls.chat.menuItems 1.0
Pane {
id: root
property bool readOnly
property string publicKey: contactsStore.myPublicKey
property var profileStore
property var contactsStore
signal closeRequested()
padding: 0
topPadding: 40
background: StatusDialogBackground {
id: background
}
QtObject {
id: d
property var contactDetails: Utils.getContactDetailsAsJson(root.publicKey)
function reload() {
contactDetails = Utils.getContactDetailsAsJson(root.publicKey)
}
readonly property bool isCurrentUser: root.profileStore.pubkey === root.publicKey
readonly property string userDisplayName: contactDetails.displayName
readonly property string userNickName: contactDetails.localNickname
readonly property string prettyEnsName: '@' + Utils.removeStatusEns(contactDetails.name)
readonly property bool isContact: contactDetails.isContact
readonly property bool isBlocked: contactDetails.isBlocked
readonly property bool isContactRequestSent: contactDetails.isAdded
readonly property bool isContactRequestReceived: contactDetails.hasAddedUs
readonly property int outgoingVerificationStatus: contactDetails.verificationStatus
readonly property int incomingVerificationStatus: contactDetails.incomingVerificationStatus
readonly property bool isVerificationRequestSent:
outgoingVerificationStatus !== Constants.verificationStatus.unverified &&
outgoingVerificationStatus !== Constants.verificationStatus.verified &&
outgoingVerificationStatus !== Constants.verificationStatus.trusted
readonly property bool isVerificationRequestReceived: d.isCurrentUser ? false : root.contactsStore.hasReceivedVerificationRequestFrom(root.publicKey)
readonly property bool isTrusted: outgoingVerificationStatus === Constants.verificationStatus.trusted ||
incomingVerificationStatus === Constants.verificationStatus.trusted
readonly property bool isVerified: outgoingVerificationStatus === Constants.verificationStatus.verified
readonly property string linkToProfile: {
let user = ""
if (d.isCurrentUser)
user = root.profileStore.ensName
else
user = contactDetails.name
if (!user)
user = root.publicKey
return Constants.userLinkPrefix + user
}
readonly property var conns: Connections {
target: Global
function onNickNameChanged(publicKey, nickname) {
if (publicKey === root.publicKey) d.reload()
}
function onContactBlocked(publicKey) {
if (publicKey === root.publicKey) d.reload()
}
function onContactUnblocked(publicKey) {
if (publicKey === root.publicKey) d.reload()
}
}
}
function reload() {
d.reload()
}
Component {
id: btnEditProfileComponent
StatusButton {
size: StatusButton.Size.Small
text: qsTr("Edit Profile")
enabled: !root.readOnly
onClicked: {
Global.changeAppSectionBySectionType(Constants.appSection.profile)
root.closeRequested()
}
}
}
Component {
id: btnSendMessageComponent
StatusButton {
size: StatusButton.Size.Small
text: qsTr("Send Message")
onClicked: {
root.contactsStore.joinPrivateChat(root.publicKey)
root.closeRequested()
}
}
}
Component {
id: btnAcceptContactRequestComponent
ColumnLayout {
spacing: Style.current.halfPadding
StatusBaseText {
color: Theme.palette.baseColor1
font.pixelSize: 13
text: qsTr("Respond to contact request")
}
AcceptRejectOptionsButtonsPanel {
menuButton.visible: false
onAcceptClicked: {
root.contactsStore.acceptContactRequest(root.publicKey)
d.reload()
}
onDeclineClicked: {
root.contactsStore.dismissContactRequest(root.publicKey)
d.reload()
}
}
}
}
Component {
id: btnSendContactRequestComponent
StatusButton {
size: StatusButton.Size.Small
text: qsTr("Send Contact Request")
onClicked: {
let contactRequestPopup = Global.openContactRequestPopup(root.publicKey)
contactRequestPopup.accepted.connect(d.reload)
}
}
}
Component {
id: btnBlockUserComponent
StatusButton {
size: StatusButton.Size.Small
type: StatusBaseButton.Type.Danger
text: qsTr("Block User")
onClicked: Global.blockContactRequested(root.publicKey, d.userDisplayName)
}
}
Component {
id: btnUnblockUserComponent
StatusButton {
size: StatusButton.Size.Small
text: qsTr("Unblock User")
onClicked: Global.unblockContactRequested(root.publicKey, d.userDisplayName)
}
}
Component {
id: txtPendingContactRequestComponent
StatusBaseText {
font.pixelSize: 13
font.weight: Font.Medium
color: Theme.palette.baseColor1
verticalAlignment: Text.AlignVCenter
text: qsTr("Contact Request Pending...")
}
}
Component {
id: txtRejectedContactRequestComponent
StatusBaseText {
font.pixelSize: 13
font.weight: Font.Medium
color: Theme.palette.baseColor1
verticalAlignment: Text.AlignVCenter
text: qsTr("Contact Request Rejected")
}
}
Component {
id: btnRespondToIdRequestComponent
StatusButton {
size: StatusButton.Size.Small
text: qsTr("Respond to ID Request")
onClicked: {
let idRequestPopup = Global.openIncomingIDRequestPopup(root.publicKey)
idRequestPopup.closed.connect(d.reload)
}
}
}
ConfirmationDialog {
id: removeContactConfirmationDialog
header.title: qsTr("Remove contact '%1'").arg(d.userDisplayName)
confirmationText: qsTr("This will remove the user as a contact. Please confirm.")
onConfirmButtonClicked: {
root.contactsStore.removeContact(root.publicKey)
close()
d.reload()
}
}
ConfirmationDialog {
id: removeVerificationConfirmationDialog
header.title: qsTr("Remove contact verification")
confirmationText: qsTr("This will remove the contact's verified status. Please confirm.")
onConfirmButtonClicked: {
root.contactsStore.removeTrustStatus(root.publicKey)
close()
d.reload()
}
}
ColumnLayout {
id: column
spacing: 20
anchors {
fill: parent
leftMargin: Style.current.bigPadding
rightMargin: Style.current.bigPadding
}
RowLayout {
Layout.fillWidth: true
spacing: Style.current.halfPadding
UserImage {
Layout.alignment: Qt.AlignTop
objectName: "ProfileDialog_userImage"
name: d.userDisplayName
pubkey: root.publicKey
image: d.contactDetails.largeImage
interactive: false
imageWidth: 80
imageHeight: imageWidth
showRing: !d.contactDetails.ensVerified
}
ColumnLayout {
Layout.fillWidth: true
Layout.leftMargin: 4
Layout.alignment: Qt.AlignTop
spacing: 4
Item {
id: contactRow
Layout.fillWidth: true
Layout.preferredHeight: childrenRect.height
StatusBaseText {
id: contactName
anchors.left: parent.left
width: Math.min(implicitWidth, contactRow.width - verificationIcons.width - verificationIcons.anchors.leftMargin)
objectName: "ProfileDialog_displayName"
font.bold: true
font.pixelSize: 22
elide: Text.ElideRight
text: d.userDisplayName
}
StatusContactVerificationIcons {
id: verificationIcons
anchors.left: contactName.right
anchors.leftMargin: Style.current.halfPadding
anchors.verticalCenter: contactName.verticalCenter
objectName: "ProfileDialog_userVerificationIcons"
visible: !d.isCurrentUser
isContact: d.isContact
trustIndicator: d.contactDetails.trustStatus
tiny: false
}
}
StatusBaseText {
id: contactSecondaryName
font.pixelSize: 12
color: Theme.palette.baseColor1
text: {
let result = ""
if (d.userNickName) {
if (d.contactDetails.ensVerified)
result = d.prettyEnsName
else
result = d.contactDetails.optionalName // original display name
}
if (result)
return "(%1)".arg(result)
return ""
}
visible: text
}
EmojiHash {
objectName: "ProfileDialog_userEmojiHash"
publicKey: root.publicKey
}
}
Loader {
Layout.alignment: Qt.AlignTop
Layout.preferredHeight: menuButton.visible ? menuButton.height : -1
sourceComponent: {
// current user
if (d.isCurrentUser)
return btnEditProfileComponent
// contact request, outgoing, rejected
if (!d.isContact && d.isContactRequestSent && d.outgoingVerificationStatus === Constants.verificationStatus.declined)
return txtRejectedContactRequestComponent
// contact request, outgoing, pending
if (!d.isContact && d.isContactRequestSent)
return txtPendingContactRequestComponent
// contact request, incoming, pending
if (!d.isContact && d.isContactRequestReceived)
return btnAcceptContactRequestComponent
// contact request, incoming, rejected
if (d.isContactRequestSent && d.incomingVerificationStatus === Constants.verificationStatus.declined)
return btnBlockUserComponent
// verified contact request, incoming, pending
if (d.isContact && !d.isTrusted && d.isVerificationRequestReceived)
return btnRespondToIdRequestComponent
// block user
if (!d.isContact && !d.isBlocked &&
(d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy || d.outgoingVerificationStatus === Constants.verificationStatus.declined))
return btnBlockUserComponent
// send contact request
if (!d.isContact && !d.isBlocked && !d.isContactRequestSent)
return btnSendContactRequestComponent
// blocked contact
if (d.isBlocked)
return btnUnblockUserComponent
// send message
if (d.isContact && !d.isBlocked)
return btnSendMessageComponent
console.warn("!!! UNHANDLED CONTACT ACTION BUTTON; PUBKEY", root.publicKey)
}
}
StatusFlatButton {
id: menuButton
Layout.alignment: Qt.AlignTop
Layout.preferredWidth: height
visible: !d.isCurrentUser
size: StatusBaseButton.Size.Small
horizontalPadding: 6
verticalPadding: 6
icon.name: "more"
icon.color: Theme.palette.directColor1
highlighted: moreMenu.opened
onClicked: moreMenu.popup(-moreMenu.width + width, height + 4)
StatusPopupMenu {
id: moreMenu
width: 230
SendContactRequestMenuItem {
enabled: !d.isContact && !d.isBlocked && !d.isContactRequestSent && !d.contactDetails.removed &&
d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy // we have an action button otherwise
onTriggered: {
moreMenu.close()
let contactRequestPopup = Global.openContactRequestPopup(root.publicKey)
contactRequestPopup.closed.connect(d.reload)
}
}
StatusMenuItem {
text: qsTr("Verify Identity")
icon.name: "checkmark-circle"
enabled: d.isContact && !d.isBlocked &&
d.outgoingVerificationStatus === Constants.verificationStatus.unverified &&
!d.isVerificationRequestReceived
onTriggered: {
moreMenu.close()
let idRequestPopup = Global.openSendIDRequestPopup(root.publicKey)
idRequestPopup.accepted.connect(d.reload)
}
}
StatusMenuItem {
text: qsTr("ID Request Pending...")
icon.name: "checkmark-circle"
enabled: d.isContact && !d.isBlocked && !d.isTrusted && d.isVerificationRequestSent
onTriggered: {
moreMenu.close()
let idRequestPopup = Global.openOutgoingIDRequestPopup(root.publicKey)
idRequestPopup.closed.connect(d.reload)
}
}
StatusMenuItem {
text: qsTr("Rename")
icon.name: "edit_pencil"
onTriggered: {
moreMenu.close()
Global.openNicknamePopupRequested(root.publicKey, d.userNickName,
"%1 (%2)".arg(d.userDisplayName).arg(Utils.getElidedCompressedPk(root.publicKey)))
}
}
StatusMenuItem {
text: qsTr("Reverse Contact Rejection")
icon.name: "refresh"
enabled: d.contactDetails.removed
onTriggered: {
moreMenu.close()
root.contactsStore.removeContactRequestRejection(root.publicKey)
d.reload()
}
}
StatusMenuItem {
text: qsTr("Copy Link to Profile")
icon.name: "copy"
onTriggered: {
moreMenu.close()
root.profileStore.copyToClipboard(d.linkToProfile)
}
}
StatusMenuItem {
text: qsTr("Unblock User")
icon.name: "remove-circle"
enabled: d.isBlocked
onTriggered: {
moreMenu.close()
Global.unblockContactRequested(root.publicKey, d.userDisplayName)
}
}
StatusMenuSeparator {}
StatusMenuItem {
text: qsTr("Mark as Untrustworthy")
icon.name: "warning"
type: StatusMenuItem.Type.Danger
enabled: d.contactDetails.trustStatus === Constants.trustStatus.unknown
onTriggered: {
moreMenu.close()
if (d.isContact && !d.isTrusted && d.isVerificationRequestReceived)
root.contactsStore.verifiedUntrustworthy(root.publicKey)
else
root.contactsStore.markUntrustworthy(root.publicKey)
d.reload()
}
}
StatusMenuItem {
text: qsTr("Remove Untrustworthy Mark")
icon.name: "warning"
enabled: d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy
onTriggered: {
moreMenu.close()
root.contactsStore.removeTrustStatus(root.publicKey)
d.reload()
}
}
StatusMenuItem {
text: qsTr("Remove Identity Verification")
icon.name: "warning"
type: StatusMenuItem.Type.Danger
enabled: d.isContact && d.isTrusted
onTriggered: {
moreMenu.close()
removeVerificationConfirmationDialog.open()
}
}
StatusMenuItem {
text: qsTr("Remove Contact")
icon.name: "remove-contact"
type: StatusMenuItem.Type.Danger
enabled: d.isContact && !d.isBlocked
onTriggered: {
moreMenu.close()
removeContactConfirmationDialog.open()
}
}
StatusMenuItem {
text: qsTr("Cancel Contact Request")
icon.name: "cancel"
type: StatusMenuItem.Type.Danger
enabled: !d.isContact && d.isContactRequestSent && !d.contactDetails.removed
onTriggered: {
moreMenu.close()
root.contactsStore.removeContact(root.publicKey)
d.reload()
}
}
StatusMenuItem {
text: qsTr("Block User")
icon.name: "cancel"
type: StatusMenuItem.Type.Danger
enabled: !d.isBlocked
onTriggered: {
moreMenu.close()
Global.blockContactRequested(root.publicKey, d.userDisplayName)
}
}
}
}
}
StatusDialogDivider {
Layout.fillWidth: true
Layout.leftMargin: -column.anchors.leftMargin
Layout.rightMargin: -column.anchors.rightMargin
Layout.topMargin: -column.spacing
Layout.bottomMargin: -column.spacing
opacity: scrollView.atYBeginning ? 0 : 1
Behavior on opacity { OpacityAnimator {} }
}
StatusScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: -column.anchors.leftMargin
Layout.rightMargin: -column.anchors.rightMargin
Layout.topMargin: -column.spacing
padding: 0
ColumnLayout {
width: scrollView.width
spacing: 20
ProfileBioSocialsPanel {
Layout.fillWidth: true
Layout.leftMargin: column.anchors.leftMargin + Style.current.halfPadding
Layout.rightMargin: column.anchors.rightMargin + Style.current.halfPadding
bio: d.contactDetails.bio
userSocialLinksJson: d.contactDetails.socialLinks
}
GridLayout {
Layout.fillWidth: true
Layout.leftMargin: column.anchors.leftMargin
Layout.rightMargin: column.anchors.rightMargin
flow: GridLayout.TopToBottom
rowSpacing: Style.current.halfPadding
columnSpacing: Style.current.bigPadding
visible: d.isCurrentUser
enabled: visible
columns: 2
rows: 4
StatusBaseText {
Layout.fillWidth: true
text: qsTr("Link to Profile")
font.pixelSize: 13
}
StatusBaseInput {
Layout.fillWidth: true
Layout.preferredHeight: 56
leftPadding: 14
rightPadding: Style.current.halfPadding
topPadding: 0
bottomPadding: 0
placeholder.rightPadding: Style.current.halfPadding
placeholderText: d.linkToProfile
placeholderTextColor: Theme.palette.directColor1
edit.readOnly: true
rightComponent: StatusButton {
anchors.verticalCenter: parent.verticalCenter
borderColor: Theme.palette.primaryColor1
size: StatusBaseButton.Size.Tiny
text: qsTr("Copy")
onClicked: {
text = qsTr("Copied")
root.profileStore.copyToClipboard(d.linkToProfile)
}
}
}
StatusBaseText {
Layout.fillWidth: true
Layout.topMargin: Style.current.smallPadding
text: qsTr("Emoji Hash")
font.pixelSize: 13
}
StatusBaseInput {
Layout.fillWidth: true
Layout.preferredHeight: 56
leftPadding: 14
rightPadding: Style.current.halfPadding
topPadding: 0
bottomPadding: 0
edit.readOnly: true
leftComponent: EmojiHash {
publicKey: root.publicKey
oneRow: !root.readOnly
}
rightComponent: StatusButton {
anchors.verticalCenter: parent.verticalCenter
borderColor: Theme.palette.primaryColor1
size: StatusBaseButton.Size.Tiny
text: qsTr("Copy")
onClicked: {
root.profileStore.copyToClipboard(Utils.getEmojiHashAsJson(root.publicKey).join("").toString())
text = qsTr("Copied")
}
}
}
Rectangle {
Layout.rowSpan: 4
Layout.fillHeight: true
Layout.preferredWidth: height
Layout.alignment: Qt.AlignCenter
color: "transparent"
border.width: 1
border.color: Theme.palette.baseColor2
radius: Style.current.halfPadding
Image {
anchors.centerIn: parent
asynchronous: true
fillMode: Image.PreserveAspectFit
width: 170
height: width
mipmap: true
smooth: false
source: root.profileStore.getQrCodeSource(root.profileStore.pubkey)
}
}
}
StatusTabBar {
Layout.fillWidth: true
Layout.leftMargin: column.anchors.leftMargin
Layout.rightMargin: column.anchors.rightMargin
bottomPadding: -4
StatusTabButton {
leftPadding: 0
width: implicitWidth
text: qsTr("Tokens")
}
StatusTabButton {
width: implicitWidth
text: qsTr("NFTs")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Communities")
}
StatusTabButton {
width: implicitWidth
text: qsTr("Accounts")
}
}
StatusDialogBackground {
Layout.fillWidth: true
Layout.topMargin: -column.spacing
Layout.preferredHeight: 300
color: Theme.palette.baseColor4
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
height: parent.radius
color: parent.color
}
StatusBaseText {
anchors.centerIn: parent
color: Theme.palette.baseColor1
text: qsTr("More content to appear here soon...")
}
}
}
}
}
layer.enabled: !root.readOnly // profile preview has its own layer.effect
layer.effect: OpacityMask {
maskSource: Rectangle {
anchors.centerIn: parent
width: column.width
height: column.height
radius: background.radius
}
}
}

View File

@ -1,484 +0,0 @@
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.Core.Utils 0.1 as StatusQUtils
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
import StatusQ.Popups 0.1
import "../panels"
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 userBio: profileStore.bio
property string userSocialLinks: profileStore.socialLinksJson
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)
objectName: "profileView"
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
userIsEnsVerified: root.userIsEnsVerified
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")
}
ProfileBioSocialsPanel {
Layout.fillWidth: true
Layout.leftMargin: 16
Layout.rightMargin: 16
bio: root.userBio
userSocialLinksJson: root.userSocialLinks
}
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
asset.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 : StatusQUtils.Utils.elideText(root.profileStore.pubkey, 5)
} else if (userIsEnsVerified) {
user = userEnsName
}
if (user === ""){
user = StatusQUtils.Utils.elideText(userPublicKey, 5)
}
return Constants.userLinkPrefix + user;
}
tooltip.text: qsTr("Copied to clipboard")
tooltip.timeout: 1000
asset.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(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(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
asset.name: "checkbox"
asset.width: 16
asset.height: 16
asset.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
asset.name: "copy"
iconButton.onClicked: {
globalUtils.copyToClipboard(subTitle)
tooltip.open();
}
}
StatusRoundIcon {
id: dangerIcon
visible: confirmUntrustworthyLbl.visible
asset.name: "tiny/subtract"
asset.width: 5
asset.height: 21
asset.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 %1 to enter a code or phrase you have sent to them via a different communication channel (phone, post, etc...).").arg(userDisplayName)
}
MessageView {
id: challengeMessage
visible: root.showVerificationPendingSection
Layout.fillWidth: true
isMessage: true
shouldRepeatHeader: true
messageTimestamp: root.verificationRequestedAt
senderId: profileStore.pubkey
senderDisplayName: userProfile.name
senderIcon: userProfile.icon
messageText: root.verificationChallenge
messageContentType: Constants.messageContentType.messageType
placeholderMessage: true
}
MessageView {
id: responseMessage
visible: root.showVerificationPendingSection && !!root.verificationResponse
Layout.fillWidth: true
isMessage: true
shouldRepeatHeader: true
messageTimestamp: root.verificationRepliedAt
senderId: root.userPublicKey
senderDisplayName: root.verificationResponseDisplayName
senderIcon: root.verificationResponseIcon
messageText: 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)
}
}
}

View File

@ -106,7 +106,7 @@ StatusPopupMenu {
property var emojiReactionsReactedByUser: [] property var emojiReactionsReactedByUser: []
signal openProfileClicked(string publicKey, string state) signal openProfileClicked(string publicKey)
signal pinMessage(string messageId) signal pinMessage(string messageId)
signal unpinMessage(string messageId) signal unpinMessage(string messageId)
signal pinnedMessagesLimitReached(string messageId) signal pinnedMessagesLimitReached(string messageId)
@ -238,7 +238,7 @@ StatusPopupMenu {
id: viewProfileAction id: viewProfileAction
enabled: root.isProfile && !root.pinnedPopup enabled: root.isProfile && !root.pinnedPopup
onTriggered: { onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, "") root.openProfileClicked(root.selectedUserPublicKey)
root.close() root.close()
} }
} }
@ -256,8 +256,7 @@ StatusPopupMenu {
enabled: root.isProfile && !root.isMe && !root.isContact enabled: root.isProfile && !root.isMe && !root.isContact
&& !root.isBlockedContact && !root.hasPendingContactRequest && !root.isBlockedContact && !root.hasPendingContactRequest
onTriggered: { onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, Global.openContactRequestPopup(root.selectedUserPublicKey)
Constants.profilePopupStates.contactRequest)
root.close() root.close()
} }
} }
@ -270,8 +269,7 @@ StatusPopupMenu {
&& root.outgoingVerificationStatus === Constants.verificationStatus.unverified && root.outgoingVerificationStatus === Constants.verificationStatus.unverified
&& !root.hasReceivedVerificationRequestFrom && !root.hasReceivedVerificationRequestFrom
onTriggered: { onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, Global.openSendIDRequestPopup(root.selectedUserPublicKey)
Constants.profilePopupStates.verifyIdentity)
root.close() root.close()
} }
} }
@ -288,11 +286,9 @@ StatusPopupMenu {
|| root.isVerificationRequestSent) || root.isVerificationRequestSent)
onTriggered: { onTriggered: {
if (hasReceivedVerificationRequestFrom) { if (hasReceivedVerificationRequestFrom) {
root.openProfileClicked(root.selectedUserPublicKey, Global.openIncomingIDRequestPopup(root.selectedUserPublicKey)
Constants.profilePopupStates.respondToPendingRequest)
} else if (root.isVerificationRequestSent) { } else if (root.isVerificationRequestSent) {
root.openProfileClicked(root.selectedUserPublicKey, Global.openOutgoingIDRequestPopup(root.selectedUserPublicKey)
Constants.profilePopupStates.showVerificationPendingSection)
} }
root.close() root.close()
@ -304,8 +300,8 @@ StatusPopupMenu {
icon.name: "edit_pencil" icon.name: "edit_pencil"
enabled: root.isProfile && !root.isMe enabled: root.isProfile && !root.isMe
onTriggered: { onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, Global.openNicknamePopupRequested(root.selectedUserPublicKey, d.contactDetails.localNickname,
Constants.profilePopupStates.openNickname) "%1 (%2)".arg(root.selectedUserDisplayName).arg(Utils.getElidedCompressedPk(root.selectedUserPublicKey)))
root.close() root.close()
} }
} }
@ -314,7 +310,7 @@ StatusPopupMenu {
text: qsTr("Unblock User") text: qsTr("Unblock User")
icon.name: "remove-circle" icon.name: "remove-circle"
enabled: root.isProfile && !root.isMe && root.isBlockedContact enabled: root.isProfile && !root.isMe && root.isBlockedContact
onTriggered: root.store.contactsStore.unblockContact(root.selectedUserPublicKey) onTriggered: Global.unblockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName)
} }
StatusMenuSeparator { StatusMenuSeparator {
@ -344,7 +340,7 @@ StatusPopupMenu {
icon.name: "cancel" icon.name: "cancel"
type: StatusMenuItem.Type.Danger type: StatusMenuItem.Type.Danger
enabled: root.isProfile && !root.isMe && !root.isBlockedContact enabled: root.isProfile && !root.isMe && !root.isBlockedContact
onTriggered: root.store.contactsStore.blockContact(root.selectedUserPublicKey) onTriggered: Global.blockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName)
} }
StatusMenuItem { StatusMenuItem {

View File

@ -7,7 +7,7 @@ TransactionPreview 1.0 TransactionPreview.qml
TransactionSigner 1.0 TransactionSigner.qml TransactionSigner 1.0 TransactionSigner.qml
TransactionStackView 1.0 TransactionStackView.qml TransactionStackView 1.0 TransactionStackView.qml
PasswordView 1.0 PasswordView.qml PasswordView 1.0 PasswordView.qml
ProfileView 1.0 ProfileView.qml ProfileDialogView 1.0 ProfileDialogView.qml
AssetsView 1.0 AssetsView.qml AssetsView 1.0 AssetsView.qml
HistoryView 1.0 HistoryView.qml HistoryView 1.0 HistoryView.qml
AssetsDetailView 1.0 AssetsDetailView.qml AssetsDetailView 1.0 AssetsDetailView.qml

View File

@ -280,16 +280,6 @@ QtObject {
readonly property int blockedContacts: 6 readonly property int blockedContacts: 6
} }
readonly property QtObject profilePopupStates: QtObject {
readonly property string openNickname: "openNickname"
readonly property string contactRequest: "contactRequest"
readonly property string blockUser: "blockUser"
readonly property string unblockUser: "unblockUser"
readonly property string verifyIdentity: "verifyIdentity"
readonly property string showVerificationPendingSection: "showVerificationPendingSection"
readonly property string respondToPendingRequest: "respondToPendingRequest"
}
readonly property QtObject validators: QtObject { readonly property QtObject validators: QtObject {
readonly property list<StatusValidator> displayName: [ readonly property list<StatusValidator> displayName: [
StatusMinLengthValidator { StatusMinLengthValidator {
@ -567,7 +557,7 @@ QtObject {
readonly property int maxNumberOfPins: 3 readonly property int maxNumberOfPins: 3
readonly property var acceptedImageExtensions: [".png", ".jpg", ".jpeg", ".svg", ".gif"] readonly property var acceptedImageExtensions: [".png", ".jpg", ".jpeg", ".svg", ".gif"]
readonly property var acceptedDragNDropImageExtensions: [".png", ".jpg", ".jpeg", ".heif", "tif", ".tiff"] readonly property var acceptedDragNDropImageExtensions: [".png", ".jpg", ".jpeg", ".heif", ".tif", ".tiff"]
readonly property string mentionSpanTag: `<span style="background-color: ${Style.current.mentionBgColor};"><a style="color:${Style.current.mentionColor};text-decoration:none" href='http://'>` readonly property string mentionSpanTag: `<span style="background-color: ${Style.current.mentionBgColor};"><a style="color:${Style.current.mentionColor};text-decoration:none" href='http://'>`

View File

@ -38,7 +38,16 @@ Item {
signal openCreateChatView() signal openCreateChatView()
signal closeCreateChatView() signal closeCreateChatView()
signal openProfilePopupRequested(string publicKey, var parentPopup, string state) signal openProfilePopupRequested(string publicKey, var parentPopup)
signal openNicknamePopupRequested(string publicKey, string nickname, string subtitle)
signal nickNameChanged(string publicKey, string nickname)
signal blockContactRequested(string publicKey, string contactName)
signal contactBlocked(string publicKey)
signal unblockContactRequested(string publicKey, string contactName)
signal contactUnblocked(string publicKey)
signal openChangeProfilePicPopup() signal openChangeProfilePicPopup()
signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url) signal displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
signal openEditDisplayNamePopup() signal openEditDisplayNamePopup()
@ -50,7 +59,7 @@ Item {
userPublicKey: publicKey, userPublicKey: publicKey,
userDisplayName: contactDetails.displayName, userDisplayName: contactDetails.displayName,
userIcon: contactDetails.largeImage, userIcon: contactDetails.largeImage,
userIsEnsVerified: contactDetails.ensVerified, userIsEnsVerified: contactDetails.ensVerified
}) })
} }
@ -61,8 +70,56 @@ Item {
}) })
} }
function openProfilePopup(publicKey, parentPopup, state = "") { function openSendIDRequestPopup(publicKey) {
openProfilePopupRequested(publicKey, parentPopup, state); const contactDetails = Utils.getContactDetailsAsJson(publicKey);
return openPopup(sendIDRequestPopupComponent, {
userPublicKey: publicKey,
userDisplayName: contactDetails.displayName,
userIcon: contactDetails.largeImage,
userIsEnsVerified: contactDetails.ensVerified,
"header.title": qsTr("Verify %1's Identity").arg(contactDetails.displayName),
challengeText: qsTr("Ask a question that only the real %1 will be able to answer e.g. a question about a shared experience, or ask %1 to enter a code or phrase you have sent to them via a different communication channel (phone, post, etc...).").arg(contactDetails.displayName),
buttonText: qsTr("Send verification request")
})
}
function openIncomingIDRequestPopup(publicKey) {
try {
const request = appMain.rootStore.profileSectionStore.contactsStore.getVerificationDetailsFromAsJson(publicKey)
return openPopup(contactVerificationRequestPopupComponent, {
senderPublicKey: request.from,
senderDisplayName: request.displayName,
senderIcon: request.icon,
challengeText: request.challenge,
responseText: request.response,
messageTimestamp: request.requestedAt,
responseTimestamp: request.repliedAt
})
} catch (e) {
console.error("Error getting or parsing verification data", e)
}
}
function openOutgoingIDRequestPopup(publicKey) {
try {
const verificationDetails = appMain.rootStore.profileSectionStore.contactsStore.getSentVerificationDetailsAsJson(publicKey)
return openPopup(contactOutgoingVerificationRequestPopupComponent, {
userPublicKey: publicKey,
verificationStatus: verificationDetails.requestStatus,
verificationChallenge: verificationDetails.challenge,
verificationResponse: verificationDetails.response,
verificationResponseDisplayName: verificationDetails.displayName,
verificationResponseIcon: verificationDetails.icon,
verificationRequestedAt: verificationDetails.requestedAt,
verificationRepliedAt: verificationDetails.repliedAt
})
} catch (e) {
console.error("Error getting or parsing verification data", e)
}
}
function openProfilePopup(publicKey, parentPopup) {
openProfilePopupRequested(publicKey, parentPopup)
} }
function openActivityCenterPopup() { function openActivityCenterPopup() {
@ -145,9 +202,45 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
rootStore: appMain.rootStore rootStore: appMain.rootStore
contactsStore: appMain.rootStore.contactStore contactsStore: appMain.rootStore.contactStore
onClosed: { onClosed: destroy()
destroy() }
}
Component {
id: sendIDRequestPopupComponent
SendContactRequestModal {
anchors.centerIn: parent
onAccepted: appMain.rootStore.profileSectionStore.contactsStore.sendVerificationRequest(userPublicKey, message)
onClosed: destroy()
}
}
Component {
id: contactVerificationRequestPopupComponent
ContactVerificationRequestPopup {
onResponseSent: {
appMain.rootStore.profileSectionStore.contactsStore.acceptVerificationRequest(senderPublicKey, response)
} }
onVerificationRefused: {
appMain.rootStore.profileSectionStore.contactsStore.declineVerificationRequest(senderPublicKey)
}
onClosed: destroy()
}
}
Component {
id: contactOutgoingVerificationRequestPopupComponent
OutgoingContactVerificationRequestPopup {
onVerificationRequestCanceled: {
appMain.rootStore.profileSectionStore.contactsStore.cancelVerificationRequest(userPublicKey)
}
onUntrustworthyVerified: {
appMain.rootStore.profileSectionStore.contactsStore.verifiedUntrustworthy(userPublicKey)
}
onTrustedVerified: {
appMain.rootStore.profileSectionStore.contactsStore.verifiedTrusted(userPublicKey)
}
onClosed: destroy()
} }
} }
} }

View File

@ -580,7 +580,7 @@ QtObject {
function isEnsVerified(publicKey, getVerificationRequest=true) { function isEnsVerified(publicKey, getVerificationRequest=true) {
if (!publicKey) if (!publicKey)
return false return false
return getContactDetailsAsJson(publicKey, getVerificationRequest).ensVerified return getContactDetailsAsJson(publicKey, getVerificationRequest).ensVerified
} }