Improve timeline UI/UX.

This commit is contained in:
Black Hat
2019-07-12 14:49:34 +08:00
parent 18de53f49a
commit 4c4bf2d195
3 changed files with 155 additions and 28 deletions

View File

@@ -224,6 +224,9 @@ Item {
spacing: 16 spacing: 16
AutoListView { 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.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
@@ -250,27 +253,59 @@ Item {
] ]
onModelReset: { onModelReset: {
movingTimer.stop()
if (currentRoom) { if (currentRoom) {
movingTimer.restart()
var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex()) 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) if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20)
currentRoom.getPreviousContent(50) currentRoom.getPreviousContent(50)
} }
} }
} }
property int largestVisibleIndex: count > 0 ? indexAt(contentX, contentY + height - 1) : -1
onContentYChanged: { onContentYChanged: {
if(currentRoom && contentY - 5000 < originY) if(!noNeedMoreContent && contentY - 5000 < originY)
currentRoom.getPreviousContent(20); 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 { displaced: Transition {
NumberAnimation { NumberAnimation {
property: "y"; duration: 200 property: "y"; duration: 200
easing.type: Easing.OutQuad easing.type: Easing.OutQuad
} }
NumberAnimation {
property: "opacity"; to: 1
}
} }
delegate: DelegateChooser { delegate: DelegateChooser {
@@ -305,6 +340,15 @@ Item {
MessageDelegate { MessageDelegate {
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft 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 { MessageDelegate {
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft 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 { ImageDelegate {
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft 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 { VideoDelegate {
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft 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 { FileDelegate {
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft 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.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter anchors.topMargin: 16
padding: 8
id: goReadMarkerFab
visible: currentRoom && currentRoom.hasUnreadMessages visible: currentRoom && currentRoom.hasUnreadMessages
topPadding: 8 contentItem: MaterialIcon {
bottomPadding: 8 icon: "\ue316"
leftPadding: 24 font.pixelSize: 28
rightPadding: 24 }
Material.foreground: MPalette.foreground background: Rectangle {
Material.background: MPalette.background 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 { Control {
width: 64
height: 64
anchors.right: parent.right anchors.right: parent.right
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
padding: 8
id: goTopFab id: goTopFab
visible: !messageListView.atYEnd visible: !messageListView.atYEnd
contentItem: MaterialIcon { contentItem: MaterialIcon {
anchors.fill: parent
icon: "\ue313" 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 { Control {
anchors.left: parent.left anchors.left: parent.left
anchors.bottom: parent.bottom anchors.bottom: parent.bottom
@@ -488,7 +600,9 @@ Item {
Keys.onUpPressed: scrollBar.decrease() Keys.onUpPressed: scrollBar.decrease()
Keys.onDownPressed: scrollBar.increase() Keys.onDownPressed: scrollBar.increase()
ScrollBar.vertical: ScrollBar { id: scrollBar } ScrollBar.vertical: ScrollBar {
id: scrollBar
}
} }
RoomPanelInput { RoomPanelInput {
@@ -499,17 +613,29 @@ Item {
} }
} }
Timer {
id: movingTimer
interval: 10000
repeat: true
running: false
onTriggered: saveReadMarker()
}
function goToEvent(eventID) { function goToEvent(eventID) {
var index = messageEventModel.eventIDToIndex(eventID) var index = messageEventModel.eventIDToIndex(eventID)
if (index === -1) return if (index === -1) return
// messageListView.currentIndex = sortedMessageEventModel.mapFromSource(index)
messageListView.positionViewAtIndex(sortedMessageEventModel.mapFromSource(index), ListView.Contain) 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 var readMarker = sortedMessageEventModel.get(messageListView.largestVisibleIndex).eventId
if (!readMarker) return if (!readMarker) return
room.readMarkerEventId = readMarker currentRoom.readMarkerEventId = readMarker
currentRoom.saveViewport(sortedMessageEventModel.mapToSource(messageListView.indexAt(messageListView.contentX, messageListView.contentY)), sortedMessageEventModel.mapToSource(messageListView.largestVisibleIndex))
} }
} }

View File

@@ -138,7 +138,7 @@ ApplicationWindow {
connection: spectralController.connection connection: spectralController.connection
onLeaveRoom: roomForm.saveReadMarker(room) onLeaveRoom: roomForm.saveViewport()
} }
} }

View File

@@ -61,6 +61,7 @@ int main(int argc, char* argv[]) {
qRegisterMetaType<MessageEventType>("MessageEventType"); qRegisterMetaType<MessageEventType>("MessageEventType");
qRegisterMetaType<SpectralRoom*>("SpectralRoom*"); qRegisterMetaType<SpectralRoom*>("SpectralRoom*");
qRegisterMetaType<SpectralUser*>("SpectralUser*"); qRegisterMetaType<SpectralUser*>("SpectralUser*");
qRegisterMetaType<GetRoomEventsJob*>("GetRoomEventsJob*");
qRegisterMetaTypeStreamOperators<Emoji>(); qRegisterMetaTypeStreamOperators<Emoji>();