summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Werner <nicolas.werner@hotmail.de>2022-02-19 02:49:58 +0100
committerNicolas Werner <nicolas.werner@hotmail.de>2022-02-19 02:49:58 +0100
commitf7ea4c604c498af88bb635941d5780884c00d81b (patch)
tree12b8c83c91220a3ebe90d7262f7d343ce047ee39
parent0629ea5932d0af30fb86888d897cb63bb4f235af (diff)
Use ListView without scrollview for messagesfix-touch-scrolling
That way we can autohide the scollbar if needed, it should fix some jumping issues, it makes it possible to flick on mobile, etc. Some related bugs: https://bugreports.qt.io/browse/QTBUG-75223 https://bugreports.qt.io/browse/QTBUG-44902
-rw-r--r--CMakeLists.txt2
-rw-r--r--resources/qml/Avatar.qml1
-rw-r--r--resources/qml/MessageView.qml897
-rw-r--r--src/MainWindow.cpp2
-rw-r--r--src/ui/NhekoEventObserver.cpp61
-rw-r--r--src/ui/NhekoEventObserver.h27
6 files changed, 551 insertions, 439 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4c7a9ccd..a211b1f6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -336,6 +336,7 @@ set(SRC_FILES
src/ui/MxcAnimatedImage.cpp
src/ui/MxcMediaProxy.cpp
src/ui/NhekoCursorShape.cpp
+ src/ui/NhekoEventObserver.cpp
src/ui/NhekoDropArea.cpp
src/ui/NhekoGlobalObject.cpp
src/ui/RoomSettings.cpp
@@ -532,6 +533,7 @@ qt5_wrap_cpp(MOC_HEADERS
src/ui/MxcAnimatedImage.h
src/ui/MxcMediaProxy.h
src/ui/NhekoCursorShape.h
+ src/ui/NhekoEventObserver.h
src/ui/NhekoDropArea.h
src/ui/NhekoGlobalObject.h
src/ui/RoomSettings.h
diff --git a/resources/qml/Avatar.qml b/resources/qml/Avatar.qml
index aca4a1a7..5875e309 100644
--- a/resources/qml/Avatar.qml
+++ b/resources/qml/Avatar.qml
@@ -105,6 +105,7 @@ Rectangle {
id: mouseArea
onSingleTapped: avatar.clicked(eventPoint)
+ dragThreshold: 0
}
Ripple {
diff --git a/resources/qml/MessageView.qml b/resources/qml/MessageView.qml
index 2700cda6..e8cc9ed8 100644
--- a/resources/qml/MessageView.qml
+++ b/resources/qml/MessageView.qml
@@ -14,544 +14,564 @@ import QtQuick.Layouts 1.2
import QtQuick.Window 2.13
import im.nheko 1.0
-ScrollView {
- clip: false
- palette: Nheko.colors
- padding: 8
- ScrollBar.horizontal.visible: false
-
- ListView {
- id: chat
-
- property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < parent.availableWidth) ? Settings.timelineMaxWidth : parent.availableWidth) - parent.padding * 2
-
- displayMarginBeginning: height / 2
- displayMarginEnd: height / 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: 2
- verticalLayoutDirection: ListView.BottomToTop
- onCountChanged: {
- // Mark timeline as read
- if (atYEnd && room)
- model.currentIndex = 0;
- }
+Item {
+ id: chatRoot
+ property int padding: Nheko.paddingMedium
+
+ property int availableWidth: width
- Rectangle {
- //closePolicy: Popup.NoAutoClose
+ ScrollBar {
+ id: scrollbar
+ interactive: !touchObserver.wasTouched
+ parent: chat.parent
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.bottom: parent.bottom
+ }
- id: messageActions
+ EventObserver {
+ id: touchObserver
+ anchors.fill: parent
- property Item attached: null
- property alias model: row.model
- // use comma to update on scroll
- property var attachedPos: chat.contentY, attached ? chat.mapFromItem(attached, attached ? attached.width - width : 0, -height) : null
- readonly property int padding: Nheko.paddingSmall
+ ListView {
+ id: chat
- visible: Settings.buttonsInTimeline && !!attached && (attached.hovered || messageActionHover.hovered)
- x: attached ? attachedPos.x : 0
- y: attached ? attachedPos.y : 0
- z: 10
- height: row.implicitHeight + padding * 2
- width: row.implicitWidth + padding * 2
- color: Nheko.colors.window
- border.color: Nheko.colors.buttonText
- border.width: 1
- radius: padding
+ anchors.fill: parent
- HoverHandler {
- id: messageActionHover
+ property int delegateMaxWidth: ((Settings.timelineMaxWidth > 100 && Settings.timelineMaxWidth < chatRoot.availableWidth) ? Settings.timelineMaxWidth : chatRoot.availableWidth) - chatRoot.padding * 2 - scrollbar.width
+
+ displayMarginBeginning: height / 2
+ displayMarginEnd: height / 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: 2
+ verticalLayoutDirection: ListView.BottomToTop
+ onCountChanged: {
+ // Mark timeline as read
+ if (atYEnd && room) model.currentIndex = 0;
- grabPermissions: PointerHandler.CanTakeOverFromAnything
}
- Row {
- id: row
+ ScrollBar.vertical: scrollbar
- property var model
+ anchors.rightMargin: scrollbar.interactive ? scrollbar.width : 0
- anchors.centerIn: parent
- spacing: messageActions.padding
+ Rectangle {
+ //closePolicy: Popup.NoAutoClose
- Repeater {
- model: Settings.recentReactions
+ id: messageActions
- delegate: TextButton {
- required property string modelData
+ property Item attached: null
+ property alias model: row.model
+ // use comma to update on scroll
+ property var attachedPos: chat.contentY, attached ? chat.mapFromItem(attached, attached ? attached.width - width : 0, -height) : null
+ readonly property int padding: Nheko.paddingSmall
- visible: chat.model ? chat.model.permissions.canSend(MtxEvent.Reaction) : false
+ visible: Settings.buttonsInTimeline && !!attached && (attached.hovered || messageActionHover.hovered)
+ x: attached ? attachedPos.x : 0
+ y: attached ? attachedPos.y : 0
+ z: 10
+ height: row.implicitHeight + padding * 2
+ width: row.implicitWidth + padding * 2
+ color: Nheko.colors.window
+ border.color: Nheko.colors.buttonText
+ border.width: 1
+ radius: padding
- height: fontMetrics.height
- font.family: Settings.emojiFont
+ HoverHandler {
+ id: messageActionHover
- text: modelData
- onClicked: {
- room.input.reaction(row.model.eventId, modelData);
- TimelineManager.focusMessageInput();
+ grabPermissions: PointerHandler.CanTakeOverFromAnything
+ }
+
+ Row {
+ id: row
+
+ property var model
+
+ anchors.centerIn: parent
+ spacing: messageActions.padding
+
+ Repeater {
+ model: Settings.recentReactions
+
+ delegate: TextButton {
+ required property string modelData
+
+ visible: chat.model ? chat.model.permissions.canSend(MtxEvent.Reaction) : false
+
+ height: fontMetrics.height
+ font.family: Settings.emojiFont
+
+ text: modelData
+ onClicked: {
+ room.input.reaction(row.model.eventId, modelData);
+ TimelineManager.focusMessageInput();
+ }
}
}
- }
- ImageButton {
- id: editButton
-
- visible: !!row.model && row.model.isEditable
- buttonTextColor: Nheko.colors.buttonText
- width: 16
- hoverEnabled: true
- image: ":/icons/icons/ui/edit.svg"
- ToolTip.visible: hovered
- ToolTip.delay: Nheko.tooltipDelay
- ToolTip.text: qsTr("Edit")
- onClicked: {
- if (row.model.isEditable)
+ ImageButton {
+ id: editButton
+
+ visible: !!row.model && row.model.isEditable
+ buttonTextColor: Nheko.colors.buttonText
+ width: 16
+ hoverEnabled: true
+ image: ":/icons/icons/ui/edit.svg"
+ ToolTip.visible: hovered
+ ToolTip.delay: Nheko.tooltipDelay
+ ToolTip.text: qsTr("Edit")
+ onClicked: {
+ if (row.model.isEditable)
chat.model.editAction(row.model.eventId);
+ }
}
- }
- ImageButton {
- id: reactButton
-
- visible: chat.model ? chat.model.permissions.canSend(MtxEvent.Reaction) : false
- width: 16
- hoverEnabled: true
- image: ":/icons/icons/ui/smile.svg"
- ToolTip.visible: hovered
- ToolTip.delay: Nheko.tooltipDelay
- ToolTip.text: qsTr("React")
- onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(reactButton, function(emoji) {
- var event_id = row.model ? row.model.eventId : "";
- room.input.reaction(event_id, emoji);
- TimelineManager.focusMessageInput();
- })
- }
+ ImageButton {
+ id: reactButton
- ImageButton {
- id: replyButton
-
- visible: chat.model ? chat.model.permissions.canSend(MtxEvent.TextMessage) : false
- width: 16
- hoverEnabled: true
- image: ":/icons/icons/ui/reply.svg"
- ToolTip.visible: hovered
- ToolTip.delay: Nheko.tooltipDelay
- ToolTip.text: qsTr("Reply")
- onClicked: chat.model.replyAction(row.model.eventId)
- }
+ visible: chat.model ? chat.model.permissions.canSend(MtxEvent.Reaction) : false
+ width: 16
+ hoverEnabled: true
+ image: ":/icons/icons/ui/smile.svg"
+ ToolTip.visible: hovered
+ ToolTip.delay: Nheko.tooltipDelay
+ ToolTip.text: qsTr("React")
+ onClicked: emojiPopup.visible ? emojiPopup.close() : emojiPopup.show(reactButton, function(emoji) {
+ var event_id = row.model ? row.model.eventId : "";
+ room.input.reaction(event_id, emoji);
+ TimelineManager.focusMessageInput();
+ })
+ }
- ImageButton {
- id: optionsButton
+ ImageButton {
+ id: replyButton
+
+ visible: chat.model ? chat.model.permissions.canSend(MtxEvent.TextMessage) : false
+ width: 16
+ hoverEnabled: true
+ image: ":/icons/icons/ui/reply.svg"
+ ToolTip.visible: hovered
+ ToolTip.delay: Nheko.tooltipDelay
+ ToolTip.text: qsTr("Reply")
+ onClicked: chat.model.replyAction(row.model.eventId)
+ }
+
+ ImageButton {
+ id: optionsButton
+
+ width: 16
+ hoverEnabled: true
+ image: ":/icons/icons/ui/options.svg"
+ ToolTip.visible: hovered
+ ToolTip.delay: Nheko.tooltipDelay
+ ToolTip.text: qsTr("Options")
+ onClicked: messageContextMenu.show(row.model.eventId, row.model.type, row.model.isSender, row.model.isEncrypted, row.model.isEditable, "", row.model.body, optionsButton)
+ }
- width: 16
- hoverEnabled: true
- image: ":/icons/icons/ui/options.svg"
- ToolTip.visible: hovered
- ToolTip.delay: Nheko.tooltipDelay
- ToolTip.text: qsTr("Options")
- onClicked: messageContextMenu.show(row.model.eventId, row.model.type, row.model.isSender, row.model.isEncrypted, row.model.isEditable, "", row.model.body, optionsButton)
}
}
- }
-
- ScrollHelper {
- flickable: parent
- anchors.fill: parent
- enabled: !Settings.mobileMode
- }
+ ScrollHelper {
+ flickable: parent
+ anchors.fill: parent
+ }
- Shortcut {
- sequence: StandardKey.MoveToPreviousPage
- onActivated: {
- chat.contentY = chat.contentY - chat.height / 2;
- chat.returnToBounds();
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ onActivated: {
+ chat.contentY = chat.contentY - chat.height / 2;
+ chat.returnToBounds();
+ }
}
- }
- Shortcut {
- sequence: StandardKey.MoveToNextPage
- onActivated: {
- chat.contentY = chat.contentY + chat.height / 2;
- chat.returnToBounds();
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ onActivated: {
+ chat.contentY = chat.contentY + chat.height / 2;
+ chat.returnToBounds();
+ }
}
- }
- Shortcut {
- sequence: StandardKey.Cancel
- onActivated: {
- if (chat.model.reply)
+ Shortcut {
+ sequence: StandardKey.Cancel
+ onActivated: {
+ if (chat.model.reply)
chat.model.reply = undefined;
- else
+ else
chat.model.edit = undefined;
+ }
}
- }
-
- Shortcut {
- sequence: "Alt+Up"
- onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0)
- }
- Shortcut {
- sequence: "Alt+Down"
- onActivated: {
- var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1;
- chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : null;
+ Shortcut {
+ sequence: "Alt+Up"
+ onActivated: chat.model.reply = chat.model.indexToId(chat.model.reply ? chat.model.idToIndex(chat.model.reply) + 1 : 0)
}
- }
- Shortcut {
- sequence: "Alt+F"
- onActivated: {
- if (chat.model.reply) {
- var forwardMess = forwardCompleterComponent.createObject(timelineRoot);
- forwardMess.setMessageEventId(chat.model.reply);
- forwardMess.open();
- chat.model.reply = null;
+ Shortcut {
+ sequence: "Alt+Down"
+ onActivated: {
+ var idx = chat.model.reply ? chat.model.idToIndex(chat.model.reply) - 1 : -1;
+ chat.model.reply = idx >= 0 ? chat.model.indexToId(idx) : null;
}
}
- }
- Shortcut {
- sequence: "Ctrl+E"
- onActivated: {
- chat.model.edit = chat.model.reply;
+ Shortcut {
+ sequence: "Alt+F"
+ onActivated: {
+ if (chat.model.reply) {
+ var forwardMess = forwardCompleterComponent.createObject(timelineRoot);
+ forwardMess.setMessageEventId(chat.model.reply);
+ forwardMess.open();
+ chat.model.reply = null;
+ }
+ }
}
- }
- Connections {
- function onFocusChanged() {
- readTimer.running = TimelineManager.isWindowFocused;
+ Shortcut {
+ sequence: "Ctrl+E"
+ onActivated: {
+ chat.model.edit = chat.model.reply;
+ }
}
- target: TimelineManager
- }
+ Connections {
+ function onFocusChanged() {
+ readTimer.running = TimelineManager.isWindowFocused;
+ }
+
+ target: TimelineManager
+ }
- Timer {
- id: readTimer
+ Timer {
+ id: readTimer
- // force current read index to update
- onTriggered: {
- if (chat.model)
+ // force current read index to update
+ onTriggered: {
+ if (chat.model)
chat.model.setCurrentIndex(chat.model.currentIndex);
+ }
+ interval: 1000
}
- interval: 1000
- }
- Component {
- id: sectionHeader
-
- Column {
- topPadding: userName_.visible? 4: 0
- bottomPadding: Settings.bubbles? (isSender? 0 : 2) : 3
- spacing: 8
- visible: (previousMessageUserId !== userId || previousMessageDay !== day || isStateEvent !== previousMessageIsStateEvent)
- width: parentWidth
- height: ((previousMessageDay !== day) ? dateBubble.height : 0) + (isStateEvent? 0 : userName.height +8 )
-
- Label {
- id: dateBubble
-
- anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
- visible: room && previousMessageDay !== day
- text: room ? room.formatDateSeparator(timestamp) : ""
- color: Nheko.colors.text
- height: Math.round(fontMetrics.height * 1.4)
- width: contentWidth * 1.2
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignVCenter
-
- background: Rectangle {
- radius: parent.height / 2
- color: Nheko.colors.window
- }
-
- }
+ Component {
+ id: sectionHeader
- Row {
- height: userName_.height
+ Column {
+ topPadding: userName_.visible? 4: 0
+ bottomPadding: Settings.bubbles? (isSender? 0 : 2) : 3
spacing: 8
- visible: !isStateEvent && (!isSender || !Settings.bubbles)
-
- Avatar {
- id: messageUserAvatar
-
- width: Nheko.avatarSize * (Settings.smallAvatars? 0.5 : 1)
- height: Nheko.avatarSize * (Settings.smallAvatars? 0.5 : 1)
- url: !room ? "" : room.avatarUrl(userId).replace("mxc://", "image://MxcImage/")
- displayName: userName
- userid: userId
- onClicked: room.openUserProfile(userId)
- ToolTip.visible: avatarHover.hovered
- ToolTip.delay: Nheko.tooltipDelay
- ToolTip.text: userid
+ visible: (previousMessageUserId !== userId || previousMessageDay !== day || isStateEvent !== previousMessageIsStateEvent)
+ width: parentWidth
+ height: ((previousMessageDay !== day) ? dateBubble.height : 0) + (isStateEvent? 0 : userName.height +8 )
- HoverHandler {
- id: avatarHover
+ Label {
+ id: dateBubble
+
+ anchors.horizontalCenter: parent ? parent.horizontalCenter : undefined
+ visible: room && previousMessageDay !== day
+ text: room ? room.formatDateSeparator(timestamp) : ""
+ color: Nheko.colors.text
+ height: Math.round(fontMetrics.height * 1.4)
+ width: contentWidth * 1.2
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+
+ background: Rectangle {
+ radius: parent.height / 2
+ color: Nheko.colors.window
}
}
- Connections {
- function onRoomAvatarUrlChanged() {
- messageUserAvatar.url = chat.model.avatarUrl(userId).replace("mxc://", "image://MxcImage/");
- }
+ Row {
+ height: userName_.height
+ spacing: 8
+ visible: !isStateEvent && (!isSender || !Settings.bubbles)
+
+ Avatar {
+ id: messageUserAvatar
+
+ width: Nheko.avatarSize * (Settings.smallAvatars? 0.5 : 1)
+ height: Nheko.avatarSize * (Settings.smallAvatars? 0.5 : 1)
+ url: !room ? "" : room.avatarUrl(userId).replace("mxc://", "image://MxcImage/")
+ displayName: userName
+ userid: userId
+ onClicked: room.openUserProfile(userId)
+ ToolTip.visible: avatarHover.hovered
+ ToolTip.delay: Nheko.tooltipDelay
+ ToolTip.text: userid
+
+ HoverHandler {
+ id: avatarHover
+ }
- function onScrollToIndex(index) {
- chat.positionViewAtIndex(index, ListView.Center);
}
- target: chat.model
- }
-
- Label {
- id: userName_
+ Connections {
+ function onRoomAvatarUrlChanged() {
+ messageUserAvatar.url = chat.model.avatarUrl(userId).replace("mxc://", "image://MxcImage/");
+ }
- text: TimelineManager.escapeEmoji(userName)
- color: TimelineManager.userColor(userId, Nheko.colors.base)
- textFormat: Text.RichText
- ToolTip.visible: displayNameHover.hovered
- ToolTip.delay: Nheko.tooltipDelay
- ToolTip.text: userId
+ function onScrollToIndex(index) {
+ chat.positionViewAtIndex(index, ListView.Center);
+ }
- TapHandler {
- onSingleTapped: chat.model.openUserProfile(userId)
+ target: chat.model
}
- CursorShape {
- anchors.fill: parent
- cursorShape: Qt.PointingHandCursor
- }
+ Label {
+ id: userName_
- HoverHandler {
- id: displayNameHover
- }
+ text: TimelineManager.escapeEmoji(userName)
+ color: TimelineManager.userColor(userId, Nheko.colors.base)
+ textFormat: Text.RichText
+ ToolTip.visible: displayNameHover.hovered
+ ToolTip.delay: Nheko.tooltipDelay
+ ToolTip.text: userId
- }
+ TapHandler {
+ onSingleTapped: chat.model.openUserProfile(userId)
+ dragThreshold: 0
+ }
- Label {
- id: statusMsg
- color: Nheko.colors.buttonText
- text: Presence.userStatus(userId)
- textFormat: Text.PlainText
- elide: Text.ElideRight
- width: chat.delegateMaxWidth - parent.spacing * 2 - userName.implicitWidth - Nheko.avatarSize
- font.italic: true
+ CursorShape {
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ }
- Connections {
- target: Presence
+ HoverHandler {
+ id: displayNameHover
+ }
- function onPresenceChanged(id) {
- if (id == userId) statusMsg.text = Presence.userStatus(userId);
+ }
+
+ Label {
+ id: statusMsg
+ color: Nheko.colors.buttonText
+ text: Presence.userStatus(userId)
+ textFormat: Text.PlainText
+ elide: Text.ElideRight
+ width: chat.delegateMaxWidth - parent.spacing * 2 - userName.implicitWidth - Nheko.avatarSize
+ font.italic: true
+
+ Connections {
+ target: Presence
+
+ function onPresenceChanged(id) {
+ if (id == userId) statusMsg.text = Presence.userStatus(userId);
+ }
}
}
+
}
}
}
- }
+ delegate: ItemDelegate {
+ id: wrapper
+
+ 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 bool isStateEvent
+ required property bool previousMessageIsStateEvent
+ required property string replyTo
+ required property string userId
+ required property string roomTopic
+ required property string roomName
+ required property string callType
+ required property var reactions
+ required property int trustlevel
+ required property int encryptionError
+ required property var timestamp
+ required property int status
+ required property int index
+ required property int relatedEventCacheBuster
+ 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
+ height: section.active ? section.height + timelinerow.height : timelinerow.height
+
+ hoverEnabled: true
+
+ background: Rectangle {
+ id: scrollHighlight
+
+ opacity: 0
+ visible: true
+ z: 1
+ enabled: false
+ color: Nheko.colors.highlight
+
+ states: State {
+ name: "revealed"
+ when: wrapper.scrolledToThis
+ }
- delegate: ItemDelegate {
- id: wrapper
-
- 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 bool isStateEvent
- required property bool previousMessageIsStateEvent
- required property string replyTo
- required property string userId
- required property string roomTopic
- required property string roomName
- required property string callType
- required property var reactions
- required property int trustlevel
- required property int encryptionError
- required property var timestamp
- required property int status
- required property int index
- required property int relatedEventCacheBuster
- 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
- height: section.active ? section.height + timelinerow.height : timelinerow.height
-
- hoverEnabled: true
-
- background: Rectangle {
- id: scrollHighlight
-
- opacity: 0
- visible: true
- z: 1
- enabled: false
- color: Nheko.colors.highlight
-
- states: State {
- name: "revealed"
- when: wrapper.scrolledToThis
- }
+ transitions: Transition {
+ from: ""
+ to: "revealed"
+
+ SequentialAnimation {
+ PropertyAnimation {
+ target: scrollHighlight
+ properties: "opacity"
+ easing.type: Easing.InOutQuad
+ from: 0
+ to: 1
+ duration: 500
+ }
- transitions: Transition {
- from: ""
- to: "revealed"
-
- SequentialAnimation {
- PropertyAnimation {
- target: scrollHighlight
- properties: "opacity"
- easing.type: Easing.InOutQuad
- from: 0
- to: 1
- duration: 500
- }
+ PropertyAnimation {
+ target: scrollHighlight
+ properties: "opacity"
+ easing.type: Easing.InOutQuad
+ from: 1
+ to: 0
+ duration: 500
+ }
- PropertyAnimation {
- target: scrollHighlight
- properties: "opacity"
- easing.type: Easing.InOutQuad
- from: 1
- to: 0
- duration: 500
- }
+ ScriptAction {
+ script: chat.model.eventShown()
+ }
- ScriptAction {
- script: chat.model.eventShown()
}
}
}
- }
-
- Loader {
- id: section
-
- 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 bool previousMessageIsStateEvent: wrapper.previousMessageIsStateEvent
- property bool isStateEvent: wrapper.isStateEvent