diff --git a/imports/NeoChat/Component/Timeline/ImageDelegate.qml b/imports/NeoChat/Component/Timeline/ImageDelegate.qml index dbac770c1..075278d5f 100644 --- a/imports/NeoChat/Component/Timeline/ImageDelegate.qml +++ b/imports/NeoChat/Component/Timeline/ImageDelegate.qml @@ -15,6 +15,7 @@ import NeoChat.Menu.Timeline 1.0 Image { id: img + property var content: model.content readonly property bool isAnimated: contentType === "image/gif" property bool openOnFinished: false diff --git a/imports/NeoChat/Component/Timeline/ReplyComponent.qml b/imports/NeoChat/Component/Timeline/ReplyComponent.qml index c654b4796..4607914e3 100644 --- a/imports/NeoChat/Component/Timeline/ReplyComponent.qml +++ b/imports/NeoChat/Component/Timeline/ReplyComponent.qml @@ -14,8 +14,8 @@ import NeoChat.Component.Timeline 1.0 MouseArea { id: replyButton Layout.fillWidth: true - implicitHeight: replyName.implicitHeight + replyText.implicitHeight + Kirigami.Units.largeSpacing - implicitWidth: Math.min(bubbleMaxWidth, Math.max(replyText.implicitWidth, replyName.implicitWidth)) + Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3 + implicitHeight: replyName.implicitHeight + (loader.item ? loader.item.height : 0) + Kirigami.Units.largeSpacing + implicitWidth: Math.min(bubbleMaxWidth, Math.max((loader.item ? loader.item.width : 0), replyName.implicitWidth)) + Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 3 Component.onCompleted: { parent.Layout.fillWidth = true; parent.Layout.preferredWidth = Qt.binding(function() { return implicitWidth; }) @@ -56,18 +56,48 @@ MouseArea { elide: Text.ElideRight } - TextDelegate { - id: replyText - anchors { - left: avatatReply.right - top: replyName.bottom - leftMargin: Kirigami.Units.smallSpacing - topMargin: Kirigami.Units.smallSpacing - right: parent.right - rightMargin: Kirigami.Units.smallSpacing + Loader { + id: loader + anchors.top: replyName.bottom + sourceComponent: { + switch (reply.type) { + case "image": + case "sticker": + return imageComponent; + case "message": + return textComponent; + // TODO support more types + default: + return textComponent; + } + } + + Component { + id: textComponent + TextDelegate { + id: replyText + textMessage: reply.display + textFormat: Text.RichText + wrapMode: Text.WordWrap + width: Math.min(implicitWidth, bubbleMaxWidth) - Kirigami.Units.smallSpacing * 5 - avatatReply.width + x: Kirigami.Units.smallSpacing * 3 + avatatReply.width + } + } + + Component { + id: imageComponent + Image { + readonly property var content: reply.content + readonly property bool isThumbnail: !(content.info.thumbnail_info == null || content.thumbnailMediaId == null) + // readonly property var info: isThumbnail ? content.info.thumbnail_info : content.info + readonly property var info: content.info + readonly property string mediaId: isThumbnail ? content.thumbnailMediaId : content.mediaId + source: "image://mxc/" + mediaId + + width: bubbleMaxWidth * 0.75 - Kirigami.Units.smallSpacing * 5 - avatatReply.width + height: reply.content.info.h / reply.content.info.w * width + x: Kirigami.Units.smallSpacing * 3 + avatatReply.width + } } - textMessage: reply.display - textFormat: Text.RichText - wrapMode: Text.WordWrap } } diff --git a/src/messageeventmodel.cpp b/src/messageeventmodel.cpp index 1d67a187d..2c8e7c1c0 100644 --- a/src/messageeventmodel.cpp +++ b/src/messageeventmodel.cpp @@ -559,9 +559,56 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const }; const auto &replyEvt = **replyIt; - return QVariantMap{{"eventId", replyEventId}, - {"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)}, - {"author", userAtEvent(static_cast(m_currentRoom->user(replyEvt.senderId())), m_currentRoom, evt)}}; + QString type; + if (auto e = eventCast(&replyEvt)) { + switch (e->msgtype()) { + case MessageEventType::Emote: + type = "emote"; + break; + case MessageEventType::Notice: + type = "notice"; + break; + case MessageEventType::Image: + type = "image"; + break; + case MessageEventType::Audio: + type = "audio"; + break; + case MessageEventType::Video: + type = "video"; + break; + default: + if (e->hasFileContent()) { + type = "file"; + break; + } + type = "message"; + } + + } else if (is(replyEvt)) { + type = "sticker"; + } else { + type = "other"; + } + + QVariant content; + if (auto e = eventCast(&replyEvt)) { + // Cannot use e.contentJson() here because some + // EventContent classes inject values into the copy of the + // content JSON stored in EventContent::Base + content = e->hasFileContent() ? QVariant::fromValue(e->content()->originalJson) : QVariant(); + }; + + if (auto e = eventCast(&replyEvt)) { + content = QVariant::fromValue(e->image().originalJson); + } + + return QVariantMap{ + {"eventId", replyEventId}, + {"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)}, + {"content", content}, + {"type", type}, + {"author", userAtEvent(static_cast(m_currentRoom->user(replyEvt.senderId())), m_currentRoom, evt)}}; } if (role == ShowAuthorRole) {