status-desktop/storybook/pages/MembersSelectorPage.qml
Jonathan Rainville 50132c5a0e
Refactor contacts models to have a single model, remove useless properties and improve updating (#16667)
* refactor(contacts): refactor 5 contact models into one and filter in QML

Fixes #16549

Refactors the 5 types of contact models (all, mutuals, banned, received and sent) into only the `allContacts` and use an Adaptor on the QML side to filter into the needed models.
This cleans the Nim side a lot and makes applying updates to the contacts' model way simpler.

* chore(contacts): remove useless and duplicated contact properties

OptionalName and isSyncing were never used.
DefaultDisplayName was not really used and is actually a duplication of preferredDisplayName, so I replaced the limited usages of DefaultDisplayName by preferredDisplayName

* refactor(contacts): improve updates by not removing and re-adding

We used to update contact items by removing them from the models and re-adding them. This is highly inefficient.
Instead, the proper way is to update only the values that changed.

* user_model: onItemChanged signal removed

* user_model: sorting by online status no longer needed on nim side

* Chat/RootStore: contactsModel property removed

* ContactsStore encapsulation improved

* ContactsStore: contacts model adaptor moved outside store

---------

Co-authored-by: Michał Cieślak <michalcieslak@status.im>
2024-11-28 09:15:34 -05:00

262 lines
7.3 KiB
QML

import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import AppLayouts.Chat.views 1.0
import AppLayouts.Chat.stores 1.0 as ChatStores
import Storybook 1.0
import utils 1.0
import shared.stores 1.0 as SharedStores
SplitView {
id: root
Logs { id: logs }
property bool globalUtilsReady: false
property bool mainModuleReady: false
QtObject {
function getColorHashAsJson(publicKey) {
return JSON.stringify([{colorId: 0, segmentLength: 1},
{colorId: 19, segmentLength: 2}])
}
function getColorId(publicKey) {
return Math.floor(Math.random() * 10)
}
Component.onCompleted: {
Utils.globalUtilsInst = this
root.globalUtilsReady = true
}
Component.onDestruction: {
root.globalUtilsReady = false
Utils.globalUtilsInst = {}
}
}
QtObject {
function getContactDetailsAsJson() {
return JSON.stringify({
ensVerified: false,
isCurrentUser: false,
contactRequestState: Constants.ContactRequestState.Mutual
})
}
Component.onCompleted: {
Utils.mainModuleInst = this
root.mainModuleReady = true
}
Component.onDestruction: {
root.mainModuleReady = false
Utils.mainModuleInst = {}
}
}
ListModel {
id: contacts
Component.onCompleted: {
for(let i=0; i < 20; i++) {
append(usersModelEditor.getNewUser(i))
}
}
}
ChatStores.RootStore {
id: rootStoreMock
readonly property var contactsStore: QtObject {
readonly property var mainModuleInst: null
}
function amIChatAdmin() {
return chatAdminSwitch.checked
}
}
ChatStores.UsersStore {
id: usersStoreMock
readonly property var usersModel: ListModel {
Component.onCompleted: {
for(let i=0; i < 4; i++) {
append(d.createMemberDict(i))
}
}
}
readonly property var temporaryModel: ListModel {
Component.onCompleted: usersStoreMock.resetTemporaryModel()
}
function appendTemporaryModel(pubKey, displayName) {
temporaryModel.append({
pubKey: pubKey,
displayName: displayName,
})
}
function removeFromTemporaryModel(pubKey) {
for(let i = 0; i < temporaryModel.count; i++) {
if (temporaryModel.get(i).pubKey === pubKey) {
temporaryModel.remove(i, 1)
return
}
}
}
function resetTemporaryModel() {
temporaryModel.clear()
for(let i = 0; i < usersModel.count; i++) {
const obj = usersModel.get(i)
temporaryModel.append(obj)
}
}
function updateGroupMembers() {
const users = []
for(let i = 0; i < temporaryModel.count; i++) {
const obj = temporaryModel.get(i)
users.push({
pubKey: obj.pubKey,
compressedPubKey: "compressed_" + obj.pubKey,
displayName: obj.displayName,
localNickname: "",
alias: "three word name(%1)".arg(obj.pubKey),
isVerified: false,
isUntrustworthy: false,
isContact: true,
icon: "",
color: "red",
onlineStatus: 0,
isAdmin: i == 0 ? true : false
})
}
usersModel.clear()
usersModel.append(users)
logs.logEvent("UsersStore::updateGroupMembers")
}
}
QtObject {
id: d
function createMemberDict(seed: int) {
var member = usersModelEditor.getNewUser(seed)
member["isAdmin"] = seed === 0
return member
}
}
SplitView {
orientation: Qt.Vertical
SplitView.fillWidth: true
SplitView.fillHeight: true
SwipeView {
id: swipeView
SplitView.fillWidth: true
SplitView.fillHeight: true
interactive: false
currentIndex: selectorsSwitch.checked
Item {
Loader {
active: root.globalUtilsReady && root.mainModuleReady
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 64
}
sourceComponent: MembersSelectorView {
rootStore: rootStoreMock
utilsStore: SharedStores.UtilsStore {
function isChatKey() {
return true
}
function isCompressedPubKey(publicKey) {
return true
}
}
contactsModel: contacts
}
}
}
Item {
Loader {
active: root.globalUtilsReady && root.mainModuleReady
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: 64
}
sourceComponent: MembersEditSelectorView {
rootStore: rootStoreMock
usersStore: usersStoreMock
contactsModel: contacts
}
}
}
}
LogsAndControlsPanel {
id: logsAndControlsPanel
SplitView.minimumHeight: 100
SplitView.preferredHeight: 200
logsView.logText: logs.logText
ColumnLayout {
Switch {
id: selectorsSwitch
text: "members editor"
}
Switch {
id: chatAdminSwitch
visible: selectorsSwitch.checked
text: "chat admin"
onCheckedChanged: usersStore.resetTemporaryModel()
}
}
}
}
Pane {
SplitView.minimumWidth: 300
SplitView.preferredWidth: 300
UsersModelEditor {
id: usersModelEditor
anchors.fill: parent
model: contacts
onRemoveClicked: contacts.remove(index, 1)
onRemoveAllClicked: contacts.clear()
onAddClicked: contacts.append(usersModelEditor.getNewUser(contacts.count))
}
}
}
// category: Components