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
This commit is contained in:
Pascal Precht 2021-02-23 11:18:09 +01:00 committed by Iuri Matias
parent fd8a84eb9d
commit 84806ee96c
3 changed files with 50 additions and 3 deletions

View File

@ -131,6 +131,7 @@ Item {
} }
// Get contact nickname // Get contact nickname
let nickname = appMain.getUserNickname(fromAuthor) let nickname = appMain.getUserNickname(fromAuthor)
messageContextMenu.linkUrls = root.linkUrls
messageContextMenu.isProfile = !!isProfileClick messageContextMenu.isProfile = !!isProfileClick
messageContextMenu.isSticker = isSticker messageContextMenu.isSticker = isSticker
messageContextMenu.emojiOnly = emojiOnly messageContextMenu.emojiOnly = emojiOnly

View File

@ -11,6 +11,7 @@ PopupMenu {
property bool isProfile: false property bool isProfile: false
property bool isSticker: false property bool isSticker: false
property bool emojiOnly: false property bool emojiOnly: false
property string linkUrls: ""
property alias emojiContainer: emojiContainer property alias emojiContainer: emojiContainer
id: messageContextMenu id: messageContextMenu
@ -22,6 +23,13 @@ PopupMenu {
property var fromAuthor: "" property var fromAuthor: ""
property var text: "" property var text: ""
property var emojiReactionsReactedByUser: [] 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) { function show(userNameParam, fromAuthorParam, identiconParam, textParam, nicknameParam, emojiReactionsModel) {
userName = userNameParam || "" userName = userNameParam || ""
@ -37,6 +45,9 @@ PopupMenu {
} }
emojiReactionsReactedByUser = newEmojiReactions emojiReactionsReactedByUser = newEmojiReactions
const numLinkUrls = messageContextMenu.linkUrls.split(" ").length
copyLinkMenu.enabled = numLinkUrls > 1
copyLinkAction.enabled = !!messageContextMenu.linkUrls && numLinkUrls === 1
popup(); popup();
} }
@ -123,6 +134,35 @@ PopupMenu {
visible: !messageContextMenu.emojiOnly 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 { Action {
id: viewProfileAction id: viewProfileAction
//% "View Profile" //% "View Profile"

View File

@ -36,6 +36,12 @@ Menu {
return index return index
} }
enabled: {
if (this.subMenu) {
return this.subMenu.enabled
}
return this.action.enabled
}
action: Action{} // Meant to be overwritten action: Action{} // Meant to be overwritten
id: popupMenuItem id: popupMenuItem
implicitWidth: 200 implicitWidth: 200
@ -46,7 +52,7 @@ Menu {
icon.source: this.subMenu ? subMenuIcons[subMenuIndex].source : popupMenuItem.action.icon.source icon.source: this.subMenu ? subMenuIcons[subMenuIndex].source : popupMenuItem.action.icon.source
icon.width: this.subMenu ? subMenuIcons[subMenuIndex].width : popupMenuItem.action.icon.width icon.width: this.subMenu ? subMenuIcons[subMenuIndex].width : popupMenuItem.action.icon.width
icon.height: this.subMenu ? subMenuIcons[subMenuIndex].height : popupMenuItem.action.icon.height icon.height: this.subMenu ? subMenuIcons[subMenuIndex].height : popupMenuItem.action.icon.height
visible: popupMenuItem.action.enabled && !!popupMenuItem.text visible: enabled
height: visible ? popupMenuItem.implicitHeight : 0 height: visible ? popupMenuItem.implicitHeight : 0
arrow: SVGImage { arrow: SVGImage {
@ -57,7 +63,7 @@ Menu {
anchors.rightMargin: 12 anchors.rightMargin: 12
width: 9 width: 9
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
visible: popupMenuItem.subMenu visible: popupMenuItem.subMenu && popupMenuItem.subMenu.enabled
ColorOverlay { ColorOverlay {
anchors.fill: parent anchors.fill: parent
@ -107,7 +113,7 @@ Menu {
background: Rectangle { background: Rectangle {
implicitWidth: 220 implicitWidth: 220
implicitHeight: 24 implicitHeight: enabled ? 24 : 0
color: popupMenuItem.highlighted ? Style.current.backgroundHover : "transparent" color: popupMenuItem.highlighted ? Style.current.backgroundHover : "transparent"
} }
} }