Patryk Osmaczko f9b3f91bf1 fix(@desktop/chat): sort users by online status
Users model has to be sorted by online status first, otherwise
`UserListPanel` sections will be duplicated. That's because:

> Note: Adding sections to a ListView does not automatically re-order
the list items by the section criteria. If the model is not ordered by
section, then it is possible that the sections created will not be
unique; each boundary between differing sections will result in a
section header being created even if that section exists elsewhere.

fixes: #6563
2022-07-22 09:03:57 +02:00

137 lines
4.7 KiB
QML

import QtQuick 2.13
import QtQuick.Controls 2.13
import StatusQ.Core 0.1
import StatusQ.Core.Theme 0.1
import StatusQ.Components 0.1
import shared 1.0
import shared.panels 1.0
import shared.status 1.0
import utils 1.0
import "../controls"
import SortFilterProxyModel 0.2
Item {
id: root
anchors.fill: parent
// Important:
// Each chat/channel has its own ChatContentModule and each ChatContentModule has a single usersModule
// usersModule on the backend contains everything needed for this component
property var usersModule
property var messageContextMenu
property string label
property var rootStore
StatusBaseText {
id: titleText
anchors.top: parent.top
anchors.topMargin: Style.current.padding
anchors.left: parent.left
anchors.leftMargin: Style.current.padding
opacity: (root.width > 58) ? 1.0 : 0.0
visible: (opacity > 0.1)
font.pixelSize: Style.current.primaryTextFontSize
font.weight: Font.Medium
color: Theme.palette.directColor1
text: root.label
}
StatusListView {
id: userListView
anchors {
top: titleText.bottom
topMargin: Style.current.padding
left: parent.left
right: parent.right
bottom: parent.bottom
bottomMargin: Style.current.bigPadding
}
model: SortFilterProxyModel {
sourceModel: usersModule.model
sorters: [
RoleSorter {
roleName: "onlineStatus"
sortOrder: Qt.DescendingOrder
},
StringSorter {
roleName: "displayName"
caseSensitivity: Qt.CaseInsensitive
}
]
}
section.property: "onlineStatus"
section.delegate: (root.width > 58) ? sectionDelegateComponent : null
delegate: StatusMemberListItem {
anchors.left: parent.left
anchors.leftMargin: 8
anchors.right: parent.right
anchors.rightMargin: 8
nickName: model.localNickname
userName: model.displayName
pubKey: Utils.getCompressedPk(model.pubKey)
isContact: model.isContact
isVerified: model.isVerified
isUntrustworthy: model.isUntrustworthy
isAdmin: model.isAdmin
image.source: {
if ((!model.isContact &&
Global.privacyModuleInst.profilePicturesVisibility !==
Constants.profilePicturesVisibility.everyone)) {
return "";
}
return model.icon;
}
image.isIdenticon: false
status: model.onlineStatus
icon.color: Theme.palette.userCustomizationColors[Utils.colorIdForPubkey(model.pubKey)] // FIXME: use model.colorId
ringSettings.ringSpecModel: Utils.getColorHashAsJson(model.pubKey) // FIXME: use model.colorHash
onClicked: {
if (mouse.button === Qt.RightButton) {
// Set parent, X & Y positions for the messageContextMenu
messageContextMenu.parent = this
messageContextMenu.setXPosition = function() { return 0; }
messageContextMenu.setYPosition = function() { return mouse.y + (Style.current.halfPadding/2); }
messageContextMenu.isProfile = true
messageContextMenu.myPublicKey = userProfile.pubKey
messageContextMenu.selectedUserPublicKey = model.pubKey
messageContextMenu.selectedUserDisplayName = model.displayName
messageContextMenu.selectedUserIcon = image.source
messageContextMenu.popup()
} else if (mouse.button === Qt.LeftButton && !!messageContextMenu) {
Global.openProfilePopup(model.pubKey);
}
}
}
}
Component {
id: sectionDelegateComponent
Item {
width: parent.width
height: 24
StyledText {
anchors.fill: parent
anchors.leftMargin: Style.current.padding
verticalAlignment: Text.AlignVCenter
font.pixelSize: Style.current.additionalTextSize
color: Theme.palette.baseColor1
text: {
switch(parseInt(section)) {
case Constants.onlineStatus.online:
return qsTr("Online")
default:
return qsTr("Inactive")
}
}
}
}
}
}