Improve timeline UI/UX.
This commit is contained in:
@@ -224,6 +224,9 @@ Item {
|
||||
spacing: 16
|
||||
|
||||
AutoListView {
|
||||
readonly property int largestVisibleIndex: count > 0 ? indexAt(contentX + (width / 2), contentY + height - 1) : -1
|
||||
readonly property bool noNeedMoreContent: !currentRoom || currentRoom.eventsHistoryJob || currentRoom.allHistoryLoaded
|
||||
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
@@ -250,27 +253,59 @@ Item {
|
||||
]
|
||||
|
||||
onModelReset: {
|
||||
movingTimer.stop()
|
||||
if (currentRoom) {
|
||||
movingTimer.restart()
|
||||
|
||||
var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex())
|
||||
messageListView.currentIndex = lastScrollPosition
|
||||
if (lastScrollPosition === 0) {
|
||||
messageListView.positionViewAtBeginning()
|
||||
} else {
|
||||
messageListView.currentIndex = lastScrollPosition
|
||||
}
|
||||
|
||||
if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20)
|
||||
currentRoom.getPreviousContent(50)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property int largestVisibleIndex: count > 0 ? indexAt(contentX, contentY + height - 1) : -1
|
||||
|
||||
onContentYChanged: {
|
||||
if(currentRoom && contentY - 5000 < originY)
|
||||
if(!noNeedMoreContent && contentY - 5000 < originY)
|
||||
currentRoom.getPreviousContent(20);
|
||||
}
|
||||
|
||||
populate: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"; from: 0; to: 1
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
|
||||
add: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"; from: 0; to: 1
|
||||
duration: 200
|
||||
}
|
||||
}
|
||||
|
||||
move: Transition {
|
||||
NumberAnimation {
|
||||
property: "y"; duration: 200
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"; to: 1
|
||||
}
|
||||
}
|
||||
|
||||
displaced: Transition {
|
||||
NumberAnimation {
|
||||
property: "y"; duration: 200
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
NumberAnimation {
|
||||
property: "opacity"; to: 1
|
||||
}
|
||||
}
|
||||
|
||||
delegate: DelegateChooser {
|
||||
@@ -305,6 +340,15 @@ Item {
|
||||
MessageDelegate {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2
|
||||
|
||||
visible: readMarker
|
||||
|
||||
color: MPalette.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -323,6 +367,15 @@ Item {
|
||||
MessageDelegate {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2
|
||||
|
||||
visible: readMarker
|
||||
|
||||
color: MPalette.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -341,6 +394,15 @@ Item {
|
||||
ImageDelegate {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2
|
||||
|
||||
visible: readMarker
|
||||
|
||||
color: MPalette.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,6 +421,15 @@ Item {
|
||||
VideoDelegate {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2
|
||||
|
||||
visible: readMarker
|
||||
|
||||
color: MPalette.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,6 +448,15 @@ Item {
|
||||
FileDelegate {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 2
|
||||
|
||||
visible: readMarker
|
||||
|
||||
color: MPalette.primary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -386,47 +466,79 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Control {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 16
|
||||
|
||||
padding: 8
|
||||
|
||||
id: goReadMarkerFab
|
||||
|
||||
visible: currentRoom && currentRoom.hasUnreadMessages
|
||||
|
||||
topPadding: 8
|
||||
bottomPadding: 8
|
||||
leftPadding: 24
|
||||
rightPadding: 24
|
||||
contentItem: MaterialIcon {
|
||||
icon: "\ue316"
|
||||
font.pixelSize: 28
|
||||
}
|
||||
|
||||
Material.foreground: MPalette.foreground
|
||||
Material.background: MPalette.background
|
||||
background: Rectangle {
|
||||
color: MPalette.background
|
||||
radius: height / 2
|
||||
|
||||
text: "Go to read marker"
|
||||
layer.enabled: true
|
||||
layer.effect: ElevationEffect {
|
||||
elevation: 2
|
||||
}
|
||||
|
||||
onClicked: goToEvent(currentRoom.readMarkerEventId)
|
||||
RippleEffect {
|
||||
anchors.fill: parent
|
||||
|
||||
circular: true
|
||||
|
||||
onClicked: goToEvent(currentRoom.readMarkerEventId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RoundButton {
|
||||
width: 64
|
||||
height: 64
|
||||
Control {
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
padding: 8
|
||||
|
||||
id: goTopFab
|
||||
|
||||
visible: !messageListView.atYEnd
|
||||
|
||||
contentItem: MaterialIcon {
|
||||
anchors.fill: parent
|
||||
|
||||
icon: "\ue313"
|
||||
color: "white"
|
||||
font.pixelSize: 28
|
||||
}
|
||||
|
||||
Material.background: Material.accent
|
||||
background: Rectangle {
|
||||
color: MPalette.background
|
||||
radius: height / 2
|
||||
|
||||
onClicked: messageListView.positionViewAtBeginning()
|
||||
layer.enabled: true
|
||||
layer.effect: ElevationEffect {
|
||||
elevation: 2
|
||||
}
|
||||
|
||||
RippleEffect {
|
||||
anchors.fill: parent
|
||||
|
||||
circular: true
|
||||
|
||||
onClicked: {
|
||||
currentRoom.markAllMessagesAsRead()
|
||||
messageListView.positionViewAtBeginning()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Control {
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
@@ -488,7 +600,9 @@ Item {
|
||||
Keys.onUpPressed: scrollBar.decrease()
|
||||
Keys.onDownPressed: scrollBar.increase()
|
||||
|
||||
ScrollBar.vertical: ScrollBar { id: scrollBar }
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollBar
|
||||
}
|
||||
}
|
||||
|
||||
RoomPanelInput {
|
||||
@@ -499,17 +613,29 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: movingTimer
|
||||
|
||||
interval: 10000
|
||||
repeat: true
|
||||
running: false
|
||||
|
||||
onTriggered: saveReadMarker()
|
||||
}
|
||||
|
||||
function goToEvent(eventID) {
|
||||
var index = messageEventModel.eventIDToIndex(eventID)
|
||||
if (index === -1) return
|
||||
// messageListView.currentIndex = sortedMessageEventModel.mapFromSource(index)
|
||||
messageListView.positionViewAtIndex(sortedMessageEventModel.mapFromSource(index), ListView.Contain)
|
||||
}
|
||||
|
||||
function saveReadMarker(room) {
|
||||
function saveViewport() {
|
||||
currentRoom.saveViewport(sortedMessageEventModel.mapToSource(messageListView.indexAt(messageListView.contentX + (messageListView.width / 2), messageListView.contentY)), sortedMessageEventModel.mapToSource(messageListView.largestVisibleIndex))
|
||||
}
|
||||
|
||||
function saveReadMarker() {
|
||||
var readMarker = sortedMessageEventModel.get(messageListView.largestVisibleIndex).eventId
|
||||
if (!readMarker) return
|
||||
room.readMarkerEventId = readMarker
|
||||
currentRoom.saveViewport(sortedMessageEventModel.mapToSource(messageListView.indexAt(messageListView.contentX, messageListView.contentY)), sortedMessageEventModel.mapToSource(messageListView.largestVisibleIndex))
|
||||
currentRoom.readMarkerEventId = readMarker
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ ApplicationWindow {
|
||||
|
||||
connection: spectralController.connection
|
||||
|
||||
onLeaveRoom: roomForm.saveReadMarker(room)
|
||||
onLeaveRoom: roomForm.saveViewport()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,7 @@ int main(int argc, char* argv[]) {
|
||||
qRegisterMetaType<MessageEventType>("MessageEventType");
|
||||
qRegisterMetaType<SpectralRoom*>("SpectralRoom*");
|
||||
qRegisterMetaType<SpectralUser*>("SpectralUser*");
|
||||
qRegisterMetaType<GetRoomEventsJob*>("GetRoomEventsJob*");
|
||||
|
||||
qRegisterMetaTypeStreamOperators<Emoji>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user