2023-04-17 09:35:44 +00:00
|
|
|
import QtQuick 2.15
|
|
|
|
import QtQuick.Controls 2.15
|
|
|
|
import QtQuick.Layouts 1.15
|
|
|
|
|
|
|
|
import StatusQ.Core 0.1
|
|
|
|
import StatusQ.Core.Theme 0.1
|
|
|
|
import StatusQ.Controls 0.1
|
|
|
|
import StatusQ.Core.Utils 0.1
|
|
|
|
|
|
|
|
import shared.controls 1.0
|
|
|
|
import shared.controls.delegates 1.0
|
|
|
|
|
|
|
|
StatusDropdown {
|
|
|
|
id: root
|
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
property var selectedKeys: new Set()
|
2023-04-28 09:40:58 +00:00
|
|
|
property bool forceButtonDisabled: false
|
2023-04-17 09:35:44 +00:00
|
|
|
property int maximumListHeight: 288
|
|
|
|
|
|
|
|
property alias model: listView.model
|
|
|
|
readonly property alias count: listView.count
|
|
|
|
|
|
|
|
readonly property alias searchText: filterInput.text
|
|
|
|
|
2023-04-28 09:40:58 +00:00
|
|
|
enum Mode {
|
|
|
|
Add, Update
|
|
|
|
}
|
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
Instantiator {
|
|
|
|
id: selectionChecker
|
|
|
|
|
|
|
|
model: root.model
|
|
|
|
|
|
|
|
property var keys: []
|
|
|
|
|
|
|
|
delegate: QtObject {
|
|
|
|
readonly property string key: model.pubKey
|
|
|
|
}
|
|
|
|
|
|
|
|
readonly property bool allSelected:
|
|
|
|
keys.every(key => root.selectedKeys.has(key))
|
|
|
|
|
|
|
|
onObjectAdded: {
|
|
|
|
const keysCopy = [...keys]
|
|
|
|
keysCopy.splice(index, 0, object.key)
|
|
|
|
keys = keysCopy
|
|
|
|
}
|
|
|
|
|
|
|
|
onObjectRemoved: {
|
|
|
|
const keysCopy = [...keys]
|
|
|
|
keysCopy.splice(index, 1)
|
|
|
|
keys = keysCopy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-28 09:40:58 +00:00
|
|
|
property int mode: MembersDropdown.Mode.Add
|
|
|
|
|
2023-04-17 09:35:44 +00:00
|
|
|
signal backButtonClicked
|
|
|
|
signal addButtonClicked
|
|
|
|
|
|
|
|
width: 295
|
|
|
|
|
|
|
|
padding: 11
|
|
|
|
bottomInset: 10
|
|
|
|
bottomPadding: padding + bottomInset
|
|
|
|
|
2023-04-28 09:40:58 +00:00
|
|
|
onOpened: {
|
|
|
|
listView.positionViewAtBeginning()
|
|
|
|
filterInput.text = ""
|
|
|
|
}
|
2023-04-25 21:24:04 +00:00
|
|
|
|
2023-04-17 09:35:44 +00:00
|
|
|
QtObject {
|
|
|
|
id: d
|
|
|
|
|
|
|
|
readonly property int sectionDelegateHeight: 40
|
|
|
|
readonly property int delegateHeight: 47
|
2023-04-28 09:40:58 +00:00
|
|
|
readonly property int scrollBarWidth: 4
|
2023-04-17 09:35:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
contentItem: ColumnLayout {
|
|
|
|
id: content
|
|
|
|
|
|
|
|
spacing: 8
|
|
|
|
height: root.availableHeight
|
|
|
|
clip: true
|
|
|
|
|
|
|
|
StatusIconTextButton {
|
|
|
|
id: backButton
|
|
|
|
|
|
|
|
Layout.preferredHeight: 48
|
|
|
|
Layout.maximumWidth: root.availableWidth
|
|
|
|
|
|
|
|
spacing: 0
|
|
|
|
leftPadding: 4
|
|
|
|
statusIcon: "previous"
|
|
|
|
icon.width: 12
|
|
|
|
icon.height: 12
|
|
|
|
text: qsTr("Back")
|
|
|
|
|
|
|
|
onClicked: root.backButtonClicked()
|
|
|
|
}
|
|
|
|
|
|
|
|
SearchBox {
|
|
|
|
id: filterInput
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
|
|
|
placeholderText: qsTr("Search members")
|
|
|
|
maximumHeight: 36
|
|
|
|
topPadding: 0
|
|
|
|
bottomPadding: 0
|
|
|
|
|
|
|
|
input.asset.width: 15
|
|
|
|
input.asset.height: 15
|
|
|
|
input.leftPadding: 13
|
|
|
|
input.font.pixelSize: 13
|
|
|
|
input.placeholder.font.pixelSize: 13
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusBaseText {
|
|
|
|
id: noContactsText
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.preferredHeight: 50
|
|
|
|
horizontalAlignment: Text.AlignHCenter
|
|
|
|
verticalAlignment: Text.AlignVCenter
|
|
|
|
|
|
|
|
visible: listView.count === 0
|
|
|
|
|
|
|
|
text: qsTr("No contacts found")
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
font.pixelSize: Theme.tertiaryTextFontSize
|
|
|
|
elide: Text.ElideRight
|
|
|
|
lineHeight: 1.2
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusListView {
|
|
|
|
id: listView
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
Layout.fillHeight: true
|
2023-05-12 12:38:09 +00:00
|
|
|
Layout.preferredHeight: Math.min(contentHeight,
|
|
|
|
root.maximumListHeight)
|
2023-04-17 09:35:44 +00:00
|
|
|
|
2023-04-28 09:40:58 +00:00
|
|
|
verticalScrollBar {
|
|
|
|
implicitWidth: d.scrollBarWidth + ScrollBar.vertical.padding * 2
|
|
|
|
}
|
|
|
|
|
2023-04-17 09:35:44 +00:00
|
|
|
visible: count > 0
|
|
|
|
|
|
|
|
header: StatusCheckBox {
|
|
|
|
width: ListView.view.width
|
|
|
|
|
|
|
|
text: qsTr("Select all")
|
|
|
|
font.weight: Font.Medium
|
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
checked: selectionChecker.allSelected
|
2023-04-17 09:35:44 +00:00
|
|
|
|
|
|
|
leftSide: false
|
|
|
|
size: StatusCheckBox.Size.Small
|
|
|
|
indicator.anchors.rightMargin: 12
|
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
|
|
|
|
onClicked: {
|
2023-05-11 10:44:47 +00:00
|
|
|
const currentKeys = selectionChecker.keys
|
|
|
|
const keysSet = new Set([...root.selectedKeys])
|
2023-04-17 09:35:44 +00:00
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
if (listView.headerItem.checked)
|
|
|
|
currentKeys.forEach(key => keysSet.delete(key))
|
|
|
|
else
|
|
|
|
currentKeys.forEach(key => keysSet.add(key))
|
2023-04-17 09:35:44 +00:00
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
root.selectedKeys = keysSet
|
2023-04-17 09:35:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
delegate: ContactListItemDelegate {
|
|
|
|
id: delegateRoot
|
|
|
|
|
|
|
|
width: ListView.view.width
|
|
|
|
height: d.delegateHeight
|
|
|
|
asset.width: 29
|
|
|
|
asset.height: 29
|
|
|
|
|
|
|
|
rightPadding: 0
|
|
|
|
leftPadding: 6
|
|
|
|
|
|
|
|
color: "transparent"
|
|
|
|
|
|
|
|
onClicked: {
|
2023-05-11 10:44:47 +00:00
|
|
|
const selectedKeysCopy = new Set([...root.selectedKeys])
|
2023-04-17 09:35:44 +00:00
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
if (root.selectedKeys.has(model.pubKey))
|
|
|
|
selectedKeysCopy.delete(model.pubKey)
|
2023-04-17 09:35:44 +00:00
|
|
|
else
|
2023-05-11 10:44:47 +00:00
|
|
|
selectedKeysCopy.add(model.pubKey)
|
2023-04-17 09:35:44 +00:00
|
|
|
|
|
|
|
root.selectedKeys = selectedKeysCopy
|
|
|
|
}
|
|
|
|
|
|
|
|
components: [
|
|
|
|
StatusCheckBox {
|
|
|
|
id: contactCheckbox
|
|
|
|
|
|
|
|
size: StatusCheckBox.Size.Small
|
2023-05-11 10:44:47 +00:00
|
|
|
checked: root.selectedKeys.has(model.pubKey)
|
2023-04-17 09:35:44 +00:00
|
|
|
|
|
|
|
MouseArea {
|
|
|
|
anchors.fill: parent
|
|
|
|
cursorShape: Qt.PointingHandCursor
|
|
|
|
|
|
|
|
onClicked: delegateRoot.clicked(
|
|
|
|
delegateRoot.itemId, mouse)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
section.property: "displayName"
|
|
|
|
section.criteria: ViewSection.FirstCharacter
|
|
|
|
section.delegate: StatusBaseText {
|
|
|
|
text: section.toUpperCase()
|
|
|
|
|
|
|
|
width: ListView.view.width
|
|
|
|
height: d.sectionDelegateHeight
|
|
|
|
|
|
|
|
padding: 5
|
|
|
|
verticalAlignment: Qt.AlignVCenter
|
|
|
|
|
|
|
|
color: Theme.palette.baseColor1
|
|
|
|
font.pixelSize: Theme.tertiaryTextFontSize
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
StatusButton {
|
|
|
|
id: addButton
|
|
|
|
|
|
|
|
Layout.fillWidth: true
|
|
|
|
|
2023-04-28 09:40:58 +00:00
|
|
|
enabled: {
|
|
|
|
if (root.forceButtonDisabled)
|
|
|
|
return false
|
|
|
|
|
|
|
|
if (root.mode === MembersDropdown.Mode.Add)
|
2023-05-11 10:44:47 +00:00
|
|
|
return root.selectedKeys.size > 0
|
2023-04-28 09:40:58 +00:00
|
|
|
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
text: {
|
|
|
|
if (root.mode === MembersDropdown.Mode.Update)
|
|
|
|
return qsTr("Update members")
|
|
|
|
|
2023-05-11 10:44:47 +00:00
|
|
|
return root.selectedKeys.size > 0
|
|
|
|
? qsTr("Add %n member(s)", "", root.selectedKeys.size)
|
2023-04-28 09:40:58 +00:00
|
|
|
: qsTr("Add")
|
|
|
|
}
|
2023-04-17 09:35:44 +00:00
|
|
|
|
|
|
|
onClicked: root.addButtonClicked()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|