diff --git a/src/qml/DelegateContextMenu.qml b/src/qml/DelegateContextMenu.qml index 2de8825d6..574fff074 100644 --- a/src/qml/DelegateContextMenu.qml +++ b/src/qml/DelegateContextMenu.qml @@ -57,6 +57,11 @@ Loader { */ property string selectedText: "" + /** + * @brief The link the user has currently hovered. + */ + property string hoveredLink: "" + /** * @brief The list of menu item actions that have sub-actions. * diff --git a/src/qml/MessageDelegateContextMenu.qml b/src/qml/MessageDelegateContextMenu.qml index 33f0c12b6..25a65f654 100644 --- a/src/qml/MessageDelegateContextMenu.qml +++ b/src/qml/MessageDelegateContextMenu.qml @@ -63,6 +63,12 @@ DelegateContextMenu { separator: true }, DelegateContextMenu.RemoveMessageAction {}, + Kirigami.Action { + text: i18nc("@action:inmenu", "Copy Link Address") + icon.name: "edit-copy" + visible: root.hoveredLink.length > 0 + onTriggered: Clipboard.saveText(root.hoveredLink) + }, Kirigami.Action { text: i18nc("@action:inmenu", "Copy Text") icon.name: "edit-copy" diff --git a/src/qml/RoomPage.qml b/src/qml/RoomPage.qml index 8a7f4b955..fdce1a171 100644 --- a/src/qml/RoomPage.qml +++ b/src/qml/RoomPage.qml @@ -245,9 +245,10 @@ Kirigami.Page { }); } - function onShowMessageMenu(eventId, author, messageComponentType, plainText, htmlText, selectedText, isThread) { + function onShowMessageMenu(eventId, author, messageComponentType, plainText, htmlText, selectedText, hoveredLink, isThread) { const contextMenu = messageDelegateContextMenu.createObject(root, { selectedText: selectedText, + hoveredLink: hoveredLink, author: author, eventId: eventId, messageComponentType: messageComponentType, diff --git a/src/roommanager.cpp b/src/roommanager.cpp index 9135f2b31..6b455eaed 100644 --- a/src/roommanager.cpp +++ b/src/roommanager.cpp @@ -195,7 +195,7 @@ void RoomManager::viewEventSource(const QString &eventId) Q_EMIT showEventSource(eventId); } -void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText) +void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText, const QString &hoveredLink) { const auto &event = **room->findInTimeline(eventId); @@ -214,7 +214,8 @@ void RoomManager::viewEventMenu(const QString &eventId, NeoChatRoom *room, Neoch MessageComponentType::typeForEvent(event), EventHandler::plainBody(room, &event), EventHandler::richBody(room, &event), - selectedText); + selectedText, + hoveredLink); } bool RoomManager::hasOpenRoom() const diff --git a/src/roommanager.h b/src/roommanager.h index 7679f3fe3..8f26fad71 100644 --- a/src/roommanager.h +++ b/src/roommanager.h @@ -232,7 +232,8 @@ public: /** * @brief Show a context menu for the given event. */ - Q_INVOKABLE void viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {}); + Q_INVOKABLE void + viewEventMenu(const QString &eventId, NeoChatRoom *room, NeochatRoomMember *sender, const QString &selectedText = {}, const QString &hoveredLink = {}); ChatDocumentHandler *chatDocumentHandler() const; void setChatDocumentHandler(ChatDocumentHandler *handler); @@ -313,7 +314,8 @@ Q_SIGNALS: MessageComponentType::Type messageComponentType, const QString &plainText, const QString &htmlText, - const QString &selectedText); + const QString &selectedText, + const QString &hoveredLink); /** * @brief Request to show a menu for the given media event. diff --git a/src/timeline/Bubble.qml b/src/timeline/Bubble.qml index d035fea4b..5e161b899 100644 --- a/src/timeline/Bubble.qml +++ b/src/timeline/Bubble.qml @@ -78,6 +78,11 @@ QQC2.Control { */ signal selectedTextChanged(string selectedText) + /** + * @brief The user hovered link has changed. + */ + signal hoveredLinkChanged(string hoveredLink) + /** * @brief Request a context menu be show for the message. */ @@ -108,6 +113,9 @@ QQC2.Control { onSelectedTextChanged: selectedText => { root.selectedTextChanged(selectedText); } + onHoveredLinkChanged: hoveredLink => { + root.hoveredLinkChanged(hoveredLink); + } onShowMessageMenu: root.showMessageMenu() onRemoveLinkPreview: index => root.contentModel.closeLinkPreview(index) } diff --git a/src/timeline/MessageComponentChooser.qml b/src/timeline/MessageComponentChooser.qml index 00a92247b..88471acf8 100644 --- a/src/timeline/MessageComponentChooser.qml +++ b/src/timeline/MessageComponentChooser.qml @@ -42,6 +42,11 @@ DelegateChooser { */ signal selectedTextChanged(string selectedText) + /** + * @brief The user hovered link has changed. + */ + signal hoveredLinkChanged(string hoveredLink) + /** * @brief Request a context menu be show for the message. */ @@ -63,6 +68,7 @@ DelegateChooser { delegate: TextComponent { maxContentWidth: root.maxContentWidth onSelectedTextChanged: root.selectedTextChanged(selectedText) + onHoveredLinkChanged: root.hoveredLinkChanged(hoveredLink) onShowMessageMenu: root.showMessageMenu() } } diff --git a/src/timeline/MessageDelegate.qml b/src/timeline/MessageDelegate.qml index 0f108a9f6..68793d62b 100644 --- a/src/timeline/MessageDelegate.qml +++ b/src/timeline/MessageDelegate.qml @@ -182,6 +182,11 @@ TimelineDelegate { */ property string selectedText: "" + /** + * @brief The user hovered link. + */ + property string hoveredLink: "" + onIsTemporaryHighlightedChanged: if (isTemporaryHighlighted) { temporaryHighlightTimer.start(); } @@ -307,6 +312,9 @@ TimelineDelegate { onSelectedTextChanged: selectedText => { root.selectedText = selectedText; } + onHoveredLinkChanged: hoveredLink => { + root.hoveredLink = hoveredLink; + } onShowMessageMenu: _private.showMessageMenu() showBackground: root.cardBackground && !NeoChatConfig.compactLayout @@ -378,7 +386,7 @@ TimelineDelegate { property bool showUserMessageOnRight: NeoChatConfig.showLocalMessagesOnRight && root.author.isLocalMember && !NeoChatConfig.compactLayout && !root.alwaysFillWidth function showMessageMenu() { - RoomManager.viewEventMenu(root.eventId, root.room, root.author, root.selectedText); + RoomManager.viewEventMenu(root.eventId, root.room, root.author, root.selectedText, root.hoveredLink); } } }