diff --git a/resources/qml/ForwardCompleter.qml b/resources/qml/ForwardCompleter.qml
index eee3879c..127b59c2 100644
--- a/resources/qml/ForwardCompleter.qml
+++ b/resources/qml/ForwardCompleter.qml
@@ -50,9 +50,24 @@ Popup {
Reply {
id: replyPreview
- modelData: room ? room.getDump(mid, "") : {
+ property var modelData: room ? room.getDump(mid, "") : {
}
+
userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.window)
+ blurhash: modelData.blurhash ?? ""
+ body: modelData.body ?? ""
+ formattedBody: modelData.formattedBody ?? ""
+ eventId: modelData.eventId ?? ""
+ filename: modelData.filename ?? ""
+ filesize: modelData.filesize ?? ""
+ proportionalHeight: modelData.proportionalHeight ?? 1
+ type: modelData.type ?? MtxEvent.UnknownMessage
+ typeString: modelData.typeString ?? ""
+ url: modelData.url ?? ""
+ originalWidth: modelData.originalWidth ?? 0
+ isOnlyEmoji: modelData.isOnlyEmoji ?? false
+ userId: modelData.userId ?? ""
+ userName: modelData.userName ?? ""
}
MatrixTextField {
diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml
index 260bc9da..9e01ef9a 100644
--- a/resources/qml/MessageView.qml
+++ b/resources/qml/MessageView.qml
@@ -7,8 +7,8 @@ import "./emoji"
import "./ui"
import Qt.labs.platform 1.1 as Platform
import QtGraphicalEffects 1.0
-import QtQuick 2.12
-import QtQuick.Controls 2.3
+import QtQuick 2.15
+import QtQuick.Controls 2.15
import QtQuick.Layouts 1.2
import QtQuick.Window 2.2
import im.nheko 1.0
@@ -25,6 +25,9 @@ ScrollView {
property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < parent.availableWidth) ? Settings.timelineMaxWidth : parent.availableWidth) - parent.padding * 2
model: room
+ // reuseItems still has a few bugs, see https://bugreports.qt.io/browse/QTBUG-95105 https://bugreports.qt.io/browse/QTBUG-95107
+ //onModelChanged: if (room) room.sendReset()
+ //reuseItems: true
boundsBehavior: Flickable.StopAtBounds
pixelAligned: true
spacing: 4
@@ -84,7 +87,7 @@ ScrollView {
ToolTip.text: qsTr("Edit")
onClicked: {
if (row.model.isEditable)
- chat.model.editAction(row.model.id);
+ chat.model.editAction(row.model.eventId);
}
}
@@ -98,7 +101,7 @@ ScrollView {
ToolTip.visible: hovered
ToolTip.text: qsTr("React")
emojiPicker: emojiPopup
- event_id: row.model ? row.model.id : ""
+ event_id: row.model ? row.model.eventId : ""
}
ImageButton {
@@ -110,7 +113,7 @@ ScrollView {
image: ":/icons/icons/ui/mail-reply.png"
ToolTip.visible: hovered
ToolTip.text: qsTr("Reply")
- onClicked: chat.model.replyAction(row.model.id)
+ onClicked: chat.model.replyAction(row.model.eventId)
}
ImageButton {
@@ -121,7 +124,7 @@ ScrollView {
image: ":/icons/icons/ui/vertical-ellipsis.png"
ToolTip.visible: hovered
ToolTip.text: qsTr("Options")
- onClicked: messageContextMenu.show(row.model.id, row.model.type, row.model.isSender, row.model.isEncrypted, row.model.isEditable, "", row.model.body, optionsButton)
+ onClicked: messageContextMenu.show(row.model.eventId, row.model.type, row.model.isSender, row.model.isEncrypted, row.model.isEditable, "", row.model.body, optionsButton)
}
}
@@ -212,16 +215,16 @@ ScrollView {
topPadding: 4
bottomPadding: 4
spacing: 8
- visible: modelData && (modelData.previousMessageUserId !== modelData.userId || modelData.previousMessageDay !== modelData.day)
+ visible: (previousMessageUserId !== userId || previousMessageDay !== day)
width: parentWidth
- height: ((modelData && modelData.previousMessageDay !== modelData.day) ? dateBubble.height + 8 + userName.height : userName.height) + 8
+ height: ((previousMessageDay !== day) ? dateBubble.height + 8 + userName.height : userName.height) + 8
Label {
id: dateBubble
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
- visible: modelData && modelData.previousMessageDay !== modelData.day
- text: modelData ? chat.model.formatDateSeparator(modelData.timestamp) : ""
+ visible: previousMessageDay !== day
+ text: chat.model.formatDateSeparator(timestamp)
color: Nheko.colors.text
height: Math.round(fontMetrics.height * 1.4)
width: contentWidth * 1.2
@@ -236,7 +239,7 @@ ScrollView {
}
Row {
- height: userName.height
+ height: userName_.height
spacing: 8
Avatar {
@@ -244,10 +247,10 @@ ScrollView {
width: Nheko.avatarSize
height: Nheko.avatarSize
- url: modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : ""
- displayName: modelData ? modelData.userName : ""
- userid: modelData ? modelData.userId : ""
- onClicked: chat.model.openUserProfile(modelData.userId)
+ url: chat.model.avatarUrl(userId).replace("mxc://", "image://MxcImage/")
+ displayName: userName
+ userid: userId
+ onClicked: chat.model.openUserProfile(userId)
ToolTip.visible: avatarHover.hovered
ToolTip.text: userid
@@ -260,22 +263,22 @@ ScrollView {
Connections {
target: chat.model
onRoomAvatarUrlChanged: {
- messageUserAvatar.url = modelData ? chat.model.avatarUrl(modelData.userId).replace("mxc://", "image://MxcImage/") : "";
+ messageUserAvatar.url = chat.model.avatarUrl(userId).replace("mxc://", "image://MxcImage/");
}
onScrollToIndex: chat.positionViewAtIndex(index, ListView.Visible)
}
Label {
- id: userName
+ id: userName_
- text: modelData ? TimelineManager.escapeEmoji(modelData.userName) : ""
- color: TimelineManager.userColor(modelData ? modelData.userId : "", Nheko.colors.window)
+ text: TimelineManager.escapeEmoji(userName)
+ color: TimelineManager.userColor(userId, Nheko.colors.window)
textFormat: Text.RichText
ToolTip.visible: displayNameHover.hovered
- ToolTip.text: modelData ? modelData.userId : ""
+ ToolTip.text: userId
TapHandler {
- onSingleTapped: chat.model.openUserProfile(modelData.userId)
+ onSingleTapped: chat.model.openUserProfile(userId)
}
CursorShape {
@@ -291,7 +294,7 @@ ScrollView {
Label {
color: Nheko.colors.buttonText
- text: modelData ? TimelineManager.userStatus(modelData.userId) : ""
+ text: TimelineManager.userStatus(userId)
textFormat: Text.PlainText
elide: Text.ElideRight
width: chat.delegateMaxWidth - parent.spacing * 2 - userName.implicitWidth - Nheko.avatarSize
@@ -307,7 +310,35 @@ ScrollView {
delegate: Item {
id: wrapper
- property bool scrolledToThis: model.id === chat.model.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY)
+ required property double proportionalHeight
+ required property int type
+ required property string typeString
+ required property int originalWidth
+ required property string blurhash
+ required property string body
+ required property string formattedBody
+ required property string eventId
+ required property string filename
+ required property string filesize
+ required property string url
+ required property string thumbnailUrl
+ required property bool isOnlyEmoji
+ required property bool isSender
+ required property bool isEncrypted
+ required property bool isEditable
+ required property bool isEdited
+ required property string replyTo
+ required property string userId
+ required property var reactions
+ required property int trustlevel
+ required property var timestamp
+ required property int status
+ required property int index
+ required property string previousMessageUserId
+ required property string day
+ required property string previousMessageDay
+ required property string userName
+ property bool scrolledToThis: eventId === chat.model.scrollTarget && (y + height > chat.y + chat.contentY && y < chat.y + chat.height + chat.contentY)
anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
width: chat.delegateMaxWidth
@@ -362,10 +393,15 @@ ScrollView {
Loader {
id: section
- property var modelData: model
property int parentWidth: parent.width
+ property string userId: wrapper.userId
+ property string previousMessageUserId: wrapper.previousMessageUserId
+ property string day: wrapper.day
+ property string previousMessageDay: wrapper.previousMessageDay
+ property string userName: wrapper.userName
+ property var timestamp: wrapper.timestamp
- active: model.previousMessageUserId !== undefined && model.previousMessageUserId !== model.userId || model.previousMessageDay !== model.day
+ active: previousMessageUserId !== undefined && previousMessageUserId !== userId || previousMessageDay !== day
//asynchronous: true
sourceComponent: sectionHeader
visible: status == Loader.Ready
@@ -376,6 +412,30 @@ ScrollView {
property alias hovered: hoverHandler.hovered
+ proportionalHeight: wrapper.proportionalHeight
+ type: chat.model, wrapper.type
+ typeString: wrapper.typeString
+ originalWidth: wrapper.originalWidth
+ blurhash: wrapper.blurhash
+ body: wrapper.body
+ formattedBody: wrapper.formattedBody
+ eventId: chat.model, wrapper.eventId
+ filename: wrapper.filename
+ filesize: wrapper.filesize
+ url: wrapper.url
+ thumbnailUrl: wrapper.thumbnailUrl
+ isOnlyEmoji: wrapper.isOnlyEmoji
+ isSender: wrapper.isSender
+ isEncrypted: wrapper.isEncrypted
+ isEditable: wrapper.isEditable
+ isEdited: wrapper.isEdited
+ replyTo: wrapper.replyTo
+ userId: wrapper.userId
+ userName: wrapper.userName
+ reactions: wrapper.reactions
+ trustlevel: wrapper.trustlevel
+ timestamp: wrapper.timestamp
+ status: wrapper.status
y: section.visible && section.active ? section.y + section.height : 0
HoverHandler {
@@ -386,7 +446,7 @@ ScrollView {
if (hovered) {
if (!messageActionHover.hovered) {
messageActions.attached = timelinerow;
- messageActions.model = model;
+ messageActions.model = timelinerow;
}
}
}
diff --git a/resources/qml/ReplyPopup.qml b/resources/qml/ReplyPopup.qml
index 0de68fe8..54b4f20c 100644
--- a/resources/qml/ReplyPopup.qml
+++ b/resources/qml/ReplyPopup.qml
@@ -21,15 +21,30 @@ Rectangle {
Reply {
id: replyPreview
+ property var modelData: room ? room.getDump(room.reply, room.id) : {
+ }
+
visible: room && room.reply
anchors.left: parent.left
anchors.leftMargin: 2 * 22 + 3 * 16
anchors.right: closeReplyButton.left
anchors.rightMargin: 2 * 22 + 3 * 16
anchors.bottom: parent.bottom
- modelData: room ? room.getDump(room.reply, room.id) : {
- }
userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.window)
+ blurhash: modelData.blurhash ?? ""
+ body: modelData.body ?? ""
+ formattedBody: modelData.formattedBody ?? ""
+ eventId: modelData.eventId ?? ""
+ filename: modelData.filename ?? ""
+ filesize: modelData.filesize ?? ""
+ proportionalHeight: modelData.proportionalHeight ?? 1
+ type: modelData.type ?? MtxEvent.UnknownMessage
+ typeString: modelData.typeString ?? ""
+ url: modelData.url ?? ""
+ originalWidth: modelData.originalWidth ?? 0
+ isOnlyEmoji: modelData.isOnlyEmoji ?? false
+ userId: modelData.userId ?? ""
+ userName: modelData.userName ?? ""
}
ImageButton {
diff --git a/resources/qml/StatusIndicator.qml b/resources/qml/StatusIndicator.qml
index 739cc007..7e471d69 100644
--- a/resources/qml/StatusIndicator.qml
+++ b/resources/qml/StatusIndicator.qml
@@ -9,14 +9,17 @@ import im.nheko 1.0
ImageButton {
id: indicator
+ required property int status
+ required property string eventId
+
width: 16
height: 16
hoverEnabled: true
- changeColorOnHover: (model.state == MtxEvent.Read)
- cursor: (model.state == MtxEvent.Read) ? Qt.PointingHandCursor : Qt.ArrowCursor
- ToolTip.visible: hovered && model.state != MtxEvent.Empty
+ changeColorOnHover: (status == MtxEvent.Read)
+ cursor: (status == MtxEvent.Read) ? Qt.PointingHandCursor : Qt.ArrowCursor
+ ToolTip.visible: hovered && status != MtxEvent.Empty
ToolTip.text: {
- switch (model.state) {
+ switch (status) {
case MtxEvent.Failed:
return qsTr("Failed");
case MtxEvent.Sent:
@@ -30,12 +33,12 @@ ImageButton {
}
}
onClicked: {
- if (model.state == MtxEvent.Read)
- room.readReceiptsAction(model.id);
+ if (status == MtxEvent.Read)
+ room.readReceiptsAction(eventId);
}
image: {
- switch (model.state) {
+ switch (status) {
case MtxEvent.Failed:
return ":/icons/icons/ui/remove-symbol.png";
case MtxEvent.Sent:
diff --git a/resources/qml/TimelineRow.qml b/resources/qml/TimelineRow.qml
index e66dd2de..c1cdaf9b 100644
--- a/resources/qml/TimelineRow.qml
+++ b/resources/qml/TimelineRow.qml
@@ -11,6 +11,33 @@ import QtQuick.Window 2.2
import im.nheko 1.0
Item {
+ id: r
+
+ required property double proportionalHeight
+ required property int type
+ required property string typeString
+ required property int originalWidth
+ required property string blurhash
+ required property string body
+ required property string formattedBody
+ required property string eventId
+ required property string filename
+ required property string filesize
+ required property string url
+ required property string thumbnailUrl
+ required property bool isOnlyEmoji
+ required property bool isSender
+ required property bool isEncrypted
+ required property bool isEditable
+ required property bool isEdited
+ required property string replyTo
+ required property string userId
+ required property string userName
+ required property var reactions
+ required property int trustlevel
+ required property var timestamp
+ required property int status
+
anchors.left: parent.left
anchors.right: parent.right
height: row.height
@@ -28,19 +55,21 @@ Item {
TapHandler {
acceptedButtons: Qt.RightButton
- onSingleTapped: messageContextMenu.show(model.id, model.type, model.isSender, model.isEncrypted, model.isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
+ onSingleTapped: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
gesturePolicy: TapHandler.ReleaseWithinBounds
}
TapHandler {
- onLongPressed: messageContextMenu.show(model.id, model.type, model.isSender, model.isEncrypted, model.isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
- onDoubleTapped: chat.model.reply = model.id
+ onLongPressed: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
+ onDoubleTapped: chat.model.reply = eventId
gesturePolicy: TapHandler.ReleaseWithinBounds
}
RowLayout {
id: row
+ property var replyData: chat.model.getDump(replyTo, eventId)
+
anchors.rightMargin: 1
anchors.leftMargin: Nheko.avatarSize + 16
anchors.left: parent.left
@@ -55,9 +84,23 @@ Item {
// fancy reply, if this is a reply
Reply {
- visible: model.replyTo
- modelData: chat.model.getDump(model.replyTo, model.id)
- userColor: TimelineManager.userColor(modelData.userId, Nheko.colors.base)
+ visible: replyTo
+ userColor: TimelineManager.userColor(userId, Nheko.colors.base)
+ blurhash: row.replyData.blurhash ?? ""
+ body: row.replyData.body ?? ""
+ formattedBody: row.replyData.formattedBody ?? ""
+ eventId: row.replyData.eventId ?? ""
+ filename: row.replyData.filename ?? ""
+ filesize: row.replyData.filesize ?? ""
+ proportionalHeight: row.replyData.proportionalHeight ?? 1
+ type: row.replyData.type ?? MtxEvent.UnknownMessage
+ typeString: row.replyData.typeString ?? ""
+ url: row.replyData.url ?? ""
+ originalWidth: row.replyData.originalWidth ?? 0
+ isOnlyEmoji: row.replyData.isOnlyEmoji ?? false
+ userId: row.replyData.userId ?? ""
+ userName: row.replyData.userName ?? ""
+ thumbnailUrl: row.replyData.thumbnailUrl ?? ""
}
// actual message content
@@ -65,14 +108,29 @@ Item {
id: contentItem
width: parent.width
- modelData: model
+ blurhash: r.blurhash
+ body: r.body
+ formattedBody: r.formattedBody
+ eventId: r.eventId
+ filename: r.filename
+ filesize: r.filesize
+ proportionalHeight: r.proportionalHeight
+ type: r.type
+ typeString: r.typeString ?? ""
+ url: r.url
+ thumbnailUrl: r.thumbnailUrl
+ originalWidth: r.originalWidth
+ isOnlyEmoji: r.isOnlyEmoji
+ userId: r.userId
+ userName: r.userName
+ isReply: false
}
Reactions {
id: reactionRow
- reactions: model.reactions
- eventId: model.id
+ reactions: r.reactions
+ eventId: r.eventId
}
}
@@ -81,19 +139,21 @@ Item {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.preferredHeight: 16
width: 16
+ status: r.status
+ eventId: r.eventId
}
EncryptionIndicator {
visible: room.isEncrypted
- encrypted: model.isEncrypted
- trust: model.trustlevel
+ encrypted: isEncrypted
+ trust: trustlevel
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.preferredHeight: 16
Layout.preferredWidth: 16
}
Image {
- visible: model.isEdited || model.id == chat.model.edit
+ visible: isEdited || eventId == chat.model.edit
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.preferredHeight: 16
Layout.preferredWidth: 16
@@ -101,7 +161,7 @@ Item {
width: 16
sourceSize.width: 16
sourceSize.height: 16
- source: "image://colorimage/:/icons/icons/ui/edit.png?" + ((model.id == chat.model.edit) ? Nheko.colors.highlight : Nheko.colors.buttonText)
+ source: "image://colorimage/:/icons/icons/ui/edit.png?" + ((eventId == chat.model.edit) ? Nheko.colors.highlight : Nheko.colors.buttonText)
ToolTip.visible: editHovered.hovered
ToolTip.text: qsTr("Edited")
@@ -113,11 +173,11 @@ Item {
Label {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
- text: model.timestamp.toLocaleTimeString(Locale.ShortFormat)
+ text: timestamp.toLocaleTimeString(Locale.ShortFormat)
width: Math.max(implicitWidth, text.length * fontMetrics.maximumCharacterWidth)
color: Nheko.inactiveColors.text
ToolTip.visible: ma.hovered
- ToolTip.text: Qt.formatDateTime(model.timestamp, Qt.DefaultLocaleLongDate)
+ ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate)
HoverHandler {
id: ma
diff --git a/resources/qml/delegates/FileMessage.qml b/resources/qml/delegates/FileMessage.qml
index 0392c73a..4f2a2836 100644
--- a/resources/qml/delegates/FileMessage.qml
+++ b/resources/qml/delegates/FileMessage.qml
@@ -7,6 +7,10 @@ import QtQuick.Layouts 1.2
import im.nheko 1.0
Item {
+ required property string eventId
+ required property string filename
+ required property string filesize
+
height: row.height + 24
width: parent ? parent.width : undefined
@@ -34,7 +38,7 @@ Item {
}
TapHandler {
- onSingleTapped: room.saveMedia(model.data.id)
+ onSingleTapped: room.saveMedia(eventId)
gesturePolicy: TapHandler.ReleaseWithinBounds
}
@@ -49,20 +53,20 @@ Item {
id: col
Text {
- id: filename
+ id: filename_
Layout.fillWidth: true
- text: model.data.filename
+ text: filename
textFormat: Text.PlainText
elide: Text.ElideRight
color: Nheko.colors.text
}
Text {
- id: filesize
+ id: filesize_
Layout.fillWidth: true
- text: model.data.filesize
+ text: filesize
textFormat: Text.PlainText
elide: Text.ElideRight
color: Nheko.colors.text
@@ -77,7 +81,7 @@ Item {
z: -1
radius: 10
height: row.height + 24
- width: 44 + 24 + 24 + Math.max(Math.min(filesize.width, filesize.implicitWidth), Math.min(filename.width, filename.implicitWidth))
+ width: 44 + 24 + 24 + Math.max(Math.min(filesize_.width, filesize_.implicitWidth), Math.min(filename_.width, filename_.implicitWidth))
}
}
diff --git a/resources/qml/delegates/ImageMessage.qml b/resources/qml/delegates/ImageMessage.qml
index ce8e779c..b432018c 100644
--- a/resources/qml/delegates/ImageMessage.qml
+++ b/resources/qml/delegates/ImageMessage.qml
@@ -6,20 +6,28 @@ import QtQuick 2.12
import im.nheko 1.0
Item {
- property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? parent.width : model.data.width)
- property double tempHeight: tempWidth * model.data.proportionalHeight
- property double divisor: model.isReply ? 5 : 3
+ required property int type
+ required property int originalWidth
+ required property double proportionalHeight
+ required property string url
+ required property string blurhash
+ required property string body
+ required property string filename
+ required property bool isReply
+ property double tempWidth: Math.min(parent ? parent.width : undefined, originalWidth < 1 ? 200 : originalWidth)
+ property double tempHeight: tempWidth * proportionalHeight
+ property double divisor: isReply ? 5 : 3
property bool tooHigh: tempHeight > timelineView.height / divisor
height: Math.round(tooHigh ? timelineView.height / divisor : tempHeight)
- width: Math.round(tooHigh ? (timelineView.height / divisor) / model.data.proportionalHeight : tempWidth)
+ width: Math.round(tooHigh ? (timelineView.height / divisor) / proportionalHeight : tempWidth)
Image {
- id: blurhash
+ id: blurhash_
anchors.fill: parent
visible: img.status != Image.Ready
- source: model.data.blurhash ? ("image://blurhash/" + model.data.blurhash) : ("image://colorimage/:/icons/icons/ui/do-not-disturb-rounded-sign@2x.png?" + Nheko.colors.buttonText)
+ source: blurhash ? ("image://blurhash/" + blurhash) : ("image://colorimage/:/icons/icons/ui/do-not-disturb-rounded-sign@2x.png?" + Nheko.colors.buttonText)
asynchronous: true
fillMode: Image.PreserveAspectFit
sourceSize.width: parent.width
@@ -30,16 +38,16 @@ Item {
id: img
anchors.fill: parent
- source: model.data.url.replace("mxc://", "image://MxcImage/")
+ source: url.replace("mxc://", "image://MxcImage/")
asynchronous: true
fillMode: Image.PreserveAspectFit
smooth: true
mipmap: true
TapHandler {
- enabled: model.data.type == MtxEvent.ImageMessage && img.status == Image.Ready
+ enabled: type == MtxEvent.ImageMessage && img.status == Image.Ready
onSingleTapped: {
- TimelineManager.openImageOverlay(model.data.url, model.data.id);
+ TimelineManager.openImageOverlay(url, room.data.eventId);
eventPoint.accepted = true;
}
gesturePolicy: TapHandler.ReleaseWithinBounds
@@ -73,7 +81,7 @@ Item {
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
// See this MSC: https://github.com/matrix-org/matrix-doc/pull/2530
- text: model.data.filename ? model.data.filename : model.data.body
+ text: filename ? filename : body
color: Nheko.colors.text
}
diff --git a/resources/qml/delegates/MessageDelegate.qml b/resources/qml/delegates/MessageDelegate.qml
index 1befcec3..4b32751c 100644
--- a/resources/qml/delegates/MessageDelegate.qml
+++ b/resources/qml/delegates/MessageDelegate.qml
@@ -6,32 +6,41 @@ import QtQuick 2.6
import im.nheko 1.0
Item {
- property alias modelData: model.data
- property alias isReply: model.isReply
+ id: d
+
+ required property bool isReply
property alias child: chooser.child
property real implicitWidth: (chooser.child && chooser.child.implicitWidth) ? chooser.child.implicitWidth : width
+ required property double proportionalHeight
+ required property int type
+ required property string typeString
+ required property int originalWidth
+ required property string blurhash
+ required property string body
+ required property string formattedBody
+ required property string eventId
+ required property string filename
+ required property string filesize
+ required property string url
+ required property string thumbnailUrl
+ required property bool isOnlyEmoji
+ required property string userId
+ required property string userName
height: chooser.childrenRect.height
- // Workaround to have an assignable global property
- Item {
- id: model
-
- property var data
- property bool isReply: false
- }
-
DelegateChooser {
id: chooser
//role: "type" //< not supported in our custom implementation, have to use roleValue
- roleValue: model.data.type
+ roleValue: type
anchors.fill: parent
DelegateChoice {
roleValue: MtxEvent.UnknownMessage
Placeholder {
+ typeString: d.typeString
text: "Unretrieved event"
}
@@ -41,6 +50,10 @@ Item {
roleValue: MtxEvent.TextMessage
TextMessage {
+ formatted: d.formattedBody
+ body: d.body
+ isOnlyEmoji: d.isOnlyEmoji
+ isReply: d.isReply
}
}
@@ -49,6 +62,10 @@ Item {
roleValue: MtxEvent.NoticeMessage
NoticeMessage {
+ formatted: d.formattedBody
+ body: d.body
+ isOnlyEmoji: d.isOnlyEmoji
+ isReply: d.isReply
}
}
@@ -57,8 +74,11 @@ Item {
roleValue: MtxEvent.EmoteMessage
NoticeMessage {
- formatted: TimelineManager.escapeEmoji(modelData.userName) + " " + model.data.formattedBody
- color: TimelineManager.userColor(modelData.userId, Nheko.colors.window)
+ formatted: TimelineManager.escapeEmoji(d.userName) + " " + d.formattedBody
+ color: TimelineManager.userColor(d.userId, Nheko.colors.window)
+ body: d.body
+ isOnlyEmoji: d.isOnlyEmoji
+ isReply: d.isReply
}
}
@@ -67,6 +87,14 @@ Item {
roleValue: MtxEvent.ImageMessage
ImageMessage {
+ type: d.type
+ originalWidth: d.originalWidth
+ proportionalHeight: d.proportionalHeight
+ url: d.url
+ blurhash: d.blurhash
+ body: d.body
+ filename: d.filename
+ isReply: d.isReply
}
}
@@ -75,6 +103,14 @@ Item {
roleValue: MtxEvent.Sticker
ImageMessage {
+ type: d.type
+ originalWidth: d.originalWidth
+ proportionalHeight: d.proportionalHeight
+ url: d.url
+ blurhash: d.blurhash
+ body: d.body
+ filename: d.filename
+ isReply: d.isReply
}
}
@@ -83,6 +119,9 @@ Item {
roleValue: MtxEvent.FileMessage
FileMessage {
+ eventId: d.eventId
+ filename: d.filename
+ filesize: d.filesize
}
}
@@ -91,6 +130,14 @@ Item {
roleValue: MtxEvent.VideoMessage
PlayableMediaMessage {
+ proportionalHeight: d.proportionalHeight
+ type: d.type
+ originalWidth: d.originalWidth
+ thumbnailUrl: d.thumbnailUrl
+ eventId: d.eventId
+ url: d.url
+ body: d.body
+ filesize: d.filesize
}
}
@@ -99,6 +146,14 @@ Item {
roleValue: MtxEvent.AudioMessage
PlayableMediaMessage {
+ proportionalHeight: d.proportionalHeight
+ type: d.type
+ originalWidth: d.originalWidth
+ thumbnailUrl: d.thumbnailUrl
+ eventId: d.eventId
+ url: d.url
+ body: d.body
+ filesize: d.filesize
}
}
@@ -134,7 +189,10 @@ Item {
roleValue: MtxEvent.Name
NoticeMessage {
- text: model.data.roomName ? qsTr("room name changed to: %1").arg(model.data.roomName) : qsTr("removed room name")
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: model.data.roomName ? qsTr("room name changed to: %1").arg(model.data.roomName) : qsTr("removed room name")
}
}
@@ -143,7 +201,10 @@ Item {
roleValue: MtxEvent.Topic
NoticeMessage {
- text: model.data.roomTopic ? qsTr("topic changed to: %1").arg(model.data.roomTopic) : qsTr("removed topic")
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: model.data.roomTopic ? qsTr("topic changed to: %1").arg(model.data.roomTopic) : qsTr("removed topic")
}
}
@@ -152,7 +213,10 @@ Item {
roleValue: MtxEvent.Avatar
NoticeMessage {
- text: qsTr("%1 changed the room avatar").arg(model.data.userName)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: qsTr("%1 changed the room avatar").arg(d.userName)
}
}
@@ -161,7 +225,10 @@ Item {
roleValue: MtxEvent.RoomCreate
NoticeMessage {
- text: qsTr("%1 created and configured room: %2").arg(model.data.userName).arg(model.data.roomId)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: qsTr("%1 created and configured room: %2").arg(d.userName).arg(model.data.roomId)
}
}
@@ -170,14 +237,17 @@ Item {
roleValue: MtxEvent.CallInvite
NoticeMessage {
- text: {
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: {
switch (model.data.callType) {
case "voice":
- return qsTr("%1 placed a voice call.").arg(model.data.userName);
+ return qsTr("%1 placed a voice call.").arg(d.userName);
case "video":
- return qsTr("%1 placed a video call.").arg(model.data.userName);
+ return qsTr("%1 placed a video call.").arg(d.userName);
default:
- return qsTr("%1 placed a call.").arg(model.data.userName);
+ return qsTr("%1 placed a call.").arg(d.userName);
}
}
}
@@ -188,7 +258,10 @@ Item {
roleValue: MtxEvent.CallAnswer
NoticeMessage {
- text: qsTr("%1 answered the call.").arg(model.data.userName)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: qsTr("%1 answered the call.").arg(d.userName)
}
}
@@ -197,7 +270,10 @@ Item {
roleValue: MtxEvent.CallHangUp
NoticeMessage {
- text: qsTr("%1 ended the call.").arg(model.data.userName)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: qsTr("%1 ended the call.").arg(d.userName)
}
}
@@ -206,7 +282,10 @@ Item {
roleValue: MtxEvent.CallCandidates
NoticeMessage {
- text: qsTr("Negotiating call...")
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: qsTr("Negotiating call...")
}
}
@@ -216,7 +295,10 @@ Item {
roleValue: MtxEvent.PowerLevels
NoticeMessage {
- text: room.formatPowerLevelEvent(model.data.id)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: room.formatPowerLevelEvent(d.eventId)
}
}
@@ -225,7 +307,10 @@ Item {
roleValue: MtxEvent.RoomJoinRules
NoticeMessage {
- text: room.formatJoinRuleEvent(model.data.id)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: room.formatJoinRuleEvent(d.eventId)
}
}
@@ -234,7 +319,10 @@ Item {
roleValue: MtxEvent.RoomHistoryVisibility
NoticeMessage {
- text: room.formatHistoryVisibilityEvent(model.data.id)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: room.formatHistoryVisibilityEvent(d.eventId)
}
}
@@ -243,7 +331,10 @@ Item {
roleValue: MtxEvent.RoomGuestAccess
NoticeMessage {
- text: room.formatGuestAccessEvent(model.data.id)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: room.formatGuestAccessEvent(d.eventId)
}
}
@@ -252,7 +343,10 @@ Item {
roleValue: MtxEvent.Member
NoticeMessage {
- text: room.formatMemberEvent(model.data.id)
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: room.formatMemberEvent(d.eventId)
}
}
@@ -261,7 +355,10 @@ Item {
roleValue: MtxEvent.KeyVerificationRequest
NoticeMessage {
- text: "KeyVerificationRequest"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationRequest"
}
}
@@ -270,7 +367,10 @@ Item {
roleValue: MtxEvent.KeyVerificationStart
NoticeMessage {
- text: "KeyVerificationStart"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationStart"
}
}
@@ -279,7 +379,10 @@ Item {
roleValue: MtxEvent.KeyVerificationReady
NoticeMessage {
- text: "KeyVerificationReady"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationReady"
}
}
@@ -288,7 +391,10 @@ Item {
roleValue: MtxEvent.KeyVerificationCancel
NoticeMessage {
- text: "KeyVerificationCancel"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationCancel"
}
}
@@ -297,7 +403,10 @@ Item {
roleValue: MtxEvent.KeyVerificationKey
NoticeMessage {
- text: "KeyVerificationKey"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationKey"
}
}
@@ -306,7 +415,10 @@ Item {
roleValue: MtxEvent.KeyVerificationMac
NoticeMessage {
- text: "KeyVerificationMac"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationMac"
}
}
@@ -315,7 +427,10 @@ Item {
roleValue: MtxEvent.KeyVerificationDone
NoticeMessage {
- text: "KeyVerificationDone"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationDone"
}
}
@@ -324,7 +439,10 @@ Item {
roleValue: MtxEvent.KeyVerificationDone
NoticeMessage {
- text: "KeyVerificationDone"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationDone"
}
}
@@ -333,13 +451,17 @@ Item {
roleValue: MtxEvent.KeyVerificationAccept
NoticeMessage {
- text: "KeyVerificationAccept"
+ body: formatted
+ isOnlyEmoji: false
+ isReply: d.isReply
+ formatted: "KeyVerificationAccept"
}
}
DelegateChoice {
Placeholder {
+ typeString: d.typeString
}
}
diff --git a/resources/qml/delegates/Placeholder.qml b/resources/qml/delegates/Placeholder.qml
index c4fc6cc3..692fe4a9 100644
--- a/resources/qml/delegates/Placeholder.qml
+++ b/resources/qml/delegates/Placeholder.qml
@@ -6,7 +6,9 @@ import ".."
import im.nheko 1.0
MatrixText {
- text: qsTr("unimplemented event: ") + model.data.typeString
+ required property string typeString
+
+ text: qsTr("unimplemented event: ") + typeString
width: parent ? parent.width : undefined
color: Nheko.inactiveColors.text
}
diff --git a/resources/qml/delegates/PlayableMediaMessage.qml b/resources/qml/delegates/PlayableMediaMessage.qml
index 83864db9..fd764d52 100644
--- a/resources/qml/delegates/PlayableMediaMessage.qml
+++ b/resources/qml/delegates/PlayableMediaMessage.qml
@@ -12,10 +12,21 @@ import im.nheko 1.0
Rectangle {
id: bg
+ required property double proportionalHeight
+ required property int type
+ required property int originalWidth
+ required property string thumbnailUrl
+ required property string eventId
+ required property string url
+ required property string body
+ required property string filesize
+
radius: 10
color: Nheko.colors.alternateBase
height: Math.round(content.height + 24)
width: parent ? parent.width : undefined
+ ListView.onPooled: height = 4
+ ListView.onReused: height = Math.round(content.height + 24)
Column {
id: content
@@ -26,18 +37,18 @@ Rectangle {
Rectangle {
id: videoContainer
- property double tempWidth: Math.min(parent ? parent.width : undefined, model.data.width < 1 ? 400 : model.data.width)
- property double tempHeight: tempWidth * model.data.proportionalHeight
- property double divisor: model.isReply ? 4 : 2
+ property double tempWidth: Math.min(parent ? parent.width : undefined, originalWidth < 1 ? 400 : originalWidth)
+ property double tempHeight: tempWidth * proportionalHeight
+ property double divisor: isReply ? 4 : 2
property bool tooHigh: tempHeight > timelineView.height / divisor
- visible: model.data.type == MtxEvent.VideoMessage
+ visible: type == MtxEvent.VideoMessage
height: tooHigh ? timelineView.height / divisor : tempHeight
- width: tooHigh ? (timelineView.height / divisor) / model.data.proportionalHeight : tempWidth
+ width: tooHigh ? (timelineView.height / divisor) / proportionalHeight : tempWidth
Image {
anchors.fill: parent
- source: model.data.thumbnailUrl.replace("mxc://", "image://MxcImage/")
+ source: thumbnailUrl.replace("mxc://", "image://MxcImage/")
asynchronous: true
fillMode: Image.PreserveAspectFit
@@ -121,7 +132,7 @@ Rectangle {
onClicked: {
switch (button.state) {
case "":
- room.cacheMedia(model.data.id);
+ room.cacheMedia(eventId);
break;
case "stopped":
media.play();
@@ -176,7 +187,7 @@ Rectangle {
Connections {
target: room
onMediaCached: {
- if (mxcUrl == model.data.url) {
+ if (mxcUrl == url) {
media.source = cacheUrl;
button.state = "stopped";
console.log("media loaded: " + mxcUrl + " at " + cacheUrl);
@@ -192,14 +203,14 @@ Rectangle {
Text {
Layout.fillWidth: true
- text: model.data.body
+ text: body
elide: Text.ElideRight
color: Nheko.colors.text
}
Text {
Layout.fillWidth: true
- text: model.data.filesize
+ text: filesize
textFormat: Text.PlainText
elide: Text.ElideRight
color: Nheko.colors.text
diff --git a/resources/qml/delegates/Reply.qml b/resources/qml/delegates/Reply.qml
index b5090529..08f13955 100644
--- a/resources/qml/delegates/Reply.qml
+++ b/resources/qml/delegates/Reply.qml
@@ -9,16 +9,30 @@ import QtQuick.Window 2.2
import im.nheko 1.0
Item {
- id: replyComponent
+ id: r
- property alias modelData: reply.modelData
property color userColor: "red"
+ property double proportionalHeight
+ property int type
+ property string typeString
+ property int originalWidth
+ property string blurhash
+ property string body
+ property string formattedBody
+ property string eventId
+ property string filename
+ property string filesize
+ property string url
+ property bool isOnlyEmoji
+ property string userId
+ property string userName
+ property string thumbnailUrl
width: parent.width
height: replyContainer.height
TapHandler {
- onSingleTapped: chat.model.showEvent(modelData.id)
+ onSingleTapped: chat.model.showEvent(eventId)
gesturePolicy: TapHandler.ReleaseWithinBounds
}
@@ -33,7 +47,7 @@ Item {
anchors.top: replyContainer.top
anchors.bottom: replyContainer.bottom
width: 4
- color: TimelineManager.userColor(reply.modelData.userId, Nheko.colors.window)
+ color: TimelineManager.userColor(userId, Nheko.colors.window)
}
Column {
@@ -44,14 +58,14 @@ Item {
width: parent.width - 8
Text {
- id: userName
+ id: userName_
- text: TimelineManager.escapeEmoji(reply.modelData.userName)
- color: replyComponent.userColor
+ text: TimelineManager.escapeEmoji(userName)
+ color: r.userColor
textFormat: Text.RichText
TapHandler {
- onSingleTapped: chat.model.openUserProfile(reply.modelData.userId)
+ onSingleTapped: chat.model.openUserProfile(userId)
gesturePolicy: TapHandler.ReleaseWithinBounds
}
@@ -60,6 +74,21 @@ Item {
MessageDelegate {
id: reply
+ blurhash: r.blurhash
+ body: r.body
+ formattedBody: r.formattedBody
+ eventId: r.eventId
+ filename: r.filename
+ filesize: r.filesize
+ proportionalHeight: r.proportionalHeight
+ type: r.type
+ typeString: r.typeString ?? ""
+ url: r.url
+ thumbnailUrl: r.thumbnailUrl
+ originalWidth: r.originalWidth
+ isOnlyEmoji: r.isOnlyEmoji
+ userId: r.userId
+ userName: r.userName
enabled: false
width: parent.width
isReply: true
@@ -72,7 +101,7 @@ Item {
z: -1
height: replyContainer.height
- width: Math.min(Math.max(reply.implicitWidth, userName.implicitWidth) + 8 + 4, parent.width)
+ width: Math.min(Math.max(reply.implicitWidth, userName_.implicitWidth) + 8 + 4, parent.width)
color: Qt.rgba(userColor.r, userColor.g, userColor.b, 0.1)
}
diff --git a/resources/qml/delegates/TextMessage.qml b/resources/qml/delegates/TextMessage.qml
index cd46f8ca..58aa99ca 100644
--- a/resources/qml/delegates/TextMessage.qml
+++ b/resources/qml/delegates/TextMessage.qml
@@ -6,8 +6,11 @@ import ".."
import im.nheko 1.0
MatrixText {
- property string formatted: model.data.formattedBody
- property string copyText: selectedText ? getText(selectionStart, selectionEnd) : model.data.body
+ required property string body
+ required property bool isOnlyEmoji
+ required property bool isReply
+ required property string formatted
+ property string copyText: selectedText ? getText(selectionStart, selectionEnd) : body
// table border-collapse doesn't seem to work
text: "
@@ -31,5 +34,5 @@ MatrixText {
height: isReply ? Math.round(Math.min(timelineView.height / 8, implicitHeight)) : undefined
clip: isReply
selectByMouse: !Settings.mobileMode && !isReply
- font.pointSize: (Settings.enlargeEmojiOnlyMessages && model.data.isOnlyEmoji > 0 && model.data.isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize
+ font.pointSize: (Settings.enlargeEmojiOnlyMessages && isOnlyEmoji > 0 && isOnlyEmoji < 4) ? Settings.fontSize * 3 : Settings.fontSize
}
diff --git a/resources/qml/voip/ActiveCallBar.qml b/resources/qml/voip/ActiveCallBar.qml
index 3106c382..d44c5edf 100644
--- a/resources/qml/voip/ActiveCallBar.qml
+++ b/resources/qml/voip/ActiveCallBar.qml
@@ -35,7 +35,7 @@ Rectangle {
height: Nheko.avatarSize
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
displayName: CallManager.callParty
- onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.id)
+ onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
}
Label {
diff --git a/resources/qml/voip/CallInviteBar.qml b/resources/qml/voip/CallInviteBar.qml
index 2d8e3040..f6c1ecde 100644
--- a/resources/qml/voip/CallInviteBar.qml
+++ b/resources/qml/voip/CallInviteBar.qml
@@ -42,7 +42,7 @@ Rectangle {
height: Nheko.avatarSize
url: CallManager.callPartyAvatarUrl.replace("mxc://", "image://MxcImage/")
displayName: CallManager.callParty
- onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.id)
+ onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
}
Label {
diff --git a/resources/qml/voip/PlaceCall.qml b/resources/qml/voip/PlaceCall.qml
index 97e39e02..5f564853 100644
--- a/resources/qml/voip/PlaceCall.qml
+++ b/resources/qml/voip/PlaceCall.qml
@@ -79,7 +79,7 @@ Popup {
height: Nheko.avatarSize
url: room.roomAvatarUrl.replace("mxc://", "image://MxcImage/")
displayName: room.roomName
- onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.id)
+ onClicked: TimelineManager.openImageOverlay(room.avatarUrl(userid), room.data.eventId)
}
Button {
|