2020-08-21 15:26:56 +03:00
/ *
2020-10-19 20:34:47 +03:00
Copyright ( C ) 2020 Sebastian J . Wolf and other contributors
2020-08-21 15:26:56 +03:00
This file is part of Fernschreiber .
Fernschreiber is free software: you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
Fernschreiber is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with Fernschreiber . If not , see < http: //www.gnu.org/licenses/>.
* /
import QtQuick 2.5
import QtGraphicalEffects 1.0
import QtMultimedia 5.0
import Sailfish . Silica 1.0
2020-09-27 14:49:06 +03:00
import Sailfish . Pickers 1.0
2020-09-28 00:24:22 +03:00
import Nemo . Thumbnailer 1.0
2020-08-21 15:26:56 +03:00
import WerkWolf . Fernschreiber 1.0
import "../components"
import "../js/twemoji.js" as Emoji
import "../js/functions.js" as Functions
Page {
id: chatPage
allowedOrientations: Orientation . All
2020-10-16 00:43:55 +03:00
backNavigation: ! stickerPickerLoader . active
2020-08-21 15:26:56 +03:00
property bool loading: true ;
2020-08-30 00:59:29 +03:00
property bool isInitialized: false ;
2020-08-22 22:43:20 +03:00
property int myUserId: tdLibWrapper . getUserInformation ( ) . id ;
2020-08-21 15:26:56 +03:00
property variant chatInformation ;
2020-08-21 19:03:51 +03:00
property bool isPrivateChat: false ;
property bool isBasicGroup: false ;
property bool isSuperGroup: false ;
property bool isChannel: false ;
property variant chatPartnerInformation ;
property variant chatGroupInformation ;
property int chatOnlineMemberCount: 0 ;
2020-10-18 19:57:01 +03:00
property variant emojiProposals ;
2020-08-21 19:03:51 +03:00
function updateChatPartnerStatusText ( ) {
2020-10-19 13:20:02 +03:00
var statusText = Functions . getChatPartnerStatusText ( chatPartnerInformation . status [ '@type' ] , chatPartnerInformation . status . was_online ) ;
if ( statusText ) {
chatStatusText . text = statusText ;
2020-08-21 19:03:51 +03:00
}
}
function updateGroupStatusText ( ) {
if ( chatOnlineMemberCount > 0 ) {
2020-09-24 10:55:05 +03:00
chatStatusText . text = qsTr ( "%1 members, %2 online" ) . arg ( Functions . getShortenedCount ( chatGroupInformation . member_count ) ) . arg ( Functions . getShortenedCount ( chatOnlineMemberCount ) ) ;
2020-08-21 19:03:51 +03:00
} else {
if ( isChannel ) {
2020-09-24 10:55:05 +03:00
chatStatusText . text = qsTr ( "%1 subscribers" ) . arg ( Functions . getShortenedCount ( chatGroupInformation . member_count ) ) ;
2020-08-21 19:03:51 +03:00
} else {
2020-09-24 10:55:05 +03:00
chatStatusText . text = qsTr ( "%1 members" ) . arg ( Functions . getShortenedCount ( chatGroupInformation . member_count ) ) ;
2020-08-21 19:03:51 +03:00
}
}
}
2020-08-21 15:26:56 +03:00
function initializePage ( ) {
2020-08-30 00:59:29 +03:00
console . log ( "[ChatPage] Initializing chat page..." ) ;
2020-08-29 22:39:57 +03:00
chatView . currentIndex = - 1 ;
2020-08-30 20:04:16 +03:00
chatView . lastReadSentIndex = 0 ;
2020-08-21 19:03:51 +03:00
var chatType = chatInformation . type [ '@type' ] ;
isPrivateChat = ( chatType === "chatTypePrivate" ) ;
isBasicGroup = ( chatType === "chatTypeBasicGroup" ) ;
isSuperGroup = ( chatType === "chatTypeSupergroup" ) ;
if ( isPrivateChat ) {
chatPartnerInformation = tdLibWrapper . getUserInformation ( chatInformation . type . user_id ) ;
updateChatPartnerStatusText ( ) ;
}
if ( isBasicGroup ) {
chatGroupInformation = tdLibWrapper . getBasicGroup ( chatInformation . type . basic_group_id ) ;
updateGroupStatusText ( ) ;
}
if ( isSuperGroup ) {
chatGroupInformation = tdLibWrapper . getSuperGroup ( chatInformation . type . supergroup_id ) ;
isChannel = chatGroupInformation . is_channel ;
updateGroupStatusText ( ) ;
}
2020-10-17 00:00:08 +03:00
if ( stickerManager . needsReload ( ) ) {
console . log ( "Stickers will be reloaded!" ) ;
tdLibWrapper . getRecentStickers ( ) ;
tdLibWrapper . getInstalledStickerSets ( ) ;
stickerManager . setNeedsReload ( false ) ;
}
2020-08-21 15:26:56 +03:00
}
2020-08-31 22:51:52 +03:00
function getMessageStatusText ( message , listItemIndex , lastReadSentIndex ) {
var messageStatusSuffix = "" ;
2020-10-19 13:20:02 +03:00
if ( ! message ) {
return "" ;
}
2020-09-19 21:33:51 +03:00
if ( message . edit_date > 0 ) {
2020-09-20 01:13:42 +03:00
messageStatusSuffix += " - " + qsTr ( "edited" ) ;
2020-09-19 21:33:51 +03:00
}
2020-08-31 22:51:52 +03:00
if ( chatPage . myUserId === message . sender_user_id ) {
messageStatusSuffix += " "
if ( listItemIndex <= lastReadSentIndex ) {
// Read by other party
messageStatusSuffix += Emoji . emojify ( "✅" , Theme . fontSizeTiny ) ;
} else {
// Not yet read by other party
if ( message . sending_state ) {
if ( message . sending_state [ '@type' ] === "messageSendingStatePending" ) {
messageStatusSuffix += Emoji . emojify ( "🕙" , Theme . fontSizeTiny ) ;
} else {
// Sending failed...
messageStatusSuffix += Emoji . emojify ( "❌" , Theme . fontSizeTiny ) ;
}
} else {
messageStatusSuffix += Emoji . emojify ( "☑️" , Theme . fontSizeTiny ) ;
}
}
}
return Functions . getDateTimeElapsed ( message . date ) + messageStatusSuffix ;
}
2020-09-27 14:49:06 +03:00
function clearAttachmentPreviewRow ( ) {
attachmentPreviewRow . visible = false ;
attachmentPreviewRow . isPicture = false ;
2020-09-28 00:24:22 +03:00
attachmentPreviewRow . isVideo = false ;
attachmentPreviewRow . isDocument = false ;
2020-09-29 00:08:22 +03:00
attachmentPreviewRow . fileProperties = { } ;
}
2020-09-29 22:00:23 +03:00
function controlSendButton ( ) {
2020-09-29 00:08:22 +03:00
if ( newMessageTextField . text . length !== 0
|| attachmentPreviewRow . isPicture
|| attachmentPreviewRow . isDocument
|| attachmentPreviewRow . isVideo ) {
newMessageSendButton . enabled = true ;
} else {
newMessageSendButton . enabled = false ;
}
2020-09-27 14:49:06 +03:00
}
function sendMessage ( ) {
if ( newMessageColumn . editMessageId !== "0" ) {
tdLibWrapper . editMessageText ( chatInformation . id , newMessageColumn . editMessageId , newMessageTextField . text ) ;
} else {
if ( attachmentPreviewRow . visible ) {
if ( attachmentPreviewRow . isPicture ) {
2020-09-29 00:08:22 +03:00
tdLibWrapper . sendPhotoMessage ( chatInformation . id , attachmentPreviewRow . fileProperties . filePath , newMessageTextField . text , newMessageColumn . replyToMessageId ) ;
2020-09-27 14:49:06 +03:00
}
2020-09-28 00:24:22 +03:00
if ( attachmentPreviewRow . isVideo ) {
2020-09-29 00:08:22 +03:00
tdLibWrapper . sendVideoMessage ( chatInformation . id , attachmentPreviewRow . fileProperties . filePath , newMessageTextField . text , newMessageColumn . replyToMessageId ) ;
2020-09-28 00:24:22 +03:00
}
if ( attachmentPreviewRow . isDocument ) {
2020-09-29 00:08:22 +03:00
tdLibWrapper . sendDocumentMessage ( chatInformation . id , attachmentPreviewRow . fileProperties . filePath , newMessageTextField . text , newMessageColumn . replyToMessageId ) ;
2020-09-28 00:24:22 +03:00
}
2020-09-27 14:49:06 +03:00
clearAttachmentPreviewRow ( ) ;
} else {
tdLibWrapper . sendTextMessage ( chatInformation . id , newMessageTextField . text , newMessageColumn . replyToMessageId ) ;
}
}
2020-09-29 22:00:23 +03:00
controlSendButton ( ) ;
2020-10-18 22:54:15 +03:00
newMessageInReplyToRow . inReplyToMessage = null ;
newMessageColumn . editMessageId = "0" ;
2020-09-27 14:49:06 +03:00
}
2020-10-18 19:57:01 +03:00
function getWordBoundaries ( text , cursorPosition ) {
var wordBoundaries = { beginIndex : 0 , endIndex : text . length } ;
var currentIndex = 0 ;
for ( currentIndex = ( cursorPosition - 1 ) ; currentIndex > 0 ; currentIndex -- ) {
if ( text . charAt ( currentIndex ) === ' ' ) {
wordBoundaries . beginIndex = currentIndex + 1 ;
break ;
}
}
for ( currentIndex = cursorPosition ; currentIndex < text . length ; currentIndex ++ ) {
if ( text . charAt ( currentIndex ) === ' ' ) {
wordBoundaries . endIndex = currentIndex ;
break ;
}
}
return wordBoundaries ;
}
function handleMessageTextReplacement ( text , cursorPosition ) {
var wordBoundaries = getWordBoundaries ( text , cursorPosition ) ;
var currentWord = text . substring ( wordBoundaries . beginIndex , wordBoundaries . endIndex ) ;
if ( currentWord . length > 1 && currentWord . charAt ( 0 ) === ':' ) {
tdLibWrapper . searchEmoji ( currentWord . substring ( 1 ) ) ;
} else {
chatPage . emojiProposals = null ;
}
}
function replaceMessageText ( text , cursorPosition , newText ) {
var wordBoundaries = getWordBoundaries ( text , cursorPosition ) ;
var newCompleteText = text . substring ( 0 , wordBoundaries . beginIndex ) + newText + " " + text . substring ( wordBoundaries . endIndex ) ;
var newIndex = wordBoundaries . beginIndex + newText . length + 1 ;
newMessageTextField . text = newCompleteText ;
newMessageTextField . cursorPosition = newIndex ;
lostFocusTimer . start ( ) ;
}
2020-08-21 15:26:56 +03:00
Component.onCompleted: {
initializePage ( ) ;
}
2020-10-19 13:20:02 +03:00
Component.onDestruction: {
tdLibWrapper . closeChat ( chatInformation . id ) ;
}
2020-08-21 15:47:08 +03:00
onStatusChanged: {
2020-10-19 13:20:02 +03:00
switch ( status ) {
case PageStatus.Activating:
2020-08-25 00:02:08 +03:00
tdLibWrapper . openChat ( chatInformation . id ) ;
2020-10-19 13:20:02 +03:00
break ;
case PageStatus.Active:
2020-08-30 00:59:29 +03:00
if ( ! chatPage . isInitialized ) {
chatModel . initialize ( chatInformation ) ;
chatPage . isInitialized = true ;
}
2020-10-19 13:20:02 +03:00
break ;
2020-08-29 19:04:23 +03:00
}
2020-10-19 13:20:02 +03:00
2020-08-21 15:47:08 +03:00
}
2020-08-21 19:03:51 +03:00
Connections {
target: tdLibWrapper
onUserUpdated: {
if ( isPrivateChat && chatPartnerInformation . id . toString ( ) === userId ) {
chatPartnerInformation = userInformation ;
updateChatPartnerStatusText ( ) ;
}
}
onBasicGroupUpdated: {
if ( isBasicGroup && chatGroupInformation . id . toString ( ) === groupId ) {
chatGroupInformation = groupInformation ;
updateGroupStatusText ( ) ;
}
}
onSuperGroupUpdated: {
if ( isSuperGroup && chatGroupInformation . id . toString ( ) === groupId ) {
chatGroupInformation = groupInformation ;
updateGroupStatusText ( ) ;
}
}
onChatOnlineMemberCountUpdated: {
console . log ( isSuperGroup + "/" + isBasicGroup + "/" + chatInformation . id . toString ( ) + "/" + chatId ) ;
if ( ( isSuperGroup || isBasicGroup ) && chatInformation . id . toString ( ) === chatId ) {
chatOnlineMemberCount = onlineMemberCount ;
updateGroupStatusText ( ) ;
}
}
2020-09-30 00:37:56 +03:00
onFileUpdated: {
uploadStatusRow . visible = fileInformation . remote . is_uploading_active ;
uploadingProgressBar . maximumValue = fileInformation . size ;
uploadingProgressBar . value = fileInformation . remote . uploaded_size ;
}
2020-10-18 19:57:01 +03:00
onEmojiSearchSuccessful: {
chatPage . emojiProposals = result ;
}
2020-08-21 19:03:51 +03:00
}
2020-08-22 22:43:20 +03:00
Connections {
target: chatModel
onMessagesReceived: {
2020-08-30 20:04:16 +03:00
console . log ( "[ChatPage] Messages received, view has " + chatView . count + " messages, setting view to index " + modelIndex + ", own messages were read before index " + lastReadSentIndex ) ;
2020-10-19 13:20:02 +03:00
if ( totalCount === 0 ) {
console . log ( "[ChatPage] actually, skipping that: No Messages in Chat." ) ;
chatView . positionViewAtEnd ( ) ;
chatPage . loading = false ;
return ;
}
2020-08-30 20:04:16 +03:00
chatView . lastReadSentIndex = lastReadSentIndex ;
2020-09-20 15:26:09 +03:00
if ( modelIndex === ( chatView . count - 1 ) ) {
chatView . positionViewAtEnd ( ) ;
} else {
chatView . positionViewAtIndex ( modelIndex , ListView . Beginning ) ;
}
2020-09-14 00:25:48 +03:00
chatPage . loading = false ;
2020-09-16 22:12:39 +03:00
if ( chatView . height > chatView . contentHeight ) {
console . log ( "[ChatPage] Chat content quite small..." ) ;
2020-10-19 16:30:03 +03:00
tdLibWrapper . viewMessage ( chatInformation . id , chatModel . getMessage ( chatView . count - 1 ) . id , false ) ;
2020-09-16 22:12:39 +03:00
}
2020-08-22 22:43:20 +03:00
}
2020-08-23 00:49:02 +03:00
onNewMessageReceived: {
2020-09-22 21:32:35 +03:00
if ( message . sender_user_id === chatPage . myUserId ) {
console . log ( "[ChatPage] Own message received, scrolling down to see it..." ) ;
chatView . scrollToBottom ( ) ;
}
2020-08-23 00:49:02 +03:00
}
2020-08-29 22:39:57 +03:00
onUnreadCountUpdated: {
console . log ( "[ChatPage] Unread count updated, new count: " + unreadCount ) ;
chatInformation . unread_count = unreadCount ;
2020-09-15 23:47:39 +03:00
chatUnreadMessagesCountBackground . visible = ( ! chatPage . loading && unreadCount > 0 ) ;
chatUnreadMessagesCount . text = unreadCount > 99 ? "99+" : unreadCount ;
2020-08-29 22:39:57 +03:00
}
2020-08-30 20:04:16 +03:00
onLastReadSentMessageUpdated: {
console . log ( "[ChatPage] Updating last read sent index, new index: " + lastReadSentIndex ) ;
chatView . lastReadSentIndex = lastReadSentIndex ;
}
2020-09-01 23:37:48 +03:00
onMessagesIncrementalUpdate: {
console . log ( "Incremental update received. View now has " + chatView . count + " messages, view is on index " + modelIndex + ", own messages were read before index " + lastReadSentIndex ) ;
chatView . currentIndex = modelIndex ;
chatView . lastReadSentIndex = lastReadSentIndex ;
2020-09-22 22:05:24 +03:00
chatViewCooldownTimer . start ( ) ;
2020-09-01 23:37:48 +03:00
}
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
onNotificationSettingsUpdated: {
chatInformation = chatModel . getChatInformation ( ) ;
muteChatMenuItem . text = chatInformation . notification_settings . mute_for > 0 ? qsTr ( "Unmute Chat" ) : qsTr ( "Mute Chat" ) ;
}
2020-08-22 22:43:20 +03:00
}
2020-10-18 19:57:01 +03:00
Timer {
id: lostFocusTimer
interval: 200
running: false
repeat: false
onTriggered: {
newMessageTextField . forceActiveFocus ( ) ;
}
}
Timer {
id: textReplacementTimer
interval: 600
running: false
repeat: false
onTriggered: {
handleMessageTextReplacement ( newMessageTextField . text , newMessageTextField . cursorPosition ) ;
}
}
2020-08-21 19:03:51 +03:00
Timer {
id: chatContactTimeUpdater
interval: 60000
2020-10-19 13:20:02 +03:00
running: isPrivateChat
2020-08-21 19:03:51 +03:00
repeat: true
onTriggered: {
updateChatPartnerStatusText ( ) ;
}
}
2020-08-21 15:26:56 +03:00
SilicaFlickable {
id: chatContainer
anchors.fill: parent
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
contentHeight: height
contentWidth: width
2020-08-21 15:26:56 +03:00
2020-09-16 21:43:36 +03:00
PullDownMenu {
2020-10-16 00:43:55 +03:00
visible: chatInformation . id !== chatPage . myUserId && ! stickerPickerLoader . active
2020-09-16 21:43:36 +03:00
MenuItem {
id: muteChatMenuItem
onClicked: {
var newNotificationSettings = chatInformation . notification_settings ;
if ( newNotificationSettings . mute_for > 0 ) {
newNotificationSettings . mute_for = 0 ;
} else {
newNotificationSettings . mute_for = 6666666 ;
}
tdLibWrapper . setChatNotificationSettings ( chatInformation . id , newNotificationSettings ) ;
}
text: chatInformation . notification_settings . mute_for > 0 ? qsTr ( "Unmute Chat" ) : qsTr ( "Mute Chat" )
}
}
2020-10-19 13:20:02 +03:00
BackgroundItem {
id: headerMouseArea
height: headerRow . height
width: parent . width
onClicked: {
pageStack . push ( Qt . resolvedUrl ( "../pages/ChatInformationPage.qml" ) , { "chatInformation" : chatInformation , "privateChatUserInformation" : chatPartnerInformation , "groupInformation" : chatGroupInformation , "chatOnlineMemberCount" : chatOnlineMemberCount } ) ;
}
}
2020-08-21 15:26:56 +03:00
Column {
id: chatColumn
width: parent . width
height: parent . height
2020-09-19 19:49:11 +03:00
spacing: Theme . paddingSmall
2020-08-21 15:26:56 +03:00
Row {
id: headerRow
width: parent . width - ( 3 * Theme . horizontalPageMargin )
2020-09-18 23:55:59 +03:00
height: chatOverviewColumn . height + Theme . paddingLarge
2020-08-21 15:26:56 +03:00
anchors.horizontalCenter: parent . horizontalCenter
spacing: Theme . paddingMedium
ProfileThumbnail {
id: chatPictureThumbnail
photoData: ( typeof chatInformation . photo !== "undefined" ) ? chatInformation.photo.small : ""
replacementStringHint: chatNameText . text
width: chatOverviewColumn . height
height: chatOverviewColumn . height
2020-09-19 19:49:11 +03:00
anchors.bottom: parent . bottom
anchors.bottomMargin: Theme . paddingSmall
2020-08-21 15:26:56 +03:00
}
Column {
id: chatOverviewColumn
width: parent . width - chatPictureThumbnail . width - Theme . paddingMedium
2020-09-19 19:49:11 +03:00
anchors.bottom: parent . bottom
anchors.bottomMargin: Theme . paddingSmall
2020-08-21 15:26:56 +03:00
Text {
id: chatNameText
text: chatInformation . title !== "" ? Emoji . emojify ( chatInformation . title , font . pixelSize ) : qsTr ( "Unknown" )
textFormat: Text . StyledText
font.pixelSize: Theme . fontSizeLarge
font.family: Theme . fontFamilyHeading
color: Theme . highlightColor
elide: Text . ElideRight
width: parent . width
maximumLineCount: 1
horizontalAlignment: Text . AlignRight
onTruncatedChanged: {
// There is obviously a bug in QML in truncating text with images.
// We simply remove Emojis then...
if ( truncated ) {
text = text . replace ( /\<img [^>]+\/\>/g , "" ) ;
}
}
}
Text {
id: chatStatusText
2020-08-21 19:03:51 +03:00
text: ""
2020-08-21 15:26:56 +03:00
textFormat: Text . StyledText
2020-08-21 19:03:51 +03:00
font.pixelSize: Theme . fontSizeExtraSmall
2020-08-21 15:26:56 +03:00
font.family: Theme . fontFamilyHeading
2020-10-19 13:20:02 +03:00
color: headerMouseArea . pressed ? Theme.secondaryHighlightColor : Theme . secondaryColor
2020-08-21 15:26:56 +03:00
elide: Text . ElideRight
width: parent . width
maximumLineCount: 1
horizontalAlignment: Text . AlignRight
}
}
}
2020-08-29 19:04:23 +03:00
Item {
id: chatViewItem
2020-08-21 15:26:56 +03:00
width: parent . width
2020-09-19 19:49:11 +03:00
height: parent . height - headerRow . height - Theme . paddingSmall - ( chatPage . isChannel ? 0 : ( newMessageColumn . height + Theme . paddingSmall ) )
2020-08-21 15:26:56 +03:00
2020-09-18 23:55:59 +03:00
property int previousHeight ;
Component.onCompleted: {
previousHeight = height ;
}
onHeightChanged: {
var deltaHeight = previousHeight - height ;
chatView . contentY = chatView . contentY + deltaHeight ;
previousHeight = height ;
}
2020-09-22 22:05:24 +03:00
Timer {
id: chatViewCooldownTimer
interval: 2000
repeat: false
running: false
onTriggered: {
console . log ( "[ChatPage] Cooldown completed..." ) ;
chatView . inCooldown = false ;
}
}
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
2020-08-29 19:04:23 +03:00
SilicaListView {
id: chatView
2020-08-21 15:26:56 +03:00
2020-08-29 19:04:23 +03:00
anchors.fill: parent
opacity: chatPage . loading ? 0 : 1
Behavior on opacity { NumberAnimation { } }
clip: true
2020-08-23 00:05:45 +03:00
2020-08-30 20:04:16 +03:00
property int lastReadSentIndex: 0
2020-09-22 22:05:24 +03:00
property bool inCooldown: false
2020-08-30 20:04:16 +03:00
2020-08-29 19:04:23 +03:00
function handleScrollPositionChanged ( ) {
2020-08-30 00:06:14 +03:00
console . log ( "Current position: " + chatView . contentY ) ;
2020-10-19 16:30:03 +03:00
tdLibWrapper . viewMessage ( chatInformation . id , chatView . itemAt ( chatView . contentX , ( chatView . contentY + chatView . height - Theme . horizontalPageMargin ) ) . myMessage . id , false ) ;
2020-08-29 19:04:23 +03:00
}
2020-08-29 22:39:57 +03:00
onContentYChanged: {
2020-09-22 23:46:48 +03:00
if ( ! chatPage . loading && ! chatView . inCooldown && chatView . indexAt ( chatView . contentX , chatView . contentY ) < 10 ) {
console . log ( "[ChatPage] Trying to get older history items..." ) ;
chatView . inCooldown = true ;
chatModel . triggerLoadMoreHistory ( ) ;
2020-08-30 16:04:15 +03:00
}
2020-08-29 22:39:57 +03:00
}
2020-08-29 19:04:23 +03:00
onMovementEnded: {
2020-08-26 23:52:06 +03:00
handleScrollPositionChanged ( ) ;
2020-08-23 00:05:45 +03:00
}
2020-08-29 19:04:23 +03:00
onQuickScrollAnimatingChanged: {
if ( ! quickScrollAnimating ) {
handleScrollPositionChanged ( ) ;
}
}
model: chatModel
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
property variant contentComponentNames: ( {
messageSticker: "StickerPreview" ,
messagePhoto: "ImagePreview" ,
messageVideo: "VideoPreview" ,
messageAnimation: "VideoPreview" ,
messageAudio: "AudioPreview" ,
messageVoiceNote: "AudioPreview" ,
messageDocument: "DocumentPreview" ,
messageLocation: "LocationPreview" ,
messageVenue: "LocationPreview" ,
messagePoll: "PollPreview"
} )
2020-10-31 22:02:18 +03:00
function getContentComponentHeight ( componentName , content , parentWidth ) {
switch ( componentName ) {
case "StickerPreview" : return content . sticker . height ;
case "ImagePreview" :
case "LocationPreview" :
return parentWidth * 0.66666666 ; // 2 / 3;
case "VideoPreview" :
return Functions . getVideoHeight ( parentWidth , ( content [ '@type' ] === "messageVideo" ) ? content.video : content . animation ) ;
case "AudioPreview" :
return parentWidth / 2 ;
case "DocumentPreview" :
return Theme . itemSizeSmall ;
case "PollPreview" :
return Theme . itemSizeSmall * ( 4 + content . poll . options ) ;
}
}
2020-08-29 19:04:23 +03:00
delegate: ListItem {
id: messageListItem
contentHeight: messageBackground . height + Theme . paddingMedium
contentWidth: parent . width
2020-08-21 15:26:56 +03:00
2020-08-29 19:04:23 +03:00
property variant myMessage: display
property variant userInformation: tdLibWrapper . getUserInformation ( display . sender_user_id )
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
property Page page: chatPage
2020-10-11 23:02:30 +03:00
property bool isOwnMessage: chatPage . myUserId === display . sender_user_id
2020-10-31 22:02:18 +03:00
property string extraContentComponentName: typeof display . content !== "undefined"
&& chatView . contentComponentNames . hasOwnProperty ( display . content [ '@type' ] ) ?
chatView . contentComponentNames [ display . content [ '@type' ] ] : ""
2020-08-29 19:04:23 +03:00
menu: ContextMenu {
MenuItem {
onClicked: {
newMessageInReplyToRow . inReplyToMessage = display ;
newMessageTextField . focus = true ;
}
text: qsTr ( "Reply to Message" )
2020-08-28 18:40:25 +03:00
}
2020-09-19 00:43:23 +03:00
MenuItem {
onClicked: {
newMessageColumn . editMessageId = display . id ;
2020-09-30 01:09:51 +03:00
newMessageTextField . text = Functions . getMessageText ( display , false , false ) ;
2020-09-19 19:49:11 +03:00
newMessageTextField . focus = true ;
2020-09-19 00:43:23 +03:00
}
text: qsTr ( "Edit Message" )
visible: display . can_be_edited
}
2020-09-20 01:13:42 +03:00
MenuItem {
onClicked: {
2020-10-31 22:02:18 +03:00
var chatId = chatInformation . id ;
var messageId = display . id ;
Remorse . itemAction ( messageListItem , qsTr ( "Message deleted" ) , function ( ) { tdLibWrapper . deleteMessages ( chatId , [ messageId ] ) ; } )
2020-09-20 01:13:42 +03:00
}
text: qsTr ( "Delete Message" )
2020-10-07 02:11:44 +03:00
visible: display . can_be_deleted_for_all_users || ( display . can_be_deleted_only_for_self && display . chat_id === chatPage . myUserId )
2020-09-20 01:13:42 +03:00
}
2020-08-28 18:40:25 +03:00
}
2020-09-15 23:47:39 +03:00
Connections {
target: chatModel
onUnreadCountUpdated: {
messageBackground . color = index > ( chatView . count - unreadCount - 1 ) ? Theme.secondaryHighlightColor : Theme . secondaryColor ;
messageBackground . opacity = index > ( chatView . count - unreadCount - 1 ) ? 0.5 : 0.2 ;
}
2020-09-19 19:49:11 +03:00
onNewMessageReceived: {
messageBackground . color = index > ( chatView . count - chatInformation . unreadCount - 1 ) ? Theme.secondaryHighlightColor : Theme . secondaryColor ;
messageBackground . opacity = index > ( chatView . count - chatInformation . unreadCount - 1 ) ? 0.5 : 0.2 ;
}
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
onLastReadSentMessageUpdated: {
console . log ( "[ChatModel] Messages in this chat were read, new last read: " + lastReadSentIndex + ", updating description for index " + index + ", status: " + ( index <= lastReadSentIndex ) ) ;
messageDateText . text = getMessageStatusText ( display , index , lastReadSentIndex ) ;
}
onMessageUpdated: {
if ( index === modelIndex ) {
console . log ( "[ChatModel] This message was updated, index " + index + ", updating content..." ) ;
messageDateText . text = getMessageStatusText ( display , index , chatView . lastReadSentIndex ) ;
messageText . text = Emoji . emojify ( Functions . getMessageText ( display , false , messageListItem . isOwnMessage ) , messageText . font . pixelSize ) ;
if ( locationPreviewLoader . active && locationPreviewLoader . status === Loader . Ready ) {
locationPreviewLoader . item . locationData = display . content . location ;
locationPreviewLoader . item . updatePicture ( )
}
}
}
}
Connections {
target: tdLibWrapper
onReceivedMessage: {
if ( messageId === display . reply_to_message_id . toString ( ) ) {
messageInReplyToRow . inReplyToMessage = message ;
messageInReplyToRow . visible = true ;
}
}
2020-09-15 23:47:39 +03:00
}
2020-09-22 23:46:48 +03:00
Component.onCompleted: {
delegateComponentLoadingTimer . start ( ) ;
}
Timer {
id: delegateComponentLoadingTimer
interval: 500
repeat: false
running: false
onTriggered: {
2020-10-11 23:02:30 +03:00
if ( typeof display . content !== "undefined" ) {
2020-10-31 22:02:18 +03:00
if ( messageListItem . extraContentComponentName !== "" ) {
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
extraContentLoader . setSource (
2020-10-31 22:02:18 +03:00
"../components/" + messageListItem . extraContentComponentName + ".qml" ,
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
{
messageListItem: messageListItem
} )
} else {
if ( typeof display . content . web_page !== "undefined" ) { // only in messageText
webPagePreviewLoader . active = true ;
}
}
2020-10-11 23:02:30 +03:00
}
2020-09-22 23:46:48 +03:00
}
}
2020-09-20 01:13:42 +03:00
2020-08-29 19:04:23 +03:00
Row {
id: messageTextRow
spacing: Theme . paddingSmall
width: parent . width - ( 2 * Theme . horizontalPageMargin )
anchors.horizontalCenter: parent . horizontalCenter
2020-09-15 22:27:16 +03:00
anchors.verticalCenter: parent . verticalCenter
2020-08-29 19:04:23 +03:00
2020-09-22 00:07:30 +03:00
Loader {
id: profileThumbnailLoader
2020-09-22 23:46:48 +03:00
active: ( ( chatPage . isBasicGroup || chatPage . isSuperGroup ) && ! chatPage . isChannel )
2020-09-22 00:07:30 +03:00
asynchronous: true
width: active ? Theme.itemSizeSmall : 0
height: active ? Theme.itemSizeSmall : 0
2020-08-29 19:04:23 +03:00
anchors.bottom: parent . bottom
anchors.bottomMargin: Theme . paddingSmall
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
sourceComponent: Component {
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
visible: ( chatPage . isBasicGroup || chatPage . isSuperGroup ) && ! chatPage . isChannel
}
}
2020-08-29 19:04:23 +03:00
}
2020-08-23 20:17:30 +03:00
2020-08-29 19:04:23 +03:00
Item {
id: messageTextItem
2020-08-22 22:43:20 +03:00
2020-09-22 00:07:30 +03:00
width: parent . width - profileThumbnailLoader . width - Theme . paddingSmall
2020-08-29 19:04:23 +03:00
height: messageBackground . height
2020-08-23 20:17:30 +03:00
2020-08-29 19:04:23 +03:00
Rectangle {
id: messageBackground
anchors {
left: parent . left
2020-10-11 23:02:30 +03:00
leftMargin: messageListItem . isOwnMessage ? 2 * Theme.horizontalPageMargin : 0
2020-08-29 19:04:23 +03:00
right: parent . right
2020-10-11 23:02:30 +03:00
rightMargin: messageListItem . isOwnMessage ? 0 : 2 * Theme . horizontalPageMargin
2020-08-29 19:04:23 +03:00
verticalCenter: parent . verticalCenter
}
height: messageTextColumn . height + ( 2 * Theme . paddingMedium )
2020-08-23 20:17:30 +03:00
2020-09-15 23:47:39 +03:00
color: index > ( chatView . count - chatInformation . unread_count - 1 ) ? Theme.secondaryHighlightColor : Theme . secondaryColor
2020-08-29 19:04:23 +03:00
radius: parent . width / 50
2020-09-15 23:47:39 +03:00
opacity: index > ( chatView . count - chatInformation . unread_count - 1 ) ? 0.5 : 0.2
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
visible: appSettings . showStickersAsImages || display . content [ '@type' ] !== "messageSticker"
2020-08-23 20:17:30 +03:00
}
2020-08-22 22:43:20 +03:00
2020-08-29 19:04:23 +03:00
Column {
id: messageTextColumn
2020-08-23 20:17:30 +03:00
2020-08-29 19:04:23 +03:00
spacing: Theme . paddingSmall
2020-08-23 20:17:30 +03:00
2020-08-29 19:04:23 +03:00
width: messageBackground . width - Theme . horizontalPageMargin
anchors.centerIn: messageBackground
2020-08-23 20:17:30 +03:00
2020-09-24 23:27:17 +03:00
Component.onCompleted: {
if ( display . reply_to_message_id !== 0 ) {
tdLibWrapper . getMessage ( chatInformation . id , display . reply_to_message_id ) ;
}
2020-08-29 12:22:18 +03:00
}
2020-08-29 19:04:23 +03:00
Text {
id: userText
width: parent . width
2020-10-11 23:02:30 +03:00
text: ! messageListItem . isOwnMessage ? Emoji . emojify ( Functions . getUserName ( messageListItem . userInformation ) , font . pixelSize ) : qsTr ( "You" )
2020-08-29 19:04:23 +03:00
font.pixelSize: Theme . fontSizeExtraSmall
font.weight: Font . ExtraBold
2020-10-11 23:02:30 +03:00
color: messageListItem . isOwnMessage ? Theme.highlightColor : Theme . primaryColor
2020-08-29 19:04:23 +03:00
maximumLineCount: 1
elide: Text . ElideRight
textFormat: Text . StyledText
2020-10-11 23:02:30 +03:00
horizontalAlignment: messageListItem . isOwnMessage ? Text.AlignRight : Text . AlignLeft
2020-08-29 19:04:23 +03:00
visible: ( chatPage . isBasicGroup || chatPage . isSuperGroup ) && ! chatPage . isChannel
}
2020-08-23 20:17:30 +03:00
2020-08-29 19:04:23 +03:00
InReplyToRow {
id: messageInReplyToRow
myUserId: chatPage . myUserId
visible: false
}
2020-08-25 17:42:46 +03:00
2020-10-07 23:17:44 +03:00
Loader {
id: forwardedInformationLoader
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
active: typeof display . forward_info !== "undefined"
2020-10-07 23:17:44 +03:00
asynchronous: true
width: parent . width
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
// height: active ? ( item ? item.height : Theme.itemSizeExtraSmall ) : 0
2020-10-07 23:17:44 +03:00
sourceComponent: Component {
Row {
id: forwardedMessageInformationRow
spacing: Theme . paddingSmall
width: parent . width
Component.onCompleted: {
if ( display . forward_info . origin [ "@type" ] === "messageForwardOriginChannel" ) {
var otherChatInformation = tdLibWrapper . getChat ( display . forward_info . origin . chat_id ) ;
forwardedThumbnail . photoData = ( typeof otherChatInformation . photo !== "undefined" ) ? otherChatInformation.photo.small : "" ;
2020-10-15 00:25:56 +03:00
forwardedChannelText . text = Emoji . emojify ( otherChatInformation . title , Theme . fontSizeExtraSmall ) ;
2020-10-07 23:17:44 +03:00
} else if ( display . forward_info . origin [ "@type" ] === "messageForwardOriginUser" ) {
var otherUserInformation = tdLibWrapper . getUserInformation ( display . forward_info . origin . sender_user_id ) ;
forwardedThumbnail . photoData = ( typeof otherUserInformation . profile_photo !== "undefined" ) ? otherUserInformation.profile_photo.small : "" ;
2020-10-15 00:25:56 +03:00
forwardedChannelText . text = Emoji . emojify ( Functions . getUserName ( otherUserInformation ) , Theme . fontSizeExtraSmall ) ;
2020-10-07 23:17:44 +03:00
} else {
forwardedThumbnail . photoData = "" ;
2020-10-15 00:25:56 +03:00
forwardedChannelText . text = Emoji . emojify ( display . forward_info . origin . sender_user_name , Theme . fontSizeExtraSmall ) ;
2020-10-07 23:17:44 +03:00
}
}
ProfileThumbnail {
id: forwardedThumbnail
replacementStringHint: forwardedChannelText . text
width: Theme . itemSizeExtraSmall
height: Theme . itemSizeExtraSmall
}
Column {
spacing: Theme . paddingSmall
width: parent . width
Text {
font.pixelSize: Theme . fontSizeExtraSmall
color: Theme . primaryColor
width: parent . width
font.italic: true
elide: Text . ElideRight
textFormat: Text . StyledText
text: qsTr ( "Forwarded Message" )
onTruncatedChanged: {
// There is obviously a bug in QML in truncating text with images.
// We simply remove Emojis then...
if ( truncated ) {
text = text . replace ( /\<img [^>]+\/\>/g , "" ) ;
}
}
}
Text {
id: forwardedChannelText
font.pixelSize: Theme . fontSizeExtraSmall
color: Theme . primaryColor
width: parent . width
font.bold: true
elide: Text . ElideRight
textFormat: Text . StyledText
2020-10-15 00:25:56 +03:00
text: Emoji . emojify ( forwardedMessageInformationRow . otherChatInformation . title , font . pixelSize )
2020-10-07 23:17:44 +03:00
onTruncatedChanged: {
// There is obviously a bug in QML in truncating text with images.
// We simply remove Emojis then...
if ( truncated ) {
text = text . replace ( /\<img [^>]+\/\>/g , "" ) ;
}
}
}
}
}
}
}
2020-08-29 19:04:23 +03:00
Text {
id: messageText
width: parent . width
2020-10-11 23:02:30 +03:00
text: Emoji . emojify ( Functions . getMessageText ( display , false , messageListItem . isOwnMessage ) , font . pixelSize )
2020-08-29 19:04:23 +03:00
font.pixelSize: Theme . fontSizeSmall
2020-10-11 23:02:30 +03:00
color: messageListItem . isOwnMessage ? Theme.highlightColor : Theme . primaryColor
2020-08-29 19:04:23 +03:00
wrapMode: Text . Wrap
textFormat: Text . StyledText
onLinkActivated: {
Functions . handleLink ( link ) ;
}
2020-10-11 23:02:30 +03:00
horizontalAlignment: messageListItem . isOwnMessage ? Text.AlignRight : Text . AlignLeft
2020-08-29 19:04:23 +03:00
linkColor: Theme . highlightColor
visible: ( text !== "" )
2020-08-23 20:17:30 +03:00
}
2020-08-25 00:02:08 +03:00
2020-09-21 23:10:03 +03:00
Loader {
id: webPagePreviewLoader
2020-09-22 23:46:48 +03:00
active: false
2020-09-21 23:10:03 +03:00
asynchronous: true
width: parent . width
2020-10-13 22:37:06 +03:00
height: messageListItem . containsWebPage ? ( ( parent . width * 2 / 3 ) + ( 6 * Theme . fontSizeExtraSmall ) + ( 7 * Theme . paddingSmall ) ) : 0
2020-10-12 00:11:37 +03:00
sourceComponent: Component {
id: webPagePreviewComponent
WebPagePreview {
id: webPagePreview
2020-10-13 22:37:06 +03:00
onImplicitHeightChanged: {
webPagePreviewLoader . height = webPagePreview . implicitHeight ;
}
2020-10-12 00:11:37 +03:00
webPageData: messageListItem . containsWebPage ? display.content.web_page : ""
width: parent . width
}
}
2020-09-21 23:10:03 +03:00
}
Loader {
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
id: extraContentLoader
2020-08-29 19:04:23 +03:00
width: parent . width
2020-09-21 23:10:03 +03:00
asynchronous: true
2020-10-31 22:02:18 +03:00
property int heightPreset: messageListItem . extraContentComponentName !== "" ? chatView . getContentComponentHeight ( messageListItem . extraContentComponentName , display . content , width ) : 0
height: item ? item.height : heightPreset
2020-10-23 11:29:50 +03:00
}
2020-08-29 19:04:23 +03:00
Timer {
id: messageDateUpdater
interval: 60000
running: true
repeat: true
onTriggered: {
2020-08-31 22:51:52 +03:00
messageDateText . text = getMessageStatusText ( display , index , chatView . lastReadSentIndex ) ;
2020-08-30 20:04:16 +03:00
}
}
2020-08-23 20:17:30 +03:00
2020-08-29 19:04:23 +03:00
Text {
width: parent . width
id: messageDateText
font.pixelSize: Theme . fontSizeTiny
2020-10-11 23:02:30 +03:00
color: messageListItem . isOwnMessage ? Theme.secondaryHighlightColor : Theme . secondaryColor
horizontalAlignment: messageListItem . isOwnMessage ? Text.AlignRight : Text . AlignLeft
2020-08-31 22:51:52 +03:00
text: getMessageStatusText ( display , index , chatView . lastReadSentIndex )
2020-08-29 19:04:23 +03:00
}
2020-08-23 20:17:30 +03:00
}
2020-08-22 22:43:20 +03:00
}
}
}
2020-08-29 19:04:23 +03:00
VerticalScrollDecorator { }
2020-10-19 13:20:02 +03:00
ViewPlaceholder {
enabled: chatView . count === 0
text: qsTr ( "This chat is empty." )
}
2020-08-29 19:04:23 +03:00
}
Column {
width: parent . width
height: loadingLabel . height + loadingBusyIndicator . height + Theme . paddingMedium
spacing: Theme . paddingMedium
anchors.verticalCenter: parent . verticalCenter
opacity: chatPage . loading ? 1 : 0
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
Behavior on opacity { FadeAnimation { } }
2020-08-29 19:04:23 +03:00
visible: chatPage . loading
InfoLabel {
id: loadingLabel
text: qsTr ( "Loading messages..." )
}
BusyIndicator {
id: loadingBusyIndicator
anchors.horizontalCenter: parent . horizontalCenter
running: chatPage . loading
size: BusyIndicatorSize . Large
}
2020-08-21 15:26:56 +03:00
}
2020-09-22 20:26:49 +03:00
Item {
id: chatUnreadMessagesItem
2020-08-29 22:39:57 +03:00
width: Theme . fontSizeHuge
height: Theme . fontSizeHuge
anchors.right: parent . right
anchors.rightMargin: Theme . paddingMedium
anchors.bottom: parent . bottom
anchors.bottomMargin: Theme . paddingMedium
2020-09-22 20:26:49 +03:00
Rectangle {
id: chatUnreadMessagesCountBackground
color: Theme . highlightBackgroundColor
anchors.fill: parent
radius: width / 2
visible: ! chatPage . loading && chatInformation . unread_count > 0
}
2020-08-29 22:39:57 +03:00
2020-09-22 20:26:49 +03:00
Text {
id: chatUnreadMessagesCount
font.pixelSize: Theme . fontSizeMedium
font.bold: true
color: Theme . primaryColor
anchors.centerIn: chatUnreadMessagesCountBackground
visible: chatUnreadMessagesCountBackground . visible
text: chatInformation . unread_count > 99 ? "99+" : chatInformation . unread_count
}
MouseArea {
anchors.fill: parent
onClicked: {
chatView . positionViewAtIndex ( chatView . count - 1 - chatInformation . unread_count , ListView . Beginning ) ;
}
}
2020-08-29 22:39:57 +03:00
}
2020-10-12 23:44:21 +03:00
2020-10-16 00:43:55 +03:00
Loader {
id: stickerPickerLoader
active: false
asynchronous: true
2020-10-16 01:02:58 +03:00
width: parent . width
height: active ? parent.height : 0
2020-10-16 00:43:55 +03:00
source: "../components/StickerPicker.qml"
}
2020-08-21 15:26:56 +03:00
}
2020-08-28 18:40:25 +03:00
Column {
id: newMessageColumn
2020-09-19 19:49:11 +03:00
spacing: Theme . paddingSmall
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
2020-08-28 18:40:25 +03:00
width: parent . width - ( 2 * Theme . horizontalPageMargin )
anchors.horizontalCenter: parent . horizontalCenter
2020-08-30 12:12:13 +03:00
visible: ! chatPage . isChannel
2020-08-28 18:40:25 +03:00
2020-08-29 14:38:28 +03:00
property string replyToMessageId: "0" ;
2020-09-19 00:43:23 +03:00
property string editMessageId: "0" ;
2020-08-29 14:38:28 +03:00
2020-08-28 18:40:25 +03:00
InReplyToRow {
2020-08-29 12:22:18 +03:00
onInReplyToMessageChanged: {
2020-08-29 17:58:48 +03:00
if ( inReplyToMessage ) {
2020-08-29 14:38:28 +03:00
newMessageColumn . replyToMessageId = newMessageInReplyToRow . inReplyToMessage . id . toString ( )
newMessageInReplyToRow . visible = true ;
2020-08-29 12:22:18 +03:00
} else {
2020-08-29 14:38:28 +03:00
newMessageInReplyToRow . visible = false ;
newMessageColumn . replyToMessageId = "0" ;
2020-08-29 12:22:18 +03:00
}
}
2020-10-18 22:54:15 +03:00
editable: true
onClearRequested: {
newMessageInReplyToRow . inReplyToMessage = null ;
}
2020-08-29 12:22:18 +03:00
id: newMessageInReplyToRow
myUserId: chatPage . myUserId
visible: false
2020-08-21 15:26:56 +03:00
}
2020-09-27 14:49:06 +03:00
Row {
id: attachmentOptionsRow
visible: false
anchors.right: parent . right
2020-09-29 00:08:22 +03:00
width: parent . width
layoutDirection: Qt . RightToLeft
2020-09-28 00:24:22 +03:00
spacing: Theme . paddingMedium
IconButton {
2020-09-29 00:08:22 +03:00
id: imageAttachmentButton
icon.source: "image://theme/icon-m-image"
2020-09-28 00:24:22 +03:00
onClicked: {
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
var picker = pageStack . push ( "Sailfish.Pickers.ImagePickerPage" ) ;
picker . selectedContentPropertiesChanged . connect ( function ( ) {
attachmentOptionsRow . visible = false ;
console . log ( "Selected document: " + picker . selectedContentProperties . filePath ) ;
attachmentPreviewRow . fileProperties = picker . selectedContentProperties ;
2020-11-01 19:54:00 +03:00
attachmentPreviewRow . isPicture = true ;
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
attachmentPreviewRow . visible = true ;
controlSendButton ( ) ;
} )
2020-09-28 00:24:22 +03:00
}
}
IconButton {
id: videoAttachmentButton
icon.source: "image://theme/icon-m-video"
onClicked: {
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
var picker = pageStack . push ( "Sailfish.Pickers.VideoPickerPage" ) ;
picker . selectedContentPropertiesChanged . connect ( function ( ) {
attachmentOptionsRow . visible = false ;
console . log ( "Selected video: " + picker . selectedContentProperties . filePath ) ;
attachmentPreviewRow . fileProperties = picker . selectedContentProperties ;
attachmentPreviewRow . isVideo = true ;
attachmentPreviewRow . visible = true ;
controlSendButton ( ) ;
} )
2020-09-28 00:24:22 +03:00
}
}
2020-09-27 14:49:06 +03:00
IconButton {
2020-09-29 00:08:22 +03:00
id: documentAttachmentButton
icon.source: "image://theme/icon-m-document"
2020-09-27 14:49:06 +03:00
onClicked: {
2020-11-01 19:54:00 +03:00
var picker = pageStack . push ( "Sailfish.Pickers.DocumentPickerPage" ) ;
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
picker . selectedContentPropertiesChanged . connect ( function ( ) {
attachmentOptionsRow . visible = false ;
console . log ( "Selected document: " + picker . selectedContentProperties . filePath ) ;
attachmentPreviewRow . fileProperties = picker . selectedContentProperties ;
attachmentPreviewRow . isDocument = true ;
attachmentPreviewRow . visible = true ;
controlSendButton ( ) ;
} )
2020-09-27 14:49:06 +03:00
}
}
2020-10-26 17:15:53 +03:00
IconButton {
icon.source: "../../images/icon-m-sticker.svg"
icon . sourceSize {
width: Theme . iconSizeMedium
height: Theme . iconSizeMedium
}
highlighted: down || stickerPickerLoader . active
onClicked: {
stickerPickerLoader . active = ! stickerPickerLoader . active ;
2020-10-04 16:09:06 +03:00
}
}
2020-10-23 11:29:50 +03:00
IconButton {
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
visible: ! chatPage . isPrivateChat && chatGroupInformation &&
2020-10-26 12:24:50 +03:00
( chatGroupInformation . status [ "@type" ] === "chatMemberStatusCreator"
|| chatGroupInformation . status [ "@type" ] === "chatMemberStatusAdministrator"
|| ( chatGroupInformation . status [ "@type" ] === "chatMemberStatusMember" && chatInformation . permissions . can_send_polls ) )
2020-10-23 11:29:50 +03:00
icon.source: "image://theme/icon-m-question"
onClicked: {
pageStack . push ( Qt . resolvedUrl ( "../pages/PollCreationPage.qml" ) , { "chatId" : chatInformation . id , groupName: chatInformation . title } ) ;
attachmentOptionsRow . visible = false ;
}
}
2020-09-27 14:49:06 +03:00
}
Row {
id: attachmentPreviewRow
visible: false
spacing: Theme . paddingMedium
2020-09-29 00:08:22 +03:00
width: parent . width
layoutDirection: Qt . RightToLeft
2020-09-27 14:49:06 +03:00
anchors.right: parent . right
property bool isPicture: false ;
2020-09-28 00:24:22 +03:00
property bool isVideo: false ;
property bool isDocument: false ;
2020-10-19 13:20:02 +03:00
property variant fileProperties: ( { } ) ;
2020-09-29 00:08:22 +03:00
IconButton {
id: removeAttachmentsIconButton
icon.source: "image://theme/icon-m-clear"
onClicked: {
clearAttachmentPreviewRow ( ) ;
2020-09-29 22:00:23 +03:00
controlSendButton ( ) ;
2020-09-29 00:08:22 +03:00
}
}
2020-09-27 14:49:06 +03:00
2020-09-28 00:24:22 +03:00
Thumbnail {
2020-09-27 14:49:06 +03:00
id: attachmentPreviewImage
width: Theme . itemSizeMedium
height: Theme . itemSizeMedium
2020-09-28 00:24:22 +03:00
sourceSize.width: width
sourceSize.height: height
2020-09-27 14:49:06 +03:00
2020-09-28 00:24:22 +03:00
fillMode: Thumbnail . PreserveAspectCrop
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
mimeType: typeof attachmentPreviewRow . fileProperties !== "undefined" ? attachmentPreviewRow . fileProperties . mimeType || "" : ""
source: typeof attachmentPreviewRow . fileProperties !== "undefined" ? attachmentPreviewRow . fileProperties . url || "" : ""
2020-09-28 00:24:22 +03:00
visible: attachmentPreviewRow . isPicture || attachmentPreviewRow . isVideo
}
Text {
id: attachmentPreviewText
font.pixelSize: Theme . fontSizeSmall
Reduce ChatPage.qml jit compile time
First of all: Take all measurements I mention with a grain of salt – all of them are rough and not necessarily measured more than a few times. All times were measured on an Xperia X run via SDK.
Visiting a chat page can take a long time, especially before the qml is cached by the engine.
When opening it for the first time after application launch, it sometimes takes >1000ms from onClicked (OverviewPage) to Component.OnCompleted (Chatpage).
Subsequent activations take roughly 470-480ms.
With these changes, I was able to reduce these times to ~450ms for the first, ~100ms for subsequent activations of the ChatPage on my test device.
Things changed:
- The components for displaying extra content to a message are (mostly) gone and replaced by a single Loader. This Loader does not use sourceComponent to trade the initial compilation boost for a neglegible bit of runtime penalty.
- Connections were consolidated
- I was surprised how costly the inclusion of the RemorseItem was (compiling ~75ms, initializing up to ~20ms for every delegate). So I traded a bit for a compromise. deleteMessageRemorseItem is now defined on the appWindow level, where it gets a bit mitigated by the animations at application start. Also, only one deletion at a time is now possible. We can easily revert this change, but I thought it worthwhile despite its drawbacks.
- profileThumbnailComponent is now defined directly as sourceComponent, removing the need for its id. Probably didn't do anything.
- InReplyToRow had width: parent.width, so I removed horizontalCenter. Also probably didn't change compilation time at all.
- Another compromise I was willing to take – your opinion may differ: The PickerPages took ages (~200ms) to just parse/compile inside those Components, so I replaced them with the "string notation" of pageStack.push. Drawback: The first time a picker gets activated, you'll see how slow it is. Subsequent activations aren't that bad – also for the other pickers.
2020-10-30 22:36:32 +03:00
text: typeof attachmentPreviewRow . fileProperties !== "undefined" ? attachmentPreviewRow . fileProperties . fileName || "" : "" ;
2020-09-29 00:08:22 +03:00
anchors.verticalCenter: parent . verticalCenter
2020-09-28 00:24:22 +03:00
maximumLineCount: 1
elide: Text . ElideRight
color: Theme . secondaryColor
2020-09-29 00:08:22 +03:00
visible: attachmentPreviewRow . isDocument
2020-09-27 14:49:06 +03:00
}
}
2020-09-30 00:37:56 +03:00
Row {
id: uploadStatusRow
visible: false
spacing: Theme . paddingMedium
width: parent . width
anchors.right: parent . right
Text {
id: uploadingText
font.pixelSize: Theme . fontSizeSmall
text: qsTr ( "Uploading..." )
anchors.verticalCenter: parent . verticalCenter
color: Theme . secondaryColor
visible: uploadStatusRow . visible
}
ProgressBar {
id: uploadingProgressBar
minimumValue: 0
maximumValue: 100
value: 0
visible: uploadStatusRow . visible
width: parent . width - uploadingText . width - Theme . paddingMedium
}
}
2020-10-18 19:57:01 +03:00
Column {
id: emojiColumn
width: parent . width
anchors.horizontalCenter: parent . horizontalCenter
visible: emojiProposals ? ( emojiProposals . length > 0 ? true : false ) : false
opacity: emojiProposals ? ( emojiProposals . length > 0 ? 1 : 0 ) : 0
Behavior on opacity { NumberAnimation { } }
spacing: Theme . paddingMedium
Flickable {
width: parent . width
height: emojiResultRow . height + Theme . paddingSmall
anchors.horizontalCenter: parent . horizontalCenter
contentWidth: emojiResultRow . width
clip: true
Row {
id: emojiResultRow
spacing: Theme . paddingMedium
Repeater {
model: emojiProposals
Item {
height: singleEmojiRow . height
width: singleEmojiRow . width
Row {
id: singleEmojiRow
spacing: Theme . paddingSmall
Image {
id: emojiPicture
source: "../js/emoji/" + modelData . file_name
width: Theme . fontSizeLarge
height: Theme . fontSizeLarge
}
}
MouseArea {
anchors.fill: parent
onClicked: {
replaceMessageText ( newMessageTextField . text , newMessageTextField . cursorPosition , modelData . emoji ) ;
emojiProposals = null ;
}
}
}
}
}
}
}
2020-10-18 22:54:15 +03:00
Row {
2020-09-19 00:43:23 +03:00
width: parent . width
2020-10-18 22:54:15 +03:00
spacing: Theme . paddingSmall
2020-09-19 00:43:23 +03:00
visible: newMessageColumn . editMessageId !== "0"
2020-10-18 22:54:15 +03:00
Text {
width: parent . width - Theme . paddingSmall - removeEditMessageIconButton . width
anchors.verticalCenter: parent . verticalCenter
id: editMessageText
font.pixelSize: Theme . fontSizeSmall
font.bold: true
text: qsTr ( "Edit Message" )
color: Theme . secondaryColor
}
IconButton {
id: removeEditMessageIconButton
icon.source: "image://theme/icon-m-clear"
onClicked: {
newMessageColumn . editMessageId = "0" ;
newMessageTextField . text = "" ;
}
}
2020-09-19 00:43:23 +03:00
}
2020-08-28 18:40:25 +03:00
Row {
id: newMessageRow
width: parent . width
anchors.horizontalCenter: parent . horizontalCenter
2020-09-24 00:41:17 +03:00
TextArea {
id: newMessageTextField
width: parent . width - attachmentIconButton . width - newMessageSendButton . width
height: Math . min ( chatContainer . height / 3 , implicitHeight )
2020-08-28 18:40:25 +03:00
anchors.verticalCenter: parent . verticalCenter
2020-09-24 00:41:17 +03:00
font.pixelSize: Theme . fontSizeSmall
placeholderText: qsTr ( "Your message" )
labelVisible: false
textLeftMargin: 0
textTopMargin: 0
EnterKey.onClicked: {
2020-10-06 04:40:12 +03:00
if ( appSettings . sendByEnter ) {
2020-09-27 14:49:06 +03:00
sendMessage ( ) ;
2020-09-24 00:41:17 +03:00
newMessageTextField . text = "" ;
newMessageTextField . focus = false ;
}
}
2020-10-06 04:40:12 +03:00
EnterKey.enabled: ! appSettings . sendByEnter || text . length
EnterKey.iconSource: appSettings . sendByEnter ? "image://theme/icon-m-chat" : "image://theme/icon-m-enter"
2020-09-16 23:04:02 +03:00
2020-09-24 00:41:17 +03:00
onTextChanged: {
2020-09-29 22:00:23 +03:00
controlSendButton ( ) ;
2020-10-18 19:57:01 +03:00
textReplacementTimer . restart ( ) ;
2020-08-28 18:40:25 +03:00
}
}
2020-09-24 00:41:17 +03:00
IconButton {
id: attachmentIconButton
2020-09-27 14:49:06 +03:00
icon.source: attachmentOptionsRow . visible ? "image://theme/icon-m-attach?" + Theme.highlightColor : "image://theme/icon-m-attach?" + Theme . primaryColor
2020-09-24 23:27:17 +03:00
anchors.bottom: parent . bottom
anchors.bottomMargin: Theme . paddingSmall
2020-10-16 00:43:55 +03:00
enabled: ! attachmentPreviewRow . visible
2020-09-24 00:41:17 +03:00
onClicked: {
2020-09-27 14:49:06 +03:00
if ( attachmentOptionsRow . visible ) {
attachmentOptionsRow . visible = false ;
2020-10-16 00:43:55 +03:00
stickerPickerLoader . active = false ;
2020-09-27 14:49:06 +03:00
} else {
attachmentOptionsRow . visible = true ;
}
2020-09-24 00:41:17 +03:00
}
}
IconButton {
id: newMessageSendButton
icon.source: "image://theme/icon-m-chat"
2020-09-24 23:27:17 +03:00
anchors.bottom: parent . bottom
anchors.bottomMargin: Theme . paddingSmall
2020-09-24 00:41:17 +03:00
enabled: false
onClicked: {
2020-09-27 14:49:06 +03:00
sendMessage ( ) ;
2020-09-24 00:41:17 +03:00
newMessageTextField . text = "" ;
newMessageTextField . focus = false ;
2020-08-21 15:26:56 +03:00
}
}
}
}
}
}
}