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() {
chatModel.initialize(chatInformation.id);
var chatType = chatInformation.type['@type'];
isPrivateChat = ( chatType === "chatTypePrivate" );
isBasicGroup = ( chatType === "chatTypeBasicGroup" );
@ -102,8 +101,6 @@ Page {
isChannel = chatGroupInformation.is_channel;
updateGroupStatusText();
}
tdLibWrapper.getChatHistory(chatInformation.id);
chatPage.loading = false;
}
Component.onCompleted: {
@ -114,6 +111,9 @@ Page {
if (status === PageStatus.Activating) {
tdLibWrapper.openChat(chatInformation.id);
}
if (status === PageStatus.Active) {
chatModel.initialize(chatInformation.id);
}
if (status === PageStatus.Deactivating) {
tdLibWrapper.closeChat(chatInformation.id);
}
@ -151,6 +151,7 @@ Page {
Connections {
target: chatModel
onMessagesReceived: {
chatPage.loading = false;
chatView.positionViewAtEnd();
}
onNewMessageReceived: {
@ -173,7 +174,6 @@ Page {
contentHeight: parent.height
contentWidth: parent.width
anchors.fill: parent
visible: !chatPage.loading
Column {
id: chatColumn
@ -235,222 +235,230 @@ Page {
}
}
SilicaListView {
id: chatView
Item {
id: chatViewItem
width: parent.width
height: parent.height - ( 2 * Theme.paddingMedium ) - headerRow.height - newMessageColumn.height
clip: true
visible: count > 0
SilicaListView {
id: chatView
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();
anchors.fill: parent
opacity: chatPage.loading ? 0 : 1
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: {
handleScrollPositionChanged();
}
onQuickScrollAnimatingChanged: {
if (!quickScrollAnimating) {
onMovementEnded: {
handleScrollPositionChanged();
}
}
onCurrentIndexChanged: {
console.log("Current index: " + currentIndex);
tdLibWrapper.viewMessage(chatInformation.id, currentItem.myMessage.id);
}
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")
onQuickScrollAnimatingChanged: {
if (!quickScrollAnimating) {
handleScrollPositionChanged();
}
}
Row {
id: messageTextRow
spacing: Theme.paddingSmall
width: parent.width - ( 2 * Theme.horizontalPageMargin )
anchors.horizontalCenter: parent.horizontalCenter
onCurrentIndexChanged: {
tdLibWrapper.viewMessage(chatInformation.id, currentItem.myMessage.id);
}
ProfileThumbnail {
id: messagePictureThumbnail
photoData: (typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ""
replacementStringHint: userText.text
width: visible ? Theme.itemSizeSmall : 0
height: visible ? Theme.itemSizeSmall : 0
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.paddingSmall
visible: ( chatPage.isBasicGroup || chatPage.isSuperGroup ) && !chatPage.isChannel
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")
}
}
Item {
id: messageTextItem
Row {
id: messageTextRow
spacing: Theme.paddingSmall
width: parent.width - ( 2 * Theme.horizontalPageMargin )
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width - messagePictureThumbnail.width - Theme.paddingSmall
height: messageBackground.height
Rectangle {
id: messageBackground
anchors {
left: parent.left
leftMargin: (chatPage.myUserId === display.sender_user_id) ? 2 * Theme.horizontalPageMargin : 0
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
ProfileThumbnail {
id: messagePictureThumbnail
photoData: (typeof messageListItem.userInformation.profile_photo !== "undefined") ? messageListItem.userInformation.profile_photo.small : ""
replacementStringHint: userText.text
width: visible ? Theme.itemSizeSmall : 0
height: visible ? Theme.itemSizeSmall : 0
anchors.bottom: parent.bottom
anchors.bottomMargin: Theme.paddingSmall
visible: ( chatPage.isBasicGroup || chatPage.isSuperGroup ) && !chatPage.isChannel
}
Column {
id: messageTextColumn
Item {
id: messageTextItem
spacing: Theme.paddingSmall
width: parent.width - messagePictureThumbnail.width - Theme.paddingSmall
height: messageBackground.height
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);
Rectangle {
id: messageBackground
anchors {
left: parent.left
leftMargin: (chatPage.myUserId === display.sender_user_id) ? 2 * Theme.horizontalPageMargin : 0
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 {
target: tdLibWrapper
onReceivedMessage: {
if (messageId === display.reply_to_message_id.toString()) {
messageInReplyToRow.inReplyToMessage = message;
messageInReplyToRow.visible = true;
Column {
id: messageTextColumn
spacing: Theme.paddingSmall
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 {
id: userText
width: parent.width
text: display.sender_user_id !== chatPage.myUserId ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")
font.pixelSize: Theme.fontSizeExtraSmall
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);
Connections {
target: tdLibWrapper
onReceivedMessage: {
if (messageId === display.reply_to_message_id.toString()) {
messageInReplyToRow.inReplyToMessage = message;
messageInReplyToRow.visible = true;
}
}
}
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"
}
Text {
id: userText
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);
width: parent.width
text: display.sender_user_id !== chatPage.myUserId ? Emoji.emojify(Functions.getUserName(messageListItem.userInformation), font.pixelSize) : qsTr("You")
font.pixelSize: Theme.fontSizeExtraSmall
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
}
}
Text {
width: parent.width
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 {
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 {

View file

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

View file

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

View file

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

View file

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