diff --git a/src/app/modules/main/module.nim b/src/app/modules/main/module.nim
index 31cc1565a9..cb2ba2bc29 100644
--- a/src/app/modules/main/module.nim
+++ b/src/app/modules/main/module.nim
@@ -760,6 +760,7 @@ method getContactDetailsAsJson*[T](self: Module[T], publicKey: string, getVerifi
requestStatus = self.getVerificationRequestFrom(publicKey).status.int
let jsonObj = %* {
"displayName": name,
+ "optionalName": self.controller.getContactDetails(contact.id).optionalName, # original display name, if renamed
"displayIcon": contact.image.thumbnail,
"publicKey": contact.id,
"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)
method onDisplayKeycardSharedModuleFlow*[T](self: Module[T]) =
- self.view.emitDisplayKeycardSharedModuleFlow()
\ No newline at end of file
+ self.view.emitDisplayKeycardSharedModuleFlow()
diff --git a/src/app/modules/shared_models/user_model.nim b/src/app/modules/shared_models/user_model.nim
index 08f3fb639e..7211ff6437 100644
--- a/src/app/modules/shared_models/user_model.nim
+++ b/src/app/modules/shared_models/user_model.nim
@@ -229,6 +229,7 @@ QtObject:
self.items[ind].ensName = ensName
self.items[ind].localNickname = localNickname
self.items[ind].alias = alias
+ self.items[ind].icon = icon
self.items[ind].isUntrustworthy = isUntrustworthy
let index = self.createIndex(ind, 0, nil)
@@ -310,4 +311,4 @@ QtObject:
return self.items.map(i => i.pubKey)
proc containsItemWithPubKey*(self: Model, pubKey: string): bool =
- return self.findIndexByPubKey(pubKey) != -1
\ No newline at end of file
+ return self.findIndexByPubKey(pubKey) != -1
diff --git a/ui/StatusQ/src/StatusQ/Components/StatusContactVerificationIcons.qml b/ui/StatusQ/src/StatusQ/Components/StatusContactVerificationIcons.qml
index 7d5de32393..2067860e57 100644
--- a/ui/StatusQ/src/StatusQ/Components/StatusContactVerificationIcons.qml
+++ b/ui/StatusQ/src/StatusQ/Components/StatusContactVerificationIcons.qml
@@ -1,21 +1,23 @@
-import QtQuick 2.0
+import QtQuick 2.14
import StatusQ.Core 0.1
+import StatusQ.Controls 0.1
import StatusQ.Core.Theme 0.1
Row {
id: root
property bool isContact: false
- property var trustIndicator: StatusContactVerificationIcons.TrustedType.None
+ property int trustIndicator: StatusContactVerificationIcons.TrustedType.None
+ property bool tiny: true
property StatusAssetSettings mutualConnectionIcon: StatusAssetSettings {
- name: "tiny/tiny-contact"
+ name: root.tiny ? "tiny/tiny-contact" : "tiny/contact"
color: Theme.palette.indirectColor1
- width: dummyImage.width
- height: dummyImage.height
- bgWidth: 10
- bgHeight: 10
+ width: Math.min(bgWidth, dummyImage.width)
+ height: Math.min(bgHeight, dummyImage.height)
+ bgWidth: root.tiny ? 10 : 16.5
+ bgHeight: root.tiny ? 10 : 16.5
bgColor: Theme.palette.primaryColor1
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
@@ -26,12 +28,13 @@ Row {
property StatusAssetSettings trustContactIcon: StatusAssetSettings {
// 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
- width: dummyImage.width
- height: dummyImage.height
- bgWidth: 10
- bgHeight: 10
+ width: Math.min(bgWidth, dummyImage.width)
+ height: Math.min(bgHeight, dummyImage.height)
+ bgWidth: root.tiny ? 10 : 16
+ bgHeight: root.tiny ? 10 : 16
bgColor: root.trustIndicator === StatusContactVerificationIcons.TrustedType.Verified ? Theme.palette.primaryColor1 : Theme.palette.dangerColor1
// Only used to get implicit width and height from the actual image
property Image dummyImage: Image {
@@ -49,27 +52,34 @@ Row {
spacing: 4
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 {
- visible: root.isContact
- asset.name: root.mutualConnectionIcon.name
- 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
+ visible: root.isContact && root.trustIndicator !== StatusContactVerificationIcons.TrustedType.Verified
+ asset: root.mutualConnectionIcon
}
StatusRoundIcon {
visible: root.trustIndicator !== StatusContactVerificationIcons.TrustedType.None
- asset.name: root.trustContactIcon.name
- 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
+ asset: root.trustContactIcon
}
}
diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml b/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml
index 6ab39fb1ac..02d91a39ed 100644
--- a/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml
+++ b/ui/StatusQ/src/StatusQ/Controls/StatusBaseButton.qml
@@ -70,6 +70,7 @@ Button {
icon.height: 24
icon.width: 24
+ icon.color: d.textColor
background: Rectangle {
radius: root.radius
@@ -90,7 +91,7 @@ Button {
rotation: root.asset.rotation
opacity: !loading && root.icon.name !== ""
visible: root.icon.name !== ""
- color: d.textColor
+ color: root.icon.color
}
StatusEmoji {
Layout.preferredWidth: visible ? root.icon.width : 0
diff --git a/ui/StatusQ/src/StatusQ/Controls/StatusPickerButton.qml b/ui/StatusQ/src/StatusQ/Controls/StatusPickerButton.qml
index 949dd9dae2..3a6ad9bd3f 100644
--- a/ui/StatusQ/src/StatusQ/Controls/StatusPickerButton.qml
+++ b/ui/StatusQ/src/StatusQ/Controls/StatusPickerButton.qml
@@ -14,7 +14,7 @@ Button {
property var type: StatusPickerButton.Type.Next
/*!
- \qmlproperty StatusAssetSettings StatusPickerButton::image
+ \qmlproperty StatusAssetSettings StatusPickerButton::asset
This property holds the image settings information.
*/
property StatusAssetSettings asset: StatusAssetSettings {
diff --git a/ui/StatusQ/src/StatusQ/Core/StatusCenteredFlow.qml b/ui/StatusQ/src/StatusQ/Core/StatusCenteredFlow.qml
index 7fe978ad53..bd329978fc 100644
--- a/ui/StatusQ/src/StatusQ/Core/StatusCenteredFlow.qml
+++ b/ui/StatusQ/src/StatusQ/Core/StatusCenteredFlow.qml
@@ -57,10 +57,14 @@ Item {
onCenteredChanged: flow.onPositioningComplete()
+ implicitHeight: flow.implicitHeight
+
Flow {
id: flow
- anchors.fill: parent
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
onPositioningComplete: {
if (!root.centered || children.length === 0)
diff --git a/ui/StatusQ/src/StatusQ/Core/Theme/Theme.qml b/ui/StatusQ/src/StatusQ/Core/Theme/Theme.qml
index 662f0f203e..ddff0de891 100644
--- a/ui/StatusQ/src/StatusQ/Core/Theme/Theme.qml
+++ b/ui/StatusQ/src/StatusQ/Core/Theme/Theme.qml
@@ -14,7 +14,7 @@ QtObject {
FontSizeXXL
}
- property QtObject palette: StatusLightTheme {}
+ property ThemePalette palette: StatusLightTheme {}
property int primaryTextFontSize: 15
property int secondaryTextFontSize: 14
diff --git a/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialog.qml b/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialog.qml
index feed40321e..5ba571f001 100644
--- a/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialog.qml
+++ b/ui/StatusQ/src/StatusQ/Popups/Dialog/StatusDialog.qml
@@ -10,6 +10,8 @@ import StatusQ.Core.Theme 0.1
Dialog {
id: root
+ property string subtitle
+
anchors.centerIn: Overlay.overlay
padding: 16
@@ -25,8 +27,9 @@ Dialog {
background: StatusDialogBackground {}
header: StatusDialogHeader {
- visible: root.title
+ visible: root.title || root.subtitle
headline.title: root.title
+ headline.subtitle: root.subtitle
actions.closeButton.onClicked: root.close()
}
diff --git a/ui/StatusQ/src/StatusQ/Popups/StatusColorDialog.qml b/ui/StatusQ/src/StatusQ/Popups/StatusColorDialog.qml
index a5209a41db..6e5d9962a8 100644
--- a/ui/StatusQ/src/StatusQ/Popups/StatusColorDialog.qml
+++ b/ui/StatusQ/src/StatusQ/Popups/StatusColorDialog.qml
@@ -77,7 +77,7 @@ StatusModal {
validators: [
StatusRegularExpressionValidator {
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
@@ -115,7 +115,7 @@ StatusModal {
}
StatusBaseText {
- text: qsTr("Standart colours")
+ text: qsTr("Standard colours")
font.pixelSize: 15
}
diff --git a/ui/StatusQ/src/assets/img/icons/checkmark-circle.svg b/ui/StatusQ/src/assets/img/icons/checkmark-circle.svg
index 1f1c1fd608..d7e7be03ed 100644
--- a/ui/StatusQ/src/assets/img/icons/checkmark-circle.svg
+++ b/ui/StatusQ/src/assets/img/icons/checkmark-circle.svg
@@ -1,4 +1,3 @@
diff --git a/ui/StatusQ/src/assets/img/icons/tiny/exclamation.svg b/ui/StatusQ/src/assets/img/icons/tiny/exclamation.svg
new file mode 100644
index 0000000000..a4f451572a
--- /dev/null
+++ b/ui/StatusQ/src/assets/img/icons/tiny/exclamation.svg
@@ -0,0 +1,3 @@
+
diff --git a/ui/StatusQ/src/assets/img/icons/tiny/subtract.svg b/ui/StatusQ/src/assets/img/icons/tiny/tiny-exclamation.svg
similarity index 100%
rename from ui/StatusQ/src/assets/img/icons/tiny/subtract.svg
rename to ui/StatusQ/src/assets/img/icons/tiny/tiny-exclamation.svg
diff --git a/ui/StatusQ/src/assets/img/icons/warning.svg b/ui/StatusQ/src/assets/img/icons/warning.svg
index 75d435681f..4808e96489 100644
--- a/ui/StatusQ/src/assets/img/icons/warning.svg
+++ b/ui/StatusQ/src/assets/img/icons/warning.svg
@@ -1,5 +1,3 @@
diff --git a/ui/app/AppLayouts/Chat/popups/ContactRequestsPopup.qml b/ui/app/AppLayouts/Chat/popups/ContactRequestsPopup.qml
index 38949ba97d..fd14cb209c 100644
--- a/ui/app/AppLayouts/Chat/popups/ContactRequestsPopup.qml
+++ b/ui/app/AppLayouts/Chat/popups/ContactRequestsPopup.qml
@@ -37,9 +37,7 @@ ModalPopup {
Global.openProfilePopup(model.pubKey)
}
onBlockContactActionTriggered: {
- blockContactConfirmationDialog.contactName = model.displayName
- blockContactConfirmationDialog.contactAddress = model.pubKey
- blockContactConfirmationDialog.open()
+ Global.blockContactRequested(model.pubKey, model.displayName)
}
onAcceptClicked: {
popup.store.acceptContactRequest(model.pubKey)
@@ -54,14 +52,6 @@ ModalPopup {
width: parent.width
height: children[0].height
- BlockContactConfirmationDialog {
- id: blockContactConfirmationDialog
- onBlockButtonClicked: {
- popup.store.blockContact(blockContactConfirmationDialog.contactAddress)
- blockContactConfirmationDialog.close()
- }
- }
-
ConfirmationDialog {
id: declineAllDialog
header.title: qsTr("Decline all contacts")
diff --git a/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml b/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml
index d848bda7cf..97c7582088 100644
--- a/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml
+++ b/ui/app/AppLayouts/Chat/popups/RenameGroupPopup.qml
@@ -23,7 +23,6 @@ StatusDialog {
signal updateGroupChatDetails(string groupName, string groupColor, string groupImage)
- anchors.centerIn: parent
title: qsTr("Edit group name and image")
width: 480
height: 610
@@ -34,7 +33,7 @@ StatusDialog {
}
onOpened: {
- groupName.forceActiveFocus(Qt.MouseFocusReason)
+ groupName.input.edit.forceActiveFocus()
groupName.text = root.activeGroupName.substring(0, d.nameCharLimit)
colorSelectionGrid.selectedColor = activeGroupColor
diff --git a/ui/app/AppLayouts/Chat/popups/community/CommunityDetailPopup.qml b/ui/app/AppLayouts/Chat/popups/community/CommunityDetailPopup.qml
index eb6c89d3ba..5b659c3e04 100644
--- a/ui/app/AppLayouts/Chat/popups/community/CommunityDetailPopup.qml
+++ b/ui/app/AppLayouts/Chat/popups/community/CommunityDetailPopup.qml
@@ -81,7 +81,7 @@ StatusModal {
}
StatusBaseText {
- text: qsTr("%1 members").arg(nbMembers)
+ text: qsTr("%n member(s)", "", nbMembers)
font.pixelSize: 15
font.weight: Font.Medium
color: Theme.palette.directColor1
diff --git a/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml b/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml
index 58de1e2419..e39c577d2e 100644
--- a/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml
+++ b/ui/app/AppLayouts/Chat/popups/community/CreateCategoryPopup.qml
@@ -34,7 +34,7 @@ StatusModal {
root.channels = []
root.store.prepareEditCategoryModel(categoryId);
}
- root.contentItem.categoryName.input.forceActiveFocus(Qt.MouseFocusReason)
+ root.contentItem.categoryName.input.edit.forceActiveFocus()
}
onClosed: destroy()
@@ -42,9 +42,7 @@ StatusModal {
return contentItem.categoryName.valid
}
- header.title: isEdit ?
- qsTr("Edit category") :
- qsTr("New category")
+ header.title: isEdit ? qsTr("Edit category") : qsTr("New category")
contentItem: Column {
property alias categoryName: nameInput
@@ -59,6 +57,7 @@ StatusModal {
anchors.leftMargin: 16
input.edit.objectName: "createOrEditCommunityCategoryNameInput"
+ input.clearable: true
label: qsTr("Category title")
charLimit: maxCategoryNameLength
placeholderText: qsTr("Name the category")
@@ -123,6 +122,8 @@ StatusModal {
anchors.horizontalCenter: parent.horizontalCenter
height: visible ? implicitHeight : 0
title: "#" + model.name
+ asset.width: 30
+ asset.height: 30
asset.emoji: model.emoji
asset.color: model.color
asset.imgIsIdenticon: false
diff --git a/ui/app/AppLayouts/Chat/stores/MessageStore.qml b/ui/app/AppLayouts/Chat/stores/MessageStore.qml
index e5f1a8e3c4..e0f6341617 100644
--- a/ui/app/AppLayouts/Chat/stores/MessageStore.qml
+++ b/ui/app/AppLayouts/Chat/stores/MessageStore.qml
@@ -1,8 +1,6 @@
-import QtQuick 2.13
+import QtQuick 2.14
import utils 1.0
-import StatusQ.Core.Utils 0.1 as StatusQUtils
-
QtObject {
id: root
@@ -172,7 +170,7 @@ QtObject {
function interpretMessage(msg) {
if (msg.startsWith("/shrug")) {
- return msg.replace("/shrug", "") + " ¯\\\\\\_(ツ)\\_/¯"
+ return msg.replace("/shrug", "") + " ¯\\\\\\_(ツ)\\_/¯"
}
if (msg.startsWith("/tableflip")) {
return msg.replace("/tableflip", "") + " (╯°□°)╯︵ ┻━┻"
diff --git a/ui/app/AppLayouts/Chat/stores/RootStore.qml b/ui/app/AppLayouts/Chat/stores/RootStore.qml
index 52334ee50f..9479681074 100644
--- a/ui/app/AppLayouts/Chat/stores/RootStore.qml
+++ b/ui/app/AppLayouts/Chat/stores/RootStore.qml
@@ -401,9 +401,9 @@ QtObject {
if (index > -1) {
const pk = link.substring(index + 3)
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 () {
- if (isChatKey(pk)) {
+ if (Utils.isChatKey(pk)) {
chatCommunitySectionModule.createOneToOneChat("", pk, "")
} else {
// Not Refactored Yet
diff --git a/ui/app/AppLayouts/Chat/stores/StickerData.qml b/ui/app/AppLayouts/Chat/stores/StickerData.qml
index bb5a369ac8..604262d95c 100644
--- a/ui/app/AppLayouts/Chat/stores/StickerData.qml
+++ b/ui/app/AppLayouts/Chat/stores/StickerData.qml
@@ -1,8 +1,4 @@
-import QtQuick 2.3
-import QtQuick.Controls 2.3
-import QtQuick.Controls 2.12 as QQC2
-import QtQuick.Layouts 1.3
-import Qt.labs.platform 1.1
+import QtQml.Models 2.14
ListModel {
ListElement {
@@ -58,9 +54,3 @@ ListModel {
url: "QmY4QULmzFQ2AAbEuMvnd3Nd7qD8eWtyxiLD9CAf3kFZWU"
}
}
-
-/*##^##
-Designer {
- D{i:0;autoSize:true;height:480;width:640}
-}
-##^##*/
diff --git a/ui/app/AppLayouts/Chat/stores/StickerPackData.qml b/ui/app/AppLayouts/Chat/stores/StickerPackData.qml
index 23153a0102..541ad1569d 100644
--- a/ui/app/AppLayouts/Chat/stores/StickerPackData.qml
+++ b/ui/app/AppLayouts/Chat/stores/StickerPackData.qml
@@ -1,5 +1,4 @@
-import QtQuick 2.13
-import QtQuick.Controls 2.13
+import QtQml.Models 2.14
ListModel {
ListElement {
@@ -24,9 +23,3 @@ ListModel {
thumbnail: "QmZdTTRiMvupRUWq6ctVbuPfEmc8Js53TmBKyjSYNHmGdi"
}
}
-
-/*##^##
-Designer {
- D{i:0;autoSize:true;height:480;width:640}
-}
-##^##*/
diff --git a/ui/app/AppLayouts/Chat/views/ChatContentView.qml b/ui/app/AppLayouts/Chat/views/ChatContentView.qml
index d8a472571c..d3175283d7 100644
--- a/ui/app/AppLayouts/Chat/views/ChatContentView.qml
+++ b/ui/app/AppLayouts/Chat/views/ChatContentView.qml
@@ -108,7 +108,7 @@ ColumnLayout {
}
onOpenProfileClicked: {
- Global.openProfilePopup(publicKey, null, state)
+ Global.openProfilePopup(publicKey, null)
}
onDeleteMessage: {
diff --git a/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml b/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml
index 2310eec199..c680dd8d93 100644
--- a/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml
+++ b/ui/app/AppLayouts/Chat/views/ChatContextMenuView.qml
@@ -185,9 +185,6 @@ StatusPopupMenu {
Global.openPopup(deleteChatConfirmationDialogComponent)
close()
}
- onClosed: {
- destroy()
- }
}
}
diff --git a/ui/app/AppLayouts/Chat/views/ChatView.qml b/ui/app/AppLayouts/Chat/views/ChatView.qml
index 6dc01b5aaa..ac2350fe46 100644
--- a/ui/app/AppLayouts/Chat/views/ChatView.qml
+++ b/ui/app/AppLayouts/Chat/views/ChatView.qml
@@ -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 {
id: quickActionMessageOptionsMenu
store: root.rootStore
onOpenProfileClicked: {
- Global.openProfilePopup(publicKey, null, state)
+ Global.openProfilePopup(publicKey, null)
}
onCreateOneToOneChat: {
Global.changeAppSectionBySectionType(Constants.appSection.chat)
diff --git a/ui/app/AppLayouts/Onboarding/popups/BeforeGetStartedModal.qml b/ui/app/AppLayouts/Onboarding/popups/BeforeGetStartedModal.qml
index dd4acf6f2e..ef267092b6 100644
--- a/ui/app/AppLayouts/Onboarding/popups/BeforeGetStartedModal.qml
+++ b/ui/app/AppLayouts/Onboarding/popups/BeforeGetStartedModal.qml
@@ -14,7 +14,6 @@ StatusDialog {
id: root
width: 480
- anchors.centerIn: parent
closePolicy: Popup.NoAutoClose
header: StatusDialogHeader {
diff --git a/ui/app/AppLayouts/Profile/ProfileLayout.qml b/ui/app/AppLayouts/Profile/ProfileLayout.qml
index 8554250539..16a58b3099 100644
--- a/ui/app/AppLayouts/Profile/ProfileLayout.qml
+++ b/ui/app/AppLayouts/Profile/ProfileLayout.qml
@@ -38,10 +38,6 @@ StatusSectionLayout {
}
}
- Component.onCompleted: {
- Global.privacyModuleInst = store.privacyStore.privacyModule
- }
-
QtObject {
id: d
@@ -106,6 +102,7 @@ StatusSectionLayout {
walletStore: root.store.walletStore
profileStore: root.store.profileStore
privacyStore: root.store.privacyStore
+ contactsStore: root.store.contactsStore
sectionTitle: root.store.getNameForSubsection(Constants.settingsSubsection.profile)
contentWidth: d.contentWidth
}
diff --git a/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml b/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml
index a046bbfcf3..0df0da7657 100644
--- a/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml
+++ b/ui/app/AppLayouts/Profile/controls/WalletAccountDelegate.qml
@@ -20,6 +20,8 @@ StatusListItem {
asset.letterSize: 14
asset.isLetterIdenticon: !!account.emoji
asset.bgColor: Theme.palette.primaryColor3
+ asset.width: 40
+ asset.height: 40
width: parent.width
components: !showShevronIcon ? [] : [ shevronIcon ]
diff --git a/ui/app/AppLayouts/Profile/panels/ContactPanel.qml b/ui/app/AppLayouts/Profile/panels/ContactPanel.qml
index 0b4028e7b1..fb7fe4e93d 100644
--- a/ui/app/AppLayouts/Profile/panels/ContactPanel.qml
+++ b/ui/app/AppLayouts/Profile/panels/ContactPanel.qml
@@ -70,7 +70,7 @@ StatusListItem {
asset.isImage: asset.name.includes("data")
asset.isLetterIdenticon: root.iconSource.toString() === ""
ringSettings {
- ringSpecModel: Utils.getColorHashAsJson(root.publicKey)
+ ringSpecModel: d.ensVerified ? undefined : Utils.getColorHashAsJson(root.publicKey, true)
ringPxSize: Math.max(asset.width / 24.0)
}
diff --git a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml
index badb0a2052..c7442f0ebf 100644
--- a/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml
+++ b/ui/app/AppLayouts/Profile/stores/ProfileSectionStore.qml
@@ -16,7 +16,7 @@ QtObject {
property var profileSectionModuleInst: profileSectionModule
- property bool fetchingUpdate: aboutModule.fetching
+ readonly property bool fetchingUpdate: aboutModuleInst.fetching
property ContactsStore contactsStore: ContactsStore {
contactsModule: profileSectionModuleInst.contactsModule
diff --git a/ui/app/AppLayouts/Profile/views/ContactsView.qml b/ui/app/AppLayouts/Profile/views/ContactsView.qml
index dab22d2fb3..db920fa92a 100644
--- a/ui/app/AppLayouts/Profile/views/ContactsView.qml
+++ b/ui/app/AppLayouts/Profile/views/ContactsView.qml
@@ -27,8 +27,6 @@ SettingsContentBase {
headerComponents: [
StatusButton {
- implicitHeight: 38
- size: StatusBaseButton.Size.Normal
text: qsTr("Send contact request to chat key")
onClicked: {
sendContactRequest.open()
@@ -54,8 +52,8 @@ SettingsContentBase {
store: ({contactsStore: root.contactsStore})
isProfile: true
- onOpenProfileClicked: function (pubkey, state) {
- Global.openProfilePopup(pubkey, null, state)
+ onOpenProfileClicked: function (pubkey) {
+ Global.openProfilePopup(pubkey, null)
}
onCreateOneToOneChat: function (communityId, chatId, ensName) {
@@ -196,6 +194,10 @@ SettingsContentBase {
contactsModel: root.contactsStore.receivedContactRequestsModel
panelUsage: Constants.contactsPanelUsage.receivedContactRequest
+ onSendMessageActionTriggered: {
+ root.contactsStore.joinPrivateChat(publicKey)
+ }
+
onContactRequestAccepted: {
root.contactsStore.acceptContactRequest(publicKey)
}
@@ -205,20 +207,7 @@ SettingsContentBase {
}
onShowVerificationRequest: {
- try {
- 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)
- }
+ Global.openIncomingIDRequestPopup(publicKey)
}
}
@@ -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 {
id: sendContactRequest
width: parent.width
diff --git a/ui/app/AppLayouts/Profile/views/EnsTermsAndConditionsView.qml b/ui/app/AppLayouts/Profile/views/EnsTermsAndConditionsView.qml
index eb9fe44799..2ae3578c65 100644
--- a/ui/app/AppLayouts/Profile/views/EnsTermsAndConditionsView.qml
+++ b/ui/app/AppLayouts/Profile/views/EnsTermsAndConditionsView.qml
@@ -64,7 +64,7 @@ Item {
gasPrice,
tipLimit,
overallLimit,
- password,
+ password,
eip1559Enabled,
)
}
diff --git a/ui/app/AppLayouts/Profile/views/MessagingView.qml b/ui/app/AppLayouts/Profile/views/MessagingView.qml
index a63d26e66d..b0a0150f9a 100644
--- a/ui/app/AppLayouts/Profile/views/MessagingView.qml
+++ b/ui/app/AppLayouts/Profile/views/MessagingView.qml
@@ -200,7 +200,7 @@ SettingsContentBase {
Connections {
target: Global
- onSettingsLoaded: {
+ function onSettingsLoaded() {
generalColumn.populatePreviewableSites()
}
}
diff --git a/ui/app/AppLayouts/Profile/views/MyProfileView.qml b/ui/app/AppLayouts/Profile/views/MyProfileView.qml
index 790ae523c4..9e7153c142 100644
--- a/ui/app/AppLayouts/Profile/views/MyProfileView.qml
+++ b/ui/app/AppLayouts/Profile/views/MyProfileView.qml
@@ -24,6 +24,7 @@ SettingsContentBase {
property WalletStore walletStore
property ProfileStore profileStore
property PrivacyStore privacyStore
+ property ContactsStore contactsStore
titleRowComponentLoader.sourceComponent: StatusButton {
objectName: "profileSettingsChangePasswordButton"
@@ -35,8 +36,14 @@ SettingsContentBase {
dirty: settingsView.dirty
saveChangesButtonEnabled: settingsView.valid
- onResetChangesClicked: settingsView.reset()
- onSaveChangesClicked: settingsView.save()
+ onResetChangesClicked: {
+ settingsView.reset()
+ profilePreview.reload()
+ }
+ onSaveChangesClicked: {
+ settingsView.save()
+ profilePreview.reload()
+ }
ColumnLayout {
id: layout
@@ -73,6 +80,7 @@ SettingsContentBase {
id: profilePreview
Layout.fillWidth: true
profileStore: root.profileStore
+ contactsStore: root.contactsStore
}
}
diff --git a/ui/app/AppLayouts/Profile/views/NotificationsView.qml b/ui/app/AppLayouts/Profile/views/NotificationsView.qml
index a678282a1a..536acbeb41 100644
--- a/ui/app/AppLayouts/Profile/views/NotificationsView.qml
+++ b/ui/app/AppLayouts/Profile/views/NotificationsView.qml
@@ -58,7 +58,7 @@ SettingsContentBase {
StatusListItem {
property string lowerCaseSearchString: searchBox.text.toLowerCase()
- width: parent.width
+ width: ListView.view.width
height: visible ? implicitHeight : 0
visible: lowerCaseSearchString === "" ||
model.itemId.toLowerCase().includes(lowerCaseSearchString) ||
diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml
index d346b4e7b4..951dd404e6 100644
--- a/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml
+++ b/ui/app/AppLayouts/Profile/views/profile/MyProfilePreview.qml
@@ -1,4 +1,4 @@
-import QtQuick 2.13
+import QtQuick 2.14
import QtGraphicalEffects 1.14
import shared.views 1.0 as SharedViews
@@ -7,6 +7,7 @@ import StatusQ.Core.Theme 0.1
Item {
property alias profileStore: profilePreview.profileStore
+ property alias contactsStore: profilePreview.contactsStore
implicitHeight: profilePreview.implicitHeight
+ profilePreview.anchors.topMargin
@@ -16,10 +17,15 @@ Item {
+ profilePreview.anchors.leftMargin
+ profilePreview.anchors.rightMargin
- SharedViews.ProfileView {
+ function reload() {
+ profilePreview.reload()
+ }
+
+ SharedViews.ProfileDialogView {
id: profilePreview
anchors.fill: parent
anchors.margins: 24
+ readOnly: true
}
DropShadow {
@@ -32,4 +38,4 @@ Item {
color: "#40000000"
source: profilePreview
}
-}
\ No newline at end of file
+}
diff --git a/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml b/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml
index ca4fcccd2c..b25becea37 100644
--- a/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml
+++ b/ui/app/AppLayouts/Profile/views/profile/MyProfileSettingsView.qml
@@ -181,7 +181,6 @@ ColumnLayout {
visible: communitiesRepeater.count == 0
width: parent.width
horizontalAlignment: Text.AlignHCenter
- font.pixelSize: 15
color: Theme.palette.directColor1
text: qsTr("You haven't joined any communities yet")
}
@@ -204,7 +203,6 @@ ColumnLayout {
visible: accountsRepeater.count == 0
width: parent.width
horizontalAlignment: Text.AlignHCenter
- font.pixelSize: 15
color: Theme.palette.directColor1
text: qsTr("You don't have any wallet accounts yet")
}
@@ -233,5 +231,4 @@ ColumnLayout {
}
}
}
-
}
diff --git a/ui/app/AppLayouts/Wallet/views/RightTabView.qml b/ui/app/AppLayouts/Wallet/views/RightTabView.qml
index aae6813bda..c90853f16f 100644
--- a/ui/app/AppLayouts/Wallet/views/RightTabView.qml
+++ b/ui/app/AppLayouts/Wallet/views/RightTabView.qml
@@ -52,7 +52,6 @@ Item {
}
ColumnLayout {
- anchors.fill: parent
WalletHeader {
Layout.fillWidth: true
locale: RootStore.locale
diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml
index fda7dbde2f..d83093deed 100644
--- a/ui/app/mainui/AppMain.qml
+++ b/ui/app/mainui/AppMain.qml
@@ -84,13 +84,19 @@ Item {
})
return downloadPage
}
+
onOpenProfilePopupRequested: {
- var popup = profilePopupComponent.createObject(appMain);
- if (parentPopup) {
- popup.parentPopup = parentPopup;
- }
- popup.openPopup(publicKey, state);
- Global.profilePopupOpened = true;
+ Global.openPopup(profilePopupComponent, {publicKey: publicKey, parentPopup: parentPopup})
+ Global.profilePopupOpened = true
+ }
+ onOpenNicknamePopupRequested: {
+ Global.openPopup(nicknamePopupComponent, {publicKey: publicKey, nickname: nickname, "header.subTitle": subtitle})
+ }
+ onBlockContactRequested: {
+ Global.openPopup(blockContactConfirmationComponent, {contactName: contactName, contactAddress: publicKey})
+ }
+ onUnblockContactRequested: {
+ Global.openPopup(unblockContactConfirmationComponent, {contactName: contactName, contactAddress: publicKey})
}
onOpenActivityCenterPopupRequested: {
@@ -106,28 +112,30 @@ Item {
onDisplayToastMessage: {
appMain.rootStore.mainModuleInst.displayEphemeralNotification(title, subTitle, icon, loading, ephNotifType, url);
}
- onOpenEditDisplayNamePopup: {
- var popup = displayNamePopupComponent.createObject(appMain)
- popup.open()
- }
+ onOpenEditDisplayNamePopup: Global.openPopup(displayNamePopupComponent)
}
function changeAppSectionBySectionId(sectionId) {
mainModule.setActiveSectionById(sectionId)
}
- property Component backupSeedModalComponent: BackupSeedModal {
- id: backupSeedModal
- anchors.centerIn: parent
- privacyStore: appMain.rootStore.profileSectionStore.privacyStore
- onClosed: destroy()
+ Component {
+ id: backupSeedModalComponent
+ BackupSeedModal {
+ anchors.centerIn: parent
+ privacyStore: appMain.rootStore.profileSectionStore.privacyStore
+ onClosed: destroy()
+ }
}
- property Component displayNamePopupComponent: DisplayNamePopup {
- anchors.centerIn: parent
- profileStore: appMain.rootStore.profileSectionStore.profileStore
- onClosed: {
- destroy()
+ Component {
+ id: displayNamePopupComponent
+ DisplayNamePopup {
+ anchors.centerIn: parent
+ profileStore: appMain.rootStore.profileSectionStore.profileStore
+ onClosed: {
+ destroy()
+ }
}
}
@@ -164,21 +172,24 @@ Item {
}
}
- property Component profilePopupComponent: ProfilePopup {
- id: profilePopup
- anchors.centerIn: parent
- profileStore: appMain.rootStore.profileSectionStore.profileStore
- contactsStore: appMain.rootStore.profileSectionStore.contactsStore
- onClosed: {
- if (profilePopup.parentPopup) {
- profilePopup.parentPopup.close();
+ Component {
+ id: profilePopupComponent
+ ProfileDialog {
+ id: profilePopup
+ profileStore: appMain.rootStore.profileSectionStore.profileStore
+ contactsStore: appMain.rootStore.profileSectionStore.contactsStore
+ onClosed: {
+ if (profilePopup.parentPopup) {
+ profilePopup.parentPopup.close()
+ }
+ Global.profilePopupOpened = false
+ destroy()
}
- Global.profilePopupOpened = false;
- destroy();
}
}
- property Component changeProfilePicComponent: Component {
+ Component {
+ id: changeProfilePicComponent
ImageCropWorkflow {
title: qsTr("Profile Picture")
acceptButtonText: qsTr("Make this my Profile Pic")
@@ -636,7 +647,6 @@ Item {
}
}
}
-
}
Item {
@@ -711,8 +721,6 @@ Item {
ChatLayout {
id: chatLayoutContainer
- Layout.fillWidth: true
- Layout.fillHeight: true
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
Loader {
id: sendModal
@@ -1183,8 +1229,8 @@ Item {
} catch (e) {
console.error('Could not parse the whitelist for sites', e)
}
+ Global.privacyModuleInst = appMain.rootStore.profileSectionStore.privacyStore.privacyModule
Global.settingsHasLoaded();
- Global.errorSound = errorSound;
}
Loader {
diff --git a/ui/app/mainui/AppSearch.qml b/ui/app/mainui/AppSearch.qml
index a2ae2eae7c..e745a0b5bb 100644
--- a/ui/app/mainui/AppSearch.qml
+++ b/ui/app/mainui/AppSearch.qml
@@ -44,6 +44,7 @@ Item {
onItemClicked: {
appSearch.store.setSearchLocation(firstLevelItemValue, secondLevelItemValue)
+ searchPopup.forceActiveFocus()
if(searchPopup.searchText !== "")
searchMessages(searchPopup.searchText)
}
diff --git a/ui/imports/shared/controls/AddressInput.qml b/ui/imports/shared/controls/AddressInput.qml
index 146b8c31e2..af699bdf43 100644
--- a/ui/imports/shared/controls/AddressInput.qml
+++ b/ui/imports/shared/controls/AddressInput.qml
@@ -15,7 +15,7 @@ Item {
property string ensAsyncValidationError: qsTr("ENS Username not found")
property alias input: contactFieldAndList.chatKey
property string selectedAddress
- property var isValid: false
+ property bool isValid: false
property alias isPending: contactFieldAndList.loading
property bool isResolvedAddress: false
property int parentWidth
diff --git a/ui/imports/shared/controls/CopyToClipBoardButton.qml b/ui/imports/shared/controls/CopyToClipBoardButton.qml
index 79e69dd142..7c1d818f18 100644
--- a/ui/imports/shared/controls/CopyToClipBoardButton.qml
+++ b/ui/imports/shared/controls/CopyToClipBoardButton.qml
@@ -2,8 +2,6 @@ import QtQuick 2.13
import StatusQ.Controls 0.1
-import shared.stores 1.0
-
import utils 1.0
StatusRoundButton {
@@ -32,16 +30,6 @@ StatusRoundButton {
id: toolTip
text: qsTr("Copied!")
orientation: tooltipUnder ? StatusToolTip.Orientation.Bottom: StatusToolTip.Orientation.Top
- }
-
- Timer {
- id: hideTimer
- interval: 2000
- running: toolTip.visible
- onTriggered: {
- toolTip.visible = false;
- }
+ timeout: 2000
}
}
-
-
diff --git a/ui/imports/shared/controls/EmojiHash.qml b/ui/imports/shared/controls/EmojiHash.qml
index 5768934eed..43f2de957c 100644
--- a/ui/imports/shared/controls/EmojiHash.qml
+++ b/ui/imports/shared/controls/EmojiHash.qml
@@ -4,12 +4,12 @@ import StatusQ.Core.Utils 0.1 as StatusQUtils
import StatusQ.Components 0.1
import utils 1.0
-import shared.panels 1.0
Item {
id: root
property bool compact: false
+ property bool oneRow
property string publicKey
readonly property real size: compact ? 10 : 15
@@ -20,8 +20,8 @@ Item {
Grid {
id: positioner
- rows: 2
- columnSpacing: 0.2
+ rows: root.oneRow ? 1 : 2
+ columnSpacing: root.oneRow ? 4 : 2
rowSpacing: root.compact ? 4 : 6
Repeater {
diff --git a/ui/imports/shared/controls/chat/ProfileHeader.qml b/ui/imports/shared/controls/chat/ProfileHeader.qml
index 1ff74465d9..b8efb79bac 100644
--- a/ui/imports/shared/controls/chat/ProfileHeader.qml
+++ b/ui/imports/shared/controls/chat/ProfileHeader.qml
@@ -140,24 +140,11 @@ Item {
}
}
- Loader {
- sourceComponent: SVGImage {
- height: compact ? 10 : 16
- width: compact ? 10 : 16
- source: Style.svg("contact")
- }
- 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
+ StatusContactVerificationIcons {
+ Layout.alignment: Qt.AlignVCenter
+ visible: !root.isCurrentUser
+ isContact: root.isContact
+ trustIndicator: root.trustStatus
}
Loader {
diff --git a/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml b/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml
index 834488a860..6769a07fc3 100644
--- a/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml
+++ b/ui/imports/shared/controls/chat/menuItems/MuteChatMenuItem.qml
@@ -5,6 +5,6 @@ import StatusQ.Popups 0.1
StatusMenuItem {
property bool muted: false
- text: !muted ? qsTr("Mute chat") : qsTr("Unmute chat")
+ text: muted ? qsTr("Unmute Chat") : qsTr("Mute Chat")
icon.name: "notification"
}
diff --git a/ui/imports/shared/controls/chat/menuItems/SendMessageMenuItem.qml b/ui/imports/shared/controls/chat/menuItems/SendMessageMenuItem.qml
index f6e7df2c70..c79f563743 100644
--- a/ui/imports/shared/controls/chat/menuItems/SendMessageMenuItem.qml
+++ b/ui/imports/shared/controls/chat/menuItems/SendMessageMenuItem.qml
@@ -3,6 +3,6 @@ import QtQuick 2.14
import StatusQ.Popups 0.1
StatusMenuItem {
- text: qsTr("Send message")
+ text: qsTr("Send Message")
icon.name: "chat"
}
diff --git a/ui/imports/shared/panels/AcceptRejectOptionsButtonsPanel.qml b/ui/imports/shared/panels/AcceptRejectOptionsButtonsPanel.qml
index 763dcbb523..0de7fe21c2 100644
--- a/ui/imports/shared/panels/AcceptRejectOptionsButtonsPanel.qml
+++ b/ui/imports/shared/panels/AcceptRejectOptionsButtonsPanel.qml
@@ -10,26 +10,16 @@ import shared.controls.chat.menuItems 1.0
Row {
id: root
+ height: declineBtn.height
+ spacing: Style.current.halfPadding
+
+ property alias menuButton: menuButton
signal acceptClicked()
signal declineClicked()
signal blockClicked()
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 {
id: declineBtn
width: 32
@@ -41,6 +31,16 @@ Row {
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 {
id: menuButton
diff --git a/ui/imports/shared/panels/ImageLoader.qml b/ui/imports/shared/panels/ImageLoader.qml
index d275503af3..15681c8368 100644
--- a/ui/imports/shared/panels/ImageLoader.qml
+++ b/ui/imports/shared/panels/ImageLoader.qml
@@ -55,7 +55,7 @@ Rectangle {
Connections {
enabled: !!mainModule
target: enabled ? mainModule : undefined
- onOnlineStatusChanged: {
+ function onOnlineStatusChanged(connected) {
if (connected && root.state !== "ready" &&
root.visible &&
root.source &&
diff --git a/ui/imports/shared/panels/ModuleWarning.qml b/ui/imports/shared/panels/ModuleWarning.qml
index 288f438161..858a8565cb 100644
--- a/ui/imports/shared/panels/ModuleWarning.qml
+++ b/ui/imports/shared/panels/ModuleWarning.qml
@@ -8,9 +8,6 @@ import StatusQ.Core.Theme 0.1
import utils 1.0
-import StatusQ.Core 0.1
-import StatusQ.Core.Theme 0.1
-
Item {
id: root
@@ -29,7 +26,7 @@ Item {
signal clicked()
signal closeClicked()
signal showStarted()
- signal showFinihsed()
+ signal showFinished()
signal hideStarted()
signal hideFinished()
@@ -73,7 +70,7 @@ Item {
root.showStarted()
}
onFinished: {
- root.showFinihsed()
+ root.showFinished()
}
}
@@ -134,7 +131,6 @@ Item {
text: root.text
font.pixelSize: 13
font.weight: Font.Medium
- anchors.verticalCenter: parent.verticalCenter
color: Theme.palette.indirectColor1
linkColor: color
onLinkActivated: root.linkActivated(link)
diff --git a/ui/imports/shared/panels/ProfileBioSocialsPanel.qml b/ui/imports/shared/panels/ProfileBioSocialsPanel.qml
index 2f085e3e40..9b439c3a13 100644
--- a/ui/imports/shared/panels/ProfileBioSocialsPanel.qml
+++ b/ui/imports/shared/panels/ProfileBioSocialsPanel.qml
@@ -1,4 +1,5 @@
import QtQuick 2.14
+import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQml.Models 2.14
@@ -10,7 +11,7 @@ import "../controls"
import SortFilterProxyModel 0.2
-Item {
+Control {
id: root
property string bio
@@ -18,9 +19,6 @@ Item {
onUserSocialLinksJsonChanged: d.buildSocialLinksModel()
- implicitWidth: layout.implicitWidth
- implicitHeight: layout.implicitHeight
-
QtObject {
id: d
@@ -83,11 +81,7 @@ Item {
]
}
- ColumnLayout {
- id: layout
-
- anchors.fill: parent
-
+ contentItem: ColumnLayout {
spacing: 20
StatusBaseText {
@@ -95,15 +89,15 @@ Item {
visible: text !== ""
text: root.bio
wrapMode: Text.Wrap
+ font.weight: Font.Medium
+ lineHeight: 1.2
}
- Flow {
+ StatusCenteredFlow {
Layout.fillWidth: true
Layout.fillHeight: true
- Layout.leftMargin: 10
- Layout.rightMargin: 10
- spacing: 16
+ spacing: Style.current.halfPadding
visible: repeater.count > 0
Repeater {
diff --git a/ui/imports/shared/panels/Separator.qml b/ui/imports/shared/panels/Separator.qml
index 277956258a..1af4755bb0 100644
--- a/ui/imports/shared/panels/Separator.qml
+++ b/ui/imports/shared/panels/Separator.qml
@@ -10,10 +10,10 @@ Item {
height: root.visible ? implicitHeight : 0
anchors.topMargin: Style.current.padding
Rectangle {
- id: separator
- width: parent.width
- height: 1
- color: root.color
- anchors.verticalCenter: parent.verticalCenter
+ id: separator
+ width: parent.width
+ height: 1
+ color: root.color
+ anchors.verticalCenter: parent.verticalCenter
}
}
diff --git a/ui/imports/shared/popups/BlockContactConfirmationDialog.qml b/ui/imports/shared/popups/BlockContactConfirmationDialog.qml
index c0f569eb8f..a2dcdd1073 100644
--- a/ui/imports/shared/popups/BlockContactConfirmationDialog.qml
+++ b/ui/imports/shared/popups/BlockContactConfirmationDialog.qml
@@ -15,7 +15,6 @@ ModalPopup {
height: 237
width: 400
- property Popup parentPopup
property string contactAddress: ""
property string contactName: ""
diff --git a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml
index 5a84b227f6..8e24e8ffae 100644
--- a/ui/imports/shared/popups/ContactVerificationRequestPopup.qml
+++ b/ui/imports/shared/popups/ContactVerificationRequestPopup.qml
@@ -1,6 +1,5 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
-import QtQuick.Dialogs 1.3
import utils 1.0
@@ -37,9 +36,6 @@ StatusModal {
onOpened: {
verificationResponse.input.edit.forceActiveFocus(Qt.MouseFocusReason)
}
- onClosed: {
- root.destroy();
- }
contentItem: Item {
anchors.left: parent.left
@@ -69,6 +65,7 @@ StatusModal {
messageTimestamp: root.messageTimestamp
senderId: root.senderPublicKey
senderDisplayName: root.senderDisplayName
+ senderIsEnsVerified: Utils.isEnsVerified(root.senderPublicKey)
senderIcon: root.senderIcon
messageText: root.challengeText
messageContentType: Constants.messageContentType.messageType
@@ -100,7 +97,8 @@ StatusModal {
shouldRepeatHeader: true
messageTimestamp: root.responseTimestamp
senderId: userProfile.pubKey
- senderDisplayName: userProfile.name
+ senderDisplayName: userProfile.displayName
+ senderIsEnsVerified: !!userProfile.ensName
senderIcon: userProfile.icon
messageText: root.responseText
messageContentType: Constants.messageContentType.messageType
@@ -115,9 +113,9 @@ StatusModal {
wrapMode: Text.WordWrap
anchors.top: responseMessage.bottom
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
- horizontalAlignment: Text.AlignHCenter
+ horizontalAlignment: Text.AlignHCenter
}
}
diff --git a/ui/imports/shared/popups/DisplayNamePopup.qml b/ui/imports/shared/popups/DisplayNamePopup.qml
index 6a5381fb0f..88e2468644 100644
--- a/ui/imports/shared/popups/DisplayNamePopup.qml
+++ b/ui/imports/shared/popups/DisplayNamePopup.qml
@@ -47,6 +47,6 @@ StatusModal {
}
]
- onOpened: { displayNameInput.input.forceActiveFocus(Qt.MouseFocusReason) }
+ onOpened: { displayNameInput.input.edit.forceActiveFocus() }
}
diff --git a/ui/imports/shared/popups/NicknamePopup.qml b/ui/imports/shared/popups/NicknamePopup.qml
index 68b31c7f29..6ac8f7d1d0 100644
--- a/ui/imports/shared/popups/NicknamePopup.qml
+++ b/ui/imports/shared/popups/NicknamePopup.qml
@@ -18,15 +18,18 @@ StatusModal {
anchors.centerIn: parent
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 maxNicknameLength: 32
signal editDone(string newNickname)
onOpened: {
- nicknameInput.forceActiveFocus(Qt.MouseFocusReason);
+ nicknameInput.input.edit.forceActiveFocus()
}
contentItem: Item {
@@ -51,9 +54,9 @@ StatusModal {
StatusInput {
id: nicknameInput
placeholderText: qsTr("Nickname")
-
+ input.clearable: true
width: parent.width
-
+ text: popup.nickname
charLimit: maxNicknameLength
validationMode: StatusInput.ValidationMode.IgnoreInvalidInput
validators: [
diff --git a/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml b/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml
new file mode 100644
index 0000000000..34633d7037
--- /dev/null
+++ b/ui/imports/shared/popups/OutgoingContactVerificationRequestPopup.qml
@@ -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
+ }
+ }
+}
diff --git a/ui/imports/shared/popups/ProfileDialog.qml b/ui/imports/shared/popups/ProfileDialog.qml
new file mode 100644
index 0000000000..044a10cd95
--- /dev/null
+++ b/ui/imports/shared/popups/ProfileDialog.qml
@@ -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()
+ }
+}
diff --git a/ui/imports/shared/popups/ProfilePopup.qml b/ui/imports/shared/popups/ProfilePopup.qml
deleted file mode 100644
index bc903d1a83..0000000000
--- a/ui/imports/shared/popups/ProfilePopup.qml
+++ /dev/null
@@ -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)
- }
- }
- }
-}
diff --git a/ui/imports/shared/popups/SendContactRequestModal.qml b/ui/imports/shared/popups/SendContactRequestModal.qml
index dbd93b86ee..dd51215577 100644
--- a/ui/imports/shared/popups/SendContactRequestModal.qml
+++ b/ui/imports/shared/popups/SendContactRequestModal.qml
@@ -19,9 +19,12 @@ StatusModal {
property string userIcon: ""
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)
- padding: 16
+ padding: Style.current.padding
header.title: qsTr("Send Contact Request to %1").arg(userDisplayName)
QtObject {
@@ -33,6 +36,10 @@ StatusModal {
readonly property int contentSpacing: 5
}
+ onAboutToShow: {
+ messageInput.input.edit.forceActiveFocus()
+ }
+
ColumnLayout {
id: content
anchors.fill: parent
@@ -55,7 +62,7 @@ StatusModal {
id: messageInput
charLimit: d.maxMsgLength
- placeholderText: qsTr("Say who you are / why you want to become a contact...")
+ placeholderText: root.challengeText
input.multiline: true
minimumHeight: d.msgHeight
maximumHeight: d.msgHeight
@@ -71,7 +78,7 @@ StatusModal {
rightButtons: StatusButton {
enabled: messageInput.valid
- text: qsTr("Send Contact Request")
+ text: root.buttonText
onClicked: {
root.accepted(Utils.escapeHtml(messageInput.text));
root.close();
diff --git a/ui/imports/shared/popups/UnblockContactConfirmationDialog.qml b/ui/imports/shared/popups/UnblockContactConfirmationDialog.qml
index b54be91f82..d6bf87fe8d 100644
--- a/ui/imports/shared/popups/UnblockContactConfirmationDialog.qml
+++ b/ui/imports/shared/popups/UnblockContactConfirmationDialog.qml
@@ -15,7 +15,6 @@ ModalPopup {
height: 237
width: 400
- property Popup parentPopup
property string contactAddress: ""
property string contactName: ""
diff --git a/ui/imports/shared/popups/qmldir b/ui/imports/shared/popups/qmldir
index 89e823b52e..870324edca 100644
--- a/ui/imports/shared/popups/qmldir
+++ b/ui/imports/shared/popups/qmldir
@@ -4,6 +4,7 @@ SettingsDirtyToastMessage 1.0 SettingsDirtyToastMessage.qml
ConfirmationDialog 1.0 ConfirmationDialog.qml
CommunityIntroDialog 1.0 CommunityIntroDialog.qml
ContactVerificationRequestPopup 1.0 ContactVerificationRequestPopup.qml
+OutgoingContactVerificationRequestPopup 1.0 OutgoingContactVerificationRequestPopup.qml
DownloadModal 1.0 DownloadModal.qml
DownloadPage 1.0 DownloadPage.qml
InviteFriendsPopup 1.0 InviteFriendsPopup.qml
@@ -17,7 +18,7 @@ UnblockContactConfirmationDialog 1.0 UnblockContactConfirmationDialog.qml
UserStatusContextMenu 1.0 UserStatusContextMenu.qml
SignTransactionModal 1.0 SignTransactionModal.qml
SelectAccountModal 1.0 SelectAccountModal.qml
-ProfilePopup 1.0 ProfilePopup.qml
+ProfileDialog 1.0 ProfileDialog.qml
ImageCropWorkflow 1.0 ImageCropWorkflow.qml
ImportCommunityPopup 1.0 ImportCommunityPopup.qml
DisplayNamePopup 1.0 DisplayNamePopup.qml
diff --git a/ui/imports/shared/status/StatusChatImageQtyValidator.qml b/ui/imports/shared/status/StatusChatImageQtyValidator.qml
index aa2e9bd038..4b170a9b89 100644
--- a/ui/imports/shared/status/StatusChatImageQtyValidator.qml
+++ b/ui/imports/shared/status/StatusChatImageQtyValidator.qml
@@ -8,7 +8,7 @@ import ".."
StatusChatImageValidator {
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: {
root.isValid = images.length <= Constants.maxUploadFiles
diff --git a/ui/imports/shared/status/StatusETHTransactionModal.qml b/ui/imports/shared/status/StatusETHTransactionModal.qml
index 90a4942cc6..560aa354f3 100644
--- a/ui/imports/shared/status/StatusETHTransactionModal.qml
+++ b/ui/imports/shared/status/StatusETHTransactionModal.qml
@@ -57,7 +57,7 @@ ModalPopup {
root.close();
} catch (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()
}
}
diff --git a/ui/imports/shared/status/StatusGifPopup.qml b/ui/imports/shared/status/StatusGifPopup.qml
index 8a7f3f3edd..0016db36f1 100644
--- a/ui/imports/shared/status/StatusGifPopup.qml
+++ b/ui/imports/shared/status/StatusGifPopup.qml
@@ -63,8 +63,6 @@ Popup {
searchBox.input.edit.forceActiveFocus()
if (RootStore.isTenorWarningAccepted) {
RootStore.getTrendingsGifs()
- } else {
- confirmationPopupLoader.active = true
}
}
@@ -202,7 +200,7 @@ Popup {
sourceComponent: ConfirmationPopup {
visible: true
}
- active: false
+ active: !RootStore.isTenorWarningAccepted
}
Component {
diff --git a/ui/imports/shared/status/StatusStickersPopup.qml b/ui/imports/shared/status/StatusStickersPopup.qml
index 4977b561e8..041f95ce4c 100644
--- a/ui/imports/shared/status/StatusStickersPopup.qml
+++ b/ui/imports/shared/status/StatusStickersPopup.qml
@@ -45,7 +45,7 @@ Popup {
}
Connections {
target: mainModule
- onOnlineStatusChanged: {
+ function onOnlineStatusChanged() {
root.close()
}
}
diff --git a/ui/imports/shared/stores/RootStore.qml b/ui/imports/shared/stores/RootStore.qml
index cd28071e9c..3a0db36c77 100644
--- a/ui/imports/shared/stores/RootStore.qml
+++ b/ui/imports/shared/stores/RootStore.qml
@@ -179,7 +179,6 @@ QtObject {
function findTokenSymbolByAddress(address) {
return walletSectionAllTokens.findTokenSymbolByAddress(address)
-
}
function getNameForSavedWalletAddress(address) {
diff --git a/ui/imports/shared/views/AssetsView.qml b/ui/imports/shared/views/AssetsView.qml
index b34134ebc4..bc1ad5c7f7 100644
--- a/ui/imports/shared/views/AssetsView.qml
+++ b/ui/imports/shared/views/AssetsView.qml
@@ -44,7 +44,7 @@ Item {
delegate: StatusListItem {
readonly property string balance: enabledNetworkBalance // Needed for the tests
objectName: "AssetView_TokenListItem_" + symbol
- width: parent.width
+ width: ListView.view.width
title: name
subTitle: `${enabledNetworkBalance} ${symbol}`
asset.name: symbol ? Style.png("tokens/" + symbol) : ""
diff --git a/ui/imports/shared/views/HistoryView.qml b/ui/imports/shared/views/HistoryView.qml
index ef55196342..7e0c42ffec 100644
--- a/ui/imports/shared/views/HistoryView.qml
+++ b/ui/imports/shared/views/HistoryView.qml
@@ -35,7 +35,7 @@ ColumnLayout {
target: RootStore.history
onLoadingTrxHistoryChanged: function(isLoading, address) {
if (historyView.account.address.toLowerCase() === address.toLowerCase()) {
- root.isLoading = isLoading
+ historyView.isLoading = isLoading
}
}
}
diff --git a/ui/imports/shared/views/ProfileDialogView.qml b/ui/imports/shared/views/ProfileDialogView.qml
new file mode 100644
index 0000000000..2c7ca24068
--- /dev/null
+++ b/ui/imports/shared/views/ProfileDialogView.qml
@@ -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
+ }
+ }
+}
diff --git a/ui/imports/shared/views/ProfileView.qml b/ui/imports/shared/views/ProfileView.qml
deleted file mode 100644
index ac12740b78..0000000000
--- a/ui/imports/shared/views/ProfileView.qml
+++ /dev/null
@@ -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)
- }
- }
-}
diff --git a/ui/imports/shared/views/chat/MessageContextMenuView.qml b/ui/imports/shared/views/chat/MessageContextMenuView.qml
index aacb4e874f..4ddf56eb79 100644
--- a/ui/imports/shared/views/chat/MessageContextMenuView.qml
+++ b/ui/imports/shared/views/chat/MessageContextMenuView.qml
@@ -106,7 +106,7 @@ StatusPopupMenu {
property var emojiReactionsReactedByUser: []
- signal openProfileClicked(string publicKey, string state)
+ signal openProfileClicked(string publicKey)
signal pinMessage(string messageId)
signal unpinMessage(string messageId)
signal pinnedMessagesLimitReached(string messageId)
@@ -238,7 +238,7 @@ StatusPopupMenu {
id: viewProfileAction
enabled: root.isProfile && !root.pinnedPopup
onTriggered: {
- root.openProfileClicked(root.selectedUserPublicKey, "")
+ root.openProfileClicked(root.selectedUserPublicKey)
root.close()
}
}
@@ -256,8 +256,7 @@ StatusPopupMenu {
enabled: root.isProfile && !root.isMe && !root.isContact
&& !root.isBlockedContact && !root.hasPendingContactRequest
onTriggered: {
- root.openProfileClicked(root.selectedUserPublicKey,
- Constants.profilePopupStates.contactRequest)
+ Global.openContactRequestPopup(root.selectedUserPublicKey)
root.close()
}
}
@@ -270,8 +269,7 @@ StatusPopupMenu {
&& root.outgoingVerificationStatus === Constants.verificationStatus.unverified
&& !root.hasReceivedVerificationRequestFrom
onTriggered: {
- root.openProfileClicked(root.selectedUserPublicKey,
- Constants.profilePopupStates.verifyIdentity)
+ Global.openSendIDRequestPopup(root.selectedUserPublicKey)
root.close()
}
}
@@ -288,11 +286,9 @@ StatusPopupMenu {
|| root.isVerificationRequestSent)
onTriggered: {
if (hasReceivedVerificationRequestFrom) {
- root.openProfileClicked(root.selectedUserPublicKey,
- Constants.profilePopupStates.respondToPendingRequest)
+ Global.openIncomingIDRequestPopup(root.selectedUserPublicKey)
} else if (root.isVerificationRequestSent) {
- root.openProfileClicked(root.selectedUserPublicKey,
- Constants.profilePopupStates.showVerificationPendingSection)
+ Global.openOutgoingIDRequestPopup(root.selectedUserPublicKey)
}
root.close()
@@ -304,8 +300,8 @@ StatusPopupMenu {
icon.name: "edit_pencil"
enabled: root.isProfile && !root.isMe
onTriggered: {
- root.openProfileClicked(root.selectedUserPublicKey,
- Constants.profilePopupStates.openNickname)
+ Global.openNicknamePopupRequested(root.selectedUserPublicKey, d.contactDetails.localNickname,
+ "%1 (%2)".arg(root.selectedUserDisplayName).arg(Utils.getElidedCompressedPk(root.selectedUserPublicKey)))
root.close()
}
}
@@ -314,7 +310,7 @@ StatusPopupMenu {
text: qsTr("Unblock User")
icon.name: "remove-circle"
enabled: root.isProfile && !root.isMe && root.isBlockedContact
- onTriggered: root.store.contactsStore.unblockContact(root.selectedUserPublicKey)
+ onTriggered: Global.unblockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName)
}
StatusMenuSeparator {
@@ -344,7 +340,7 @@ StatusPopupMenu {
icon.name: "cancel"
type: StatusMenuItem.Type.Danger
enabled: root.isProfile && !root.isMe && !root.isBlockedContact
- onTriggered: root.store.contactsStore.blockContact(root.selectedUserPublicKey)
+ onTriggered: Global.blockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName)
}
StatusMenuItem {
diff --git a/ui/imports/shared/views/qmldir b/ui/imports/shared/views/qmldir
index b6cc69e0ac..947b3e7976 100644
--- a/ui/imports/shared/views/qmldir
+++ b/ui/imports/shared/views/qmldir
@@ -7,7 +7,7 @@ TransactionPreview 1.0 TransactionPreview.qml
TransactionSigner 1.0 TransactionSigner.qml
TransactionStackView 1.0 TransactionStackView.qml
PasswordView 1.0 PasswordView.qml
-ProfileView 1.0 ProfileView.qml
+ProfileDialogView 1.0 ProfileDialogView.qml
AssetsView 1.0 AssetsView.qml
HistoryView 1.0 HistoryView.qml
AssetsDetailView 1.0 AssetsDetailView.qml
diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml
index e05c97d156..bb3538da29 100644
--- a/ui/imports/utils/Constants.qml
+++ b/ui/imports/utils/Constants.qml
@@ -280,16 +280,6 @@ QtObject {
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 list displayName: [
StatusMinLengthValidator {
@@ -567,7 +557,7 @@ QtObject {
readonly property int maxNumberOfPins: 3
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: ``
diff --git a/ui/imports/utils/Global.qml b/ui/imports/utils/Global.qml
index b6f0db4e66..e80a26aa60 100644
--- a/ui/imports/utils/Global.qml
+++ b/ui/imports/utils/Global.qml
@@ -38,7 +38,16 @@ Item {
signal openCreateChatView()
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 displayToastMessage(string title, string subTitle, string icon, bool loading, int ephNotifType, string url)
signal openEditDisplayNamePopup()
@@ -50,7 +59,7 @@ Item {
userPublicKey: publicKey,
userDisplayName: contactDetails.displayName,
userIcon: contactDetails.largeImage,
- userIsEnsVerified: contactDetails.ensVerified,
+ userIsEnsVerified: contactDetails.ensVerified
})
}
@@ -61,8 +70,56 @@ Item {
})
}
- function openProfilePopup(publicKey, parentPopup, state = "") {
- openProfilePopupRequested(publicKey, parentPopup, state);
+ function openSendIDRequestPopup(publicKey) {
+ 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() {
@@ -145,9 +202,45 @@ Item {
anchors.centerIn: parent
rootStore: appMain.rootStore
contactsStore: appMain.rootStore.contactStore
- onClosed: {
- destroy()
+ onClosed: 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()
}
}
}
diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml
index 9b2b6f31db..2c2d741df5 100644
--- a/ui/imports/utils/Utils.qml
+++ b/ui/imports/utils/Utils.qml
@@ -580,7 +580,7 @@ QtObject {
function isEnsVerified(publicKey, getVerificationRequest=true) {
if (!publicKey)
- return false
+ return false
return getContactDetailsAsJson(publicKey, getVerificationRequest).ensVerified
}