From f288367653574d7d7c86d2bb513f33311d15a61d Mon Sep 17 00:00:00 2001 From: James Graham Date: Mon, 28 Jul 2025 19:47:29 +0100 Subject: [PATCH] Add a dev setting to allow relations to be sent to any message Add a dev setting to allow relations to be sent to any message using the right click delegate menu. This shouldn't be a main feature, but since it's technically allowed in matrix this will help any future debugging --- src/app/neochatconfig.kcfg | 4 ++++ src/devtools/DebugOptions.qml | 7 +++++++ src/messagecontent/StateComponent.qml | 22 +++++++++++++++++++++ src/roominfo/RoomMedia.qml | 4 ++-- src/timeline/DelegateContextMenu.qml | 19 +++++++++++++----- src/timeline/EventDelegate.qml | 4 +++- src/timeline/FileDelegateContextMenu.qml | 5 ----- src/timeline/MessageDelegateContextMenu.qml | 9 +++------ src/timeline/StateDelegate.qml | 7 +++++++ src/timeline/models/messagefiltermodel.cpp | 1 + 10 files changed, 63 insertions(+), 19 deletions(-) diff --git a/src/app/neochatconfig.kcfg b/src/app/neochatconfig.kcfg index 56a4e47a9..a9a2c2fe6 100644 --- a/src/app/neochatconfig.kcfg +++ b/src/app/neochatconfig.kcfg @@ -189,6 +189,10 @@ false + + + false + false diff --git a/src/devtools/DebugOptions.qml b/src/devtools/DebugOptions.qml index b16830d3b..e20b0a24a 100644 --- a/src/devtools/DebugOptions.qml +++ b/src/devtools/DebugOptions.qml @@ -20,6 +20,13 @@ FormCard.FormCard { onToggled: NeoChatConfig.showAllEvents = checked } + FormCard.FormCheckDelegate { + text: i18nc("@option:check", "Allow sending relations to any event in the timeline") + description: i18nc("@info", "This includes state events") + checked: NeoChatConfig.relateAnyEvent + + onToggled: NeoChatConfig.relateAnyEvent = checked + } FormCard.FormCheckDelegate { id: roomAccountDataVisibleCheck text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification") diff --git a/src/messagecontent/StateComponent.qml b/src/messagecontent/StateComponent.qml index d9848a2e8..d35757c56 100644 --- a/src/messagecontent/StateComponent.qml +++ b/src/messagecontent/StateComponent.qml @@ -71,4 +71,26 @@ RowLayout { cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.IBeamCursor } } + + TapHandler { + acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus + acceptedButtons: Qt.RightButton + onTapped: _private.showMessageMenu() + } + TapHandler { + acceptedDevices: PointerDevice.TouchScreen + acceptedButtons: Qt.LeftButton + onLongPressed: _private.showMessageMenu() + } + + QtObject { + id: _private + + function showMessageMenu() { + if (!NeoChatConfig.developerTools) { + return; + } + RoomManager.viewEventMenu(root.modelData.eventId, root.Message.room, root.author, "", ""); + } + } } diff --git a/src/roominfo/RoomMedia.qml b/src/roominfo/RoomMedia.qml index 967d281c5..fbcbf68ba 100644 --- a/src/roominfo/RoomMedia.qml +++ b/src/roominfo/RoomMedia.qml @@ -50,18 +50,18 @@ QQC2.ScrollView { DelegateChoice { roleValue: Timeline.MediaMessageFilterModel.Image delegate: Timeline.MessageDelegate { + Timeline.Message.room: root.room alwaysFillWidth: true cardBackground: false - room: root.room } } DelegateChoice { roleValue: Timeline.MediaMessageFilterModel.Video delegate: Timeline.MessageDelegate { + Timeline.Message.room: root.room alwaysFillWidth: true cardBackground: false - room: root.room } } } diff --git a/src/timeline/DelegateContextMenu.qml b/src/timeline/DelegateContextMenu.qml index b5a9cd489..bc88341d2 100644 --- a/src/timeline/DelegateContextMenu.qml +++ b/src/timeline/DelegateContextMenu.qml @@ -53,6 +53,11 @@ KirigamiComponents.ConvergentContextMenu { */ required property var author + /** + * @brief The delegate type of the message. + */ + required property int messageComponentType + /** * @brief The display text of the message as plain text. */ @@ -79,7 +84,7 @@ KirigamiComponents.ConvergentContextMenu { } component RemoveMessageAction: Kirigami.Action { - visible: author.isLocalMember || currentRoom.canSendState("redact") + visible: (author.isLocalMember || currentRoom.canSendState("redact")) && root.messageComponentType !== MessageComponentType.Other text: i18nc("@action:button", "Remove…") icon.name: "edit-delete-remove" icon.color: "red" @@ -99,7 +104,8 @@ KirigamiComponents.ConvergentContextMenu { } } - component ReplyMessageAction: QQC2.Action { + component ReplyMessageAction: Kirigami.Action { + visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent text: i18n("Reply") icon.name: "mail-replied-symbolic" onTriggered: { @@ -109,7 +115,8 @@ KirigamiComponents.ConvergentContextMenu { } } - component ReplyThreadMessageAction: QQC2.Action { + component ReplyThreadMessageAction: Kirigami.Action { + visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent text: i18nc("@action:button", "Reply in Thread") icon.name: "dialog-messages" onTriggered: { @@ -145,7 +152,7 @@ KirigamiComponents.ConvergentContextMenu { component PinMessageAction: Kirigami.Action { readonly property bool pinned: currentRoom.isEventPinned(root.eventId) - visible: currentRoom.canSendState("m.room.pinned_events") + visible: currentRoom.canSendState("m.room.pinned_events") && root.messageComponentType !== MessageComponentType.Other text: pinned ? i18nc("@action:button 'Unpin' as in 'Unpin this message'", "Unpin") : i18nc("@action:button 'Pin' as in 'Pin the message in the room'", "Pin") icon.name: pinned ? "window-unpin-symbolic" : "pin-symbolic" onTriggered: pinned ? currentRoom.unpinEvent(root.eventId) : currentRoom.pinEvent(root.eventId) @@ -185,9 +192,11 @@ KirigamiComponents.ConvergentContextMenu { } Kirigami.Action { - visible: Kirigami.Settings.isMobile + id: emojiAction + visible: root.messageComponentType === MessageComponentType.Other ? NeoChatConfig.relateAnyEvent : true displayComponent: RowLayout { + visible: emojiAction.visible spacing: 0 Layout.fillWidth: true Layout.preferredHeight: Kirigami.Units.gridUnit * 2.5 diff --git a/src/timeline/EventDelegate.qml b/src/timeline/EventDelegate.qml index 595c69e95..844ac6ce6 100644 --- a/src/timeline/EventDelegate.qml +++ b/src/timeline/EventDelegate.qml @@ -21,7 +21,9 @@ DelegateChooser { DelegateChoice { roleValue: DelegateType.State - delegate: StateDelegate {} + delegate: StateDelegate { + room: root.room + } } DelegateChoice { diff --git a/src/timeline/FileDelegateContextMenu.qml b/src/timeline/FileDelegateContextMenu.qml index 87f5dddd5..e88d3fbf8 100644 --- a/src/timeline/FileDelegateContextMenu.qml +++ b/src/timeline/FileDelegateContextMenu.qml @@ -33,11 +33,6 @@ DelegateContextMenu { */ required property var progressInfo - /** - * @brief The delegate type of the message. - */ - required property int messageComponentType - DelegateContextMenu.ReplyMessageAction {} Kirigami.Action { diff --git a/src/timeline/MessageDelegateContextMenu.qml b/src/timeline/MessageDelegateContextMenu.qml index c22e35001..0a091624f 100644 --- a/src/timeline/MessageDelegateContextMenu.qml +++ b/src/timeline/MessageDelegateContextMenu.qml @@ -27,11 +27,6 @@ import org.kde.neochat DelegateContextMenu { id: root - /** - * @brief The delegate type of the message. - */ - required property int messageComponentType - /** * @brief The display text of the message as rich text. */ @@ -52,7 +47,8 @@ DelegateContextMenu { DelegateContextMenu.ReplyThreadMessageAction {} - QQC2.Action { + Kirigami.Action { + visible: root.messageComponentType !== MessageComponentType.Other text: i18nc("@action:inmenu As in 'Forward this message'", "Forward…") icon.name: "mail-forward-symbolic" onTriggered: { @@ -69,6 +65,7 @@ DelegateContextMenu { } } Kirigami.Action { + visible: root.messageComponentType !== MessageComponentType.Other || NeoChatConfig.relateAnyEvent separator: true } DelegateContextMenu.RemoveMessageAction {} diff --git a/src/timeline/StateDelegate.qml b/src/timeline/StateDelegate.qml index 491683ce5..873f9c4f9 100644 --- a/src/timeline/StateDelegate.qml +++ b/src/timeline/StateDelegate.qml @@ -18,6 +18,11 @@ import org.kde.neochat TimelineDelegate { id: root + /** + * @brief The NeoChatRoom the delegate is being displayed in. + */ + required property NeoChatRoom room + /** * @brief List of the first 5 unique authors of the aggregated state event. */ @@ -63,6 +68,8 @@ TimelineDelegate { */ property bool folded: true + Message.room: root.room + width: parent?.width rightPadding: NeoChatConfig.compactLayout && root.ListView.view.width >= Kirigami.Units.gridUnit * 20 ? Kirigami.Units.gridUnit * 2 + Kirigami.Units.largeSpacing : Kirigami.Units.largeSpacing diff --git a/src/timeline/models/messagefiltermodel.cpp b/src/timeline/models/messagefiltermodel.cpp index 607b58ee4..655e8c6bf 100644 --- a/src/timeline/models/messagefiltermodel.cpp +++ b/src/timeline/models/messagefiltermodel.cpp @@ -198,6 +198,7 @@ QVariantList MessageFilterModel::stateEventsList(int sourceRow) const QVariantList stateEvents; for (int i = sourceRow; i >= 0; i--) { auto nextState = QVariantMap{ + {u"eventId"_s, sourceModel()->data(sourceModel()->index(i, 0), TimelineMessageModel::EventIdRole)}, {u"author"_s, sourceModel()->data(sourceModel()->index(i, 0), TimelineMessageModel::AuthorRole)}, {u"authorDisplayName"_s, sourceModel()->data(sourceModel()->index(i, 0), TimelineMessageModel::AuthorDisplayNameRole).toString()}, {u"text"_s, sourceModel()->data(sourceModel()->index(i, 0), Qt::DisplayRole).toString()},