nheko/resources/qml/TimelineView.qml
Nicolas Werner 8c44c5e2d0 Change scroll behaviour of timeline
This requires Qt 5.9 (to calculate overshoot).
The default scroll behaviour of list views has far too much inertia.
This should make scrolling feel more like scrolling the other scroll
areas of nheko.
2019-12-08 00:54:28 +01:00

190 lines
4.7 KiB
QML

import QtQuick 2.9
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
import QtGraphicalEffects 1.0
import QtQuick.Window 2.2
import im.nheko 1.0
import "./delegates"
Item {
property var colors: currentActivePalette
property var systemInactive: SystemPalette { colorGroup: SystemPalette.Disabled }
property var inactiveColors: currentInactivePalette ? currentInactivePalette : systemInactive
property int avatarSize: 40
Rectangle {
anchors.fill: parent
color: colors.window
Text {
visible: !timelineManager.timeline && !timelineManager.isInitialSync
anchors.centerIn: parent
text: qsTr("No room open")
font.pointSize: 24
color: colors.windowText
}
BusyIndicator {
anchors.centerIn: parent
running: timelineManager.isInitialSync
height: 200
width: 200
}
ListView {
id: chat
cacheBuffer: 2000
visible: timelineManager.timeline != null
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: scrollbar.width
model: timelineManager.timeline
boundsBehavior: Flickable.StopAtBounds
onVerticalOvershootChanged: contentY = contentY - verticalOvershoot
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.NoButton
propagateComposedEvents: true
z: -1
onWheel: {
if (wheel.angleDelta != 0) {
chat.contentY = chat.contentY - wheel.angleDelta.y
if (wheel.angleDelta.y > 0 && chat.contentY > chat.contentHeight - chat.height)
chat.contentY = chat.contentHeight - chat.height
else if (wheel.angleDelta < 0 && chat.contentY < 0)
chat.contentY = 0
wheel.accepted = true
chat.forceLayout()
chat.updatePosition()
}
}
}
onModelChanged: {
if (model) {
currentIndex = model.currentIndex
if (model.currentIndex == count - 1) {
positionViewAtEnd()
} else {
positionViewAtIndex(model.currentIndex, ListView.End)
}
}
}
ScrollBar.vertical: ScrollBar {
id: scrollbar
parent: chat.parent
anchors.top: chat.top
anchors.left: chat.right
anchors.bottom: chat.bottom
onPressedChanged: if (!pressed) chat.updatePosition()
}
property bool atBottom: false
onCountChanged: {
if (atBottom) {
var newIndex = count - 1 // last index
positionViewAtEnd()
currentIndex = newIndex
model.currentIndex = newIndex
}
if (contentHeight < height && model) {
model.fetchHistory();
}
}
onAtYBeginningChanged: if (atYBeginning) { chat.model.currentIndex = 0; chat.currentIndex = 0; model.fetchHistory(); }
function updatePosition() {
for (var y = chat.contentY + chat.height; y > chat.height; y -= 9) {
var i = chat.itemAt(100, y);
if (!i) continue;
if (!i.isFullyVisible()) continue;
chat.model.currentIndex = i.getIndex();
chat.currentIndex = i.getIndex()
atBottom = i.getIndex() == count - 1;
break;
}
}
onMovementEnded: updatePosition()
spacing: 4
delegate: TimelineRow {
function isFullyVisible() {
return height > 1 && (y - chat.contentY - 1) + height < chat.height
}
function getIndex() {
return index;
}
}
section {
property: "section"
delegate: Column {
topPadding: 4
bottomPadding: 4
spacing: 8
width: parent.width
height: (section.includes(" ") ? dateBubble.height + 8 + userName.height : userName.height) + 8
Label {
id: dateBubble
anchors.horizontalCenter: parent.horizontalCenter
visible: section.includes(" ")
text: chat.model.formatDateSeparator(new Date(Number(section.split(" ")[1])))
color: colors.windowText
height: contentHeight * 1.2
width: contentWidth * 1.2
horizontalAlignment: Text.AlignHCenter
background: Rectangle {
radius: parent.height / 2
color: colors.dark
}
}
Row {
height: userName.height
spacing: 4
Avatar {
width: avatarSize
height: avatarSize
url: chat.model.avatarUrl(section.split(" ")[0]).replace("mxc://", "image://MxcImage/")
displayName: chat.model.displayName(section.split(" ")[0])
MouseArea {
anchors.fill: parent
onClicked: chat.model.openUserProfile(section.split(" ")[0])
cursorShape: Qt.PointingHandCursor
}
}
Text {
id: userName
text: chat.model.escapeEmoji(chat.model.displayName(section.split(" ")[0]))
color: chat.model.userColor(section.split(" ")[0], colors.window)
textFormat: Text.RichText
MouseArea {
anchors.fill: parent
onClicked: chat.model.openUserProfile(section.split(" ")[0])
cursorShape: Qt.PointingHandCursor
}
}
}
}
}
}
}
}