diff options
Diffstat (limited to '')
-rw-r--r-- | resources/qml/TimelineRow.qml | 61 | ||||
-rw-r--r-- | resources/qml/delegates/FileMessage.qml | 6 | ||||
-rw-r--r-- | resources/qml/delegates/ImageMessage.qml | 12 | ||||
-rw-r--r-- | resources/qml/delegates/MessageDelegate.qml | 128 | ||||
-rw-r--r-- | resources/qml/delegates/NoticeMessage.qml | 2 | ||||
-rw-r--r-- | resources/qml/delegates/Placeholder.qml | 2 | ||||
-rw-r--r-- | resources/qml/delegates/PlayableMediaMessage.qml | 16 | ||||
-rw-r--r-- | resources/qml/delegates/TextMessage.qml | 2 | ||||
-rw-r--r-- | src/timeline/TimelineModel.cpp | 16 | ||||
-rw-r--r-- | src/timeline/TimelineModel.h | 1 |
10 files changed, 159 insertions, 87 deletions
diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml index 2c2ed02a..86780413 100644 --- a/resources/qml/TimelineRow.qml +++ b/resources/qml/TimelineRow.qml @@ -14,23 +14,70 @@ RowLayout { anchors.left: parent.left anchors.right: parent.right - height: Math.max(contentItem.height, 16) + //height: Math.max(model.replyTo ? reply.height + contentItem.height + 4 : contentItem.height, 16) Column { Layout.fillWidth: true Layout.alignment: Qt.AlignTop + spacing: 4 - //property var replyTo: model.replyTo + // fancy reply, if this is a reply + Rectangle { + visible: model.replyTo + width: parent.width + height: replyContainer.height + + Rectangle { + id: colorLine + height: replyContainer.height + width: 4 + color: chat.model.userColor(reply.modelData.userId, colors.window) + } + + Column { + id: replyContainer + anchors.left: colorLine.right + anchors.leftMargin: 4 + width: parent.width - 8 + + + Text { + id: userName + text: chat.model.escapeEmoji(reply.modelData.userName) + color: chat.model.userColor(reply.modelData.userId, colors.window) + textFormat: Text.RichText + + MouseArea { + anchors.fill: parent + onClicked: chat.model.openUserProfile(reply.modelData.userId) + cursorShape: Qt.PointingHandCursor + } + } + + MessageDelegate { + id: reply + width: parent.width - //Text { - // property int idx: timelineManager.timeline.idToIndex(replyTo) - // text: "" + (idx != -1 ? timelineManager.timeline.data(timelineManager.timeline.index(idx, 0), 2) : "nothing") - //} + modelData: chat.model.getDump(model.replyTo) + } + } + + color: { var col = chat.model.userColor(reply.modelData.userId, colors.window); col.a = 0.2; return col } + + MouseArea { + anchors.fill: parent + onClicked: chat.positionViewAtIndex(chat.model.idToIndex(model.replyTo), ListView.Contain) + cursorShape: Qt.PointingHandCursor + } + } + + // actual message content MessageDelegate { id: contentItem width: parent.width - height: childrenRect.height + + modelData: model } } diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml index 2c911c5e..9a5300bb 100644 --- a/resources/qml/delegates/FileMessage.qml +++ b/resources/qml/delegates/FileMessage.qml @@ -31,7 +31,7 @@ Rectangle { } MouseArea { anchors.fill: parent - onClicked: timelineManager.timeline.saveMedia(model.id) + onClicked: timelineManager.timeline.saveMedia(model.data.id) cursorShape: Qt.PointingHandCursor } } @@ -40,14 +40,14 @@ Rectangle { Text { Layout.fillWidth: true - text: model.body + text: model.data.body textFormat: Text.PlainText elide: Text.ElideRight color: colors.text } Text { Layout.fillWidth: true - text: model.filesize + text: model.data.filesize textFormat: Text.PlainText elide: Text.ElideRight color: colors.text diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml index 15ce29b7..3393f043 100644 --- a/resources/qml/delegates/ImageMessage.qml +++ b/resources/qml/delegates/ImageMessage.qml @@ -3,26 +3,26 @@ import QtQuick 2.6 import im.nheko 1.0 Item { - property double tempWidth: Math.min(parent ? parent.width : undefined, model.width) - property double tempHeight: tempWidth * model.proportionalHeight + property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width) + property double tempHeight: tempWidth * model.data.proportionalHeight property bool tooHigh: tempHeight > chat.height - 40 height: tooHigh ? chat.height - 40 : tempHeight - width: tooHigh ? (chat.height - 40) / model.proportionalHeight : tempWidth + width: tooHigh ? (chat.height - 40) / model.data.proportionalHeight : tempWidth Image { id: img anchors.fill: parent - source: model.url.replace("mxc://", "image://MxcImage/") + source: model.data.url.replace("mxc://", "image://MxcImage/") asynchronous: true fillMode: Image.PreserveAspectFit MouseArea { - enabled: model.type == MtxEvent.ImageMessage + enabled: model.data.type == MtxEvent.ImageMessage anchors.fill: parent - onClicked: timelineManager.openImageOverlay(model.url, model.id) + onClicked: timelineManager.openImageOverlay(model.data.url, model.data.id) } } } diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml index 20ec71e5..1716d2d4 100644 --- a/resources/qml/delegates/MessageDelegate.qml +++ b/resources/qml/delegates/MessageDelegate.qml @@ -1,67 +1,81 @@ import QtQuick 2.6 import im.nheko 1.0 -DelegateChooser { - //role: "type" //< not supported in our custom implementation, have to use roleValue - roleValue: model.type - - DelegateChoice { - roleValue: MtxEvent.TextMessage - TextMessage {} - } - DelegateChoice { - roleValue: MtxEvent.NoticeMessage - NoticeMessage {} - } - DelegateChoice { - roleValue: MtxEvent.EmoteMessage - TextMessage {} - } - DelegateChoice { - roleValue: MtxEvent.ImageMessage - ImageMessage {} - } - DelegateChoice { - roleValue: MtxEvent.Sticker - ImageMessage {} - } - DelegateChoice { - roleValue: MtxEvent.FileMessage - FileMessage {} +Item { + // Workaround to have an assignable global property + Item { + id: model + property var data; } - DelegateChoice { - roleValue: MtxEvent.VideoMessage - PlayableMediaMessage {} - } - DelegateChoice { - roleValue: MtxEvent.AudioMessage - PlayableMediaMessage {} - } - DelegateChoice { - roleValue: MtxEvent.Redacted - Pill { - text: qsTr("redacted") + + property alias modelData: model.data + + height: chooser.childrenRect.height + + DelegateChooser { + id: chooser + //role: "type" //< not supported in our custom implementation, have to use roleValue + roleValue: model.data.type + anchors.fill: parent + + DelegateChoice { + roleValue: MtxEvent.TextMessage + TextMessage {} } - } - DelegateChoice { - roleValue: MtxEvent.Encryption - Pill { - text: qsTr("Encryption enabled") + DelegateChoice { + roleValue: MtxEvent.NoticeMessage + NoticeMessage {} } - } - DelegateChoice { - roleValue: MtxEvent.Name - NoticeMessage { - notice: model.roomName ? qsTr("room name changed to: %1").arg(model.roomName) : qsTr("removed room name") + DelegateChoice { + roleValue: MtxEvent.EmoteMessage + TextMessage {} } - } - DelegateChoice { - roleValue: MtxEvent.Topic - NoticeMessage { - notice: model.roomTopic ? qsTr("topic changed to: %1").arg(model.roomTopic) : qsTr("removed topic") + DelegateChoice { + roleValue: MtxEvent.ImageMessage + ImageMessage {} + } + DelegateChoice { + roleValue: MtxEvent.Sticker + ImageMessage {} + } + DelegateChoice { + roleValue: MtxEvent.FileMessage + FileMessage {} + } + DelegateChoice { + roleValue: MtxEvent.VideoMessage + PlayableMediaMessage {} + } + DelegateChoice { + roleValue: MtxEvent.AudioMessage + PlayableMediaMessage {} + } + DelegateChoice { + roleValue: MtxEvent.Redacted + Pill { + text: qsTr("redacted") + } + } + DelegateChoice { + roleValue: MtxEvent.Encryption + Pill { + text: qsTr("Encryption enabled") + } + } + DelegateChoice { + roleValue: MtxEvent.Name + NoticeMessage { + notice: model.data.roomName ? qsTr("room name changed to: %1").arg(model.data.roomName) : qsTr("removed room name") + } + } + DelegateChoice { + roleValue: MtxEvent.Topic + NoticeMessage { + notice: model.data.roomTopic ? qsTr("topic changed to: %1").arg(model.data.roomTopic) : qsTr("removed topic") + } + } + DelegateChoice { + Placeholder {} } - } - DelegateChoice { - Placeholder {} } } diff --git a/resources/qml/delegates/NoticeMessage.qml b/resources/qml/delegates/NoticeMessage.qml index f7467eca..34132bcf 100644 --- a/resources/qml/delegates/NoticeMessage.qml +++ b/resources/qml/delegates/NoticeMessage.qml @@ -1,7 +1,7 @@ import ".." MatrixText { - property string notice: model.formattedBody.replace("<pre>", "<pre style='white-space: pre-wrap'>") + property string notice: model.data.formattedBody.replace("<pre>", "<pre style='white-space: pre-wrap'>") text: notice width: parent ? parent.width : undefined font.italic: true diff --git a/resources/qml/delegates/Placeholder.qml b/resources/qml/delegates/Placeholder.qml index 4c0e68c3..36d7b2bc 100644 --- a/resources/qml/delegates/Placeholder.qml +++ b/resources/qml/delegates/Placeholder.qml @@ -1,7 +1,7 @@ import ".." MatrixText { - text: qsTr("unimplemented event: ") + model.type + text: qsTr("unimplemented event: ") + model.data.type width: parent ? parent.width : undefined color: inactiveColors.text } diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml index b3275462..ebf7487c 100644 --- a/resources/qml/delegates/PlayableMediaMessage.qml +++ b/resources/qml/delegates/PlayableMediaMessage.qml @@ -19,12 +19,12 @@ Rectangle { Rectangle { id: videoContainer - visible: model.type == MtxEvent.VideoMessage - width: Math.min(parent.width, model.width ? model.width : 400) // some media has 0 as size... - height: width*model.proportionalHeight + visible: model.data.type == MtxEvent.VideoMessage + width: Math.min(parent.width, model.data.width ? model.data.width : 400) // some media has 0 as size... + height: width*model.data.proportionalHeight Image { anchors.fill: parent - source: model.thumbnailUrl.replace("mxc://", "image://MxcImage/") + source: model.data.thumbnailUrl.replace("mxc://", "image://MxcImage/") asynchronous: true fillMode: Image.PreserveAspectFit @@ -97,7 +97,7 @@ Rectangle { anchors.fill: parent onClicked: { switch (button.state) { - case "": timelineManager.timeline.cacheMedia(model.id); break; + case "": timelineManager.timeline.cacheMedia(model.data.id); break; case "stopped": media.play(); console.log("play"); button.state = "playing" @@ -120,7 +120,7 @@ Rectangle { Connections { target: timelineManager.timeline onMediaCached: { - if (mxcUrl == model.url) { + if (mxcUrl == model.data.url) { media.source = "file://" + cacheUrl button.state = "stopped" console.log("media loaded: " + mxcUrl + " at " + cacheUrl) @@ -145,14 +145,14 @@ Rectangle { Text { Layout.fillWidth: true - text: model.body + text: model.data.body textFormat: Text.PlainText elide: Text.ElideRight color: colors.text } Text { Layout.fillWidth: true - text: model.filesize + text: model.data.filesize textFormat: Text.PlainText elide: Text.ElideRight color: colors.text diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml index f984b32f..92ba560b 100644 --- a/resources/qml/delegates/TextMessage.qml +++ b/resources/qml/delegates/TextMessage.qml @@ -1,6 +1,6 @@ import ".." MatrixText { - text: model.formattedBody.replace("<pre>", "<pre style='white-space: pre-wrap'>") + text: model.data.formattedBody.replace("<pre>", "<pre style='white-space: pre-wrap'>") width: parent ? parent.width : undefined } diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index 0e7f5259..41d864bd 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -212,6 +212,14 @@ TimelineModel::rowCount(const QModelIndex &parent) const return (int)this->eventOrder.size(); } +QVariantMap +TimelineModel::getDump(QString eventId) const +{ + if (events.contains(eventId)) + return data(index(idToIndex(eventId), 0), Dump).toMap(); + return {}; +} + QVariant TimelineModel::data(const QModelIndex &index, int role) const { @@ -263,11 +271,13 @@ TimelineModel::data(const QModelIndex &index, int role) const return QVariant(toRoomEventType(event)); case Body: return QVariant(utils::replaceEmoji(QString::fromStdString(body(event)))); - case FormattedBody: + case FormattedBody: { + const static QRegularExpression replyFallback( + "<mx-reply>.*</mx-reply>", QRegularExpression::DotMatchesEverythingOption); return QVariant( utils::replaceEmoji(utils::linkifyMessage(formattedBodyWithFallback(event))) - .remove("<mx-reply>") - .remove("</mx-reply>")); + .remove(replyFallback)); + } case Url: return QVariant(QString::fromStdString(url(event))); case ThumbnailUrl: diff --git a/src/timeline/TimelineModel.h b/src/timeline/TimelineModel.h index 0f18f7ef..61dd6b69 100644 --- a/src/timeline/TimelineModel.h +++ b/src/timeline/TimelineModel.h @@ -181,6 +181,7 @@ public slots: void setCurrentIndex(int index); int currentIndex() const { return idToIndex(currentId); } void markEventsAsRead(const std::vector<QString> &event_ids); + QVariantMap getDump(QString eventId) const; private slots: // Add old events at the top of the timeline. |