Init infinite scroll.

It constanatly crashes, TBD.
This commit is contained in:
Black Hat 2018-09-28 19:47:17 +08:00
parent 6b10c2ef2d
commit 01196e8b50
3 changed files with 215 additions and 171 deletions

View File

@ -19,6 +19,23 @@ Item {
MessageEventModel { MessageEventModel {
id: messageEventModel id: messageEventModel
room: currentRoom room: currentRoom
onModelReset: {
if (currentRoom)
{
var lastScrollPosition = currentRoom.savedTopVisibleIndex()
if (lastScrollPosition === 0)
messageListView.positionViewAtBeginning()
else
{
console.log("Scrolling to position", lastScrollPosition)
messageListView.positionViewAtIndex(lastScrollPosition, ListView.Contain)
}
if (messageListView.contentY < messageListView.originY + 10)
currentRoom.getPreviousContent(100)
}
console.log("Model timeline reset")
}
} }
RoomDrawer { RoomDrawer {
@ -46,6 +63,8 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 64 Layout.preferredHeight: 64
z: 10
color: Material.accent color: Material.accent
ItemDelegate { ItemDelegate {
@ -98,221 +117,215 @@ Item {
} }
} }
RowLayout { ListView {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: 16 Layout.margins: 16
z: -10 id: messageListView
spacing: 0 displayMarginBeginning: 40
displayMarginEnd: 40
verticalLayoutDirection: ListView.BottomToTop
spacing: 8
ListView { flickDeceleration: 4096
Layout.fillWidth: true
Layout.fillHeight: true
id: messageListView boundsBehavior: Flickable.DragOverBounds
property int largestVisibleIndex: count > 0 ? indexAt(contentX, contentY + height - 1) : -1
onContentYChanged: {
// Check whether we're about to bump into the ceiling in 2 seconds
var curVelocity = verticalVelocity // Snapshot the current speed
if( curVelocity < 0 && contentY + curVelocity*2 < originY)
{
// Request the amount of messages enough to scroll at this
// rate for 3 more seconds
var avgHeight = contentHeight / count
currentRoom.getPreviousContent(-curVelocity*3 / avgHeight);
}
}
onMovementEnded: currentRoom.saveViewport(indexAt(contentX, contentY), largestVisibleIndex)
model: SortFilterProxyModel {
id: sortedRoomListModel
sourceModel: messageEventModel
filters: ExpressionFilter {
expression: marks !== 0x08 && marks !== 0x10
}
}
delegate: ColumnLayout {
width: parent.width
id: delegateColumn
displayMarginBeginning: 40
displayMarginEnd: 40
verticalLayoutDirection: ListView.BottomToTop
spacing: 8 spacing: 8
boundsBehavior: Flickable.DragOverBounds Label {
// flickDeceleration: 4096 Layout.alignment: Qt.AlignHCenter
// cacheBuffer: 200 visible: section !== aboveSection
model: SortFilterProxyModel { text: section
id: sortedRoomListModel color: "white"
verticalAlignment: Text.AlignVCenter
leftPadding: 8
rightPadding: 8
topPadding: 4
bottomPadding: 4
sourceModel: messageEventModel background: Rectangle {
color: MSettings.darkTheme ? "#484848" : "grey"
filters: ExpressionFilter {
expression: marks !== 0x08 && marks !== 0x10
} }
} }
delegate: ColumnLayout { MessageDelegate {
width: parent.width visible: eventType === "notice" || eventType === "message" || eventType === "image" || eventType === "video" || eventType === "audio" || eventType === "file"
id: delegateColumn
spacing: 8
Label {
Layout.alignment: Qt.AlignHCenter
visible: section !== aboveSection
text: section
color: "white"
verticalAlignment: Text.AlignVCenter
leftPadding: 8
rightPadding: 8
topPadding: 4
bottomPadding: 4
background: Rectangle {
color: MSettings.darkTheme ? "#484848" : "grey"
}
}
MessageDelegate {
visible: eventType === "notice" || eventType === "message" || eventType === "image" || eventType === "video" || eventType === "audio" || eventType === "file"
}
StateDelegate {
Layout.maximumWidth: messageListView.width * 0.8
visible: eventType === "emote" || eventType === "state"
}
Label {
Layout.alignment: Qt.AlignHCenter
visible: eventType === "other"
text: display
color: "grey"
font.italic: true
}
Label {
Layout.alignment: Qt.AlignHCenter
visible: readMarker === true && index !== 0
text: "And Now"
color: "white"
verticalAlignment: Text.AlignVCenter
leftPadding: 8
rightPadding: 8
topPadding: 4
bottomPadding: 4
background: Rectangle { color: MSettings.darkTheme ? "#484848" : "grey" }
}
} }
ScrollBar.vertical: messageListViewScrollBar StateDelegate {
Layout.maximumWidth: messageListView.width * 0.8
onAtYBeginningChanged: atYBeginning && currentRoom ? currentRoom.getPreviousContent(20) : {} visible: eventType === "emote" || eventType === "state"
onAtYEndChanged: atYEnd && currentRoom ? currentRoom.markAllMessagesAsRead() : {}
RoundButton {
width: 64
height: 64
id: goTopFab
visible: !(parent.atYEnd || messageListView.moving)
anchors.right: parent.right
anchors.bottom: parent.bottom
contentItem: MaterialIcon {
anchors.fill: parent
icon: "\ue313"
color: "white"
}
Material.background: Material.accent
onClicked: parent.positionViewAtBeginning()
Behavior on opacity { NumberAnimation { duration: 200 } }
} }
MessageContextMenu { id: messageContextMenu } Label {
Layout.alignment: Qt.AlignHCenter
Popup { visible: eventType === "other"
property string sourceText
x: (window.width - width) / 2 text: display
y: (window.height - height) / 2 color: "grey"
width: 480 font.italic: true
id: sourceDialog
parent: ApplicationWindow.overlay
modal: true
padding: 16
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
contentItem: ScrollView {
TextArea {
readOnly: true
selectByMouse: true
text: sourceDialog.sourceText
}
}
} }
Popup { Label {
property alias listModel: readMarkerListView.model Layout.alignment: Qt.AlignHCenter
x: (window.width - width) / 2 visible: readMarker === true && index !== 0
y: (window.height - height) / 2
width: 320
id: readMarkerDialog text: "And Now"
color: "white"
verticalAlignment: Text.AlignVCenter
leftPadding: 8
rightPadding: 8
topPadding: 4
bottomPadding: 4
parent: ApplicationWindow.overlay background: Rectangle { color: MSettings.darkTheme ? "#484848" : "grey" }
}
}
modal: true RoundButton {
padding: 16 width: 64
height: 64
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside id: goTopFab
contentItem: ListView { visible: !(parent.atYEnd || messageListView.moving)
implicitHeight: Math.min(window.height - 64, readMarkerListView.contentHeight)
id: readMarkerListView anchors.right: parent.right
anchors.bottom: parent.bottom
clip: true contentItem: MaterialIcon {
boundsBehavior: Flickable.DragOverBounds anchors.fill: parent
delegate: ItemDelegate { icon: "\ue313"
width: parent.width color: "white"
height: 48 }
RowLayout { Material.background: Material.accent
anchors.fill: parent
anchors.margins: 8
spacing: 12
ImageItem { onClicked: parent.positionViewAtBeginning()
Layout.preferredWidth: height
Layout.fillHeight: true
image: modelData.avatar Behavior on opacity { NumberAnimation { duration: 200 } }
hint: modelData.displayName }
}
Label { MessageContextMenu { id: messageContextMenu }
Layout.fillWidth: true
text: modelData.displayName Popup {
} property string sourceText
}
}
ScrollBar.vertical: ScrollBar {} x: (window.width - width) / 2
y: (window.height - height) / 2
width: 480
id: sourceDialog
parent: ApplicationWindow.overlay
modal: true
padding: 16
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
contentItem: ScrollView {
TextArea {
readOnly: true
selectByMouse: true
text: sourceDialog.sourceText
} }
} }
} }
ScrollBar { Popup {
Layout.preferredWidth: 16 property alias listModel: readMarkerListView.model
Layout.fillHeight: true
id: messageListViewScrollBar x: (window.width - width) / 2
y: (window.height - height) / 2
width: 320
id: readMarkerDialog
parent: ApplicationWindow.overlay
modal: true
padding: 16
closePolicy: Dialog.CloseOnEscape | Dialog.CloseOnPressOutside
contentItem: ListView {
implicitHeight: Math.min(window.height - 64, readMarkerListView.contentHeight)
id: readMarkerListView
clip: true
boundsBehavior: Flickable.DragOverBounds
delegate: ItemDelegate {
width: parent.width
height: 48
RowLayout {
anchors.fill: parent
anchors.margins: 8
spacing: 12
ImageItem {
Layout.preferredWidth: height
Layout.fillHeight: true
image: modelData.avatar
hint: modelData.displayName
}
Label {
Layout.fillWidth: true
text: modelData.displayName
}
}
}
ScrollBar.vertical: ScrollBar {}
}
} }
} }

View File

@ -147,3 +147,31 @@ QDateTime SpectralRoom::lastActiveTime() {
} }
float SpectralRoom::orderForTag(QString name) { return tag(name).order; } float SpectralRoom::orderForTag(QString name) { return tag(name).order; }
int SpectralRoom::savedTopVisibleIndex() const {
return firstDisplayedMarker() == timelineEdge()
? 0
: firstDisplayedMarker() - messageEvents().rbegin();
}
int SpectralRoom::savedBottomVisibleIndex() const {
return lastDisplayedMarker() == timelineEdge()
? 0
: lastDisplayedMarker() - messageEvents().rbegin();
}
void SpectralRoom::saveViewport(int topIndex, int bottomIndex) {
if (topIndex == -1 || bottomIndex == -1 ||
(bottomIndex == savedBottomVisibleIndex() &&
(bottomIndex == 0 || topIndex == savedTopVisibleIndex())))
return;
if (bottomIndex == 0) {
qDebug() << "Saving viewport as the latest available";
setFirstDisplayedEventId({});
setLastDisplayedEventId({});
return;
}
qDebug() << "Saving viewport:" << topIndex << "thru" << bottomIndex;
setFirstDisplayedEvent(maxTimelineIndex() - topIndex);
setLastDisplayedEvent(maxTimelineIndex() - bottomIndex);
}

View File

@ -38,6 +38,9 @@ class SpectralRoom : public Room {
QDateTime lastActiveTime(); QDateTime lastActiveTime();
Q_INVOKABLE float orderForTag(QString name); Q_INVOKABLE float orderForTag(QString name);
Q_INVOKABLE int savedTopVisibleIndex() const;
Q_INVOKABLE int savedBottomVisibleIndex() const;
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
private: private:
QString m_cachedInput; QString m_cachedInput;