feat(CommunityMintTokens): added sortable token holders list component
This commit is contained in:
parent
d479077e60
commit
9f73d874c2
|
@ -1,4 +1,4 @@
|
||||||
import QtQuick 2.14
|
import QtQuick 2.15
|
||||||
|
|
||||||
ListModel {
|
ListModel {
|
||||||
ListElement {
|
ListElement {
|
||||||
|
@ -125,6 +125,10 @@ ListModel {
|
||||||
title: "TokenHoldersPanel"
|
title: "TokenHoldersPanel"
|
||||||
section: "Panels"
|
section: "Panels"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "SortableTokenHoldersPanel"
|
||||||
|
section: "Panels"
|
||||||
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "ProfileSocialLinksPanel"
|
title: "ProfileSocialLinksPanel"
|
||||||
section: "Panels"
|
section: "Panels"
|
||||||
|
@ -309,6 +313,10 @@ ListModel {
|
||||||
title: "StatusChatListItem"
|
title: "StatusChatListItem"
|
||||||
section: "Components"
|
section: "Components"
|
||||||
}
|
}
|
||||||
|
ListElement {
|
||||||
|
title: "SortableTokenHoldersList"
|
||||||
|
section: "Components"
|
||||||
|
}
|
||||||
ListElement {
|
ListElement {
|
||||||
title: "BrowserSettings"
|
title: "BrowserSettings"
|
||||||
section: "Settings"
|
section: "Settings"
|
||||||
|
|
|
@ -47,6 +47,10 @@ SplitView {
|
||||||
chainIcon: ModelsData.networks.ethereum
|
chainIcon: ModelsData.networks.ethereum
|
||||||
accountName: "helloworld"
|
accountName: "helloworld"
|
||||||
|
|
||||||
|
tokenOwnersModel: TokenHoldersModel {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
onMintCollectible: logs.logEvent("CommunityTokenView::onMintCollectible: \n"
|
onMintCollectible: logs.logEvent("CommunityTokenView::onMintCollectible: \n"
|
||||||
+ "artworkSource: " + artworkSource + "\n"
|
+ "artworkSource: " + artworkSource + "\n"
|
||||||
+ "name: " + name + "\n"
|
+ "name: " + name + "\n"
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import AppLayouts.Chat.panels.communities 1.0
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
import Models 1.0
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
Logs { id: logs }
|
||||||
|
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
|
||||||
|
TokenHoldersModel {
|
||||||
|
id: tokenHoldersModel
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
SortableTokenHoldersList {
|
||||||
|
id: holdersList
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 50
|
||||||
|
|
||||||
|
model: TokenHoldersProxyModel {
|
||||||
|
sourceModel: tokenHoldersModel
|
||||||
|
|
||||||
|
sortBy: holdersList.sortBy
|
||||||
|
sortOrder: holdersList.sorting === SortableTokenHoldersList.Sorting.Descending
|
||||||
|
? Qt.DescendingOrder : Qt.AscendingOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: logs.logEvent("holdersList.clicked: " + index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsAndControlsPanel {
|
||||||
|
id: logsAndControlsPanel
|
||||||
|
|
||||||
|
SplitView.minimumHeight: 100
|
||||||
|
SplitView.preferredHeight: 200
|
||||||
|
|
||||||
|
logsView.logText: logs.logText
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
|
||||||
|
import AppLayouts.Chat.panels.communities 1.0
|
||||||
|
|
||||||
|
import Storybook 1.0
|
||||||
|
import Models 1.0
|
||||||
|
|
||||||
|
SplitView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
Logs { id: logs }
|
||||||
|
|
||||||
|
orientation: Qt.Vertical
|
||||||
|
|
||||||
|
Item {
|
||||||
|
SplitView.fillWidth: true
|
||||||
|
SplitView.fillHeight: true
|
||||||
|
|
||||||
|
SortableTokenHoldersPanel {
|
||||||
|
id: holdersPanel
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 568
|
||||||
|
tokenName: "Aniversary"
|
||||||
|
|
||||||
|
TokenHoldersModel {
|
||||||
|
id: tokenHoldersModel
|
||||||
|
}
|
||||||
|
|
||||||
|
ListModel {
|
||||||
|
id: emptyModel
|
||||||
|
}
|
||||||
|
|
||||||
|
model: emptyCheckBox.checked ? emptyModel : tokenHoldersModel
|
||||||
|
showRemotelyDestructMenuItem: remotelyDestructCheckBox.checked
|
||||||
|
|
||||||
|
onViewProfileRequested:
|
||||||
|
logs.logEvent("onViewProfileRequested: " + address)
|
||||||
|
onViewMessagesRequested:
|
||||||
|
logs.logEvent("onViewMessagesRequested: " + address)
|
||||||
|
onAirdropRequested:
|
||||||
|
logs.logEvent("onAirdropRequested: " + address)
|
||||||
|
onRemoteDestructRequested:
|
||||||
|
logs.logEvent("onRemoteDestructRequested: " + address)
|
||||||
|
onKickRequested:
|
||||||
|
logs.logEvent("onKickRequested: " + address)
|
||||||
|
onBanRequested:
|
||||||
|
logs.logEvent("onBanRequested: " + address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LogsAndControlsPanel {
|
||||||
|
id: logsAndControlsPanel
|
||||||
|
|
||||||
|
SplitView.minimumHeight: 100
|
||||||
|
SplitView.preferredHeight: 200
|
||||||
|
|
||||||
|
logsView.logText: logs.logText
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
CheckBox {
|
||||||
|
id: emptyCheckBox
|
||||||
|
|
||||||
|
text: "Empty"
|
||||||
|
}
|
||||||
|
CheckBox {
|
||||||
|
id: remotelyDestructCheckBox
|
||||||
|
|
||||||
|
checked: true
|
||||||
|
text: "Show \"Remotely Destruct\" menu item"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,30 +5,49 @@ ListModel {
|
||||||
readonly property string image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
|
readonly property string image: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAlklEQVR4nOzW0QmDQBAG4SSkl7SUQlJGCrElq9F3QdjjVhh/5nv3cFhY9vUIYQiNITSG0BhCExPynn1gWf9bx498P7/
|
||||||
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
|
nzPcxEzGExhBdJGYihtAYQlO+tUZvqrPbqeudo5iJGEJjCE15a3VtodH3q2ImYgiNITTlTdG1nUZ5a92VITQxITFiJmIIjSE0htAYQrMHAAD//+wwFVpz+yqXAAAAAElFTkSuQmCC"
|
||||||
readonly property var data: [
|
readonly property var data: [
|
||||||
{
|
|
||||||
name: "carmen.eth",
|
|
||||||
walletAddress: "0xb794f5450ba39494ce839613fffba74279579261",
|
|
||||||
imageSource: image,
|
|
||||||
amount: 15
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: "chris.eth",
|
name: "chris.eth",
|
||||||
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579262",
|
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579262",
|
||||||
imageSource: image,
|
imageSource: image,
|
||||||
amount: 5
|
amount: 5,
|
||||||
|
noOfMessages: 3123
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "carmen.eth",
|
||||||
|
walletAddress: "0xb794f5450ba39494ce839613fffba74279579261",
|
||||||
|
imageSource: image,
|
||||||
|
amount: 15,
|
||||||
|
noOfMessages: 123
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "emily.eth",
|
name: "emily.eth",
|
||||||
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579263",
|
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579263",
|
||||||
imageSource: image,
|
imageSource: image,
|
||||||
amount: 2
|
amount: 2,
|
||||||
|
noOfMessages: 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579268",
|
walletAddress: "0xb794f5ea0ba39494ce839613fffba74279579268",
|
||||||
imageSource: "",
|
imageSource: "",
|
||||||
amount: 1
|
amount: 1,
|
||||||
|
noOfMessages: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
walletAddress: "0xc794f5ea0ba39494ce839613fffba74279579268",
|
||||||
|
imageSource: "",
|
||||||
|
amount: 11,
|
||||||
|
noOfMessages: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "",
|
||||||
|
walletAddress: "0xd794f5ea0ba39494ce839613fffba74279579268",
|
||||||
|
imageSource: "",
|
||||||
|
amount: 14,
|
||||||
|
noOfMessages: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
Component.onCompleted: append(data)
|
Component.onCompleted: append(data)
|
||||||
|
|
|
@ -0,0 +1,273 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Components 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1 as StatusQUtils
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\qmltype SortableTokenHoldersList
|
||||||
|
\inherits StatusListView
|
||||||
|
\brief Shows list of users or addresses with corrensponding numbers of
|
||||||
|
messages and holding amounts.
|
||||||
|
|
||||||
|
Expected roles: name, walletAddress, imageSource, noOfMessages, amount
|
||||||
|
*/
|
||||||
|
StatusListView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
enum SortBy {
|
||||||
|
None, Username, NoOfMessages, Holding
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Sorting {
|
||||||
|
Descending, Ascending
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property alias sortBy: d.sortBy
|
||||||
|
readonly property alias sorting: d.sorting
|
||||||
|
|
||||||
|
signal clicked(int index, var parent, var mouse)
|
||||||
|
|
||||||
|
currentIndex: -1
|
||||||
|
|
||||||
|
component ColumnHeader: StatusSortableColumnHeader {
|
||||||
|
id: columnHeader
|
||||||
|
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 4
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: d
|
||||||
|
|
||||||
|
function onResetOtherHeaders(header) {
|
||||||
|
if (header !== columnHeader)
|
||||||
|
columnHeader.reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
d.resetOtherHeaders(this)
|
||||||
|
|
||||||
|
if (sorting === StatusSortableColumnHeader.Sorting.Ascending)
|
||||||
|
d.sorting = SortableTokenHoldersList.Sorting.Ascending
|
||||||
|
else if (sorting === StatusSortableColumnHeader.Sorting.Descending)
|
||||||
|
d.sorting = SortableTokenHoldersList.Sorting.Descending
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component NumberCell: StatusBaseText {
|
||||||
|
horizontalAlignment: Qt.AlignRight
|
||||||
|
|
||||||
|
font.weight: Font.Medium
|
||||||
|
font.pixelSize: 13
|
||||||
|
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
elide: Qt.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
property int sortBy: SortableTokenHoldersList.SortBy.None
|
||||||
|
property int sorting: SortableTokenHoldersList.Sorting.Descending
|
||||||
|
|
||||||
|
readonly property int red2Color: 4
|
||||||
|
|
||||||
|
signal resetOtherHeaders(var header)
|
||||||
|
}
|
||||||
|
|
||||||
|
header: ItemDelegate {
|
||||||
|
width: ListView.view.width
|
||||||
|
|
||||||
|
padding: 0
|
||||||
|
horizontalPadding: Style.current.padding
|
||||||
|
|
||||||
|
readonly property alias usernameHeaderWidth: usernameHeader.width
|
||||||
|
readonly property alias noOfMessagesHeaderWidth: noOfMessagesHeader.width
|
||||||
|
readonly property alias holdingHeaderWidth: holdingHeader.width
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
id: row
|
||||||
|
|
||||||
|
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 = SortableTokenHoldersList.SortBy.Username
|
||||||
|
else
|
||||||
|
d.sortBy = SortableTokenHoldersList.SortBy.None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnHeader {
|
||||||
|
id: noOfMessagesHeader
|
||||||
|
|
||||||
|
text: qsTr("No. of messages")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (sorting !== StatusSortableColumnHeader.Sorting.NoSorting)
|
||||||
|
d.sortBy = SortableTokenHoldersList.SortBy.NoOfMessages
|
||||||
|
else
|
||||||
|
d.sortBy = SortableTokenHoldersList.SortBy.None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: holdingHeader
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.preferredWidth: 25
|
||||||
|
}
|
||||||
|
|
||||||
|
ColumnHeader {
|
||||||
|
text: qsTr("Hodling")
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (sorting !== StatusSortableColumnHeader.Sorting.NoSorting)
|
||||||
|
d.sortBy = SortableTokenHoldersList.SortBy.Holding
|
||||||
|
else
|
||||||
|
d.sortBy = SortableTokenHoldersList.SortBy.None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: ItemDelegate {
|
||||||
|
id: delegate
|
||||||
|
|
||||||
|
padding: 0
|
||||||
|
horizontalPadding: Style.current.padding
|
||||||
|
|
||||||
|
topPadding: showSeparator ? 10 : 0
|
||||||
|
|
||||||
|
readonly property string name: model.name
|
||||||
|
|
||||||
|
readonly property bool isFirstRowAddress: {
|
||||||
|
if (model.name !== "")
|
||||||
|
return false
|
||||||
|
|
||||||
|
const item = root.itemAtIndex(index - 1)
|
||||||
|
return item && item.name
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property bool showSeparator: isFirstRowAddress
|
||||||
|
&& root.sortBy === SortableTokenHoldersList.SortBy.Username
|
||||||
|
|
||||||
|
width: ListView.view.width
|
||||||
|
|
||||||
|
background: Item {
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
anchors.topMargin: delegate.topPadding
|
||||||
|
|
||||||
|
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 {
|
||||||
|
implicitWidth: delegateRow.implicitWidth
|
||||||
|
implicitHeight: delegateRow.implicitHeight
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: delegateRow
|
||||||
|
|
||||||
|
spacing: Style.current.padding
|
||||||
|
|
||||||
|
StatusListItem {
|
||||||
|
id: listItem
|
||||||
|
|
||||||
|
readonly property bool unknownHolder: model.name === ""
|
||||||
|
readonly property string formattedTitle: unknownHolder
|
||||||
|
? "?" : model.name
|
||||||
|
|
||||||
|
readonly property string addressElided:
|
||||||
|
StatusQUtils.Utils.elideText(
|
||||||
|
model.walletAddress, 6, 3).replace("0x", "0×")
|
||||||
|
|
||||||
|
Layout.preferredWidth: root.headerItem.usernameHeaderWidth
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
leftPadding: 0
|
||||||
|
rightPadding: 0
|
||||||
|
sensor.enabled: false
|
||||||
|
title: unknownHolder ? addressElided : model.name
|
||||||
|
|
||||||
|
statusListItemIcon.name: "?"
|
||||||
|
|
||||||
|
subTitle: unknownHolder ? "" : addressElided
|
||||||
|
|
||||||
|
statusListItemSubTitle.font.pixelSize: Theme.asideTextFontSize
|
||||||
|
statusListItemSubTitle.lineHeightMode: Text.FixedHeight
|
||||||
|
statusListItemSubTitle.lineHeight: 14
|
||||||
|
|
||||||
|
asset.name: model.imageSource
|
||||||
|
asset.isImage: true
|
||||||
|
asset.isLetterIdenticon: unknownHolder
|
||||||
|
asset.color: Theme.palette.userCustomizationColors[d.red2Color]
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberCell {
|
||||||
|
Layout.preferredWidth: root.headerItem.noOfMessagesHeaderWidth
|
||||||
|
|
||||||
|
text: model.name
|
||||||
|
? LocaleUtils.numberToLocaleString(model.noOfMessages)
|
||||||
|
: "-"
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberCell {
|
||||||
|
Layout.preferredWidth: root.headerItem.holdingHeaderWidth
|
||||||
|
|
||||||
|
text: LocaleUtils.numberToLocaleString(model.amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
acceptedButtons: Qt.AllButtons
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
|
onClicked: root.clicked(model.index, delegate, mouse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
import QtQuick 2.15
|
||||||
|
import QtQuick.Layouts 1.15
|
||||||
|
import QtQuick.Controls 2.15
|
||||||
|
|
||||||
|
import StatusQ.Controls 0.1
|
||||||
|
import StatusQ.Core 0.1
|
||||||
|
import StatusQ.Core.Theme 0.1
|
||||||
|
import StatusQ.Core.Utils 0.1
|
||||||
|
import StatusQ.Popups 0.1
|
||||||
|
|
||||||
|
import utils 1.0
|
||||||
|
import shared.controls 1.0
|
||||||
|
|
||||||
|
Control {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
// Expected roles: name, walletAddress, imageSource, amount
|
||||||
|
property var model
|
||||||
|
|
||||||
|
property string tokenName
|
||||||
|
property bool showRemotelyDestructMenuItem: true
|
||||||
|
|
||||||
|
readonly property alias sortBy: holdersList.sortBy
|
||||||
|
readonly property alias sorting: holdersList.sorting
|
||||||
|
|
||||||
|
signal viewProfileRequested(string address)
|
||||||
|
signal viewMessagesRequested(string address)
|
||||||
|
signal airdropRequested(string address)
|
||||||
|
signal remoteDestructRequested(string address)
|
||||||
|
signal kickRequested(string address)
|
||||||
|
signal banRequested(string address)
|
||||||
|
|
||||||
|
TokenHoldersProxyModel {
|
||||||
|
id: proxyModel
|
||||||
|
|
||||||
|
sourceModel: root.model
|
||||||
|
searchText: searcher.text
|
||||||
|
|
||||||
|
sortBy: holdersList.sortBy
|
||||||
|
sortOrder: holdersList.sorting === SortableTokenHoldersList.Sorting.Descending
|
||||||
|
? Qt.DescendingOrder : Qt.AscendingOrder
|
||||||
|
}
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: d
|
||||||
|
|
||||||
|
readonly property int red2Color: 4
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: ColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
font.pixelSize: Style.current.primaryTextFontSize
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
|
||||||
|
text: qsTr("%1 token holders").arg(root.tokenName)
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchBox {
|
||||||
|
id: searcher
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 12
|
||||||
|
|
||||||
|
visible: !root.empty
|
||||||
|
|
||||||
|
topPadding: 0
|
||||||
|
bottomPadding: 0
|
||||||
|
minimumHeight: 36 // by design
|
||||||
|
maximumHeight: minimumHeight
|
||||||
|
placeholderText: qsTr("Search hodlers")
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusBaseText {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.topMargin: 12
|
||||||
|
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
font.pixelSize: Style.current.primaryTextFontSize
|
||||||
|
color: Theme.palette.baseColor1
|
||||||
|
|
||||||
|
visible: searcher.text.length > 0
|
||||||
|
|
||||||
|
text: (searcher.text.length > 0 && proxyModel.count > 0)
|
||||||
|
? qsTr("Search results") : qsTr("No hodlers found")
|
||||||
|
}
|
||||||
|
|
||||||
|
SortableTokenHoldersList {
|
||||||
|
id: holdersList
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: contentHeight
|
||||||
|
Layout.topMargin: 20
|
||||||
|
|
||||||
|
model: proxyModel
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
if (mouse.button !== Qt.RightButton)
|
||||||
|
return
|
||||||
|
|
||||||
|
const entry = ModelUtils.get(proxyModel, index)
|
||||||
|
const address = entry.walletAddress
|
||||||
|
const name = entry.name
|
||||||
|
|
||||||
|
menu.rawAddress = name === ""
|
||||||
|
menu.currentAddress = address
|
||||||
|
menu.popup(parent, mouse.x, mouse.y)
|
||||||
|
|
||||||
|
holdersList.currentIndex = index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusMenu {
|
||||||
|
id: menu
|
||||||
|
|
||||||
|
property string currentAddress
|
||||||
|
property bool rawAddress
|
||||||
|
|
||||||
|
onClosed: holdersList.currentIndex = -1
|
||||||
|
|
||||||
|
StatusAction {
|
||||||
|
text: qsTr("View Profile")
|
||||||
|
icon.name: "profile"
|
||||||
|
enabled: !menu.rawAddress
|
||||||
|
|
||||||
|
onTriggered: root.viewProfileRequested(menu.currentAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusAction {
|
||||||
|
text: qsTr("View Messages")
|
||||||
|
icon.name: "chat"
|
||||||
|
enabled: !menu.rawAddress
|
||||||
|
|
||||||
|
onTriggered: root.viewMessagesRequested(menu.currentAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusAction {
|
||||||
|
text: qsTr("Airdrop")
|
||||||
|
icon.name: "airdrop"
|
||||||
|
|
||||||
|
onTriggered: root.airdropRequested(menu.currentAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusMenuSeparator {
|
||||||
|
visible: remotelyDestructAction.enabled || kickAction.enabled
|
||||||
|
|| banAction.enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusAction {
|
||||||
|
id: remotelyDestructAction
|
||||||
|
|
||||||
|
text: qsTr("Remotely destruct")
|
||||||
|
icon.name: "destroy"
|
||||||
|
enabled: root.showRemotelyDestructMenuItem
|
||||||
|
type: StatusBaseButton.Type.Danger
|
||||||
|
|
||||||
|
onTriggered: root.remoteDestructRequested(menu.currentAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusAction {
|
||||||
|
id: kickAction
|
||||||
|
|
||||||
|
text: qsTr("Kick")
|
||||||
|
icon.name: "warning"
|
||||||
|
enabled: !menu.rawAddress
|
||||||
|
type: StatusBaseButton.Type.Danger
|
||||||
|
|
||||||
|
onTriggered: root.kickRequested(menu.currentAddress)
|
||||||
|
}
|
||||||
|
|
||||||
|
StatusAction {
|
||||||
|
id: banAction
|
||||||
|
|
||||||
|
text: qsTr("Ban")
|
||||||
|
icon.name: "cancel"
|
||||||
|
enabled: !menu.rawAddress
|
||||||
|
type: StatusBaseButton.Type.Danger
|
||||||
|
|
||||||
|
onTriggered: root.banRequested(menu.currentAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
import SortFilterProxyModel 0.2
|
||||||
|
|
||||||
|
SortFilterProxyModel {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string searchText
|
||||||
|
readonly property string searchTextLowerCase: searchText.toLowerCase()
|
||||||
|
|
||||||
|
property int sortBy: SortableTokenHoldersList.SortBy.Username
|
||||||
|
property int sortOrder: Qt.AscendingOrder
|
||||||
|
|
||||||
|
filters: ExpressionFilter {
|
||||||
|
expression: {
|
||||||
|
root.searchTextLowerCase
|
||||||
|
|
||||||
|
const nameLowerCase = model.name.toLowerCase()
|
||||||
|
const addressLowerCase = model.walletAddress.toLowerCase()
|
||||||
|
|
||||||
|
return nameLowerCase.includes(searchTextLowerCase) ||
|
||||||
|
addressLowerCase.includes(searchTextLowerCase)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sorters: [
|
||||||
|
FilterSorter {
|
||||||
|
enabled: root.sortBy === SortableTokenHoldersList.SortBy.Username
|
||||||
|
|
||||||
|
ValueFilter {
|
||||||
|
roleName: "name"
|
||||||
|
value: ""
|
||||||
|
inverted: true
|
||||||
|
}
|
||||||
|
|
||||||
|
priority: 3
|
||||||
|
},
|
||||||
|
|
||||||
|
RoleSorter {
|
||||||
|
enabled: root.sortBy === SortableTokenHoldersList.SortBy.Username
|
||||||
|
roleName: "name"
|
||||||
|
sortOrder: root.sortOrder
|
||||||
|
priority: 2
|
||||||
|
},
|
||||||
|
|
||||||
|
RoleSorter {
|
||||||
|
enabled: root.sortBy === SortableTokenHoldersList.SortBy.Username
|
||||||
|
roleName: "walletAddress"
|
||||||
|
sortOrder: root.sortOrder
|
||||||
|
priority: 1
|
||||||
|
},
|
||||||
|
|
||||||
|
RoleSorter {
|
||||||
|
enabled: root.sortBy === SortableTokenHoldersList.SortBy.NoOfMessages
|
||||||
|
roleName: "noOfMessages"
|
||||||
|
sortOrder: root.sortOrder
|
||||||
|
},
|
||||||
|
|
||||||
|
RoleSorter {
|
||||||
|
enabled: root.sortBy === SortableTokenHoldersList.SortBy.Holding
|
||||||
|
roleName: "amount"
|
||||||
|
sortOrder: root.sortOrder
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
|
@ -9,5 +9,8 @@ JoinPermissionsOverlayPanel 1.0 JoinPermissionsOverlayPanel.qml
|
||||||
MintTokensFooterPanel 1.0 MintTokensFooterPanel.qml
|
MintTokensFooterPanel 1.0 MintTokensFooterPanel.qml
|
||||||
PermissionConflictWarningPanel 1.0 PermissionConflictWarningPanel.qml
|
PermissionConflictWarningPanel 1.0 PermissionConflictWarningPanel.qml
|
||||||
PermissionQualificationPanel 1.0 PermissionQualificationPanel.qml
|
PermissionQualificationPanel 1.0 PermissionQualificationPanel.qml
|
||||||
|
SortableTokenHoldersList 1.0 SortableTokenHoldersList.qml
|
||||||
|
SortableTokenHoldersPanel 1.0 SortableTokenHoldersPanel.qml
|
||||||
TokenHoldersPanel 1.0 TokenHoldersPanel.qml
|
TokenHoldersPanel 1.0 TokenHoldersPanel.qml
|
||||||
|
TokenHoldersProxyModel 1.0 TokenHoldersProxyModel.qml
|
||||||
WarningPanel 1.0 WarningPanel.qml
|
WarningPanel 1.0 WarningPanel.qml
|
||||||
|
|
Loading…
Reference in New Issue