status-desktop/ui/app/AppLayouts/Wallet/panels/SearchableCollectiblesPanel...

236 lines
7.0 KiB
QML

import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15
import StatusQ 0.1
import StatusQ.Controls 0.1
import StatusQ.Core 0.1
import StatusQ.Core.Utils 0.1
import StatusQ.Popups.Dialog 0.1
import AppLayouts.Wallet.views 1.0
import utils 1.0
import SortFilterProxyModel 0.2
/**
Panel holding search field and two-levels list of collectibles.
*/
Control {
id: root
/**
Expected model structure:
groupName [string] - group name
icon [url] - icon image of a group
type [string] - group type, can be "community" or "other"
subitems [model] - submodel of collectibles/collections of the group
key [string] - balance
name [string] - name of the subitem
balance [int] - balance of the subitem
icon [url] - icon of the subitem
**/
property alias model: sfpm.sourceModel
signal collectionSelected(string key)
signal collectibleSelected(string key)
property string highlightedKey: ""
readonly property alias currentItem: collectiblesStackView.currentItem
SortFilterProxyModel {
id: sfpm
filters: SearchFilter {
roleName: "groupName"
searchPhrase: collectiblesSearchBox.text
}
}
contentItem: StackView {
id: collectiblesStackView
implicitHeight: currentItem.implicitHeight
initialItem: ColumnLayout {
spacing: 0
TokenSearchBox {
id: collectiblesSearchBox
objectName: "collectiblesSearchBox"
Layout.fillWidth: true
placeholderText: qsTr("Search collectibles")
}
StatusDialogDivider {
Layout.fillWidth: true
visible: collectiblesListView.count
}
StatusListView {
id: collectiblesListView
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: contentHeight
clip: true
model: sfpm
delegate: TokenSelectorCollectibleDelegate {
required property var model
readonly property int subitemsCount:
model.subitems.ModelCount.count
readonly property bool isCommunity:
model.type === "community"
readonly property bool showCount:
subitemsCount > 1 || isCommunity
name: model.groupName
balance: showCount ? subitemsCount : ""
image: model.icon
goDeeperIconVisible: subitemsCount > 1
|| isCommunity
highlighted: subitemsCount === 1 && !isCommunity
? ModelUtils.get(model.subitems, 0, "key")
=== root.highlightedKey
: false
onClicked: {
if (subitemsCount === 1 && !isCommunity) {
const key = ModelUtils.get(model.subitems, 0, "key")
root.collectibleSelected(key)
return
}
const parameters = {
index: sfpm.index(model.index, 0),
model: model.subitems,
isCommunity: isCommunity
}
collectiblesStackView.push(
collectiblesSublistComponent,
parameters,
StackView.Immediate)
}
}
section.property: "type"
section.delegate: TokenSelectorSectionDelegate {
width: ListView.view.width
text: section === "community"
? qsTr("Community minted")
: qsTr("Other")
}
}
}
}
Component {
id: collectiblesSublistComponent
ColumnLayout {
property var index
property alias model: sublistSfpm.sourceModel
property bool isCommunity
spacing: 0
SortFilterProxyModel {
id: sublistSfpm
filters: SearchFilter {
roleName: "name"
searchPhrase: collectiblesSublistSearchBox.text
}
}
StatusIconTextButton {
id: backButton
statusIcon: "previous"
icon.width: 12
icon.height: 12
text: qsTr("Back")
horizontalPadding: 21
bottomPadding: Style.current.halfPadding
onClicked: collectiblesStackView.pop(StackView.Immediate)
}
StatusDialogDivider {
Layout.fillWidth: true
visible: collectiblesListView.count
}
TokenSearchBox {
id: collectiblesSublistSearchBox
Layout.fillWidth: true
placeholderText: qsTr("Search collectibles")
}
StatusDialogDivider {
Layout.fillWidth: true
visible: collectiblesListView.count
}
StatusListView {
id: sublist
Layout.fillWidth: true
Layout.fillHeight: true
Layout.preferredHeight: contentHeight
model: sublistSfpm
clip: true
delegate: TokenSelectorCollectibleDelegate {
required property var model
name: model.name
balance: model.balance > 1 ? model.balance : ""
image: model.icon
goDeeperIconVisible: false
highlighted: model.key === root.highlightedKey
onClicked: {
if (isCommunity)
root.collectionSelected(model.key)
else
root.collectibleSelected(model.key)
}
}
}
// Detection if the related model entry has been removed.
// Using model.Component.destruction.connect is not reliable because
// is not called for submodels maintained in c++ by the parent model.
ItemSelectionModel {
id: selection
model: sfpm
onHasSelectionChanged: {
if (!hasSelection)
collectiblesStackView.pop(StackView.Immediate)
}
Component.onCompleted: select(index, ItemSelectionModel.Select)
}
}
}
}