import QtQuick 2.14 import QtQuick.Layouts 1.14 import QtQuick.Controls 2.14 import StatusQ.Core 0.1 import StatusQ.Core.Theme 0.1 import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import SortFilterProxyModel 0.2 import utils 1.0 import shared.controls 1.0 /*! \qmltype TokenHoldersList \inherits StatusListView \brief Shows list of users or addresses with corrensponding numbers of messages and holding amounts. Expected roles: name, walletAddress, imageSource, amount */ Item { id: root implicitHeight: (listView.contentHeight+header.height+12)//initial height plus top margin property alias model: listView.model property bool isSelectorMode: false readonly property alias sortBy: d.sortBy readonly property alias sortOrder: d.sorting readonly property bool bottomSeparatorVisible: ((listView.contentY > 0) && (listView.contentY < (listView.contentHeight - listView.height - 40/*margins*/))) signal selfDestructAmountChanged(string walletAddress, int amount) signal selfDestructRemoved(string walletAddress) QtObject { id: d property int sortBy: TokenHoldersProxyModel.SortBy.None property int sorting: Qt.DescendingOrder property var selectedTokenAmount: new Map(); property var selectedTokenChecked: new Map(); property int delegateHeight: 64 signal resetOtherHeaders(var header) } clip: true Control { id: header width: parent.width height: 40 readonly property alias usernameHeaderWidth: usernameHeader.width readonly property alias holdingHeaderWidth: holdingHeader.width background: Rectangle { id: scrollingSeparator width: parent.width height: 4 anchors.bottom: parent.bottom color: Theme.palette.baseColor2 visible: (listView.contentY > 0) } contentItem: Item { anchors.fill: parent anchors.leftMargin: Style.current.padding anchors.rightMargin: Style.current.padding clip: true RowLayout { id: row anchors.fill: parent spacing: Style.current.padding RowLayout { id: usernameHeader ColumnHeader { text: qsTr("Username") traversalOrder: [ StatusSortableColumnHeader.Sorting.NoSorting, StatusSortableColumnHeader.Sorting.Ascending, StatusSortableColumnHeader.Sorting.Descending ] onClicked: { if (sorting !== StatusSortableColumnHeader.Sorting.NoSorting) d.sortBy = TokenHoldersProxyModel.SortBy.Username else d.sortBy = TokenHoldersProxyModel.SortBy.None } } Item { Layout.fillWidth: true } } ColumnHeader { id: holdingHeader text: qsTr("Hodling") onClicked: { if (sorting !== StatusSortableColumnHeader.Sorting.NoSorting) d.sortBy = TokenHoldersProxyModel.SortBy.Holding else d.sortBy = TokenHoldersProxyModel.SortBy.None } } Item { Layout.preferredWidth: 233 Layout.rightMargin: Style.current.halfPadding } } } } StatusListView { id: listView anchors.fill: parent anchors.topMargin: header.height currentIndex: -1 component ColumnHeader: StatusSortableColumnHeader { id: columnHeader leftPadding: 0 rightPadding: 0 Connections { target: d function onResetOtherHeaders(header) { if (header !== columnHeader) columnHeader.reset() } } onClicked: { d.resetOtherHeaders(this) if (sorting === StatusSortableColumnHeader.Sorting.Ascending) d.sorting = Qt.AscendingOrder else if (sorting === StatusSortableColumnHeader.Sorting.Descending) d.sorting = Qt.DescendingOrder } } component NumberCell: StatusBaseText { horizontalAlignment: Qt.AlignRight font.weight: Font.Medium font.pixelSize: 13 color: Theme.palette.baseColor1 elide: Qt.ElideRight } delegate: ItemDelegate { id: delegate width: ListView.view.width height: d.delegateHeight padding: 0 readonly property string name: model.name readonly property bool isFirstRowAddress: { if (model.name !== "") return false const item = listView.itemAtIndex(index - 1) return item && item.name } readonly property bool showSeparator: isFirstRowAddress && root.sortBy === TokenHoldersProxyModel.SortBy.Username background: Item { Rectangle { anchors.fill: parent radius: Style.current.radius color: (delegate.hovered || delegate.ListView.isCurrentItem) ? Theme.palette.baseColor2 : "transparent" } Rectangle { visible: delegate.showSeparator anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right anchors.topMargin: delegate.topPadding / 2 height: 1 color: Theme.palette.baseColor2 } } contentItem: Item { anchors.left: parent.left anchors.right: parent.right anchors.leftMargin: Style.current.padding anchors.rightMargin: Style.current.padding RowLayout { spacing: Style.current.halfPadding StatusListItem { readonly property bool unknownHolder: model.name === "" readonly property string formattedTitle: unknownHolder ? "?" : model.name Layout.preferredWidth: header.usernameHeaderWidth color: "transparent" leftPadding: 0 rightPadding: 0 sensor.enabled: false title: formattedTitle statusListItemTitle.visible: !unknownHolder subTitle: Utils.getElidedPk(model.walletAddress) asset.name: model.imageSource asset.isImage: true asset.isLetterIdenticon: !asset.name asset.color: Theme.palette.getColor("red2") } NumberCell { Layout.preferredWidth: header.holdingHeaderWidth Layout.leftMargin: Style.current.halfPadding text: LocaleUtils.numberToLocaleString(model.amount) } Item { Layout.preferredWidth: 100 } StatusComboBox { id: combo Layout.preferredWidth: 68 Layout.preferredHeight: 44 control.spacing: Style.current.halfPadding / 2 model: amount size: StatusComboBox.Size.Small type: StatusComboBox.Type.Secondary delegate: StatusItemDelegate { width: combo.control.width centerTextHorizontally: true highlighted: combo.control.highlightedIndex === index font: combo.control.font text: Number(modelData) + 1 } contentItem: StatusBaseText { id: comboText font: combo.control.font verticalAlignment: Text.AlignVCenter elide: Text.ElideRight color: Theme.palette.baseColor1 Component.onCompleted: { if (d.selectedTokenAmount.get(walletAddress) === undefined) { d.selectedTokenAmount.set(walletAddress, amount); } text = d.selectedTokenAmount.get(walletAddress); } } control.onActivated: { d.selectedTokenAmount.set(walletAddress, (index+1)); comboText.text = d.selectedTokenAmount.get(walletAddress); if (checkBox.checked) { root.selfDestructAmountChanged(walletAddress, d.selectedTokenAmount.get(walletAddress)) } } } Item { Layout.preferredWidth: 28 } StatusCheckBox { id: checkBox Layout.preferredWidth: 24 Layout.preferredHeight: 24 Layout.alignment: Qt.AlignRight visible: root.isSelectorMode padding: 0 onCheckStateChanged: { if (checked) root.selfDestructAmountChanged(model.walletAddress, d.selectedTokenAmount.get(walletAddress)) else root.selfDestructRemoved(model.walletAddress) d.selectedTokenChecked.set(walletAddress, checked); } Component.onCompleted: { checked = !!d.selectedTokenChecked.get(walletAddress); } } } } } } }