From 88d1f1f386db2fc044dfeffee80bca0142422dea Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Fri, 6 Sep 2024 11:55:44 -0400 Subject: [PATCH] refactor ProfileContextMenu to make it a functional component This refactor ProfileContextMenu to make it a functional component by: refactored out direct calls to backend, and passing backend data structures and moved this logic to the callers, also refactored common calls between the callers common types of context menus have been extracted to their sub components which removes a lot of logic too and makes the behaviour very clear user verification workflow (which was already disabled) has been removed refactor: use signals and call singletons on the parent instead remove unused code for now from profile context menu refactor profile context menu into two components; add property to storybook extract blocked profile context menu and self profile context menu use profileType instead of individual bools refactor to pass trustStatus as an argument make contact type a parameter remove unnecessary method from RegularProfileContextMenu add ensVerified property to ProfileContextMenu components add onlineStatus property to ProfileContextMenu components move ProfileContextMenu storybook controls to the right sidebar move contactDetails logic up from the view add local nickname property to ProfileContextMenu components fix issue with missing signal; fix logs in storybook use constant for profileType instead of string refactor common code into a single method refactor getProfileContext remove references to contactDetails which are not longer needed remove unnecessary comments fix bridged constant --- storybook/pages/MessageContextMenuPage.qml | 195 ++++++++- .../AppLayouts/Chat/panels/UserListPanel.qml | 42 +- .../Communities/panels/MembersTabPanel.qml | 12 +- .../AppLayouts/Profile/views/ContactsView.qml | 53 ++- ui/imports/shared/views/chat/MessageView.qml | 44 +- .../shared/views/chat/ProfileContextMenu.qml | 412 +++++++----------- .../BlockedProfileContextMenu.qml | 99 +++++ .../BridgeProfileContextMenu.qml | 53 +++ .../RegularProfileContextMenu.qml | 169 +++++++ .../SelfProfileContextMenu.qml | 63 +++ ui/imports/utils/Constants.qml | 14 + ui/imports/utils/Utils.qml | 38 ++ 12 files changed, 914 insertions(+), 280 deletions(-) create mode 100644 ui/imports/shared/views/chat/ProfileContextMenu/BlockedProfileContextMenu.qml create mode 100644 ui/imports/shared/views/chat/ProfileContextMenu/BridgeProfileContextMenu.qml create mode 100644 ui/imports/shared/views/chat/ProfileContextMenu/RegularProfileContextMenu.qml create mode 100644 ui/imports/shared/views/chat/ProfileContextMenu/SelfProfileContextMenu.qml diff --git a/storybook/pages/MessageContextMenuPage.qml b/storybook/pages/MessageContextMenuPage.qml index 7ad5ab93dc3..90fc461bdb2 100644 --- a/storybook/pages/MessageContextMenuPage.qml +++ b/storybook/pages/MessageContextMenuPage.qml @@ -11,6 +11,7 @@ import Models 1.0 import utils 1.0 import shared.views.chat 1.0 +import shared.status 1.0 SplitView { @@ -85,6 +86,46 @@ SplitView { ProfileContextMenu { anchors.centerIn: parent hideDisabledItems: false + profileType: profileTypeSelector.currentText + trustStatus: trustStatusSelector.currentValue + contactType: contactTypeSelector.currentValue + ensVerified: ensVerifiedCheckBox.checked + onlineStatus: onlineStatusSelector.currentValue + hasLocalNickname: hasLocalNicknameCheckBox.checked + + onOpenProfileClicked: (publicKey) => { + logs.logEvent("Open profile clicked for:", publicKey) + } + onCreateOneToOneChat: (communityId, chatId, ensName) => { + logs.logEvent("Create one-to-one chat:", communityId, chatId, ensName) + } + onReviewContactRequest: (publicKey) => { + logs.logEvent("Review contact request:", publicKey) + } + onSendContactRequest: (publicKey) => { + logs.logEvent("Send contact request:", publicKey) + } + onEditNickname: (publicKey) => { + logs.logEvent("Edit nickname:", publicKey) + } + onRemoveNickname: (publicKey, displayName) => { + logs.logEvent("Remove nickname:", publicKey, displayName) + } + onUnblockContact: (publicKey) => { + logs.logEvent("Unblock contact:", publicKey) + } + onMarkAsUntrusted: (publicKey) => { + logs.logEvent("Mark as untrusted:", publicKey) + } + onRemoveTrustStatus: (publicKey) => { + logs.logEvent("Remove trust status:", publicKey) + } + onRemoveContact: (publicKey) => { + logs.logEvent("Remove contact:", publicKey) + } + onBlockContact: (publicKey) => { + logs.logEvent("Block contact:", publicKey) + } onClosed: { destroy() } @@ -96,6 +137,47 @@ SplitView { ProfileContextMenu { anchors.centerIn: parent hideDisabledItems: true + profileType: profileTypeSelector.currentValue + trustStatus: trustStatusSelector.currentValue + contactType: contactTypeSelector.currentValue + ensVerified: ensVerifiedCheckBox.checked + onlineStatus: onlineStatusSelector.currentValue + hasLocalNickname: hasLocalNicknameCheckBox.checked + + onOpenProfileClicked: (publicKey) => { + logs.logEvent("Open profile clicked for:", publicKey) + } + onCreateOneToOneChat: (communityId, chatId, ensName) => { + logs.logEvent("Create one-to-one chat:", communityId, chatId, ensName) + } + onReviewContactRequest: (publicKey) => { + logs.logEvent("Review contact request:", publicKey) + } + onSendContactRequest: (publicKey) => { + logs.logEvent("Send contact request:", publicKey) + } + onEditNickname: (publicKey) => { + logs.logEvent("Edit nickname:", publicKey) + } + onRemoveNickname: (publicKey, displayName) => { + logs.logEvent("Remove nickname:", publicKey, displayName) + } + onUnblockContact: (publicKey) => { + logs.logEvent("Unblock contact:", publicKey) + } + onMarkAsUntrusted: (publicKey) => { + logs.logEvent("Mark as untrusted:", publicKey) + } + onRemoveTrustStatus: (publicKey) => { + logs.logEvent("Remove trust status:", publicKey) + } + onRemoveContact: (publicKey) => { + logs.logEvent("Remove contact:", publicKey) + } + onBlockContact: (publicKey) => { + logs.logEvent("Block contact:", publicKey) + } + onClosed: { destroy() } @@ -103,29 +185,114 @@ SplitView { } } - LogsAndControlsPanel { - id: logsAndControlsPanel + } - SplitView.minimumHeight: 100 - SplitView.preferredHeight: 150 + LogsAndControlsPanel { + id: logsAndControlsPanel - logsView.logText: logs.logText - } - } + SplitView.minimumWidth: 150 + SplitView.preferredWidth: 250 - Pane { - SplitView.minimumWidth: 300 - SplitView.preferredWidth: 300 + logsView.logText: logs.logText - ScrollView { - anchors.fill: parent + controls: ColumnLayout { + spacing: 16 + + ComboBox { + id: profileTypeSelector + textRole: "text" + valueRole: "value" + model: [ + { text: "Regular", value: Constants.profileType.regular }, + { text: "Self", value: Constants.profileType.self }, + { text: "Blocked", value: Constants.profileType.blocked }, + { text: "Bridged", value: Constants.profileType.bridged } + ] + currentIndex: 0 + } - ColumnLayout { - spacing: 16 + ComboBox { + id: trustStatusSelector + textRole: "text" + valueRole: "value" + model: [ + { text: "Unknown", value: Constants.trustStatus.unknown }, + { text: "Trusted", value: Constants.trustStatus.trusted }, + { text: "Untrusted", value: Constants.trustStatus.untrustworthy } + ] + currentIndex: 0 + } + + ComboBox { + id: contactTypeSelector + textRole: "text" + valueRole: "value" + model: [ + { text: "Non Contact", value: Constants.contactType.nonContact }, + { text: "Contact", value: Constants.contactType.contact }, + { text: "Contact Request Received", value: Constants.contactType.contactRequestReceived }, + { text: "Contact Request Sent", value: Constants.contactType.contactRequestSent } + ] + currentIndex: 0 + } + + CheckBox { + id: ensVerifiedCheckBox + text: "ENS Verified" + checked: false + } + + Label { + Layout.fillWidth: true + text: "ENS Verified: " + (ensVerifiedCheckBox.checked ? "Yes" : "No") + } + + Label { + Layout.fillWidth: true + text: "Profile type: " + profileTypeSelector.currentText + } + Label { + Layout.fillWidth: true + text: "Trust status: " + trustStatusSelector.currentText } + + Label { + Layout.fillWidth: true + text: "Contact type: " + contactTypeSelector.currentText + } + + ComboBox { + id: onlineStatusSelector + textRole: "text" + valueRole: "value" + model: [ + { text: "Unknown", value: Constants.onlineStatus.unknown }, + { text: "Inactive", value: Constants.onlineStatus.inactive }, + { text: "Online", value: Constants.onlineStatus.online } + ] + currentIndex: 2 // Default to online + } + + Label { + Layout.fillWidth: true + text: "Online status: " + onlineStatusSelector.currentText + } + + CheckBox { + id: hasLocalNicknameCheckBox + text: "Has Local Nickname" + checked: false + } + + Label { + Layout.fillWidth: true + text: "Has Local Nickname: " + (hasLocalNicknameCheckBox.checked ? "Yes" : "No") + } + } } + } // category: Views diff --git a/ui/app/AppLayouts/Chat/panels/UserListPanel.qml b/ui/app/AppLayouts/Chat/panels/UserListPanel.qml index 83456d6b684..9b6b8d32fb8 100644 --- a/ui/app/AppLayouts/Chat/panels/UserListPanel.qml +++ b/ui/app/AppLayouts/Chat/panels/UserListPanel.qml @@ -127,7 +127,10 @@ Item { ringSettings.ringSpecModel: model.colorHash onClicked: { if (mouse.button === Qt.RightButton) { + const { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname } = Utils.getProfileContext(model.pubKey, userProfile.pubKey) + Global.openMenu(profileContextMenuComponent, this, { + profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname, myPublicKey: root.store.myPublicKey(), selectedUserPublicKey: model.pubKey, selectedUserDisplayName: nickName || userName, @@ -170,13 +173,48 @@ Item { ProfileContextMenu { store: root.store margins: 8 - onOpenProfileClicked: { + onOpenProfileClicked: (publicKey) => { + console.log("UserListPanel.qml:1: open profile clicked", publicKey) Global.openProfilePopup(publicKey, null) } - onCreateOneToOneChat: { + onCreateOneToOneChat: (communityId, chatId, ensName) => { Global.changeAppSectionBySectionType(Constants.appSection.chat) root.store.chatCommunitySectionModule.createOneToOneChat(communityId, chatId, ensName) } + onReviewContactRequest: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openReviewContactRequestPopup(publicKey, contactDetails, null) + } + onSendContactRequest: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openContactRequestPopup(publicKey, contactDetails, null) + } + onEditNickname: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openNicknamePopupRequested(publicKey, contactDetails, null) + } + onRemoveNickname: (publicKey, displayName) => { + root.store.contactsStore.changeContactNickname(publicKey, "", displayName, true) + } + onUnblockContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.unblockContactRequested(publicKey, contactDetails) + } + onMarkAsUntrusted: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.markAsUntrustedRequested(publicKey, contactDetails) + } + onRemoveTrustStatus: (publicKey) => { + root.store.contactsStore.removeTrustStatus(publicKey) + } + onRemoveContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.removeContactRequested(publicKey, contactDetails) + } + onBlockContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.blockContactRequested(publicKey, contactDetails) + } onClosed: { destroy() } diff --git a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml index 07fd3be58dc..2180668de2d 100644 --- a/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/MembersTabPanel.qml @@ -303,11 +303,15 @@ Item { onClicked: { if(mouse.button === Qt.RightButton) { + const { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname } = Utils.getProfileContext(model.pubKey, Global.userProfile.pubKey) + Global.openMenu(memberContextMenuComponent, this, { - selectedUserPublicKey: model.pubKey, - selectedUserDisplayName: memberItem.title, - selectedUserIcon: icon.name, - }) + profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname, + myPublicKey: Global.userProfile.pubKey, + selectedUserPublicKey: model.pubKey, + selectedUserDisplayName: memberItem.title, + selectedUserIcon: icon.name, + }) } else { Global.openProfilePopup(model.pubKey) } diff --git a/ui/app/AppLayouts/Profile/views/ContactsView.qml b/ui/app/AppLayouts/Profile/views/ContactsView.qml index 7dd62142e26..5fcd72ec97c 100644 --- a/ui/app/AppLayouts/Profile/views/ContactsView.qml +++ b/ui/app/AppLayouts/Profile/views/ContactsView.qml @@ -34,11 +34,14 @@ SettingsContentBase { } function openContextMenu(publicKey, name, icon) { + const { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname } = Utils.getProfileContext(publicKey, root.contactsStore.myPublicKey) + Global.openMenu(contactContextMenuComponent, this, { - selectedUserPublicKey: publicKey, - selectedUserDisplayName: name, - selectedUserIcon: icon, - }) + profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname, + selectedUserPublicKey: publicKey, + selectedUserDisplayName: name, + selectedUserIcon: icon, + }) } Item { @@ -49,23 +52,55 @@ SettingsContentBase { Component { id: contactContextMenuComponent - ProfileContextMenu { id: contactContextMenu store: ({contactsStore: root.contactsStore}) - onOpenProfileClicked: function (pubkey) { + onOpenProfileClicked: (pubkey) => { Global.openProfilePopup(pubkey, null, null) } - onCreateOneToOneChat: function (communityId, chatId, ensName) { + onCreateOneToOneChat: (communityId, chatId, ensName) => { root.contactsStore.joinPrivateChat(chatId) } + onReviewContactRequest: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openReviewContactRequestPopup(publicKey, contactDetails, null) + } + onSendContactRequest: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openContactRequestPopup(publicKey, contactDetails, null) + } + onEditNickname: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openNicknamePopupRequested(publicKey, contactDetails, null) + } + onRemoveNickname: (publicKey, displayName) => { + root.contactsStore.changeContactNickname(publicKey, "", displayName, true) + } + onUnblockContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.unblockContactRequested(publicKey, contactDetails) + } + onMarkAsUntrusted: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.markAsUntrustedRequested(publicKey, contactDetails) + } + onRemoveTrustStatus: (publicKey) => { + root.contactsStore.removeTrustStatus(publicKey) + } + onRemoveContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.removeContactRequested(publicKey, contactDetails) + } + onBlockContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.blockContactRequested(publicKey, contactDetails) + } onClosed: { destroy() } } } - SearchBox { id: searchBox anchors.left: parent.left @@ -173,7 +208,7 @@ SettingsContentBase { visible: root.contactsStore.myContactsModel.count === 0 NoFriendsRectangle { anchors.centerIn: parent - text: qsTr("You don’t have any contacts yet") + text: qsTr("You don't have any contacts yet") } } } diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index 19a464df784..9adb08dc6fb 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -152,12 +152,14 @@ Loader { // so we don't enable to right click the unavailable profile return false } + const publicKey = isReply ? quotedMessageFrom : root.senderId + const isBridgedAccount = isReply ? (quotedMessageContentType === Constants.messageContentType.bridgeMessageType) : root.isBridgeMessage + const { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname } = Utils.getProfileContext(publicKey, root.rootStore.contactsStore.myPublicKey, isBridgedAccount) - const params = { + const params = { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname, selectedUserPublicKey: isReply ? quotedMessageFrom : root.senderId, selectedUserDisplayName: isReply ? quotedMessageAuthorDetailsDisplayName : root.senderDisplayName, selectedUserIcon: isReply ? quotedMessageAuthorDetailsThumbnailImage : root.senderIcon, - isBridgedAccount: isReply ? (quotedMessageContentType === Constants.messageContentType.bridgeMessageType) : root.isBridgeMessage } Global.openMenu(profileContextMenuComponent, sender, params) @@ -1170,16 +1172,51 @@ Loader { Component { id: profileContextMenuComponent - ProfileContextMenu { store: root.rootStore + onOpenProfileClicked: (publicKey) => { + console.log("MessageView.qml:1: open profile clicked", publicKey) Global.openProfilePopup(publicKey, null) } onCreateOneToOneChat: (communityId, chatId, ensName) => { Global.changeAppSectionBySectionType(Constants.appSection.chat) root.rootStore.chatCommunitySectionModule.createOneToOneChat("", chatId, ensName) } + onReviewContactRequest: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openReviewContactRequestPopup(publicKey, contactDetails, null) + } + onSendContactRequest: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openContactRequestPopup(publicKey, contactDetails, null) + } + onEditNickname: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.openNicknamePopupRequested(publicKey, contactDetails, null) + } + onRemoveNickname: (publicKey, displayName) => { + root.rootStore.contactsStore.changeContactNickname(publicKey, "", displayName, true) + } + onUnblockContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.unblockContactRequested(publicKey, contactDetails) + } + onMarkAsUntrusted: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.markAsUntrustedRequested(publicKey, contactDetails) + } + onRemoveTrustStatus: (publicKey) => { + root.rootStore.contactsStore.removeTrustStatus(publicKey) + } + onRemoveContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.removeContactRequested(publicKey, contactDetails) + } + onBlockContact: (publicKey) => { + const contactDetails = publicKey === "" ? {} : Utils.getContactDetailsAsJson(publicKey, true, true) + Global.blockContactRequested(publicKey, contactDetails) + } onOpened: { root.setMessageActive(root.messageId, true) } @@ -1189,7 +1226,6 @@ Loader { } } } - Component { id: messageContextMenuComponent diff --git a/ui/imports/shared/views/chat/ProfileContextMenu.qml b/ui/imports/shared/views/chat/ProfileContextMenu.qml index 9afe9f3bcc2..55580139bca 100644 --- a/ui/imports/shared/views/chat/ProfileContextMenu.qml +++ b/ui/imports/shared/views/chat/ProfileContextMenu.qml @@ -1,297 +1,215 @@ import QtQuick 2.15 - -import StatusQ.Popups 0.1 -import StatusQ.Components 0.1 -import StatusQ.Core.Utils 0.1 as StatusQUtils +import QtQuick.Controls 2.15 import AppLayouts.Chat.stores 1.0 as ChatStores - -import utils 1.0 -import shared 1.0 -import shared.panels 1.0 -import shared.popups 1.0 import shared.status 1.0 -import shared.controls.chat 1.0 -import shared.controls.chat.menuItems 1.0 +import utils 1.0 +import "./ProfileContextMenu" as PCM -StatusMenu { +Item { id: root property ChatStores.RootStore store - property string myPublicKey: "" - property string selectedUserPublicKey: "" property string selectedUserDisplayName: "" property string selectedUserIcon: "" - property bool isBridgedAccount: false - - readonly property bool isMe: { - return root.selectedUserPublicKey === root.store.contactsStore.myPublicKey; - } - readonly property var contactDetails: { - if (root.selectedUserPublicKey === "" || isMe) { - return {} - } - return Utils.getContactDetailsAsJson(root.selectedUserPublicKey, true, true); - } - readonly property bool isContact: { - return root.selectedUserPublicKey !== "" && !!contactDetails.isContact - } - readonly property bool isBlockedContact: (!!contactDetails && contactDetails.isBlocked) || false + property int profileType: Constants.profileType.regular + property int trustStatus: Constants.trustStatus.unknown + property int contactType: Constants.contactType.nonContact - readonly property bool idVerificationFlowsEnabled: false // disabled temporarily as per https://github.com/status-im/status-desktop/issues/14954 + property bool hideDisabledItems: true + property int margins: 0 - readonly property int outgoingVerificationStatus: { - if (root.selectedUserPublicKey === "" || root.isMe || !root.isContact) { - return 0 - } - return contactDetails.verificationStatus - } - readonly property int incomingVerificationStatus: { - if (root.selectedUserPublicKey === "" || root.isMe || !root.isContact) { - return 0 - } - return contactDetails.incomingVerificationStatus - } - readonly property bool hasPendingContactRequest: { - return !root.isMe && root.selectedUserPublicKey !== "" && - contactDetails.contactRequestState === Constants.ContactRequestState.Received - } - readonly property bool hasActiveReceivedVerificationRequestFrom: { - if (!root.selectedUserPublicKey || root.isMe || !root.isContact) { - return false - } - return contactDetails.incomingVerificationStatus === Constants.verificationStatus.verifying || - contactDetails.incomingVerificationStatus === Constants.verificationStatus.verified - } - readonly property bool isVerificationRequestSent: { - if (!root.selectedUserPublicKey || root.isMe || !root.isContact) { - return false - } - return root.outgoingVerificationStatus !== Constants.verificationStatus.unverified && - root.outgoingVerificationStatus !== Constants.verificationStatus.verified && - root.outgoingVerificationStatus !== Constants.verificationStatus.trusted - } - readonly property bool isTrusted: { - if (!root.selectedUserPublicKey || root.isMe || !root.isContact) { - return false - } - return root.outgoingVerificationStatus === Constants.verificationStatus.trusted || - root.incomingVerificationStatus === Constants.verificationStatus.trusted - } + property bool ensVerified: false + property int onlineStatus: Constants.onlineStatus.unknown - readonly property bool userTrustIsUnknown: contactDetails && contactDetails.trustStatus === Constants.trustStatus.unknown - readonly property bool userIsUntrustworthy: contactDetails && contactDetails.trustStatus === Constants.trustStatus.untrustworthy - readonly property bool userIsLocallyTrusted: contactDetails && contactDetails.trustStatus === Constants.trustStatus.trusted + property bool hasLocalNickname: false signal openProfileClicked(string publicKey) signal createOneToOneChat(string communityId, string chatId, string ensName) - - onClosed: { - // Reset selectedUserPublicKey so that associated properties get recalculated on re-open - selectedUserPublicKey = "" - } - - ProfileHeader { - width: parent.width - height: visible ? implicitHeight : 0 - - displayNameVisible: false - displayNamePlusIconsVisible: true - editButtonVisible: false - displayName: StatusQUtils.Emoji.parse(root.selectedUserDisplayName, StatusQUtils.Emoji.size.verySmall) - pubkey: root.selectedUserPublicKey - icon: root.selectedUserIcon - trustStatus: contactDetails && contactDetails.trustStatus ? contactDetails.trustStatus - : Constants.trustStatus.unknown - Binding on onlineStatus { - value: contactDetails.onlineStatus - when: !root.isMe + signal reviewContactRequest(string publicKey) + signal sendContactRequest(string publicKey) + signal editNickname(string publicKey) + signal removeNickname(string publicKey, string displayName) + signal unblockContact(string publicKey) + signal markAsUntrusted(string publicKey) + signal removeTrustStatus(string publicKey) + signal removeContact(string publicKey) + signal blockContact(string publicKey) + signal opened() + signal closed() + + Loader { + id: menuLoader + sourceComponent: { + switch (root.profileType) { + case Constants.profileType.self: + return selfMenuComponent + case Constants.profileType.bridged: + return bridgeMenuComponent + case Constants.profileType.blocked: + return blockedMenuComponent + default: + return regularMenuComponent + } } - isContact: root.isContact - isBlocked: root.isBlockedContact - isCurrentUser: root.isMe - userIsEnsVerified: (!!contactDetails && contactDetails.ensVerified) || false - isBridgedAccount: root.isBridgedAccount - } - - StatusMenuSeparator { - topPadding: root.topPadding - visible: !root.isBridgedAccount - } + onLoaded: { + item.store = root.store + item.selectedUserPublicKey = root.selectedUserPublicKey + item.selectedUserDisplayName = root.selectedUserDisplayName + item.selectedUserIcon = root.selectedUserIcon + item.hideDisabledItems = root.hideDisabledItems + item.margins = root.margins + item.ensVerified = root.ensVerified + + if (root.profileType !== Constants.profileType.self) { + item.onlineStatus = root.onlineStatus + } - ViewProfileMenuItem { - id: viewProfileAction - objectName: "viewProfile_StatusItem" - enabled: !root.isBridgedAccount - onTriggered: { - root.openProfileClicked(root.selectedUserPublicKey) - root.close() - } - } + if (item.opened) { + item.opened.connect(root.opened) + } + if (item.closed) { + item.closed.connect(root.closed) + } - StatusAction { - text: qsTr("Review contact request") - objectName: "reviewContactRequest_StatusItem" - icon.name: "add-contact" - enabled: !root.isMe && !root.isContact && !root.isBridgedAccount && !root.isBlockedContact && root.hasPendingContactRequest - onTriggered: Global.openReviewContactRequestPopup(root.selectedUserPublicKey, root.contactDetails, null) - } + if (root.profileType !== Constants.profileType.bridged) { + item.openProfileClicked.connect(root.openProfileClicked) + } - SendMessageMenuItem { - id: sendMessageMenuItem - objectName: "sendMessage_StatusItem" - enabled: root.isContact && !root.isBlockedContact && !root.isBridgedAccount - onTriggered: { - root.createOneToOneChat("", root.selectedUserPublicKey, "") - root.close() - } - } + if (root.profileType === Constants.profileType.blocked) { + item.unblockContact.connect(root.unblockContact) + item.editNickname.connect(root.editNickname) + // item.removeNickname.connect(root.removeNickname) + } else if (root.profileType === Constants.profileType.regular) { + item.createOneToOneChat.connect(root.createOneToOneChat) + item.reviewContactRequest.connect(root.reviewContactRequest) + item.sendContactRequest.connect(root.sendContactRequest) + item.editNickname.connect(root.editNickname) + item.removeNickname.connect(root.removeNickname) + item.unblockContact.connect(root.unblockContact) + item.markAsUntrusted.connect(root.markAsUntrusted) + item.removeTrustStatus.connect(root.removeTrustStatus) + item.removeContact.connect(root.removeContact) + item.blockContact.connect(root.blockContact) + } - SendContactRequestMenuItem { - id: sendContactRequestMenuItem - objectName: "sendContactRequest_StatusItem" - enabled: !root.isMe && !root.isContact && !root.isBlockedContact - && (contactDetails.contactRequestState === Constants.ContactRequestState.None || contactDetails.contactRequestState === Constants.ContactRequestState.Dismissed) - && !root.isBridgedAccount - onTriggered: Global.openContactRequestPopup(root.selectedUserPublicKey, root.contactDetails, null) - } + item.closed.connect(root.closed) - StatusAction { - id: verifyIdentityAction - text: qsTr("Request ID verification") - objectName: "verifyIdentity_StatusItem" - icon.name: "checkmark-circle" - enabled: idVerificationFlowsEnabled - && !root.isMe && root.isContact - && !root.isBlockedContact - && !root.userIsLocallyTrusted - && root.outgoingVerificationStatus === Constants.verificationStatus.unverified - && !root.hasActiveReceivedVerificationRequestFrom - && !root.isBridgedAccount - onTriggered: Global.openSendIDRequestPopup(root.selectedUserPublicKey, root.contactDetails, null) - } - StatusAction { - text: qsTr("Mark as ID verified") - objectName: "markAsVerified_StatusItem" - icon.name: "checkmark-circle" - enabled: idVerificationFlowsEnabled && !root.isMe && root.isContact && !root.isBridgedAccount && !root.isBlockedContact && !(root.isTrusted || root.userIsLocallyTrusted) - onTriggered: Global.openMarkAsIDVerifiedPopup(root.selectedUserPublicKey, root.contactDetails, null) - } - StatusAction { - id: pendingIdentityAction - objectName: "pendingIdentity_StatusItem" - text: { - if (root.isVerificationRequestSent) { - if (root.incomingVerificationStatus !== Constants.verificationStatus.verified) - return qsTr("ID verification pending...") - return qsTr("Review ID verification reply") + if (root.profileType === Constants.profileType.regular) { + item.trustStatus = root.trustStatus + item.contactType = root.contactType } - return qsTr("Reply to ID verification request") - } - icon.name: root.isVerificationRequestSent && root.incomingVerificationStatus !== Constants.verificationStatus.verified ? "history" - : "checkmark-circle" - enabled: idVerificationFlowsEnabled && !root.isMe && root.isContact && !root.isBridgedAccount && !root.isBlockedContact && !(root.isTrusted || root.userIsLocallyTrusted) && - (root.hasActiveReceivedVerificationRequestFrom || root.isVerificationRequestSent) - onTriggered: { - if (root.hasActiveReceivedVerificationRequestFrom) { - Global.openIncomingIDRequestPopup(root.selectedUserPublicKey, root.contactDetails, null) - } else if (root.isVerificationRequestSent) { - Global.openOutgoingIDRequestPopup(root.selectedUserPublicKey, root.contactDetails, null) - } + item.hasLocalNickname = root.hasLocalNickname - root.close() - } - } + item.closed.connect(root.closed) - StatusAction { - id: renameAction - objectName: "rename_StatusItem" - text: contactDetails.localNickname ? qsTr("Edit nickname") : qsTr("Add nickname") - icon.name: "edit_pencil" - enabled: !root.isMe && !root.isBridgedAccount - onTriggered: Global.openNicknamePopupRequested(root.selectedUserPublicKey, root.contactDetails, null) + if (root.profileType === Constants.profileType.regular) { + item.trustStatus = root.trustStatus + item.contactType = root.contactType + } + } } - StatusMenuSeparator { - visible: blockMenuItem.enabled || unblockAction.enabled + Component { + id: bridgeMenuComponent + PCM.BridgeProfileContextMenu { + store: root.store + selectedUserPublicKey: root.selectedUserPublicKey + selectedUserDisplayName: root.selectedUserDisplayName + selectedUserIcon: root.selectedUserIcon + hideDisabledItems: root.hideDisabledItems + margins: root.margins + ensVerified: root.ensVerified + onlineStatus: root.onlineStatus + onOpened: root.openedHandler && root.openedHandler() + onClosed: root.closedHandler && root.closedHandler() + } } - StatusAction { - text: qsTr("Remove nickname") - icon.name: "delete" - type: StatusAction.Type.Danger - enabled: !root.isMe && !!contactDetails.localNickname - onTriggered: root.store.contactsStore.changeContactNickname(root.selectedUserPublicKey, "", root.selectedUserDisplayName, true) + Component { + id: regularMenuComponent + PCM.RegularProfileContextMenu { + store: root.store + myPublicKey: root.myPublicKey + selectedUserPublicKey: root.selectedUserPublicKey + selectedUserDisplayName: root.selectedUserDisplayName + selectedUserIcon: root.selectedUserIcon + hideDisabledItems: root.hideDisabledItems + margins: root.margins + trustStatus: root.trustStatus + contactType: root.contactType + ensVerified: root.ensVerified + onlineStatus: root.onlineStatus + onOpened: root.openedHandler && root.openedHandler() + onClosed: root.closedHandler && root.closedHandler() + hasLocalNickname: root.hasLocalNickname + } } - StatusAction { - id: unblockAction - objectName: "unblock_StatusItem" - text: qsTr("Unblock user") - icon.name: "cancel" - type: StatusAction.Type.Danger - enabled: !root.isMe && root.isBlockedContact && !root.isBridgedAccount - onTriggered: Global.unblockContactRequested(root.selectedUserPublicKey, root.contactDetails) + Component { + id: selfMenuComponent + PCM.SelfProfileContextMenu { + store: root.store + selectedUserPublicKey: root.selectedUserPublicKey + selectedUserDisplayName: root.selectedUserDisplayName + selectedUserIcon: root.selectedUserIcon + hideDisabledItems: root.hideDisabledItems + margins: root.margins + ensVerified: root.ensVerified + onOpened: root.openedHandler && root.openedHandler() + onClosed: root.closedHandler && root.closedHandler() + } } - StatusAction { - objectName: "removeIDVerification_StatusItem" - text: qsTr("Remove ID verification") - icon.name: "delete" - type: StatusAction.Type.Danger - enabled: idVerificationFlowsEnabled && !root.isMe && root.isContact && !root.isBridgedAccount && (root.isTrusted || root.userIsLocallyTrusted) - onTriggered: Global.openRemoveIDVerificationDialog(root.selectedUserPublicKey, root.contactDetails, null) + Component { + id: blockedMenuComponent + PCM.BlockedProfileContextMenu { + store: root.store + myPublicKey: root.myPublicKey + selectedUserPublicKey: root.selectedUserPublicKey + selectedUserDisplayName: root.selectedUserDisplayName + selectedUserIcon: root.selectedUserIcon + hideDisabledItems: root.hideDisabledItems + margins: root.margins + ensVerified: root.ensVerified + onlineStatus: root.onlineStatus + onOpened: root.openedHandler && root.openedHandler() + onClosed: root.closedHandler && root.closedHandler() + hasLocalNickname: root.hasLocalNickname + } } - StatusAction { - id: markUntrustworthyMenuItem - objectName: "markUntrustworthy_StatusItem" - text: qsTr("Mark as untrusted") - icon.name: "warning" - type: StatusAction.Type.Danger - enabled: !root.isMe && !root.userIsUntrustworthy && !root.isBridgedAccount && !root.isBlockedContact - onTriggered: Global.markAsUntrustedRequested(root.selectedUserPublicKey, root.contactDetails) + function open() { + if (menuLoader.item) { + menuLoader.item.open() + } } - StatusAction { - text: qsTr("Cancel ID verification request") - icon.name: "delete" - type: StatusAction.Type.Danger - enabled: idVerificationFlowsEnabled && !root.isMe && root.isContact && !root.isBlockedContact && !root.isBridgedAccount && root.isVerificationRequestSent - onTriggered: root.store.contactsStore.cancelVerificationRequest(root.selectedUserPublicKey) + function close() { + if (menuLoader.item) { + menuLoader.item.close() + } + closed() } - StatusAction { - id: removeUntrustworthyMarkMenuItem - objectName: "removeUntrustworthy_StatusItem" - text: qsTr("Remove untrusted mark") - icon.name: "warning" - type: StatusAction.Type.Danger - enabled: !root.isMe && root.userIsUntrustworthy && !root.isBridgedAccount - onTriggered: root.store.contactsStore.removeTrustStatus(root.selectedUserPublicKey) + function popup() { + if (menuLoader.item && typeof menuLoader.item.popup === "function") { + menuLoader.item.popup() + } else { + console.warn("popup() method not available on loaded item") + } } - StatusAction { - text: qsTr("Remove contact") - objectName: "removeContact_StatusItem" - icon.name: "remove-contact" - type: StatusAction.Type.Danger - enabled: root.isContact && !root.isBlockedContact && !root.hasPendingContactRequest && !root.isBridgedAccount - onTriggered: Global.removeContactRequested(root.selectedUserPublicKey, root.contactDetails) + function setOpenedHandler(handler) { + openedHandler = handler } - StatusAction { - id: blockMenuItem - objectName: "blockUser_StatusItem" - text: qsTr("Block user") - icon.name: "cancel" - type: StatusAction.Type.Danger - enabled: !root.isMe && !root.isBlockedContact && !root.isBridgedAccount - onTriggered: Global.blockContactRequested(root.selectedUserPublicKey, root.contactDetails) + function setClosedHandler(handler) { + closedHandler = handler } } diff --git a/ui/imports/shared/views/chat/ProfileContextMenu/BlockedProfileContextMenu.qml b/ui/imports/shared/views/chat/ProfileContextMenu/BlockedProfileContextMenu.qml new file mode 100644 index 00000000000..ffcc8150b54 --- /dev/null +++ b/ui/imports/shared/views/chat/ProfileContextMenu/BlockedProfileContextMenu.qml @@ -0,0 +1,99 @@ +import QtQuick 2.15 + +import StatusQ.Popups 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core.Utils 0.1 as StatusQUtils + +import AppLayouts.Chat.stores 1.0 as ChatStores + +import utils 1.0 +import shared 1.0 +import shared.panels 1.0 +import shared.popups 1.0 +import shared.status 1.0 +import shared.controls.chat 1.0 +import shared.controls.chat.menuItems 1.0 + +StatusMenu { + id: root + + property ChatStores.RootStore store + property string myPublicKey: "" + property string selectedUserPublicKey: "" + property string selectedUserDisplayName: "" + property string selectedUserIcon: "" + property bool ensVerified: false + property int onlineStatus: Constants.onlineStatus.unknown + property bool hasLocalNickname: false + + signal openProfileClicked(string publicKey) + signal unblockContact(string publicKey) + signal editNickname(string publicKey) + + onClosed: { + selectedUserPublicKey = "" + } + + ProfileHeader { + width: parent.width + height: visible ? implicitHeight : 0 + + displayNameVisible: false + displayNamePlusIconsVisible: true + editButtonVisible: false + displayName: StatusQUtils.Emoji.parse(root.selectedUserDisplayName, StatusQUtils.Emoji.size.verySmall) + pubkey: root.selectedUserPublicKey + icon: root.selectedUserIcon + trustStatus: Constants.trustStatus.unknown + Binding on onlineStatus { + value: root.onlineStatus + when: true + } + isContact: false + isBlocked: true + isCurrentUser: false + userIsEnsVerified: root.ensVerified + isBridgedAccount: false + } + + StatusMenuSeparator { + topPadding: root.topPadding + } + + ViewProfileMenuItem { + id: viewProfileAction + objectName: "viewProfile_StatusItem" + onTriggered: { + root.openProfileClicked(root.selectedUserPublicKey) + root.close() + } + } + + StatusAction { + text: qsTr("Remove nickname") + icon.name: "delete" + type: StatusAction.Type.Danger + enabled: root.hasLocalNickname + onTriggered: root.removeNickname(root.selectedUserPublicKey, root.selectedUserDisplayName) + } + + StatusAction { + id: renameAction + objectName: "rename_StatusItem" + text: root.hasLocalNickname ? qsTr("Edit nickname") : qsTr("Add nickname") + icon.name: "edit_pencil" + enabled: true + onTriggered: root.editNickname(root.selectedUserPublicKey) + } + + StatusMenuSeparator {} + + StatusAction { + id: unblockAction + objectName: "unblock_StatusItem" + text: qsTr("Unblock user") + icon.name: "cancel" + type: StatusAction.Type.Danger + onTriggered: root.unblockContact(root.selectedUserPublicKey) + } +} diff --git a/ui/imports/shared/views/chat/ProfileContextMenu/BridgeProfileContextMenu.qml b/ui/imports/shared/views/chat/ProfileContextMenu/BridgeProfileContextMenu.qml new file mode 100644 index 00000000000..9201112cb7a --- /dev/null +++ b/ui/imports/shared/views/chat/ProfileContextMenu/BridgeProfileContextMenu.qml @@ -0,0 +1,53 @@ +import QtQuick 2.15 + +import StatusQ.Popups 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core.Utils 0.1 as StatusQUtils + +import AppLayouts.Chat.stores 1.0 as ChatStores + +import utils 1.0 +import shared 1.0 +import shared.panels 1.0 +import shared.popups 1.0 +import shared.status 1.0 +import shared.controls.chat 1.0 +import shared.controls.chat.menuItems 1.0 + +StatusMenu { + id: root + + property ChatStores.RootStore store + + property string selectedUserPublicKey: "" + property string selectedUserDisplayName: "" + property string selectedUserIcon: "" + property bool ensVerified: false + property int onlineStatus: Constants.onlineStatus.unknown + + onClosed: { + selectedUserPublicKey = "" + } + + ProfileHeader { + width: parent.width + height: visible ? implicitHeight : 0 + + displayNameVisible: false + displayNamePlusIconsVisible: true + editButtonVisible: false + displayName: StatusQUtils.Emoji.parse(root.selectedUserDisplayName, StatusQUtils.Emoji.size.verySmall) + pubkey: root.selectedUserPublicKey + icon: root.selectedUserIcon + trustStatus: Constants.trustStatus.unknown + Binding on onlineStatus { + value: root.onlineStatus + when: false + } + isContact: false + isBlocked: false + isCurrentUser: false + userIsEnsVerified: root.ensVerified + isBridgedAccount: true + } +} diff --git a/ui/imports/shared/views/chat/ProfileContextMenu/RegularProfileContextMenu.qml b/ui/imports/shared/views/chat/ProfileContextMenu/RegularProfileContextMenu.qml new file mode 100644 index 00000000000..99f117f7f6b --- /dev/null +++ b/ui/imports/shared/views/chat/ProfileContextMenu/RegularProfileContextMenu.qml @@ -0,0 +1,169 @@ +import QtQuick 2.15 + +import StatusQ.Popups 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core.Utils 0.1 as StatusQUtils + +import AppLayouts.Chat.stores 1.0 as ChatStores + +import utils 1.0 +import shared 1.0 +import shared.panels 1.0 +import shared.popups 1.0 +import shared.status 1.0 +import shared.controls.chat 1.0 +import shared.controls.chat.menuItems 1.0 + +StatusMenu { + id: root + + property ChatStores.RootStore store + + property string myPublicKey: "" + + property string selectedUserPublicKey: "" + property string selectedUserDisplayName: "" + property string selectedUserIcon: "" + property int trustStatus: Constants.trustStatus.unknown + property int contactType: Constants.contactType.nonContact + property bool ensVerified: false + property int onlineStatus: Constants.onlineStatus.unknown + property bool hasLocalNickname: false + + signal openProfileClicked(string publicKey) + signal createOneToOneChat(string communityId, string chatId, string ensName) + signal reviewContactRequest(string publicKey) + signal sendContactRequest(string publicKey) + signal editNickname(string publicKey) + signal removeNickname(string publicKey, string displayName) + signal unblockContact(string publicKey) + signal markAsUntrusted(string publicKey) + signal removeTrustStatus(string publicKey) + signal removeContact(string publicKey) + signal blockContact(string publicKey) + + onClosed: { + selectedUserPublicKey = "" + contactType = Constants.contactType.nonContact + } + + ProfileHeader { + width: parent.width + height: visible ? implicitHeight : 0 + + displayNameVisible: false + displayNamePlusIconsVisible: true + editButtonVisible: false + displayName: StatusQUtils.Emoji.parse(root.selectedUserDisplayName, StatusQUtils.Emoji.size.verySmall) + pubkey: root.selectedUserPublicKey + icon: root.selectedUserIcon + trustStatus: root.trustStatus + Binding on onlineStatus { + value: root.onlineStatus + when: true + } + isContact: root.contactType === Constants.contactType.contact + isBlocked: false + isCurrentUser: false + userIsEnsVerified: root.ensVerified + isBridgedAccount: false + } + + StatusMenuSeparator { + topPadding: root.topPadding + } + + ViewProfileMenuItem { + id: viewProfileAction + objectName: "viewProfile_StatusItem" + onTriggered: { + root.openProfileClicked(root.selectedUserPublicKey) + root.close() + } + } + + StatusAction { + text: qsTr("Review contact request") + objectName: "reviewContactRequest_StatusItem" + icon.name: "add-contact" + enabled: root.contactType === Constants.contactType.contactRequestReceived + onTriggered: root.reviewContactRequest(root.selectedUserPublicKey) + } + + SendMessageMenuItem { + id: sendMessageMenuItem + objectName: "sendMessage_StatusItem" + enabled: root.contactType === Constants.contactType.contact + onTriggered: { + root.createOneToOneChat("", root.selectedUserPublicKey, "") + root.close() + } + } + + SendContactRequestMenuItem { + id: sendContactRequestMenuItem + objectName: "sendContactRequest_StatusItem" + enabled: root.contactType === Constants.contactType.nonContact + onTriggered: root.sendContactRequest(root.selectedUserPublicKey) + } + + StatusAction { + id: renameAction + objectName: "rename_StatusItem" + text: root.hasLocalNickname ? qsTr("Edit nickname") : qsTr("Add nickname") + icon.name: "edit_pencil" + enabled: true + onTriggered: root.editNickname(root.selectedUserPublicKey) + } + + StatusMenuSeparator { + visible: blockMenuItem.enabled || unblockAction.enabled + } + + StatusAction { + text: qsTr("Remove nickname") + icon.name: "delete" + type: StatusAction.Type.Danger + enabled: root.hasLocalNickname + onTriggered: root.removeNickname(root.selectedUserPublicKey, root.selectedUserDisplayName) + } + + StatusAction { + id: markUntrustworthyMenuItem + objectName: "markUntrustworthy_StatusItem" + text: qsTr("Mark as untrusted") + icon.name: "warning" + type: StatusAction.Type.Danger + enabled: root.trustStatus !== Constants.trustStatus.untrustworthy + onTriggered: root.markAsUntrusted(root.selectedUserPublicKey) + } + + StatusAction { + id: removeUntrustworthyMarkMenuItem + objectName: "removeUntrustworthy_StatusItem" + text: qsTr("Remove untrusted mark") + icon.name: "warning" + type: StatusAction.Type.Danger + enabled: root.trustStatus === Constants.trustStatus.untrustworthy + onTriggered: root.removeTrustStatus(root.selectedUserPublicKey) + } + + StatusAction { + text: qsTr("Remove contact") + objectName: "removeContact_StatusItem" + icon.name: "remove-contact" + type: StatusAction.Type.Danger + enabled: root.contactType === Constants.contactType.contact + onTriggered: root.removeContact(root.selectedUserPublicKey) + } + + StatusAction { + id: blockMenuItem + objectName: "blockUser_StatusItem" + text: qsTr("Block user") + icon.name: "cancel" + type: StatusAction.Type.Danger + enabled: true + onTriggered: root.blockContact(root.selectedUserPublicKey) + } +} diff --git a/ui/imports/shared/views/chat/ProfileContextMenu/SelfProfileContextMenu.qml b/ui/imports/shared/views/chat/ProfileContextMenu/SelfProfileContextMenu.qml new file mode 100644 index 00000000000..d72ddc589d2 --- /dev/null +++ b/ui/imports/shared/views/chat/ProfileContextMenu/SelfProfileContextMenu.qml @@ -0,0 +1,63 @@ +import QtQuick 2.15 + +import StatusQ.Popups 0.1 +import StatusQ.Components 0.1 +import StatusQ.Core.Utils 0.1 as StatusQUtils + +import AppLayouts.Chat.stores 1.0 as ChatStores + +import utils 1.0 +import shared 1.0 +import shared.panels 1.0 +import shared.popups 1.0 +import shared.status 1.0 +import shared.controls.chat 1.0 +import shared.controls.chat.menuItems 1.0 + +StatusMenu { + id: root + + property ChatStores.RootStore store + + property string selectedUserPublicKey: "" + property string selectedUserDisplayName: "" + property string selectedUserIcon: "" + property bool ensVerified: false + + signal openProfileClicked(string publicKey) + + onClosed: { + selectedUserPublicKey = "" + } + + ProfileHeader { + width: parent.width + height: visible ? implicitHeight : 0 + + displayNameVisible: false + displayNamePlusIconsVisible: true + editButtonVisible: false + displayName: StatusQUtils.Emoji.parse(root.selectedUserDisplayName, StatusQUtils.Emoji.size.verySmall) + pubkey: root.selectedUserPublicKey + icon: root.selectedUserIcon + trustStatus: Constants.trustStatus.unknown + isContact: false + isBlocked: false + isCurrentUser: true + userIsEnsVerified: root.ensVerified + isBridgedAccount: false + } + + StatusMenuSeparator { + topPadding: root.topPadding + } + + ViewProfileMenuItem { + id: viewProfileAction + objectName: "viewProfile_StatusItem" + onTriggered: { + root.openProfileClicked(root.selectedUserPublicKey) + root.close() + } + } +} diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index fa636d7dc02..f2d12aafe12 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -430,6 +430,13 @@ QtObject { readonly property int communityChat: 6 } + readonly property QtObject profileType: QtObject { + readonly property int regular: 0 + readonly property int self: 1 + readonly property int blocked: 2 + readonly property int bridged: 3 + } + readonly property QtObject memberRole: QtObject{ readonly property int none: 0 readonly property int owner: 1 @@ -475,6 +482,13 @@ QtObject { readonly property int responseToMessageWithId: 262 // ModelRole.ResponseToMessageWithId } + readonly property QtObject contactType: QtObject { + readonly property int nonContact: 0 + readonly property int contact: 1 + readonly property int contactRequestReceived: 2 + readonly property int contactRequestSent: 3 + } + readonly property QtObject trustStatus: QtObject { readonly property int unknown: 0 readonly property int trusted: 1 diff --git a/ui/imports/utils/Utils.qml b/ui/imports/utils/Utils.qml index 9f2927870df..482513de721 100644 --- a/ui/imports/utils/Utils.qml +++ b/ui/imports/utils/Utils.qml @@ -455,6 +455,44 @@ QtObject { } } + function getProfileContext(publicKey, myPublicKey, isBridgedAccount = false) { + const contactDetails = getContactDetailsAsJson(publicKey, true, true); + const isBlocked = contactDetails ? contactDetails.isBlocked : false; + + const profileType = getProfileType(publicKey, myPublicKey, isBridgedAccount, isBlocked); + const contactType = getContactType(contactDetails ? contactDetails.contactRequestState : Constants.ContactRequestState.None, contactDetails ? contactDetails.isContact : false); + const trustStatus = contactDetails ? contactDetails.trustStatus : Constants.trustStatus.unknown; + const ensVerified = contactDetails ? contactDetails.ensVerified : false; + const onlineStatus = contactDetails ? contactDetails.onlineStatus : Constants.onlineStatus.unknown; + const hasLocalNickname = contactDetails ? !!contactDetails.localNickname : false; + + return { profileType, trustStatus, contactType, ensVerified, onlineStatus, hasLocalNickname }; + } + + function getProfileType(publicKey, myPublicKey, isBridgedAccount, isBlocked) { + if (publicKey === myPublicKey) { + return Constants.profileType.self; + } + if (isBridgedAccount) { + return Constants.profileType.bridged; + } + if (isBlocked) { + return Constants.profileType.blocked; + } + return Constants.profileType.regular; + } + + function getContactType(contactRequestState, isContact) { + switch (contactRequestState) { + case Constants.ContactRequestState.Received: + return Constants.contactType.contactRequestReceived; + case Constants.ContactRequestState.Sent: + return Constants.contactType.contactRequestSent; + default: + return isContact ? Constants.contactType.contact : Constants.contactType.nonContact; + } + } + function isEnsVerified(publicKey) { if (publicKey === "" || !isChatKey(publicKey) ) return false