diff --git a/imports/Spectral/Component/Timeline/MessageDelegate.qml b/imports/Spectral/Component/Timeline/MessageDelegate.qml index 2baf43a2a..c92d1d0d8 100644 --- a/imports/Spectral/Component/Timeline/MessageDelegate.qml +++ b/imports/Spectral/Component/Timeline/MessageDelegate.qml @@ -93,40 +93,106 @@ ColumnLayout { } } - contentItem: TextEdit { - Layout.fillWidth: true + contentItem: ColumnLayout { + Control { + Layout.fillWidth: true - id: contentLabel + visible: replyEventId || "" - text: "" + display + background: MouseArea { + onClicked: goToEvent(replyEventId) + } - color: "white" + contentItem: RowLayout { + spacing: 4 - font.family: CommonFont.font.family - font.pixelSize: 14 - selectByMouse: true - readOnly: true - wrapMode: Label.Wrap - selectedTextColor: Material.accent - selectionColor: "white" - textFormat: Text.RichText + Rectangle { + Layout.preferredWidth: 2 + Layout.fillHeight: true - onLinkActivated: { - if (link.startsWith("https://matrix.to/")) { - var result = link.replace(/\?.*/, "").match("https://matrix.to/#/(!.*:.*)/(\\$.*:.*)") - if (result.length < 3) return - if (result[1] != currentRoom.id) return - if (!result[2]) return - goToEvent(result[2]) - } else { - Qt.openUrlExternally(link) + color: "white" + } + + ColumnLayout { + Layout.fillWidth: true + + spacing: 0 + + Control { + padding: 4 + + contentItem: RowLayout { + spacing: 4 + + ImageItem { + Layout.preferredWidth: 16 + Layout.preferredHeight: 16 + + source: replyAuthor ? replyAuthor.paintable : null + } + + Label { + color: "white" + text: replyAuthor ? replyAuthor.displayName : "" + } + } + + background: Rectangle { + color: "black" + opacity: 0.2 + radius: height / 2 + } + } + + Label { + Layout.fillWidth: true + + text: "" + (replyDisplay ? replyDisplay.replace(/.*<\/mx-reply>/g, "") : "") + + color: "white" + + wrapMode: Label.Wrap + textFormat: Label.RichText + } + } } } - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.NoButton - cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + TextEdit { + Layout.fillWidth: true + + id: contentLabel + + text: "" + (replyEventId ? display.replace(/.*<\/mx-reply>/g, "") : display) + + color: "white" + + font.family: CommonFont.font.family + font.pixelSize: 14 + selectByMouse: true + readOnly: true + wrapMode: Label.Wrap + selectedTextColor: Material.accent + selectionColor: "white" + textFormat: Text.RichText + + onLinkActivated: { + if (link.startsWith("https://matrix.to/")) { + var result = link.replace(/\?.*/, "").match("https://matrix.to/#/(!.*:.*)/(\\$.*:.*)") + if (result.length < 3) return + if (result[1] != currentRoom.id) return + if (!result[2]) return + goToEvent(result[2]) + } else { + Qt.openUrlExternally(link) + } + } + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.NoButton + cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor + } } } } diff --git a/src/messageeventmodel.cpp b/src/messageeventmodel.cpp index 6973b68c1..1c1956dd0 100644 --- a/src/messageeventmodel.cpp +++ b/src/messageeventmodel.cpp @@ -39,6 +39,9 @@ QHash MessageEventModel::roleNames() const { roles[LongOperationRole] = "progressInfo"; roles[AnnotationRole] = "annotation"; roles[EventResolvedTypeRole] = "eventResolvedType"; + roles[ReplyEventIdRole] = "replyEventId"; + roles[ReplyAuthorRole] = "replyAuthor"; + roles[ReplyDisplayRole] = "replyDisplay"; roles[UserMarkerRole] = "userMarker"; return roles; } @@ -372,6 +375,28 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const { return variantList; } + if (role == ReplyEventIdRole || role == ReplyDisplayRole || + role == ReplyAuthorRole) { + const QString &replyEventId = evt.contentJson()["m.relates_to"] + .toObject()["m.in_reply_to"] + .toObject()["event_id"] + .toString(); + if (replyEventId.isEmpty()) return {}; + const auto replyIt = m_currentRoom->findInTimeline(replyEventId); + if (replyIt == m_currentRoom->timelineEdge()) return {}; + const auto& replyEvt = **replyIt; + switch (role) { + case ReplyEventIdRole: + return replyEventId; + case ReplyDisplayRole: + return utils::eventToString(replyEvt, m_currentRoom, Qt::RichText); + case ReplyAuthorRole: + return QVariant::fromValue( + m_currentRoom->user(replyEvt.senderId())); + } + return {}; + } + if (role == AboveEventTypeRole || role == AboveSectionRole || role == AboveAuthorRole || role == AboveTimeRole) for (auto r = row + 1; r < rowCount(); ++r) { diff --git a/src/messageeventmodel.h b/src/messageeventmodel.h index b211c8ddc..a828f9936 100644 --- a/src/messageeventmodel.h +++ b/src/messageeventmodel.h @@ -30,6 +30,9 @@ class MessageEventModel : public QAbstractListModel { LongOperationRole, AnnotationRole, UserMarkerRole, + ReplyEventIdRole, + ReplyAuthorRole, + ReplyDisplayRole, // For debugging EventResolvedTypeRole, };