A little bit of lazy loading for the chat view...

This commit is contained in:
Sebastian J. Wolf 2020-08-29 18:04:23 +02:00
parent a527009f86
commit 63833b3c5c
5 changed files with 231 additions and 192 deletions

View file

@ -84,7 +84,6 @@ Page {
} }
function initializePage() { function initializePage() {
chatModel.initialize(chatInformation.id);
var chatType = chatInformation.type['@type']; var chatType = chatInformation.type['@type'];
isPrivateChat = ( chatType === "chatTypePrivate" ); isPrivateChat = ( chatType === "chatTypePrivate" );
isBasicGroup = ( chatType === "chatTypeBasicGroup" ); isBasicGroup = ( chatType === "chatTypeBasicGroup" );
@ -102,8 +101,6 @@ Page {
isChannel = chatGroupInformation.is_channel; isChannel = chatGroupInformation.is_channel;
updateGroupStatusText(); updateGroupStatusText();
} }
tdLibWrapper.getChatHistory(chatInformation.id);
chatPage.loading = false;
} }
Component.onCompleted: { Component.onCompleted: {
@ -114,6 +111,9 @@ Page {
if (status === PageStatus.Activating) { if (status === PageStatus.Activating) {
tdLibWrapper.openChat(chatInformation.id); tdLibWrapper.openChat(chatInformation.id);
} }
if (status === PageStatus.Active) {
chatModel.initialize(chatInformation.id);
}
if (status === PageStatus.Deactivating) { if (status === PageStatus.Deactivating) {
tdLibWrapper.closeChat(chatInformation.id); tdLibWrapper.closeChat(chatInformation.id);
} }
@ -151,6 +151,7 @@ Page {
Connections { Connections {
target: chatModel target: chatModel
onMessagesReceived: { onMessagesReceived: {
chatPage.loading = false;
chatView.positionViewAtEnd(); chatView.positionViewAtEnd();
} }
onNewMessageReceived: { onNewMessageReceived: {
@ -173,7 +174,6 @@ Page {
contentHeight: parent.height contentHeight: parent.height
contentWidth: parent.width contentWidth: parent.width
anchors.fill: parent anchors.fill: parent
visible: !chatPage.loading
Column { Column {
id: chatColumn id: chatColumn
@ -235,222 +235,230 @@ Page {
} }
} }
SilicaListView { Item {
id: chatView id: chatViewItem
width: parent.width width: parent.width
height: parent.height - ( 2 * Theme.paddingMedium ) - headerRow.height - newMessageColumn.height height: parent.height - ( 2 * Theme.paddingMedium ) - headerRow.height - newMessageColumn.height
clip: true SilicaListView {
visible: count > 0 id: chatView
function handleScrollPositionChanged() { anchors.fill: parent
tdLibWrapper.viewMessage(chatInformation.id, chatView.itemAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin )).myMessage.id);
if (chatView.indexAt(chatView.contentX, chatView.contentY) < 10) { opacity: chatPage.loading ? 0 : 1
chatModel.triggerLoadMoreHistory(); Behavior on opacity { NumberAnimation {} }
visible: !chatPage.loading
clip: true
function handleScrollPositionChanged() {
tdLibWrapper.viewMessage(chatInformation.id, chatView.itemAt(chatView.contentX, ( chatView.contentY + chatView.height - Theme.horizontalPageMargin )).myMessage.id);
if (chatView.indexAt(chatView.contentX, chatView.contentY) < 10) {
chatModel.triggerLoadMoreHistory();
}
} }
}
onMovementEnded: { onMovementEnded: {
handleScrollPositionChanged();
}
onQuickScrollAnimatingChanged: {
if (!quickScrollAnimating) {
handleScrollPositionChanged(); handleScrollPositionChanged();
} }
}
onCurrentIndexChanged: { onQuickScrollAnimatingChanged: {
console.log("Current index: " + currentIndex); if (!quickScrollAnimating) {
tdLibWrapper.viewMessage(chatInformation.id, currentItem.myMessage.id); handleScrollPositionChanged();
}
model: chatModel
delegate: ListItem {
id: messageListItem
contentHeight: messageBackground.height + Theme.paddingMedium
contentWidth: parent.width
property variant myMessage: display
property variant userInformation: tdLibWrapper.getUserInformation(display.sender_user_id)
menu: ContextMenu {
MenuItem {
onClicked: {
newMessageInReplyToRow.inReplyToMessage = display;
newMessageTextField.focus = true;
}
text: qsTr("Reply to Message")
} }
} }
Row { onCurrentIndexChanged: {
id: messageTextRow tdLibWrapper.viewMessage(chatInformation.id, currentItem.myMessage.id);
spacing: Theme.paddingSmall }
width: parent.width - ( 2 * Theme.horizontalPageMargin )
anchors.horizontalCenter: parent.horizontalCenter
ProfileThumbnail { model: chatModel
id: messagePictureThumbnail delegate: ListItem {
photoData: (typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ""
replacementStringHint: userText.text id: messageListItem
width: visible ? Theme.itemSizeSmall : 0 contentHeight: messageBackground.height + Theme.paddingMedium
height: visible ? Theme.itemSizeSmall : 0 contentWidth: parent.width
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.paddingSmall property variant myMessage: display
visible: ( chatPage.isBasicGroup || chatPage.isSuperGroup ) && !chatPage.isChannel property variant userInformation: tdLibWrapper.getUserInformation(display.sender_user_id)
menu: ContextMenu {
MenuItem {
onClicked: {
newMessageInReplyToRow.inReplyToMessage = display;
newMessageTextField.focus = true;
}
text: qsTr("Reply to Message")
}
} }
Item { Row {
id: messageTextItem id: messageTextRow
spacing: Theme.paddingSmall
width: parent.width - ( 2 * Theme.horizontalPageMargin )
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - messagePictureThumbnail.width - Theme.paddingSmall ProfileThumbnail {
height: messageBackground.height id: messagePictureThumbnail
photoData: (typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ""
Rectangle { replacementStringHint: userText.text
id: messageBackground width: visible ? Theme.itemSizeSmall : 0
anchors { height: visible ? Theme.itemSizeSmall : 0
left: parent.left anchors.bottom: parent.bottom
leftMargin: (chatPage.myUserId === display.sender_user_id) ? 2 * Theme.horizontalPageMargin : 0 anchors.bottomMargin: Theme.paddingSmall
right: parent.right visible: ( chatPage.isBasicGroup || chatPage.isSuperGroup ) && !chatPage.isChannel
rightMargin: (chatPage.myUserId === display.sender_user_id) ? 0 : 2 * Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
}
height: messageTextColumn.height + ( 2 * Theme.paddingMedium )
color: Theme.secondaryColor
radius: parent.width / 50
opacity: 0.2
} }
Column { Item {
id: messageTextColumn id: messageTextItem
spacing: Theme.paddingSmall width: parent.width - messagePictureThumbnail.width - Theme.paddingSmall
height: messageBackground.height
width: messageBackground.width - Theme.horizontalPageMargin Rectangle {
anchors.centerIn: messageBackground id: messageBackground
anchors {
Component.onCompleted: { left: parent.left
if (display.reply_to_message_id !== 0) { leftMargin: (chatPage.myUserId === display.sender_user_id) ? 2 * Theme.horizontalPageMargin : 0
tdLibWrapper.getMessage(chatInformation.id, display.reply_to_message_id); right: parent.right
rightMargin: (chatPage.myUserId === display.sender_user_id) ? 0 : 2 * Theme.horizontalPageMargin
verticalCenter: parent.verticalCenter
} }
height: messageTextColumn.height + ( 2 * Theme.paddingMedium )
color: Theme.secondaryColor
radius: parent.width / 50
opacity: 0.2
} }
Connections { Column {
target: tdLibWrapper id: messageTextColumn
onReceivedMessage: {
if (messageId === display.reply_to_message_id.toString()) { spacing: Theme.paddingSmall
messageInReplyToRow.inReplyToMessage = message;
messageInReplyToRow.visible = true; width: messageBackground.width - Theme.horizontalPageMargin
anchors.centerIn: messageBackground
Component.onCompleted: {
if (display.reply_to_message_id !== 0) {
tdLibWrapper.getMessage(chatInformation.id, display.reply_to_message_id);
} }
} }
}
Text { Connections {
id: userText target: tdLibWrapper
onReceivedMessage: {
width: parent.width if (messageId === display.reply_to_message_id.toString()) {
text: display.sender_user_id !== chatPage.myUserId ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You") messageInReplyToRow.inReplyToMessage = message;
font.pixelSize: Theme.fontSizeExtraSmall messageInReplyToRow.visible = true;
font.weight: Font.ExtraBold }
color: (chatPage.myUserId === display.sender_user_id) ? Theme.highlightColor : Theme.primaryColor }
maximumLineCount: 1
elide: Text.ElideRight
textFormat: Text.StyledText
horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft
visible: ( chatPage.isBasicGroup || chatPage.isSuperGroup ) && !chatPage.isChannel
}
InReplyToRow {
id: messageInReplyToRow
myUserId: chatPage.myUserId
visible: false
}
Text {
id: messageText
width: parent.width
text: Emoji.emojify(Functions.getMessageText(display, false), font.pixelSize)
font.pixelSize: Theme.fontSizeSmall
color: (chatPage.myUserId === display.sender_user_id) ? Theme.highlightColor : Theme.primaryColor
wrapMode: Text.Wrap
textFormat: Text.StyledText
onLinkActivated: {
Functions.handleLink(link);
} }
horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft
linkColor: Theme.highlightColor
visible: (text !== "")
}
WebPagePreview { Text {
id: webPagePreview id: userText
webPageData: ( typeof display.content.web_page !== "undefined" ) ? display.content.web_page : ""
width: parent.width
visible: typeof display.content.web_page !== "undefined"
}
ImagePreview { width: parent.width
id: messageImagePreview text: display.sender_user_id !== chatPage.myUserId ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")
photoData: ( display.content['@type'] === "messagePhoto" ) ? display.content.photo : "" font.pixelSize: Theme.fontSizeExtraSmall
width: parent.width font.weight: Font.ExtraBold
height: parent.width * 2 / 3 color: (chatPage.myUserId === display.sender_user_id) ? Theme.highlightColor : Theme.primaryColor
visible: display.content['@type'] === "messagePhoto" maximumLineCount: 1
} elide: Text.ElideRight
textFormat: Text.StyledText
StickerPreview { horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft
id: messageStickerPreview visible: ( chatPage.isBasicGroup || chatPage.isSuperGroup ) && !chatPage.isChannel
stickerData: ( display.content['@type'] === "messageSticker" ) ? display.content.sticker : ""
visible: display.content['@type'] === "messageSticker"
anchors.horizontalCenter: parent.horizontalCenter
}
VideoPreview {
id: messageVideoPreview
videoData: ( display.content['@type'] === "messageVideo" ) ? display.content.video : ( ( display.content['@type'] === "messageAnimation" ) ? display.content.animation : "")
width: parent.width
height: ( display.content['@type'] === "messageVideo" ) ? Functions.getVideoHeight(width, display.content.video) : Functions.getVideoHeight(width, display.content.animation)
visible: ( display.content['@type'] === "messageVideo" || display.content['@type'] === "messageAnimation" )
onScreen: chatPage.status === PageStatus.Active
}
AudioPreview {
id: messageAudioPreview
audioData: ( display.content['@type'] === "messageVoiceNote" ) ? display.content.voice_note : ( ( display.content['@type'] === "messageAudio" ) ? display.content.audio : "")
width: parent.width
height: parent.width / 2
visible: ( display.content['@type'] === "messageVoiceNote" || display.content['@type'] === "messageAudio" )
onScreen: chatPage.status === PageStatus.Active
}
DocumentPreview {
id: messageDocumentPreview
documentData: ( display.content['@type'] === "messageDocument" ) ? display.content.document : ""
visible: display.content['@type'] === "messageDocument"
}
Timer {
id: messageDateUpdater
interval: 60000
running: true
repeat: true
onTriggered: {
messageDateText.text = Functions.getDateTimeElapsed(display.date);
} }
}
Text { InReplyToRow {
width: parent.width id: messageInReplyToRow
myUserId: chatPage.myUserId
visible: false
}
Text {
id: messageText
width: parent.width
text: Emoji.emojify(Functions.getMessageText(display, false), font.pixelSize)
font.pixelSize: Theme.fontSizeSmall
color: (chatPage.myUserId === display.sender_user_id) ? Theme.highlightColor : Theme.primaryColor
wrapMode: Text.Wrap
textFormat: Text.StyledText
onLinkActivated: {
Functions.handleLink(link);
}
horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft
linkColor: Theme.highlightColor
visible: (text !== "")
}
WebPagePreview {
id: webPagePreview
webPageData: ( typeof display.content.web_page !== "undefined" ) ? display.content.web_page : ""
width: parent.width
visible: typeof display.content.web_page !== "undefined"
}
ImagePreview {
id: messageImagePreview
photoData: ( display.content['@type'] === "messagePhoto" ) ? display.content.photo : ""
width: parent.width
height: parent.width * 2 / 3
visible: display.content['@type'] === "messagePhoto"
}
StickerPreview {
id: messageStickerPreview
stickerData: ( display.content['@type'] === "messageSticker" ) ? display.content.sticker : ""
visible: display.content['@type'] === "messageSticker"
anchors.horizontalCenter: parent.horizontalCenter
}
VideoPreview {
id: messageVideoPreview
videoData: ( display.content['@type'] === "messageVideo" ) ? display.content.video : ( ( display.content['@type'] === "messageAnimation" ) ? display.content.animation : "")
width: parent.width
height: ( display.content['@type'] === "messageVideo" ) ? Functions.getVideoHeight(width, display.content.video) : Functions.getVideoHeight(width, display.content.animation)
visible: ( display.content['@type'] === "messageVideo" || display.content['@type'] === "messageAnimation" )
onScreen: chatPage.status === PageStatus.Active
}
AudioPreview {
id: messageAudioPreview
audioData: ( display.content['@type'] === "messageVoiceNote" ) ? display.content.voice_note : ( ( display.content['@type'] === "messageAudio" ) ? display.content.audio : "")
width: parent.width
height: parent.width / 2
visible: ( display.content['@type'] === "messageVoiceNote" || display.content['@type'] === "messageAudio" )
onScreen: chatPage.status === PageStatus.Active
}
DocumentPreview {
id: messageDocumentPreview
documentData: ( display.content['@type'] === "messageDocument" ) ? display.content.document : ""
visible: display.content['@type'] === "messageDocument"
}
Timer {
id: messageDateUpdater
interval: 60000
running: true
repeat: true
onTriggered: {
messageDateText.text = Functions.getDateTimeElapsed(display.date);
}
}
Text {
width: parent.width
id: messageDateText
text: Functions.getDateTimeElapsed(display.date)
font.pixelSize: Theme.fontSizeTiny
color: (chatPage.myUserId === display.sender_user_id) ? Theme.secondaryHighlightColor : Theme.secondaryColor
horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft
}
id: messageDateText
text: Functions.getDateTimeElapsed(display.date)
font.pixelSize: Theme.fontSizeTiny
color: (chatPage.myUserId === display.sender_user_id) ? Theme.secondaryHighlightColor : Theme.secondaryColor
horizontalAlignment: (chatPage.myUserId === display.sender_user_id) ? Text.AlignRight : Text.AlignLeft
} }
} }
@ -459,9 +467,32 @@ Page {
} }
VerticalScrollDecorator {}
}
Column {
width: parent.width
height: loadingLabel.height + loadingBusyIndicator.height + Theme.paddingMedium
spacing: Theme.paddingMedium
anchors.verticalCenter: parent.verticalCenter
opacity: chatPage.loading ? 1 : 0
Behavior on opacity { NumberAnimation {} }
visible: chatPage.loading
InfoLabel {
id: loadingLabel
text: qsTr("Loading messages...")
}
BusyIndicator {
id: loadingBusyIndicator
anchors.horizontalCenter: parent.horizontalCenter
running: chatPage.loading
size: BusyIndicatorSize.Large
}
} }
VerticalScrollDecorator {}
} }
Column { Column {

View file

@ -38,7 +38,6 @@ Page {
property bool chatListCreated: false; property bool chatListCreated: false;
onStatusChanged: { onStatusChanged: {
console.log("[OverviewPage] Status changed: " + status + ", initialization completed: " + initializationCompleted);
if (status === PageStatus.Active && initializationCompleted && !chatListCreated) { if (status === PageStatus.Active && initializationCompleted && !chatListCreated) {
updateContent(); updateContent();
} }

View file

@ -52,6 +52,7 @@ void ChatModel::initialize(const QString &chatId)
this->messages.clear(); this->messages.clear();
this->messageIndexMap.clear(); this->messageIndexMap.clear();
this->messagesToBeAdded.clear(); this->messagesToBeAdded.clear();
tdLibWrapper->getChatHistory(chatId);
} }
void ChatModel::triggerLoadMoreHistory() void ChatModel::triggerLoadMoreHistory()

View file

@ -141,12 +141,16 @@
<source>%1 subscribers</source> <source>%1 subscribers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Reply to Message</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>You</source> <source>You</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Reply to Message</source> <source>Loading messages...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>

View file

@ -141,12 +141,16 @@
<source>%1 subscribers</source> <source>%1 subscribers</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message>
<source>Reply to Message</source>
<translation type="unfinished"></translation>
</message>
<message> <message>
<source>You</source> <source>You</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<source>Reply to Message</source> <source>Loading messages...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
</context> </context>