From 0a18dda17680e9522ae6c1b807f18805643b29db Mon Sep 17 00:00:00 2001 From: Michal Iskierko Date: Fri, 5 Jan 2024 16:34:20 +0100 Subject: [PATCH] feat(@desktop/chat): Displaying new type of chat message - bridge message Show discord user as a message sender. Show discord avatar next to user name. Show "Bridged from Discord" label. Open adjusted profile context menu. Issue #13098 --- .../modules/main/activity_center/module.nim | 1 + .../chat_content/messages/module.nim | 3 ++ .../main/chat_section/chat_content/module.nim | 1 + .../modules/shared_models/message_item.nim | 14 +++++++++ .../modules/shared_models/message_model.nim | 4 +++ src/app_service/common/types.nim | 1 + .../service/message/dto/message.nim | 23 ++++++++++++++ test/nim/message_model_test.nim | 1 + .../src/StatusQ/Components/StatusMessage.qml | 8 +++-- .../Components/StatusMessageSenderDetails.qml | 2 ++ .../Components/StatusSmartIdenticon.qml | 18 ++++++++++- .../Chat/popups/PinnedMessagesPopup.qml | 1 + .../Chat/views/ChatMessagesView.qml | 1 + ui/imports/assets/icons/discord-bridge.svg | 11 +++++++ .../shared/controls/chat/ProfileHeader.qml | 10 +++--- ui/imports/shared/controls/chat/UserImage.qml | 5 ++- ui/imports/shared/views/chat/MessageView.qml | 31 +++++++++++++++---- .../shared/views/chat/ProfileContextMenu.qml | 23 +++++++++----- ui/imports/utils/Constants.qml | 1 + 19 files changed, 137 insertions(+), 22 deletions(-) create mode 100644 ui/imports/assets/icons/discord-bridge.svg diff --git a/src/app/modules/main/activity_center/module.nim b/src/app/modules/main/activity_center/module.nim index ff55499f41..67ad7ff293 100644 --- a/src/app/modules/main/activity_center/module.nim +++ b/src/app/modules/main/activity_center/module.nim @@ -147,6 +147,7 @@ proc createMessageItemFromDto(self: Module, message: MessageDto, communityId: st imagesAlbum, albumMessageIds, message.albumImagesCount, + message.bridgeMessage, )) method convertToItems*( diff --git a/src/app/modules/main/chat_section/chat_content/messages/module.nim b/src/app/modules/main/chat_section/chat_content/messages/module.nim index 09fcbb1e1a..ca57cc2ccd 100644 --- a/src/app/modules/main/chat_section/chat_content/messages/module.nim +++ b/src/app/modules/main/chat_section/chat_content/messages/module.nim @@ -206,6 +206,7 @@ proc createMessageItemsFromMessageDtos(self: Module, messages: seq[MessageDto], if (len(message.albumId) == 0): @[] else: @[message.image], if (len(message.albumId) == 0): @[] else: @[message.id], message.albumImagesCount, + message.bridgeMessage, ) self.updateLinkPreviewsContacts(item, requestFromMailserver = item.seen) @@ -284,6 +285,7 @@ proc createFetchMoreMessagesItem(self: Module): Item = albumMessageImages = @[], albumMessageIds = @[], albumImagesCount = 0, + BridgeMessage(), ) proc createChatIdentifierItem(self: Module): Item = @@ -349,6 +351,7 @@ proc createChatIdentifierItem(self: Module): Item = albumMessageImages = @[], albumMessageIds = @[], albumImagesCount = 0, + bridgeMessage = BridgeMessage(), ) proc checkIfMessageLoadedAndScrollToItIfItIs(self: Module) = diff --git a/src/app/modules/main/chat_section/chat_content/module.nim b/src/app/modules/main/chat_section/chat_content/module.nim index 6e0ddfdc2a..3bac2c1296 100644 --- a/src/app/modules/main/chat_section/chat_content/module.nim +++ b/src/app/modules/main/chat_section/chat_content/module.nim @@ -228,6 +228,7 @@ proc buildPinnedMessageItem(self: Module, message: MessageDto, actionInitiatedBy if (len(message.albumId) == 0): @[] else: @[message.image], if (len(message.albumId) == 0): @[] else: @[message.id], message.albumImagesCount, + message.bridgeMessage, ) item.pinned = true item.pinnedBy = actionInitiatedBy diff --git a/src/app/modules/shared_models/message_item.nim b/src/app/modules/shared_models/message_item.nim index 86263f81b1..acc54e1f01 100644 --- a/src/app/modules/shared_models/message_item.nim +++ b/src/app/modules/shared_models/message_item.nim @@ -70,6 +70,7 @@ type albumMessageImages: seq[string] albumMessageIds: seq[string] albumImagesCount: int + bridgeName: string proc initItem*( id, @@ -121,6 +122,7 @@ proc initItem*( albumMessageImages: seq[string], albumMessageIds: seq[string], albumImagesCount: int, + bridgeMessage: BridgeMessage, ): Item = result = Item() result.id = id @@ -208,6 +210,13 @@ proc initItem*( if attachment.contentType.contains("image"): result.messageAttachments.add(attachment.localUrl) + if contentType == ContentType.BridgeMessage: + result.messageText = bridgeMessage.content + result.unparsedText = bridgeMessage.content + result.senderDisplayName = bridgeMessage.userName + result.senderIcon = bridgeMessage.userAvatar + result.bridgeName = bridgeMessage.bridgeName + proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item = return initItem( id = "", @@ -259,6 +268,7 @@ proc initNewMessagesMarkerItem*(clock, timestamp: int64): Item = albumMessageImages = @[], albumMessageIds = @[], albumImagesCount = 0, + bridgeMessage = BridgeMessage(), ) proc `$`*(self: Item): string = @@ -404,6 +414,9 @@ proc `albumMessageIds=`*(self: Item, value: seq[string]) {.inline.} = proc albumImagesCount*(self: Item): int {.inline.} = self.albumImagesCount +proc bridgeName*(self: Item): string {.inline.} = + self.bridgeName + proc messageContainsMentions*(self: Item): bool {.inline.} = self.messageContainsMentions @@ -542,6 +555,7 @@ proc toJsonNode*(self: Item): JsonNode = "albumMessageImages": self.albumMessageImages, "albumMessageIds": self.albumMessageIds, "albumImagesCount": self.albumImagesCount, + "bridgeName": self.bridgeName } proc editMode*(self: Item): bool {.inline.} = diff --git a/src/app/modules/shared_models/message_model.nim b/src/app/modules/shared_models/message_model.nim index 9f1f3dd300..d4790dad11 100644 --- a/src/app/modules/shared_models/message_model.nim +++ b/src/app/modules/shared_models/message_model.nim @@ -73,6 +73,7 @@ type QuotedMessageAlbumImagesCount AlbumMessageImages AlbumImagesCount + BridgeName QtObject: type @@ -178,6 +179,7 @@ QtObject: ModelRole.QuotedMessageAlbumImagesCount.int: "quotedMessageAlbumImagesCount", ModelRole.AlbumMessageImages.int: "albumMessageImages", ModelRole.AlbumImagesCount.int: "albumImagesCount", + ModelRole.BridgeName.int: "bridgeName", }.toTable method data(self: Model, index: QModelIndex, role: int): QVariant = @@ -350,6 +352,8 @@ QtObject: result = newQVariant(item.albumMessageImages.join(" ")) of ModelRole.AlbumImagesCount: result = newQVariant(item.albumImagesCount) + of ModelRole.BridgeName: + result = newQVariant(item.bridgeName) proc updateItemAtIndex(self: Model, index: int) = let ind = self.createIndex(index, 0, nil) diff --git a/src/app_service/common/types.nim b/src/app_service/common/types.nim index a81edd6ed5..e66ac48a7a 100644 --- a/src/app_service/common/types.nim +++ b/src/app_service/common/types.nim @@ -22,6 +22,7 @@ type SystemMessageMutualEventSent = 15 SystemMessageMutualEventAccepted = 16 SystemMessageMutualEventRemoved = 17 + BridgeMessage = 18 proc toContentType*(value: int): ContentType = try: diff --git a/src/app_service/service/message/dto/message.nim b/src/app_service/service/message/dto/message.nim index 5e3796fed4..d230bdf8a8 100644 --- a/src/app_service/service/message/dto/message.nim +++ b/src/app_service/service/message/dto/message.nim @@ -56,6 +56,14 @@ type DiscordMessage* = object author*: DiscordMessageAuthor attachments*: seq[DiscordMessageAttachment] +type BridgeMessage* = object + bridgeName*: string + userName*: string + userAvatar*: string + userId*: string + content*: string + messageId*: string + parentMessageId*: string type QuotedMessage* = object `from`*: string @@ -95,6 +103,7 @@ type MessageDto* = object outgoingStatus*: string quotedMessage*: QuotedMessage discordMessage*: DiscordMessage + bridgeMessage*: BridgeMessage rtl*: bool parsedText*: seq[ParsedText] lineCount*: int @@ -170,6 +179,16 @@ proc toDiscordMessage*(jsonObj: JsonNode): DiscordMessage = for attachment in attachmentsArr: result.attachments.add(toDiscordMessageAttachment(attachment)) +proc toBridgeMessage*(jsonObj: JsonNode): BridgeMessage = + result = BridgeMessage() + discard jsonObj.getProp("userName", result.userName) + discard jsonObj.getProp("bridgeName", result.bridgeName) + discard jsonObj.getProp("userAvatar", result.userAvatar) + discard jsonObj.getProp("userID", result.userId) + discard jsonObj.getProp("content", result.content) + discard jsonObj.getProp("messageID", result.messageId) + discard jsonObj.getProp("parentMessageID", result.parentMessageId) + proc toQuotedMessage*(jsonObj: JsonNode): QuotedMessage = result = QuotedMessage() var contentType: int @@ -263,6 +282,10 @@ proc toMessageDto*(jsonObj: JsonNode): MessageDto = if(jsonObj.getProp("discordMessage", discordMessageObj)): result.discordMessage = toDiscordMessage(discordMessageObj) + var bridgeMessageObj: JsonNode + if(jsonObj.getProp("bridgeMessage", bridgeMessageObj)): + result.bridgeMessage = toBridgeMessage(bridgeMessageObj) + var stickerObj: JsonNode if(jsonObj.getProp("sticker", stickerObj)): result.sticker = toSticker(stickerObj) diff --git a/test/nim/message_model_test.nim b/test/nim/message_model_test.nim index 65813509a5..dc3228203c 100644 --- a/test/nim/message_model_test.nim +++ b/test/nim/message_model_test.nim @@ -59,6 +59,7 @@ proc createTestMessageItem(id: string, clock: int64): Item = albumMessageImages = @[], albumMessageIds = @[], albumImagesCount = 0, + bridgeMessage = BridgeMessage(), ) let message0_chatIdentifier = createTestMessageItem("chat-identifier", -2) diff --git a/ui/StatusQ/src/StatusQ/Components/StatusMessage.qml b/ui/StatusQ/src/StatusQ/Components/StatusMessage.qml index 76da5cd61a..39668b05ba 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusMessage.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusMessage.qml @@ -25,7 +25,8 @@ Control { SystemMessagePinnedMessage = 14, SystemMessageMutualEventSent = 15, SystemMessageMutualEventAccepted = 16, - SystemMessageMutualEventRemoved = 17 + SystemMessageMutualEventRemoved = 17, + BridgeMessage = 18 } property list quickActions @@ -221,6 +222,8 @@ Control { name: root.messageDetails.sender.displayName asset: root.messageDetails.sender.profileImage.assetSettings ringSettings: root.messageDetails.sender.profileImage.ringSettings + bridgeBadge.visible: root.messageDetails.contentType === StatusMessage.ContentType.BridgeMessage + bridgeBadge.image.source: root.messageDetails.sender.badgeImage MouseArea { cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor @@ -267,7 +270,8 @@ Control { && ((root.messageDetails.contentType === StatusMessage.ContentType.Text) || (root.messageDetails.contentType === StatusMessage.ContentType.Emoji) || (root.messageDetails.contentType === StatusMessage.ContentType.DiscordMessage) || - (root.messageDetails.contentType === StatusMessage.ContentType.Invitation))) + (root.messageDetails.contentType === StatusMessage.ContentType.Invitation) || + (root.messageDetails.contentType === StatusMessage.ContentType.BridgeMessage))) visible: active sourceComponent: StatusTextMessage { objectName: "StatusMessage_textMessage" diff --git a/ui/StatusQ/src/StatusQ/Components/StatusMessageSenderDetails.qml b/ui/StatusQ/src/StatusQ/Components/StatusMessageSenderDetails.qml index 8ef66025df..36b0cc1d41 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusMessageSenderDetails.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusMessageSenderDetails.qml @@ -12,6 +12,8 @@ QtObject { property bool isContact: false property int trustIndicator: StatusContactVerificationIcons.TrustedType.None + property string badgeImage: "" + property StatusProfileImageSettings profileImage: StatusProfileImageSettings { pubkey: root.id showRing: !root.isEnsVerified diff --git a/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml b/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml index 7b80c48918..8b24875e8c 100644 --- a/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml +++ b/ui/StatusQ/src/StatusQ/Components/StatusSmartIdenticon.qml @@ -12,6 +12,8 @@ Loader { // Badge color properties must be set if badgeItem.visible = true property alias badge: statusBadge + property alias bridgeBadge: bridgeBadge + property StatusAssetSettings asset: StatusAssetSettings { width: 40 height: 40 @@ -33,7 +35,7 @@ Loader { property bool loading: false property bool hoverEnabled: false - readonly property bool hovered: (sourceComponent == roundedIcon && item) ? + readonly property bool hovered: (sourceComponent === roundedIcon && item) ? item.hovered : false signal clicked(var mouse) @@ -140,6 +142,20 @@ Loader { z: root.dZ } + StatusRoundedImage { + id: bridgeBadge + visible: false + anchors.bottom: root.bottom + anchors.right: root.right + anchors.rightMargin: -border.width + anchors.bottomMargin: -border.width + implicitHeight: 20 + implicitWidth: 20 + border.width: 3 + border.color: Theme.palette.statusBadge.foregroundColor + z: root.dZ + } + Component { id: loadingComp LoadingComponent { diff --git a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml index 6fa88dd603..f14f9c99af 100644 --- a/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml +++ b/ui/app/AppLayouts/Chat/popups/PinnedMessagesPopup.qml @@ -111,6 +111,7 @@ StatusDialog { quotedMessageAuthorDetailsEnsVerified: model.quotedMessageAuthorEnsVerified quotedMessageAuthorDetailsIsContact: model.quotedMessageAuthorIsContact quotedMessageAuthorDetailsColorHash: model.quotedMessageAuthorColorHash + bridgeName: model.bridgeName // This is possible since we have all data loaded before we load qml. // When we fetch messages to fulfill a gap we have to set them at once. diff --git a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml index 3e986ce660..6c4b229c1d 100644 --- a/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml +++ b/ui/app/AppLayouts/Chat/views/ChatMessagesView.qml @@ -325,6 +325,7 @@ Item { quotedMessageAuthorDetailsColorHash: model.quotedMessageAuthorColorHash quotedMessageAlbumMessageImages: model.quotedMessageAlbumMessageImages.split(" ") quotedMessageAlbumImagesCount: model.quotedMessageAlbumImagesCount + bridgeName: model.bridgeName gapFrom: model.gapFrom gapTo: model.gapTo diff --git a/ui/imports/assets/icons/discord-bridge.svg b/ui/imports/assets/icons/discord-bridge.svg new file mode 100644 index 0000000000..a25f5ebfa2 --- /dev/null +++ b/ui/imports/assets/icons/discord-bridge.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/ui/imports/shared/controls/chat/ProfileHeader.qml b/ui/imports/shared/controls/chat/ProfileHeader.qml index b8eba97bcf..770e0d5b57 100644 --- a/ui/imports/shared/controls/chat/ProfileHeader.qml +++ b/ui/imports/shared/controls/chat/ProfileHeader.qml @@ -40,6 +40,7 @@ Item { property bool editButtonVisible: displayNamePlusIconsVisible property bool loading: false readonly property bool compact: root.imageSize === ProfileHeader.ImageSize.Compact + property bool isBridgedAccount: false signal clicked() signal editClicked() @@ -119,6 +120,7 @@ Item { imageHeight: imageWidth ensVerified: root.userIsEnsVerified loading: root.loading + isBridgedAccount: root.isBridgedAccount } StatusRoundButton { @@ -206,7 +208,7 @@ Item { StatusContactVerificationIcons { Layout.alignment: Qt.AlignVCenter - visible: !root.isCurrentUser + visible: !root.isCurrentUser && !root.isBridgedAccount isContact: root.isContact trustIndicator: root.trustStatus } @@ -235,7 +237,7 @@ Item { Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter visible: root.pubkeyVisible - text: Utils.getElidedCompressedPk(pubkey) + text: root.isBridgedAccount ? qsTr("Bridged from Discord") : Utils.getElidedCompressedPk(pubkey) horizontalAlignment: Text.AlignHCenter font.pixelSize: 13 color: Style.current.secondaryText @@ -243,7 +245,7 @@ Item { RowLayout { Layout.alignment: Qt.AlignHCenter - visible: root.pubkeyVisibleWithCopy + visible: root.pubkeyVisibleWithCopy && !root.isBridgedAccount StyledText { id: txtChatKey text: qsTr("Chatkey:%1...").arg(pubkey.substring(0, 32)) @@ -265,7 +267,7 @@ Item { EmojiHash { id: emojiHash Layout.alignment: Qt.AlignHCenter - visible: root.emojiHashVisible + visible: root.emojiHashVisible && !root.isBridgedAccount compact: root.compact publicKey: root.pubkey } diff --git a/ui/imports/shared/controls/chat/UserImage.qml b/ui/imports/shared/controls/chat/UserImage.qml index 7eefb339ac..24e3977a0a 100644 --- a/ui/imports/shared/controls/chat/UserImage.qml +++ b/ui/imports/shared/controls/chat/UserImage.qml @@ -16,11 +16,12 @@ Loader { property string name property string pubkey property string image - property bool showRing: !ensVerified + property bool showRing: !ensVerified && !root.isBridgedAccount property bool interactive: true property bool disabled: false property bool ensVerified: false property bool loading: false + property bool isBridgedAccount: false property int colorId: Utils.colorIdForPubkey(pubkey) property var colorHash: Utils.getColorHashAsJson(pubkey, ensVerified) @@ -41,6 +42,8 @@ Loader { ringSpecModel: root.showRing ? root.colorHash : undefined } loading: root.loading + bridgeBadge.visible: root.isBridgedAccount + bridgeBadge.image.source: Style.svg("discord-bridge") Loader { anchors.fill: parent diff --git a/ui/imports/shared/views/chat/MessageView.qml b/ui/imports/shared/views/chat/MessageView.qml index d6ba477be5..38875e6eed 100644 --- a/ui/imports/shared/views/chat/MessageView.qml +++ b/ui/imports/shared/views/chat/MessageView.qml @@ -128,13 +128,15 @@ Loader { property bool stickersLoaded: false property string sticker property int stickerPack: -1 + property string bridgeName: "" property bool isEmoji: messageContentType === Constants.messageContentType.emojiType property bool isImage: messageContentType === Constants.messageContentType.imageType || (isDiscordMessage && messageImage != "") property bool isAudio: messageContentType === Constants.messageContentType.audioType property bool isSticker: messageContentType === Constants.messageContentType.stickerType property bool isDiscordMessage: messageContentType === Constants.messageContentType.discordMessageType - property bool isText: messageContentType === Constants.messageContentType.messageType || messageContentType === Constants.messageContentType.contactRequestType || isDiscordMessage + property bool isBridgeMessage: messageContentType === Constants.messageContentType.bridgeMessageType + property bool isText: messageContentType === Constants.messageContentType.messageType || messageContentType === Constants.messageContentType.contactRequestType || isDiscordMessage || isBridgeMessage property bool isMessage: isEmoji || isImage || isSticker || isText || isAudio || messageContentType === Constants.messageContentType.communityInviteType || messageContentType === Constants.messageContentType.transactionType @@ -152,6 +154,7 @@ Loader { selectedUserPublicKey: isReply ? quotedMessageFrom : root.senderId, selectedUserDisplayName: isReply ? quotedMessageAuthorDetailsDisplayName : root.senderDisplayName, selectedUserIcon: isReply ? quotedMessageAuthorDetailsThumbnailImage : root.senderIcon, + isBridgedAccount: root.isBridgeMessage } Global.openMenu(profileContextMenuComponent, sender, params) @@ -239,6 +242,7 @@ Loader { case Constants.messageContentType.communityInviteType: case Constants.messageContentType.discordMessageType: case Constants.messageContentType.contactRequestType: + case Constants.messageContentType.bridgeMessageType: return messageComponent case Constants.messageContentType.unknownContentType: // NOTE: We could display smth like "unknown message type, please upgrade Status to see it". @@ -296,6 +300,8 @@ Loader { return StatusMessage.ContentType.Invitation; case Constants.messageContentType.discordMessageType: return StatusMessage.ContentType.DiscordMessage; + case Constants.messageContentType.bridgeMessageType: + return StatusMessage.ContentType.BridgeMessage; case Constants.messageContentType.systemMessagePinnedMessage: return StatusMessage.ContentType.SystemMessagePinnedMessage; case Constants.messageContentType.systemMessageMutualEventSent: @@ -333,6 +339,11 @@ Loader { break; } } + + + function correctBridgeNameCapitalization(bridgeName) { + return (bridgeName === "discord") ? "Discord" : bridgeName + } } Component { @@ -724,7 +735,14 @@ Loader { messageDetails: StatusMessageDetails { contentType: delegate.contentType - messageOriginInfo: isDiscordMessage ? qsTr("Imported from discord") : "" + messageOriginInfo: { + if (isDiscordMessage) { + return qsTr("Imported from discord") + } else if (isBridgeMessage) { + return qsTr("Bridged from %1").arg(d.correctBridgeNameCapitalization(root.bridgeName)) + } + return "" + } messageText: root.messageText messageContent: { switch (delegate.contentType) @@ -747,9 +765,9 @@ Loader { sender.id: root.senderIsEnsVerified ? "" : Utils.getCompressedPk(root.senderId) sender.displayName: root.senderDisplayName sender.secondaryName: root.senderOptionalName - sender.isEnsVerified: root.senderIsEnsVerified - sender.isContact: root.senderIsAdded - sender.trustIndicator: root.senderTrustStatus + sender.isEnsVerified: root.isBridgeMessage ? false : root.senderIsEnsVerified + sender.isContact: root.isBridgeMessage ? false : root.senderIsAdded + sender.trustIndicator: root.isBridgeMessage ? StatusContactVerificationIcons.TrustedType.None: root.senderTrustStatus sender.profileImage { width: 40 height: 40 @@ -757,8 +775,9 @@ Loader { pubkey: root.senderId colorId: Utils.colorIdForPubkey(root.senderId) colorHash: root.senderColorHash - showRing: !root.isDiscordMessage && !root.senderIsEnsVerified + showRing: !root.isDiscordMessage && !root.senderIsEnsVerified && !root.isBridgeMessage } + sender.badgeImage: Style.svg("discord-bridge") } replyDetails: StatusMessageDetails { diff --git a/ui/imports/shared/views/chat/ProfileContextMenu.qml b/ui/imports/shared/views/chat/ProfileContextMenu.qml index 1e88b71901..05de979e13 100644 --- a/ui/imports/shared/views/chat/ProfileContextMenu.qml +++ b/ui/imports/shared/views/chat/ProfileContextMenu.qml @@ -25,6 +25,8 @@ StatusMenu { property string selectedUserDisplayName: "" property string selectedUserIcon: "" + property bool isBridgedAccount: false + readonly property bool isMe: { return root.selectedUserPublicKey === root.store.contactsStore.myPublicKey; } @@ -104,15 +106,18 @@ StatusMenu { isContact: root.isContact isCurrentUser: root.isMe userIsEnsVerified: (!!contactDetails && contactDetails.ensVerified) || false + isBridgedAccount: root.isBridgedAccount } StatusMenuSeparator { topPadding: root.topPadding + visible: !root.isBridgedAccount } ViewProfileMenuItem { id: viewProfileAction objectName: "viewProfile_StatusItem" + enabled: !root.isBridgedAccount onTriggered: { root.openProfileClicked(root.selectedUserPublicKey) root.close() @@ -122,7 +127,7 @@ StatusMenu { SendMessageMenuItem { id: sendMessageMenuItem objectName: "sendMessage_StatusItem" - enabled: root.isContact && !root.isBlockedContact + enabled: root.isContact && !root.isBlockedContact && !root.isBridgedAccount onTriggered: { root.createOneToOneChat("", root.selectedUserPublicKey, "") root.close() @@ -133,7 +138,7 @@ StatusMenu { id: sendContactRequestMenuItem objectName: "sendContactRequest_StatusItem" enabled: !root.isMe && !root.isContact - && !root.isBlockedContact && !root.hasPendingContactRequest + && !root.isBlockedContact && !root.hasPendingContactRequest && !root.isBridgedAccount onTriggered: { Global.openContactRequestPopup(root.selectedUserPublicKey, null) root.close() @@ -149,6 +154,7 @@ StatusMenu { && !root.isBlockedContact && root.outgoingVerificationStatus === Constants.verificationStatus.unverified && !root.hasActiveReceivedVerificationRequestFrom + && !root.isBridgedAccount onTriggered: { Global.openSendIDRequestPopup(root.selectedUserPublicKey, null) root.close() @@ -167,6 +173,7 @@ StatusMenu { && !root.isBlockedContact && !root.isTrusted && (root.hasActiveReceivedVerificationRequestFrom || root.isVerificationRequestSent) + && !root.isBridgedAccount onTriggered: { if (hasActiveReceivedVerificationRequestFrom) { Global.openIncomingIDRequestPopup(root.selectedUserPublicKey, null) @@ -183,7 +190,7 @@ StatusMenu { objectName: "rename_StatusItem" text: qsTr("Rename") icon.name: "edit_pencil" - enabled: !root.isMe + enabled: !root.isMe && !root.isBridgedAccount onTriggered: { Global.openNicknamePopupRequested(root.selectedUserPublicKey, contactDetails.localNickname, "%1 (%2)".arg(root.selectedUserDisplayName).arg(Utils.getElidedCompressedPk(root.selectedUserPublicKey))) @@ -196,7 +203,7 @@ StatusMenu { objectName: "unblock_StatusItem" text: qsTr("Unblock User") icon.name: "remove-circle" - enabled: !root.isMe && root.isBlockedContact + enabled: !root.isMe && root.isBlockedContact && !root.isBridgedAccount onTriggered: Global.unblockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName) } @@ -212,7 +219,7 @@ StatusMenu { text: qsTr("Mark as Untrustworthy") icon.name: "warning" type: StatusAction.Type.Danger - enabled: !root.isMe && root.userTrustIsUnknown + enabled: !root.isMe && root.userTrustIsUnknown && !root.isBridgedAccount onTriggered: root.store.contactsStore.markUntrustworthy(root.selectedUserPublicKey) } @@ -221,7 +228,7 @@ StatusMenu { objectName: "removeUntrustworthy_StatusItem" text: qsTr("Remove Untrustworthy Mark") icon.name: "warning" - enabled: !root.isMe && root.userIsUntrustworthy + enabled: !root.isMe && root.userIsUntrustworthy && !root.isBridgedAccount onTriggered: root.store.contactsStore.removeTrustStatus(root.selectedUserPublicKey) } @@ -230,7 +237,7 @@ StatusMenu { objectName: "removeContact_StatusItem" icon.name: "remove-contact" type: StatusAction.Type.Danger - enabled: root.isContact && !root.isBlockedContact && !root.hasPendingContactRequest + enabled: root.isContact && !root.isBlockedContact && !root.hasPendingContactRequest && !root.isBridgedAccount onTriggered: { Global.removeContactRequested(root.selectedUserDisplayName, root.selectedUserPublicKey) root.close() @@ -243,7 +250,7 @@ StatusMenu { text: qsTr("Block User") icon.name: "cancel" type: StatusAction.Type.Danger - enabled: !root.isMe && !root.isBlockedContact + enabled: !root.isMe && !root.isBlockedContact && !root.isBridgedAccount onTriggered: Global.blockContactRequested(root.selectedUserPublicKey, root.selectedUserDisplayName) } diff --git a/ui/imports/utils/Constants.qml b/ui/imports/utils/Constants.qml index 7b1b3b9021..6abc200292 100644 --- a/ui/imports/utils/Constants.qml +++ b/ui/imports/utils/Constants.qml @@ -457,6 +457,7 @@ QtObject { readonly property int systemMessageMutualEventSent: 15 readonly property int systemMessageMutualEventAccepted: 16 readonly property int systemMessageMutualEventRemoved: 17 + readonly property int bridgeMessageType: 18 } readonly property QtObject messageModelRoles: QtObject {