matrixion/qml/TimelineRow.qml

289 lines
12 KiB
QML
Raw Permalink Normal View History

2021-03-05 02:35:15 +03:00
// SPDX-FileCopyrightText: 2021 Nheko Contributors
// SPDX-FileCopyrightText: 2022 Nheko Contributors
2021-03-05 02:35:15 +03:00
// SPDX-License-Identifier: GPL-3.0-or-later
2022-04-16 03:13:01 +03:00
import "delegates"
import "emoji"
2022-03-27 22:23:40 +03:00
import QtQuick 2.15
import QtQuick.Controls 2.3
import QtQuick.Layouts 1.2
import QtQuick.Window 2.13
import im.nheko
2022-03-24 03:35:42 +03:00
AbstractButton {
id: r
required property string blurhash
required property string body
2022-04-16 03:13:01 +03:00
required property string callType
required property int duration
required property int encryptionError
required property string eventId
required property string filename
required property string filesize
2022-04-16 03:13:01 +03:00
required property string formattedBody
required property bool isEditable
required property bool isEdited
2022-04-16 03:13:01 +03:00
required property bool isEncrypted
required property bool isOnlyEmoji
required property bool isSender
required property bool isStateEvent
2022-04-16 03:13:01 +03:00
required property int originalWidth
required property double proportionalHeight
required property var reactions
required property int relatedEventCacheBuster
required property string replyTo
2021-07-12 02:28:09 +03:00
required property string roomName
2022-04-16 03:13:01 +03:00
required property string roomTopic
required property int status
2022-04-16 03:13:01 +03:00
required property string thumbnailUrl
required property var timestamp
required property int trustlevel
required property int type
required property string typeString
required property string url
required property string userId
required property string userName
2022-04-16 03:13:01 +03:00
height: row.height + (reactionRow.height > 0 ? reactionRow.height - 2 : 0)
2022-03-24 03:35:42 +03:00
hoverEnabled: true
width: parent.width
2022-03-27 22:23:40 +03:00
states: State {
name: "dragging"
when: draghandler.active
}
transitions: Transition {
from: "dragging"
to: ""
2022-04-16 03:13:01 +03:00
2022-03-27 22:23:40 +03:00
PropertyAnimation {
2022-04-16 03:13:01 +03:00
duration: 100
2022-03-27 22:23:40 +03:00
easing.type: Easing.InOutQuad
2022-04-16 03:13:01 +03:00
properties: "x"
target: r
2022-03-27 22:23:40 +03:00
to: 0
}
}
onClicked: {
2022-04-16 03:13:01 +03:00
let link = contentItem.child.linkAt != undefined && contentItem.child.linkAt(pressX - row.x - msg.x, pressY - row.y - msg.y - contentItem.y);
if (link) {
2022-04-16 03:13:01 +03:00
Nheko.openLink(link);
}
}
onDoubleClicked: chat.model.reply = eventId
onPressAndHold: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
Rectangle {
anchors.fill: parent
color: (Settings.messageHoverHighlight && hovered) ? timelineRoot.palette.alternateBase : "transparent"
// this looks better without margins
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
gesturePolicy: TapHandler.ReleaseWithinBounds
onSingleTapped: messageContextMenu.show(eventId, type, isSender, isEncrypted, isEditable, contentItem.child.hoveredLink, contentItem.child.copyText)
}
}
2022-04-16 03:13:01 +03:00
DragHandler {
id: draghandler
xAxis.maximum: 100
xAxis.minimum: -100
yAxis.enabled: false
2022-04-16 03:13:01 +03:00
onActiveChanged: {
if (!active && (x < -70 || x > 70))
chat.model.reply = eventId;
}
}
2022-03-24 03:35:42 +03:00
Rectangle {
2020-10-08 22:11:21 +03:00
id: row
2022-04-11 05:18:16 +03:00
property color bgColor: timelineRoot.palette.base
2022-04-16 03:13:01 +03:00
property bool bubbleOnRight: isSender && Settings.bubbles
property int maxWidth: (parent.width - (Settings.smallAvatars || isStateEvent ? 0 : Nheko.avatarSize + 8)) * (Settings.bubbles && !isStateEvent ? 0.9 : 1)
property color userColor: TimelineManager.userColor(userId, timelineRoot.palette.base)
anchors.horizontalCenter: isStateEvent ? parent.horizontalCenter : undefined
anchors.left: isStateEvent ? undefined : (bubbleOnRight ? undefined : parent.left)
anchors.leftMargin: isStateEvent || Settings.smallAvatars ? 0 : Nheko.avatarSize + 8 // align bubble with section header
anchors.right: isStateEvent ? undefined : (bubbleOnRight ? parent.right : undefined)
2022-03-24 03:35:42 +03:00
color: (Settings.bubbles && !isStateEvent) ? Qt.tint(bgColor, Qt.hsla(userColor.hslHue, 0.5, userColor.hslLightness, 0.2)) : "#00000000"
2022-04-16 03:13:01 +03:00
height: msg.height + msg.anchors.margins * 2
2022-03-24 03:35:42 +03:00
radius: 4
2022-04-16 03:13:01 +03:00
width: Settings.bubbles ? Math.min(maxWidth, Math.max(reply.implicitWidth + 8, contentItem.implicitWidth + metadata.width + 20)) : maxWidth
2022-02-05 01:12:30 +03:00
2022-03-24 03:35:42 +03:00
GridLayout {
2022-04-16 03:13:01 +03:00
id: msg
columnSpacing: 2
columns: Settings.bubbles ? 1 : 2
rowSpacing: 0
rows: Settings.bubbles ? 3 : 2
2022-03-24 03:35:42 +03:00
anchors {
left: parent.left
leftMargin: 4
2022-04-16 03:13:01 +03:00
margins: (Settings.bubbles && !isStateEvent) ? 4 : 2
right: parent.right
top: parent.top
2022-03-24 03:35:42 +03:00
}
2020-10-08 22:11:21 +03:00
// fancy reply, if this is a reply
Reply {
id: reply
2021-07-12 23:28:01 +03:00
function fromModel(role) {
return replyTo != "" ? room.dataById(replyTo, role, r.eventId) : null;
2021-07-12 23:28:01 +03:00
}
2022-04-16 03:13:01 +03:00
Layout.bottomMargin: visible ? 2 : 0
Layout.column: 0
Layout.fillWidth: true
Layout.maximumWidth: Settings.bubbles ? Number.MAX_VALUE : implicitWidth
Layout.preferredHeight: height
Layout.row: 0
blurhash: r.relatedEventCacheBuster, fromModel(Room.Blurhash) ?? ""
body: r.relatedEventCacheBuster, fromModel(Room.Body) ?? ""
2022-04-16 03:13:01 +03:00
callType: r.relatedEventCacheBuster, fromModel(Room.Voip) ?? ""
duration: r.relatedEventCacheBuster, fromModel(Room.Duration) ?? 0
encryptionError: r.relatedEventCacheBuster, fromModel(Room.EncryptionError) ?? 0
2021-07-12 23:28:01 +03:00
eventId: fromModel(Room.EventId) ?? ""
filename: r.relatedEventCacheBuster, fromModel(Room.Filename) ?? ""
filesize: r.relatedEventCacheBuster, fromModel(Room.Filesize) ?? ""
2022-04-16 03:13:01 +03:00
formattedBody: r.relatedEventCacheBuster, fromModel(Room.FormattedBody) ?? ""
isOnlyEmoji: r.relatedEventCacheBuster, fromModel(Room.IsOnlyEmoji) ?? false
isStateEvent: r.relatedEventCacheBuster, fromModel(Room.IsStateEvent) ?? false
originalWidth: r.relatedEventCacheBuster, fromModel(Room.OriginalWidth) ?? 0
proportionalHeight: r.relatedEventCacheBuster, fromModel(Room.ProportionalHeight) ?? 1
2022-04-16 03:13:01 +03:00
relatedEventCacheBuster: r.relatedEventCacheBuster, fromModel(Room.RelatedEventCacheBuster) ?? 0
roomName: r.relatedEventCacheBuster, fromModel(Room.RoomName) ?? ""
roomTopic: r.relatedEventCacheBuster, fromModel(Room.RoomTopic) ?? ""
thumbnailUrl: r.relatedEventCacheBuster, fromModel(Room.ThumbnailUrl) ?? ""
type: r.relatedEventCacheBuster, fromModel(Room.Type) ?? MtxEvent.UnknownMessage
typeString: r.relatedEventCacheBuster, fromModel(Room.TypeString) ?? ""
url: r.relatedEventCacheBuster, fromModel(Room.Url) ?? ""
2022-04-16 03:13:01 +03:00
userColor: r.relatedEventCacheBuster, TimelineManager.userColor(userId, timelineRoot.palette.base)
userId: r.relatedEventCacheBuster, fromModel(Room.UserId) ?? ""
userName: r.relatedEventCacheBuster, fromModel(Room.UserName) ?? ""
2022-04-16 03:13:01 +03:00
visible: replyTo
2020-10-08 22:11:21 +03:00
}
// actual message content
MessageDelegate {
2022-04-16 03:13:01 +03:00
id: contentItem
Layout.column: 0
Layout.fillWidth: true
Layout.preferredHeight: height
2022-04-16 03:13:01 +03:00
Layout.row: 1
blurhash: r.blurhash
body: r.body
2022-04-16 03:13:01 +03:00
callType: r.callType
duration: r.duration
encryptionError: r.encryptionError
eventId: r.eventId
filename: r.filename
filesize: r.filesize
2022-04-16 03:13:01 +03:00
formattedBody: r.formattedBody
isOnlyEmoji: r.isOnlyEmoji
isReply: false
isStateEvent: r.isStateEvent
metadataWidth: metadata.width
originalWidth: r.originalWidth
proportionalHeight: r.proportionalHeight
2022-04-16 03:13:01 +03:00
relatedEventCacheBuster: r.relatedEventCacheBuster
roomName: r.roomName
roomTopic: r.roomTopic
thumbnailUrl: r.thumbnailUrl
type: r.type
typeString: r.typeString ?? ""
url: r.url
userId: r.userId
userName: r.userName
2020-10-08 22:11:21 +03:00
}
2022-03-01 05:12:57 +03:00
Row {
id: metadata
2022-04-16 03:13:01 +03:00
property int iconSize: Math.floor(fontMetrics.ascent * scaling)
property double scaling: Settings.bubbles ? 0.75 : 1
Layout.alignment: Qt.AlignTop | Qt.AlignRight
2022-04-16 03:13:01 +03:00
Layout.bottomMargin: -2
Layout.column: Settings.bubbles ? 0 : 1
Layout.preferredWidth: implicitWidth
2022-04-16 03:13:01 +03:00
Layout.row: Settings.bubbles ? 2 : 0
Layout.rowSpan: Settings.bubbles ? 1 : 2
Layout.topMargin: (contentItem.fitsMetadata && Settings.bubbles) ? -height - Layout.bottomMargin : 0
2022-03-01 05:12:57 +03:00
spacing: 2
2022-04-16 03:13:01 +03:00
visible: !isStateEvent
2022-03-01 05:12:57 +03:00
StatusIndicator {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
2022-04-16 03:13:01 +03:00
anchors.verticalCenter: ts.verticalCenter
eventId: r.eventId
2022-03-01 05:12:57 +03:00
height: parent.iconSize
status: r.status
2022-04-16 03:13:01 +03:00
width: parent.iconSize
}
Image {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: qsTr("Edited")
2022-04-16 03:13:01 +03:00
ToolTip.visible: editHovered.hovered
2022-03-01 05:12:57 +03:00
anchors.verticalCenter: ts.verticalCenter
2022-04-16 03:13:01 +03:00
height: parent.iconSize
source: "image://colorimage/:/icons/icons/ui/edit.svg?" + ((eventId == chat.model.edit) ? timelineRoot.palette.highlight : timelineRoot.palette.placeholderText)
sourceSize.height: parent.iconSize * Screen.devicePixelRatio
sourceSize.width: parent.iconSize * Screen.devicePixelRatio
visible: isEdited || eventId == chat.model.edit
width: parent.iconSize
HoverHandler {
id: editHovered
}
}
EncryptionIndicator {
Layout.alignment: Qt.AlignRight | Qt.AlignTop
2022-04-16 03:13:01 +03:00
anchors.verticalCenter: ts.verticalCenter
encrypted: isEncrypted
2022-03-01 05:12:57 +03:00
height: parent.iconSize
sourceSize.height: parent.iconSize * Screen.devicePixelRatio
2022-04-16 03:13:01 +03:00
sourceSize.width: parent.iconSize * Screen.devicePixelRatio
trust: trustlevel
visible: room.isEncrypted
width: parent.iconSize
}
Label {
2022-03-01 05:12:57 +03:00
id: ts
Layout.alignment: Qt.AlignRight | Qt.AlignTop
Layout.preferredWidth: implicitWidth
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: Qt.formatDateTime(timestamp, Qt.DefaultLocaleLongDate)
2022-04-16 03:13:01 +03:00
ToolTip.visible: ma.hovered
color: timelineRoot.palette.inactive.text
font.pointSize: fontMetrics.font.pointSize * parent.scaling
text: timestamp.toLocaleTimeString(Locale.ShortFormat)
HoverHandler {
id: ma
}
}
}
2021-11-11 06:43:37 +03:00
}
2022-02-05 23:53:21 +03:00
}
Reactions {
2022-04-16 03:13:01 +03:00
id: reactionRow
eventId: r.eventId
layoutDirection: row.bubbleOnRight ? Qt.RightToLeft : Qt.LeftToRight
reactions: r.reactions
width: row.maxWidth
2022-02-05 23:53:21 +03:00
anchors {
2022-04-16 03:13:01 +03:00
left: row.bubbleOnRight ? undefined : row.left
right: row.bubbleOnRight ? row.right : undefined
2022-02-05 23:53:21 +03:00
top: row.bottom
topMargin: -2
2022-02-05 23:53:21 +03:00
}
2020-10-08 22:11:21 +03:00
}
}