From 84806ee96c8fc25d64402830cdde990e8be37db9 Mon Sep 17 00:00:00 2001 From: Pascal Precht Date: Tue, 23 Feb 2021 11:18:09 +0100 Subject: [PATCH] feat(MessageContextMenu): add copy link actions This commit adds a menu item to the message context menu to copy links that may exist inside of a message. There are three possible scenarios: 1. There's no link in the message, which causes the menu to not render the dedicated menu item at all 2. There's one link in the message, which renders an additional `Action` with a copy-to-clipboard functionality 3. There are multiple links in a single message. This adds a nested `PopupMenu` in the existing menu with menu items for each link extracted from the message To make this work there were some changes in the `PopupMenu` component needed, as it wasn't take the sub menu's `enabled` state into account properly. This makde it always render nested menus even when they should've been invisible. Closes: #1733 --- ui/app/AppLayouts/Chat/ChatColumn/Message.qml | 1 + .../Chat/components/MessageContextMenu.qml | 40 +++++++++++++++++++ ui/shared/PopupMenu.qml | 12 ++++-- 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/ui/app/AppLayouts/Chat/ChatColumn/Message.qml b/ui/app/AppLayouts/Chat/ChatColumn/Message.qml index e4e3fd318f..83a7adeaf2 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/Message.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/Message.qml @@ -131,6 +131,7 @@ Item { } // Get contact nickname let nickname = appMain.getUserNickname(fromAuthor) + messageContextMenu.linkUrls = root.linkUrls messageContextMenu.isProfile = !!isProfileClick messageContextMenu.isSticker = isSticker messageContextMenu.emojiOnly = emojiOnly diff --git a/ui/app/AppLayouts/Chat/components/MessageContextMenu.qml b/ui/app/AppLayouts/Chat/components/MessageContextMenu.qml index 6fe18d2f17..7bc5835e32 100644 --- a/ui/app/AppLayouts/Chat/components/MessageContextMenu.qml +++ b/ui/app/AppLayouts/Chat/components/MessageContextMenu.qml @@ -11,6 +11,7 @@ PopupMenu { property bool isProfile: false property bool isSticker: false property bool emojiOnly: false + property string linkUrls: "" property alias emojiContainer: emojiContainer id: messageContextMenu @@ -22,6 +23,13 @@ PopupMenu { property var fromAuthor: "" property var text: "" property var emojiReactionsReactedByUser: [] + subMenuIcons: [ + { + source: Qt.resolvedUrl("../../../../shared/img/copy-to-clipboard-icon"), + width: 16, + height: 16 + } + ] function show(userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam, emojiReactionsModel) { userName = userNameParam || "" @@ -37,6 +45,9 @@ PopupMenu { } emojiReactionsReactedByUser = newEmojiReactions + const numLinkUrls = messageContextMenu.linkUrls.split(" ").length + copyLinkMenu.enabled = numLinkUrls > 1 + copyLinkAction.enabled = !!messageContextMenu.linkUrls && numLinkUrls === 1 popup(); } @@ -123,6 +134,35 @@ PopupMenu { visible: !messageContextMenu.emojiOnly } + Action { + id: copyLinkAction + text: qsTr("Copy link") + onTriggered: { + chatsModel.copyToClipboard(linkUrls.split(" ")[0]) + messageContextMenu.close() + } + icon.source: "../../../../shared/img/copy-to-clipboard-icon" + icon.width: 16 + icon.height: 16 + enabled: false + } + + PopupMenu { + id: copyLinkMenu + title: qsTr("Copy link") + Repeater { + id: linksRepeater + model: messageContextMenu.linkUrls.split(" ") + delegate: MenuItem { + text: modelData + onTriggered: { + chatsModel.copyToClipboard(modelData) + messageContextMenu.close() + } + } + } + } + Action { id: viewProfileAction //% "View Profile" diff --git a/ui/shared/PopupMenu.qml b/ui/shared/PopupMenu.qml index 6a60b889c9..249a89d1df 100644 --- a/ui/shared/PopupMenu.qml +++ b/ui/shared/PopupMenu.qml @@ -36,6 +36,12 @@ Menu { return index } + enabled: { + if (this.subMenu) { + return this.subMenu.enabled + } + return this.action.enabled + } action: Action{} // Meant to be overwritten id: popupMenuItem implicitWidth: 200 @@ -46,7 +52,7 @@ Menu { icon.source: this.subMenu ? subMenuIcons[subMenuIndex].source : popupMenuItem.action.icon.source icon.width: this.subMenu ? subMenuIcons[subMenuIndex].width : popupMenuItem.action.icon.width icon.height: this.subMenu ? subMenuIcons[subMenuIndex].height : popupMenuItem.action.icon.height - visible: popupMenuItem.action.enabled && !!popupMenuItem.text + visible: enabled height: visible ? popupMenuItem.implicitHeight : 0 arrow: SVGImage { @@ -57,7 +63,7 @@ Menu { anchors.rightMargin: 12 width: 9 fillMode: Image.PreserveAspectFit - visible: popupMenuItem.subMenu + visible: popupMenuItem.subMenu && popupMenuItem.subMenu.enabled ColorOverlay { anchors.fill: parent @@ -107,7 +113,7 @@ Menu { background: Rectangle { implicitWidth: 220 - implicitHeight: 24 + implicitHeight: enabled ? 24 : 0 color: popupMenuItem.highlighted ? Style.current.backgroundHover : "transparent" } }