perf(@chat): Do not re-render messages when switching chat

This commit is contained in:
Anthony Laibe 2022-01-20 13:15:36 +01:00 committed by Sale Djenic
parent c505564522
commit 5bf9b587da
5 changed files with 188 additions and 167 deletions

View File

@ -70,8 +70,10 @@ QtObject:
return self.delegate.getNumberOfPinnedMessages() return self.delegate.getNumberOfPinnedMessages()
proc initialMessagesLoadedChanged*(self: View) {.signal.} proc initialMessagesLoadedChanged*(self: View) {.signal.}
proc getInitialMessagesLoaded*(self: View): bool {.slot.} = proc getInitialMessagesLoaded*(self: View): bool {.slot.} =
return self.initialMessagesLoaded return self.initialMessagesLoaded
QtProperty[bool] initialMessagesLoaded: QtProperty[bool] initialMessagesLoaded:
read = getInitialMessagesLoaded read = getInitialMessagesLoaded
notify = initialMessagesLoadedChanged notify = initialMessagesLoadedChanged
@ -83,8 +85,10 @@ QtObject:
self.initialMessagesLoadedChanged() self.initialMessagesLoadedChanged()
proc loadingHistoryMessagesInProgressChanged*(self: View) {.signal.} proc loadingHistoryMessagesInProgressChanged*(self: View) {.signal.}
proc getLoadingHistoryMessagesInProgress*(self: View): bool {.slot.} = proc getLoadingHistoryMessagesInProgress*(self: View): bool {.slot.} =
return self.loadingHistoryMessagesInProgress return self.loadingHistoryMessagesInProgress
QtProperty[bool] loadingHistoryMessagesInProgress: QtProperty[bool] loadingHistoryMessagesInProgress:
read = getLoadingHistoryMessagesInProgress read = getLoadingHistoryMessagesInProgress
notify = loadingHistoryMessagesInProgressChanged notify = loadingHistoryMessagesInProgressChanged
@ -100,10 +104,12 @@ QtObject:
self.delegate.loadMoreMessages() self.delegate.loadMoreMessages()
proc messageSuccessfullySent*(self: View) {.signal.} proc messageSuccessfullySent*(self: View) {.signal.}
proc emitSendingMessageSuccessSignal*(self: View) = proc emitSendingMessageSuccessSignal*(self: View) =
self.messageSuccessfullySent() self.messageSuccessfullySent()
proc sendingMessageFailed*(self: View) {.signal.} proc sendingMessageFailed*(self: View) {.signal.}
proc emitSendingMessageErrorSignal*(self: View) = proc emitSendingMessageErrorSignal*(self: View) =
self.sendingMessageFailed() self.sendingMessageFailed()

17
src/dev/benchmark.nim Normal file
View File

@ -0,0 +1,17 @@
import strutils, times
# benchmark measure execution time of block of code.
# usage:
# import os, strutils, times
# import benchmark
#
# benchmark("name") do:
# ...
template benchmark*(benchmarkName: string, code: untyped) =
block:
let t0 = epochTime()
code
let elapsed = epochTime() - t0
let elapsedStr = elapsed.formatFloat(format = ffDecimal, precision = 10)
echo "CPU Time [", benchmarkName, "] ", elapsedStr, "s"

View File

@ -22,7 +22,6 @@ QtObject {
return chatCommunitySectionModule.getChatContentModule() return chatCommunitySectionModule.getChatContentModule()
} }
// Contact requests related part // Contact requests related part
property var contactRequestsModel: chatCommunitySectionModule.contactRequestsModel property var contactRequestsModel: chatCommunitySectionModule.contactRequestsModel

View File

@ -158,65 +158,41 @@ Item {
} }
} }
StackLayout {
anchors.fill: parent EmptyChatPanel {
currentIndex: { visible: root.activeChatId === ""
if(root.activeChatId !== "") onShareChatKeyClicked: Global.openProfilePopup(userProfile.pubKey);
{ }
for(let i = 1; i < this.children.length; i++)
{
var obj = this.children[i];
if(obj && obj.chatContentModule)
{
let myChatId = obj.chatContentModule.getMyChatId()
if(myChatId === root.activeChatId || myChatId === root.activeSubItemId)
return i
} // This is kind of a solution for applying backend refactored changes with the minimal qml changes.
} // The best would be if we made qml to follow the struct we have on the backend side.
} Repeater {
model: parentModule && parentModule.model
delegate: delegateChooser
return 0 DelegateChooser {
} id: delegateChooser
role: "type"
EmptyChatPanel { DelegateChoice { // In case of category
onShareChatKeyClicked: Global.openProfilePopup(userProfile.pubKey); roleValue: Constants.chatType.unknown
} delegate: Repeater {
model: {
// This is kind of a solution for applying backend refactored changes with the minimal qml changes. if (!subItems) {
// The best would be if we made qml to follow the struct we have on the backend side. console.error("We got a category with no subitems. It is possible that the channel had a type unknown")
Repeater {
model: parentModule && parentModule.model
delegate: delegateChooser
DelegateChooser {
id: delegateChooser
role: "type"
DelegateChoice { // In case of category
roleValue: Constants.chatType.unknown
delegate: Repeater {
model: {
if (!subItems) {
console.error("We got a category with no subitems. It is possible that the channel had a type unknown")
}
return subItems
}
delegate: ChatContentView {
rootStore: root.rootStore
contactsStore: root.contactsStore
sendTransactionNoEnsModal: cmpSendTransactionNoEns
receiveTransactionModal: cmpReceiveTransaction
sendTransactionWithEnsModal: cmpSendTransactionWithEns
stickersLoaded: root.stickersLoaded
Component.onCompleted: {
parentModule.prepareChatContentModuleForChatId(model.itemId)
chatContentModule = parentModule.getChatContentModule()
}
} }
return subItems
} }
}
DelegateChoice { // In all other cases
delegate: ChatContentView { delegate: ChatContentView {
width: parent.width
clip: true
height: {
// dynamically calculate the height of the view, if the active one is the current one
// then set the height to parent otherwise set it to 0
let myChatId = chatContentModule.getMyChatId()
if(myChatId === root.activeChatId || myChatId === root.activeSubItemId)
return parent.height
return 0
}
rootStore: root.rootStore rootStore: root.rootStore
contactsStore: root.contactsStore contactsStore: root.contactsStore
sendTransactionNoEnsModal: cmpSendTransactionNoEns sendTransactionNoEnsModal: cmpSendTransactionNoEns
@ -224,12 +200,36 @@ Item {
sendTransactionWithEnsModal: cmpSendTransactionWithEns sendTransactionWithEnsModal: cmpSendTransactionWithEns
stickersLoaded: root.stickersLoaded stickersLoaded: root.stickersLoaded
Component.onCompleted: { Component.onCompleted: {
parentModule.prepareChatContentModuleForChatId(itemId) parentModule.prepareChatContentModuleForChatId(model.itemId)
chatContentModule = parentModule.getChatContentModule() chatContentModule = parentModule.getChatContentModule()
} }
} }
} }
} }
DelegateChoice { // In all other cases
delegate: ChatContentView {
width: parent.width
clip: true
height: {
// dynamically calculate the height of the view, if the active one is the current one
// then set the height to parent otherwise set it to 0
let myChatId = chatContentModule.getMyChatId()
if(myChatId === root.activeChatId || myChatId === root.activeSubItemId)
return parent.height
return 0
}
rootStore: root.rootStore
contactsStore: root.contactsStore
sendTransactionNoEnsModal: cmpSendTransactionNoEns
receiveTransactionModal: cmpReceiveTransaction
sendTransactionWithEnsModal: cmpSendTransactionWithEns
stickersLoaded: root.stickersLoaded
Component.onCompleted: {
parentModule.prepareChatContentModuleForChatId(itemId)
chatContentModule = parentModule.getChatContentModule()
}
}
}
} }
} }
@ -238,118 +238,117 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.bottomMargin: Style.current.bigPadding Layout.bottomMargin: Style.current.bigPadding
isContact: root.isContact isContact: root.isContact
visible: root.activeChatType === Constants.chatType.oneToOne visible: root.activeChatType === Constants.chatType.oneToOne && (!root.isContact /*|| !contactRequestReceived*/)
&& (!root.isContact /*|| !contactRequestReceived*/)
onAddContactClicked: { onAddContactClicked: {
root.rootStore.addContact(root.activeChatId); root.rootStore.addContact(root.activeChatId);
} }
} }
Component { Component {
id: cmpSendTransactionNoEns id: cmpSendTransactionNoEns
ChatCommandModal { ChatCommandModal {
id: sendTransactionNoEns id: sendTransactionNoEns
store: root.rootStore
contactsStore: root.contactsStore
isContact: root.isContact
onClosed: {
destroy()
}
sendChatCommand: root.requestAddressForTransaction
isRequested: false
//% "Send"
commandTitle: qsTrId("command-button-send")
header.title: commandTitle
//% "Request Address"
finalButtonLabel: qsTrId("request-address")
selectRecipient.selectedRecipient: {
parentModule.prepareChatContentModuleForChatId(activeChatId)
let chatContentModule = parentModule.getChatContentModule()
return {
address: Constants.zeroAddress, // Setting as zero address since we don't have the address yet
alias: chatContentModule.chatDetails.name, // Do we need the alias for real or name works?
identicon: chatContentModule.chatDetails.icon,
name: chatContentModule.chatDetails.name,
type: RecipientSelector.Type.Contact
}
}
selectRecipient.selectedType: RecipientSelector.Type.Contact
selectRecipient.readOnly: true
}
}
Component {
id: cmpReceiveTransaction
ChatCommandModal {
id: receiveTransaction
store: root.rootStore
contactsStore: root.contactsStore
isContact: root.isContact
onClosed: {
destroy()
}
sendChatCommand: root.requestTransaction
isRequested: true
//% "Request"
commandTitle: qsTrId("wallet-request")
header.title: commandTitle
//% "Request"
finalButtonLabel: qsTrId("wallet-request")
selectRecipient.selectedRecipient: {
parentModule.prepareChatContentModuleForChatId(activeChatId)
let chatContentModule = parentModule.getChatContentModule()
return {
address: Constants.zeroAddress, // Setting as zero address since we don't have the address yet
alias: chatContentModule.chatDetails.name, // Do we need the alias for real or name works?
identicon: chatContentModule.chatDetails.icon,
name: chatContentModule.chatDetails.name,
type: RecipientSelector.Type.Contact
}
}
selectRecipient.selectedType: RecipientSelector.Type.Contact
selectRecipient.readOnly: true
}
}
Component {
id: cmpSendTransactionWithEns
SendModal {
id: sendTransactionWithEns
store: root.rootStore
contactsStore: root.contactsStore
onOpened: {
// Not Refactored Yet
// root.rootStore.walletModelInst.gasView.getGasPrice()
}
onClosed: {
destroy()
}
isContact: root.isContact
selectRecipient.readOnly: true
selectRecipient.selectedRecipient: {
parentModule.prepareChatContentModuleForChatId(activeChatId)
let chatContentModule = parentModule.getChatContentModule()
return {
address: "",
alias: chatContentModule.chatDetails.name, // Do we need the alias for real or name works?
identicon: chatContentModule.chatDetails.icon,
name: chatContentModule.chatDetails.name,
type: RecipientSelector.Type.Contact,
ensVerified: true
}
}
selectRecipient.selectedType: RecipientSelector.Type.Contact
}
}
ActivityCenterPopup {
id: activityCenter
height: root.height - 56 * 2 // TODO get screen size // Taken from old code top bar height was fixed there to 56
y: 56
store: root.rootStore store: root.rootStore
chatSectionModule: root.chatSectionModule contactsStore: root.contactsStore
isContact: root.isContact
onClosed: {
destroy()
}
sendChatCommand: root.requestAddressForTransaction
isRequested: false
//% "Send"
commandTitle: qsTrId("command-button-send")
header.title: commandTitle
//% "Request Address"
finalButtonLabel: qsTrId("request-address")
selectRecipient.selectedRecipient: {
parentModule.prepareChatContentModuleForChatId(activeChatId)
let chatContentModule = parentModule.getChatContentModule()
return {
address: Constants.zeroAddress, // Setting as zero address since we don't have the address yet
alias: chatContentModule.chatDetails.name, // Do we need the alias for real or name works?
identicon: chatContentModule.chatDetails.icon,
name: chatContentModule.chatDetails.name,
type: RecipientSelector.Type.Contact
}
}
selectRecipient.selectedType: RecipientSelector.Type.Contact
selectRecipient.readOnly: true
} }
}
Component {
id: cmpReceiveTransaction
ChatCommandModal {
id: receiveTransaction
store: root.rootStore
contactsStore: root.contactsStore
isContact: root.isContact
onClosed: {
destroy()
}
sendChatCommand: root.requestTransaction
isRequested: true
//% "Request"
commandTitle: qsTrId("wallet-request")
header.title: commandTitle
//% "Request"
finalButtonLabel: qsTrId("wallet-request")
selectRecipient.selectedRecipient: {
parentModule.prepareChatContentModuleForChatId(activeChatId)
let chatContentModule = parentModule.getChatContentModule()
return {
address: Constants.zeroAddress, // Setting as zero address since we don't have the address yet
alias: chatContentModule.chatDetails.name, // Do we need the alias for real or name works?
identicon: chatContentModule.chatDetails.icon,
name: chatContentModule.chatDetails.name,
type: RecipientSelector.Type.Contact
}
}
selectRecipient.selectedType: RecipientSelector.Type.Contact
selectRecipient.readOnly: true
}
}
Component {
id: cmpSendTransactionWithEns
SendModal {
id: sendTransactionWithEns
store: root.rootStore
contactsStore: root.contactsStore
onOpened: {
// Not Refactored Yet
// root.rootStore.walletModelInst.gasView.getGasPrice()
}
onClosed: {
destroy()
}
isContact: root.isContact
selectRecipient.readOnly: true
selectRecipient.selectedRecipient: {
parentModule.prepareChatContentModuleForChatId(activeChatId)
let chatContentModule = parentModule.getChatContentModule()
return {
address: "",
alias: chatContentModule.chatDetails.name, // Do we need the alias for real or name works?
identicon: chatContentModule.chatDetails.icon,
name: chatContentModule.chatDetails.name,
type: RecipientSelector.Type.Contact,
ensVerified: true
}
}
selectRecipient.selectedType: RecipientSelector.Type.Contact
}
}
ActivityCenterPopup {
id: activityCenter
height: root.height - 56 * 2 // TODO get screen size // Taken from old code top bar height was fixed there to 56
y: 56
store: root.rootStore
chatSectionModule: root.chatSectionModule
}
// Not Refactored Yet // Not Refactored Yet
// Connections { // Connections {
@ -361,12 +360,12 @@ Item {
// } // }
// } // }
Connections { Connections {
target: systemTray target: systemTray
onMessageClicked: function () { onMessageClicked: function () {
clickOnNotification() clickOnNotification()
}
} }
}
// Not Refactored Yet // Not Refactored Yet
// Connections { // Connections {

View File

@ -302,7 +302,7 @@ ColumnLayout {
} }
} }
MessageStore{ MessageStore {
id: messageStore id: messageStore
messageModule: chatContentModule? chatContentModule.messagesModule : null messageModule: chatContentModule? chatContentModule.messagesModule : null
} }