performance(ChannelsSelectionModel): Use LeftJoinModel for ChannelsSelectionModel.qml

Motivation:
ChannelsSelectionModel.qml is freezing the app when used with a live channel that's being edited because on each channel change the selection model is re-created.

The fix for this is to use the LeftJoinModel to unify the channels selection (a light model containing only keys) and the full channels model containing the channels data. On top of this, the SortFilterProxyModel is added to decorate the model with the roles expected in the UI. Another improvement is by replacing the ExpressionRole with the FastExpressionRole.
This commit is contained in:
Alex Jbanca 2024-01-16 14:05:36 +02:00 committed by Alex Jbanca
parent 29f1bee218
commit 942482fe99
3 changed files with 36 additions and 48 deletions

View File

@ -3,71 +3,60 @@ import SortFilterProxyModel 0.2
import StatusQ.Core.Utils 0.1
import StatusQ.Core.Theme 0.1
import StatusQ 0.1
import utils 1.0
SortFilterProxyModel {
property var channelsModel
id: root
readonly property QtObject _d: QtObject {
id: d
property var selectedChannels
property var allChannels
readonly property ModelChangeTracker tracker: ModelChangeTracker {
model: channelsModel
onRevisionChanged: {
const metadata = new Map()
const count = channelsModel.rowCount()
for (let i = 0; i < count; i++) {
const item = ModelUtils.get(channelsModel, i)
const text = "#" + item.name
const imageSource = item.icon
const emoji = item.emoji
const color = !!item.color ? item.color
: Theme.palette.userCustomizationColors[item.colorId]
metadata.set(item.itemId, { text, imageSource, emoji, color })
sourceModel: LeftJoinModel {
readonly property var channelsModelAlignedKey: SortFilterProxyModel {
sourceModel: root.allChannels
proxyRoles: [
FastExpressionRole {
name: "key"
expression: model.itemId ?? ""
expectedRoles: ["itemId"]
}
d.metadata = metadata
}
onModelChanged: revisionChanged()
}
property var metadata: new Map()
function get(key, role) {
const item = metadata.get(key)
return !!item ? item[role] : ""
]
}
leftModel: root.selectedChannels
rightModel: channelsModelAlignedKey
joinRole: "key"
}
proxyRoles: [
ExpressionRole {
FastExpressionRole {
name: "text"
expression: d.get(model.key, name)
expression: "#" + model.name
expectedRoles: ["name"]
},
ExpressionRole {
FastExpressionRole {
name: "imageSource"
expression: d.get(model.key, name)
expression: model.icon
expectedRoles: ["icon"]
},
ExpressionRole {
name: "emoji"
expression: d.get(model.key, name)
},
ExpressionRole {
FastExpressionRole {
function getColor(color, colorId) {
return !!color ? color
: Theme.palette.userCustomizationColors[colorId]
}
name: "color"
expression: d.get(model.key, name)
expression: getColor(model.color, model.colorId)
expectedRoles: ["color", "colorId"]
},
ExpressionRole {
FastExpressionRole {
name: "operator"
// Direct call for singleton enum is not handled properly by SortFilterProxyModel.
readonly property int none: OperatorsUtils.Operators.None
expression: none
expectedRoles: []
}
]
}

View File

@ -513,9 +513,8 @@ StatusScrollView {
ChannelsSelectionModel {
id: channelsSelectionModel
sourceModel: d.dirtyValues.selectedChannelsModel
channelsModel: root.channelsModel
selectedChannels: d.dirtyValues.selectedChannelsModel
allChannels: root.channelsModel
}
InDropdown {

View File

@ -90,8 +90,8 @@ StatusScrollView {
ChannelsSelectionModel {
id: channelsSelectionModel
sourceModel: model.channelsListModel ?? null
channelsModel: root.channelsModel
selectedChannels: model.channelsListModel ?? null
allChannels: root.channelsModel
}
channelsListModel: channelsSelectionModel.count