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()},