Newer
Older
import im.nheko 1.0
Item {
property var colors: currentActivePalette
property var systemInactive: SystemPalette { colorGroup: SystemPalette.Disabled }
property var inactiveColors: currentInactivePalette ? currentInactivePalette : systemInactive
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
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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
}