From 24235174fd4fbdc17144cb5652db412c7f4f7b00 Mon Sep 17 00:00:00 2001 From: James Graham Date: Sat, 15 Mar 2025 16:03:27 +0000 Subject: [PATCH] Make it so that the menus for individual thread messages can be accessed This is mostly just for text type messages at the moment but give the framework so that when other message types can be sent in threads they can be added easily --- src/messageattached.cpp | 42 ++++++++++++++++++++ src/messageattached.h | 26 +++++++++++- src/timeline/AuthorComponent.qml | 17 ++++++++ src/timeline/BaseMessageComponentChooser.qml | 8 ---- src/timeline/Bubble.qml | 1 - src/timeline/CodeComponent.qml | 12 +++--- src/timeline/MessageComponentChooser.qml | 9 ++++- src/timeline/MessageDelegate.qml | 17 ++------ src/timeline/QuoteComponent.qml | 21 +++++++--- src/timeline/TextComponent.qml | 28 +++++++++---- src/timeline/ThreadBodyComponent.qml | 6 --- 11 files changed, 137 insertions(+), 50 deletions(-) diff --git a/src/messageattached.cpp b/src/messageattached.cpp index 0bdbc30f6..35775818d 100644 --- a/src/messageattached.cpp +++ b/src/messageattached.cpp @@ -82,6 +82,38 @@ void MessageAttached::setMaxContentWidth(qreal maxContentWidth) Q_EMIT maxContentWidthChanged(); } +QString MessageAttached::selectedText() const +{ + return m_selectedText; +} + +void MessageAttached::setSelectedText(const QString &selectedTest) +{ + m_explicitSelectedText = true; + if (m_selectedText == selectedTest) { + return; + } + m_selectedText = selectedTest; + propagateMessage(this); + Q_EMIT selectedTextChanged(); +} + +QString MessageAttached::hoveredLink() const +{ + return m_hoveredLink; +} + +void MessageAttached::setHoveredLink(const QString &hoveredLink) +{ + m_explicitHoveredLink = true; + if (m_hoveredLink == hoveredLink) { + return; + } + m_hoveredLink = hoveredLink; + propagateMessage(this); + Q_EMIT hoveredLinkChanged(); +} + void MessageAttached::propagateMessage(MessageAttached *message) { if (m_explicitRoom || m_room != message->room()) { @@ -104,6 +136,16 @@ void MessageAttached::propagateMessage(MessageAttached *message) Q_EMIT maxContentWidthChanged(); } + if (m_explicitSelectedText || m_selectedText != message->selectedText()) { + m_selectedText = message->selectedText(); + Q_EMIT selectedTextChanged(); + } + + if (m_explicitHoveredLink || m_hoveredLink != message->hoveredLink()) { + m_hoveredLink = message->hoveredLink(); + Q_EMIT hoveredLinkChanged(); + } + const auto styles = attachedChildren(); for (auto *child : attachedChildren()) { MessageAttached *message = qobject_cast(child); diff --git a/src/messageattached.h b/src/messageattached.h index 1585c79c3..4bb5f231c 100644 --- a/src/messageattached.h +++ b/src/messageattached.h @@ -36,6 +36,16 @@ class MessageAttached : public QQuickAttachedPropertyPropagator */ Q_PROPERTY(qreal maxContentWidth READ maxContentWidth WRITE setMaxContentWidth NOTIFY maxContentWidthChanged FINAL) + /** + * @brief The current selected message text. + */ + Q_PROPERTY(QString selectedText READ selectedText WRITE setSelectedText NOTIFY selectedTextChanged FINAL) + + /** + * @brief The text of a hovered link if any. + */ + Q_PROPERTY(QString hoveredLink READ hoveredLink WRITE setHoveredLink NOTIFY hoveredLinkChanged FINAL) + public: explicit MessageAttached(QObject *parent = nullptr); @@ -53,11 +63,19 @@ public: qreal maxContentWidth() const; void setMaxContentWidth(qreal maxContentWidth); + QString selectedText() const; + void setSelectedText(const QString &selectedTest); + + QString hoveredLink() const; + void setHoveredLink(const QString &hoveredLink); + Q_SIGNALS: void roomChanged(); void timelineChanged(); void indexChanged(); void maxContentWidthChanged(); + void selectedTextChanged(); + void hoveredLinkChanged(); protected: void propagateMessage(MessageAttached *message); @@ -70,9 +88,15 @@ private: QPointer m_timeline; bool m_explicitTimeline = false; - int m_index; + int m_index = -1; bool m_explicitIndex = false; qreal m_maxContentWidth = -1; bool m_explicitMaxContentWidth = false; + + QString m_selectedText = {}; + bool m_explicitSelectedText = false; + + QString m_hoveredLink = {}; + bool m_explicitHoveredLink = false; }; diff --git a/src/timeline/AuthorComponent.qml b/src/timeline/AuthorComponent.qml index c3a12c65f..e8df80f21 100644 --- a/src/timeline/AuthorComponent.qml +++ b/src/timeline/AuthorComponent.qml @@ -12,6 +12,11 @@ import org.kde.neochat RowLayout { id: root + /** + * @brief The matrix ID of the message event. + */ + required property string eventId + /** * @brief The message author. * @@ -68,4 +73,16 @@ RowLayout { id: timeHoverHandler } } + + TapHandler { + acceptedButtons: Qt.LeftButton + acceptedDevices: PointerDevice.TouchScreen + onLongPressed: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink); + } + TapHandler { + acceptedButtons: Qt.RightButton + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus + gesturePolicy: TapHandler.WithinBounds + onTapped: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink); + } } diff --git a/src/timeline/BaseMessageComponentChooser.qml b/src/timeline/BaseMessageComponentChooser.qml index 99409daf2..66cab0f76 100644 --- a/src/timeline/BaseMessageComponentChooser.qml +++ b/src/timeline/BaseMessageComponentChooser.qml @@ -25,11 +25,6 @@ DelegateChooser { */ signal hoveredLinkChanged(string hoveredLink) - /** - * @brief Request a context menu be show for the message. - */ - signal showMessageMenu - signal removeLinkPreview(int index) /** @@ -49,7 +44,6 @@ DelegateChooser { delegate: TextComponent { onSelectedTextChanged: root.selectedTextChanged(selectedText) onHoveredLinkChanged: root.hoveredLinkChanged(hoveredLink) - onShowMessageMenu: root.showMessageMenu() } } @@ -69,7 +63,6 @@ DelegateChooser { onSelectedTextChanged: selectedText => { root.selectedTextChanged(selectedText); } - onShowMessageMenu: root.showMessageMenu() } } @@ -79,7 +72,6 @@ DelegateChooser { onSelectedTextChanged: selectedText => { root.selectedTextChanged(selectedText); } - onShowMessageMenu: root.showMessageMenu() } } diff --git a/src/timeline/Bubble.qml b/src/timeline/Bubble.qml index 7d2d6b111..8a008052d 100644 --- a/src/timeline/Bubble.qml +++ b/src/timeline/Bubble.qml @@ -97,7 +97,6 @@ QQC2.Control { onHoveredLinkChanged: hoveredLink => { root.hoveredLinkChanged(hoveredLink); } - onShowMessageMenu: root.showMessageMenu() onRemoveLinkPreview: index => root.contentModel.closeLinkPreview(index) } } diff --git a/src/timeline/CodeComponent.qml b/src/timeline/CodeComponent.qml index eacc238cc..fdcc9a6ac 100644 --- a/src/timeline/CodeComponent.qml +++ b/src/timeline/CodeComponent.qml @@ -13,6 +13,11 @@ import org.kde.neochat QQC2.Control { id: root + /** + * @brief The matrix ID of the message event. + */ + required property string eventId + /** * @brief The message author. * @@ -42,11 +47,6 @@ QQC2.Control { */ signal selectedTextChanged(string selectedText) - /** - * @brief Request a context menu be show for the message. - */ - signal showMessageMenu - Layout.fillWidth: true Layout.fillHeight: true Layout.maximumWidth: Message.maxContentWidth @@ -129,7 +129,7 @@ QQC2.Control { TapHandler { acceptedDevices: PointerDevice.TouchScreen - onLongPressed: root.showMessageMenu() + onLongPressed: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink); } background: null diff --git a/src/timeline/MessageComponentChooser.qml b/src/timeline/MessageComponentChooser.qml index d40f6bc3b..3af15f5a1 100644 --- a/src/timeline/MessageComponentChooser.qml +++ b/src/timeline/MessageComponentChooser.qml @@ -14,6 +14,13 @@ BaseMessageComponentChooser { DelegateChoice { roleValue: MessageComponentType.ThreadBody - delegate: ThreadBodyComponent {} + delegate: ThreadBodyComponent { + onSelectedTextChanged: selectedText => { + root.selectedTextChanged(selectedText); + } + onHoveredLinkChanged: hoveredLink => { + root.hoveredLinkChanged(hoveredLink); + } + } } } diff --git a/src/timeline/MessageDelegate.qml b/src/timeline/MessageDelegate.qml index b9b60b8a1..5854ba135 100644 --- a/src/timeline/MessageDelegate.qml +++ b/src/timeline/MessageDelegate.qml @@ -166,16 +166,6 @@ TimelineDelegate { */ property bool isTemporaryHighlighted: false - /** - * @brief The user selected text. - */ - property string selectedText: "" - - /** - * @brief The user hovered link. - */ - property string hoveredLink: "" - onIsTemporaryHighlightedChanged: if (isTemporaryHighlighted) { temporaryHighlightTimer.start(); } @@ -293,12 +283,11 @@ TimelineDelegate { isPending: root.isPending onSelectedTextChanged: selectedText => { - root.selectedText = selectedText; + root.Message.selectedText = selectedText; } onHoveredLinkChanged: hoveredLink => { - root.hoveredLink = hoveredLink; + root.Message.hoveredLink = hoveredLink; } - onShowMessageMenu: _private.showMessageMenu() showBackground: root.cardBackground && !NeoChatConfig.compactLayout } @@ -358,7 +347,7 @@ TimelineDelegate { property bool showUserMessageOnRight: NeoChatConfig.showLocalMessagesOnRight && root.author.isLocalMember && !NeoChatConfig.compactLayout && !root.alwaysFillWidth && !root.isThreaded function showMessageMenu() { - RoomManager.viewEventMenu(root.eventId, root.room, root.author, root.selectedText, root.hoveredLink); + RoomManager.viewEventMenu(root.eventId, root.room, root.author, root.Message.selectedText, root.Message.hoveredLink); } } } diff --git a/src/timeline/QuoteComponent.qml b/src/timeline/QuoteComponent.qml index 237d677c5..562798fda 100644 --- a/src/timeline/QuoteComponent.qml +++ b/src/timeline/QuoteComponent.qml @@ -12,6 +12,20 @@ import org.kde.neochat QQC2.Control { id: root + /** + * @brief The matrix ID of the message event. + */ + required property string eventId + + /** + * @brief The message author. + * + * A Quotient::RoomMember object. + * + * @sa Quotient::RoomMember + */ + required property NeochatRoomMember author + /** * @brief The display text of the message. */ @@ -22,11 +36,6 @@ QQC2.Control { */ signal selectedTextChanged(string selectedText) - /** - * @brief Request a context menu be show for the message. - */ - signal showMessageMenu - Layout.fillWidth: true Layout.fillHeight: true Layout.maximumWidth: Message.maxContentWidth @@ -54,7 +63,7 @@ QQC2.Control { enabled: !quoteText.hoveredLink acceptedDevices: PointerDevice.TouchScreen acceptedButtons: Qt.LeftButton - onLongPressed: root.showMessageMenu() + onLongPressed: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink); } } diff --git a/src/timeline/TextComponent.qml b/src/timeline/TextComponent.qml index 2588d88db..475759ab3 100644 --- a/src/timeline/TextComponent.qml +++ b/src/timeline/TextComponent.qml @@ -15,6 +15,20 @@ import org.kde.neochat TextEdit { id: root + /** + * @brief The matrix ID of the message event. + */ + required property string eventId + + /** + * @brief The message author. + * + * A Quotient::RoomMember object. + * + * @sa Quotient::RoomMember + */ + required property NeochatRoomMember author + /** * @brief The display text of the message. */ @@ -35,11 +49,6 @@ TextEdit { */ property bool spoilerRevealed: !hasSpoiler.test(display) - /** - * @brief Request a context menu be show for the message. - */ - signal showMessageMenu - Layout.fillWidth: true Layout.fillHeight: true Layout.maximumWidth: Message.maxContentWidth @@ -119,7 +128,6 @@ a{ HoverHandler { cursorShape: (root.hoveredLink || !spoilerRevealed) ? Qt.PointingHandCursor : Qt.IBeamCursor } - TapHandler { enabled: !root.hoveredLink && !spoilerRevealed onTapped: spoilerRevealed = true @@ -128,6 +136,12 @@ a{ enabled: !root.hoveredLink acceptedButtons: Qt.LeftButton acceptedDevices: PointerDevice.TouchScreen - onLongPressed: root.showMessageMenu() + onLongPressed: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink); + } + TapHandler { + acceptedButtons: Qt.RightButton + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus + gesturePolicy: TapHandler.WithinBounds + onTapped: RoomManager.viewEventMenu(root.eventId, root.Message.room, root.author, root.Message.selectedText, root.Message.hoveredLink); } } diff --git a/src/timeline/ThreadBodyComponent.qml b/src/timeline/ThreadBodyComponent.qml index 921faf726..af1a161ca 100644 --- a/src/timeline/ThreadBodyComponent.qml +++ b/src/timeline/ThreadBodyComponent.qml @@ -31,11 +31,6 @@ ColumnLayout { */ signal hoveredLinkChanged(string hoveredLink) - /** - * @brief Request a context menu be show for the message. - */ - signal showMessageMenu - Layout.fillWidth: true Layout.fillHeight: true Layout.maximumWidth: Message.maxContentWidth @@ -52,7 +47,6 @@ ColumnLayout { onHoveredLinkChanged: hoveredLink => { root.hoveredLinkChanged(hoveredLink); } - onShowMessageMenu: root.showMessageMenu() onRemoveLinkPreview: index => threadRepeater.model.closeLinkPreview(index) onFetchMoreEvents: threadRepeater.model.fetchMoreEvents(5) }