matrixion/resources/qml/TimelineDefaultMessageStyle.qml

329 lines
12 KiB
QML
Raw Normal View History

// SPDX-FileCopyrightText: Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
import QtQuick
import QtQuick.Controls
import QtQuick.Window
import im.nheko
TimelineEvent {
id: wrapper
2023-10-31 05:11:03 +03:00
property int avatarMargin: (wrapper.isStateEvent || Settings.smallAvatars ? 0 : (Nheko.avatarSize + 8)) // align bubble with section header
//room: chatRoot.roommodel
required property var day
2023-10-31 05:11:03 +03:00
property alias hovered: messageHover.hovered
required property int index
2023-10-31 05:11:03 +03:00
required property bool isEditable
required property bool isEdited
required property bool isEncrypted
required property bool isSender
required property Item messageActions
required property QtObject messageContextMenu
required property int notificationlevel
property var previousMessageDay: (index + 1) >= chat.count ? 0 : chat.model.dataByIndex(index + 1, Room.Day)
property bool previousMessageIsStateEvent: (index + 1) >= chat.count ? true : chat.model.dataByIndex(index + 1, Room.IsStateEvent)
property string previousMessageUserId: (index + 1) >= chat.count ? "" : chat.model.dataByIndex(index + 1, Room.UserId)
required property var reactions
2023-10-31 05:11:03 +03:00
required property QtObject replyContextMenu
property bool scrolledToThis: false
required property int status
2023-10-31 05:11:03 +03:00
required property string threadId
required property date timestamp
required property int trustlevel
required property int type
2023-10-31 05:11:03 +03:00
required property string userId
required property string userName
required property int userPowerlevel
2023-10-31 05:11:03 +03:00
ListView.delayRemove: true
anchors.horizontalCenter: ListView.view.contentItem.horizontalCenter
height: Math.max((section.item?.height ?? 0) + gridContainer.implicitHeight + reactionRow.implicitHeight + unreadRow.height, 10)
2023-10-09 22:28:39 +03:00
mainInset: (threadId ? (4 + Nheko.paddingSmall) : 0)
maxWidth: chat.delegateMaxWidth - avatarMargin - metadata.width
2023-10-31 05:11:03 +03:00
replyInset: mainInset + 4 + Nheko.paddingSmall
width: chat.delegateMaxWidth
data: [
Loader {
id: section
active: wrapper.previousMessageUserId !== wrapper.userId || wrapper.previousMessageDay !== wrapper.day || wrapper.previousMessageIsStateEvent !== wrapper.isStateEvent
2023-10-31 05:11:03 +03:00
visible: status == Loader.Ready
z: 4
//asynchronous: true
sourceComponent: TimelineSectionHeader {
day: wrapper.day
isSender: wrapper.isSender
isStateEvent: wrapper.isStateEvent
parentWidth: wrapper.width
previousMessageDay: wrapper.previousMessageDay
previousMessageIsStateEvent: wrapper.previousMessageIsStateEvent
previousMessageUserId: wrapper.previousMessageUserId
timestamp: wrapper.timestamp
userId: wrapper.userId
userName: wrapper.userName
userPowerlevel: wrapper.userPowerlevel
}
2023-10-31 05:11:03 +03:00
},
Rectangle {
anchors.fill: gridContainer
color: (Settings.messageHoverHighlight && messageHover.hovered) ? 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(wrapper.eventId, wrapper.threadId, wrapper.type, wrapper.isSender, wrapper.isEncrypted, wrapper.isEditable, wrapper.main.hoveredLink, wrapper.main.copyText)
}
},
Rectangle {
id: scrollHighlight
2023-10-31 05:11:03 +03:00
anchors.fill: gridContainer
color: palette.highlight
enabled: false
opacity: 0
visible: true
z: 1
states: State {
name: "revealed"
when: wrapper.scrolledToThis
}
transitions: Transition {
from: ""
to: "revealed"
SequentialAnimation {
PropertyAnimation {
duration: 500
easing.type: Easing.InOutQuad
from: 0
properties: "opacity"
target: scrollHighlight
to: 1
}
PropertyAnimation {
duration: 500
easing.type: Easing.InOutQuad
from: 1
properties: "opacity"
target: scrollHighlight
to: 0
}
ScriptAction {
script: wrapper.room.eventShown()
}
}
}
},
Rectangle {
2023-10-31 05:11:03 +03:00
anchors.left: gridContainer.left
anchors.leftMargin: -2
anchors.top: gridContainer.top
anchors.topMargin: -2
border.color: Nheko.theme.red
border.width: wrapper.notificationlevel == MtxEvent.Highlight ? 1 : 0
2023-10-31 05:11:03 +03:00
color: "transparent"
height: contentColumn.implicitHeight + 4
2023-10-31 05:11:03 +03:00
radius: 4
width: contentColumn.implicitWidth + 4
},
Row {
id: gridContainer
2023-10-31 05:11:03 +03:00
spacing: Nheko.paddingSmall
width: wrapper.width - wrapper.avatarMargin
x: wrapper.avatarMargin
y: section.visible && section.active ? section.y + section.height : 0
HoverHandler {
id: messageHover
2023-10-31 05:11:03 +03:00
blocking: false
2023-10-31 05:11:03 +03:00
onHoveredChanged: () => {
if (!Settings.mobileMode && hovered) {
if (!messageActions.hovered) {
messageActions.model = wrapper;
messageActions.attached = wrapper;
2023-10-31 05:11:03 +03:00
messageActions.anchors.bottomMargin = -gridContainer.y;
messageActions.anchors.rightMargin = metadata.width;
}
}
}
}
AbstractButton {
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: qsTr("Part of a thread")
ToolTip.visible: hovered
height: contentColumn.height
visible: wrapper.threadId
width: 4
onClicked: wrapper.room.thread = wrapper.threadId
Rectangle {
id: threadLine
anchors.fill: parent
color: TimelineManager.userColor(wrapper.threadId, palette.base)
}
}
2023-10-09 00:52:23 +03:00
Item {
2023-10-31 05:11:03 +03:00
height: 1
2023-10-09 00:52:23 +03:00
visible: wrapper.isStateEvent
width: (wrapper.maxWidth - (wrapper.main?.width ?? 0)) / 2
}
Column {
id: contentColumn
2023-10-31 05:11:03 +03:00
data: [replyRow, wrapper.main,]
AbstractButton {
id: replyRow
property color userColor: TimelineManager.userColor(wrapper.reply?.userId ?? '', palette.base)
clip: true
2023-10-31 05:11:03 +03:00
height: replyLine.height
visible: wrapper.reply
2023-10-31 05:11:03 +03:00
background: Rectangle {
//width: replyRow.implicitContentWidth
color: Qt.tint(palette.base, Qt.hsla(replyRow.userColor.hslHue, 0.5, replyRow.userColor.hslLightness, 0.1))
}
contentItem: Row {
id: replyRowLay
spacing: Nheko.paddingSmall
Rectangle {
id: replyLine
2023-10-31 05:11:03 +03:00
color: replyRow.userColor
2023-10-31 05:11:03 +03:00
height: Math.min(wrapper.reply?.height, timelineView.height / 10) + Nheko.paddingSmall + replyUserButton.height
width: 4
}
Column {
id: replyCol
2023-10-31 05:11:03 +03:00
data: [replyUserButton, wrapper.reply,]
spacing: 0
AbstractButton {
id: replyUserButton
contentItem: Label {
id: userName_
2023-10-31 05:11:03 +03:00
color: replyRow.userColor
2023-10-31 05:11:03 +03:00
text: wrapper.reply?.userName ?? ''
textFormat: Text.RichText
width: wrapper.maxWidth
//elideWidth: wrapper.maxWidth
}
2023-10-31 05:11:03 +03:00
onClicked: wrapper.room.openUserProfile(wrapper.reply?.userId)
}
}
}
onClicked: {
2023-10-31 05:11:03 +03:00
let link = wrapper.reply.hoveredLink;
if (link) {
2023-10-31 05:11:03 +03:00
Nheko.openLink(link);
} else {
2023-10-31 05:11:03 +03:00
console.log("Scrolling to " + wrapper.replyTo);
wrapper.room.showEvent(wrapper.replyTo);
}
}
2023-10-31 05:11:03 +03:00
onPressAndHold: wrapper.replyContextMenu.show(wrapper.reply.copyText ?? "", wrapper.reply.linkAt ? wrapper.reply.linkAt(pressX - replyLine.width - Nheko.paddingSmall, pressY - replyUserButton.implicitHeight) : "", wrapper.replyTo)
NhekoCursorShape {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
}
2023-10-10 01:00:17 +03:00
TapHandler {
acceptedButtons: Qt.RightButton
acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus | PointerDevice.TouchPad
2023-10-31 05:11:03 +03:00
gesturePolicy: TapHandler.ReleaseWithinBounds
onSingleTapped: eventPoint => wrapper.replyContextMenu.show(wrapper.reply.copyText ?? "", wrapper.reply.linkAt ? wrapper.reply.linkAt(eventPoint.position.x - replyLine.width - Nheko.paddingSmall, eventPoint.position.y - replyUserButton.implicitHeight) : "", wrapper.replyTo)
2023-10-10 01:00:17 +03:00
}
}
}
DragHandler {
id: replyDragHandler
2023-10-31 05:11:03 +03:00
xAxis.enabled: true
xAxis.maximum: wrapper.avatarMargin
2023-10-31 05:11:03 +03:00
xAxis.minimum: wrapper.avatarMargin - 100
yAxis.enabled: false
onActiveChanged: {
if (!replyDragHandler.active) {
if (replyDragHandler.xAxis.minimum <= replyDragHandler.xAxis.activeValue + 1) {
2023-10-31 05:11:03 +03:00
wrapper.room.reply = wrapper.eventId;
}
gridContainer.x = wrapper.avatarMargin;
}
}
}
TapHandler {
onDoubleTapped: wrapper.room.reply = wrapper.eventId
}
},
2023-10-31 05:11:03 +03:00
TimelineMetadata {
id: metadata
2023-10-31 05:11:03 +03:00
anchors.right: parent.right
eventId: wrapper.eventId
isEdited: wrapper.isEdited
isEncrypted: wrapper.isEncrypted
room: wrapper.room
scaling: 1
status: wrapper.status
threadId: wrapper.threadId
timestamp: wrapper.timestamp
trustlevel: wrapper.trustlevel
visible: !wrapper.isStateEvent
y: section.visible && section.active ? section.y + section.height : 0
},
Reactions {
id: reactionRow
eventId: wrapper.eventId
reactions: wrapper.reactions
width: wrapper.width - wrapper.avatarMargin
x: wrapper.avatarMargin
anchors {
top: gridContainer.bottom
topMargin: -4
}
},
Rectangle {
id: unreadRow
color: palette.highlight
height: visible ? 3 : 0
visible: (wrapper.index > 0 && (wrapper.room.fullyReadEventId == wrapper.eventId))
anchors {
left: parent.left
right: parent.right
top: reactionRow.bottom
topMargin: 5
}
}
]
}