feat(CommunityMintTokens): Using sortable list of tokens holders
New list contains also dropdown menu with some actions, basic integration is done for holder types and actions supported currently by the backend. Closes: #10621
This commit is contained in:
parent
99ad85047d
commit
8102600c5b
|
@ -33,6 +33,10 @@ SettingsPageLayout {
|
||||||
d.selectCollectible(key, amount)
|
d.selectCollectible(key, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addAddresses(addresses) {
|
||||||
|
d.addAddresses(addresses)
|
||||||
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
|
@ -43,6 +47,7 @@ SettingsPageLayout {
|
||||||
readonly property string newAirdropViewPageTitle: qsTr("New airdrop")
|
readonly property string newAirdropViewPageTitle: qsTr("New airdrop")
|
||||||
|
|
||||||
signal selectCollectible(string key, int amount)
|
signal selectCollectible(string key, int amount)
|
||||||
|
signal addAddresses(var addresses)
|
||||||
}
|
}
|
||||||
|
|
||||||
content: StackView {
|
content: StackView {
|
||||||
|
@ -110,7 +115,10 @@ SettingsPageLayout {
|
||||||
}
|
}
|
||||||
onNavigateToMintTokenSettings: root.navigateToMintTokenSettings()
|
onNavigateToMintTokenSettings: root.navigateToMintTokenSettings()
|
||||||
|
|
||||||
Component.onCompleted: d.selectCollectible.connect(view.selectCollectible)
|
Component.onCompleted: {
|
||||||
|
d.selectCollectible.connect(view.selectCollectible)
|
||||||
|
d.addAddresses.connect(view.addAddresses)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ SettingsPageLayout {
|
||||||
signal burnCollectibles(string tokenKey,
|
signal burnCollectibles(string tokenKey,
|
||||||
int amount)
|
int amount)
|
||||||
|
|
||||||
signal airdropCollectible(string tokenKey)
|
signal airdropCollectible(string tokenKey, var addresses)
|
||||||
|
|
||||||
signal deleteToken(string tokenKey)
|
signal deleteToken(string tokenKey)
|
||||||
|
|
||||||
|
@ -127,6 +127,7 @@ SettingsPageLayout {
|
||||||
onInitialItemChanged: updateInitialStackView()
|
onInitialItemChanged: updateInitialStackView()
|
||||||
|
|
||||||
signal airdropClicked()
|
signal airdropClicked()
|
||||||
|
signal remoteDestructAddressClicked(string address)
|
||||||
|
|
||||||
signal retryMintClicked()
|
signal retryMintClicked()
|
||||||
|
|
||||||
|
@ -430,6 +431,7 @@ SettingsPageLayout {
|
||||||
|
|
||||||
collectibleName: root.title
|
collectibleName: root.title
|
||||||
model: d.tokenOwnersModel
|
model: d.tokenOwnersModel
|
||||||
|
destroyOnClose: false
|
||||||
|
|
||||||
onRemotelyDestructClicked: {
|
onRemotelyDestructClicked: {
|
||||||
d.selfDestructTokensList = selfDestructTokensList
|
d.selfDestructTokensList = selfDestructTokensList
|
||||||
|
@ -443,6 +445,8 @@ SettingsPageLayout {
|
||||||
|
|
||||||
property int tokenCount
|
property int tokenCount
|
||||||
|
|
||||||
|
destroyOnClose: false
|
||||||
|
|
||||||
title: qsTr("Remotely destruct %n token(s)", "", tokenCount)
|
title: qsTr("Remotely destruct %n token(s)", "", tokenCount)
|
||||||
acceptBtnText: qsTr("Remotely destruct")
|
acceptBtnText: qsTr("Remotely destruct")
|
||||||
alertText: qsTr("Continuing will destroy tokens held by members and revoke any permissions they are given. To undo you will have to issue them new tokens.")
|
alertText: qsTr("Continuing will destroy tokens held by members and revoke any permissions they are given. To undo you will have to issue them new tokens.")
|
||||||
|
@ -501,6 +505,15 @@ SettingsPageLayout {
|
||||||
signTransactionPopup.open()
|
signTransactionPopup.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: d
|
||||||
|
|
||||||
|
function onRemoteDestructAddressClicked(address) {
|
||||||
|
remotelyDestructPopup.open()
|
||||||
|
// TODO: set the address selected in the popup's list
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,11 +662,24 @@ SettingsPageLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onGeneralAirdropRequested: {
|
||||||
|
root.airdropCollectible(view.symbol, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
onAirdropRequested: {
|
||||||
|
root.airdropCollectible(view.symbol, [address])
|
||||||
|
}
|
||||||
|
|
||||||
|
onRemoteDestructRequested: {
|
||||||
|
d.remoteDestructAddressClicked(address)
|
||||||
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: d
|
target: d
|
||||||
|
|
||||||
|
// handle airdrop request from the footer
|
||||||
function onAirdropClicked() {
|
function onAirdropClicked() {
|
||||||
root.airdropCollectible(view.symbol) // TODO: Backend. It should just be the key (hash(chainId + contractAddress)
|
root.airdropCollectible(view.symbol, []) // TODO: Backend. It should just be the key (hash(chainId + contractAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -342,7 +342,9 @@ StatusSectionLayout {
|
||||||
}
|
}
|
||||||
onSignBurnTransactionOpened: communityTokensStore.computeBurnFee(chainId)
|
onSignBurnTransactionOpened: communityTokensStore.computeBurnFee(chainId)
|
||||||
onBurnCollectibles: communityTokensStore.burnCollectibles(tokenKey, amount)
|
onBurnCollectibles: communityTokensStore.burnCollectibles(tokenKey, amount)
|
||||||
onAirdropCollectible: root.goTo(Constants.CommunitySettingsSections.Airdrops)
|
onAirdropCollectible: {
|
||||||
|
root.goTo(Constants.CommunitySettingsSections.Airdrops)
|
||||||
|
}
|
||||||
onDeleteToken: communityTokensStore.deleteToken(root.community.id, tokenKey)
|
onDeleteToken: communityTokensStore.deleteToken(root.community.id, tokenKey)
|
||||||
onRetryMintToken: communityTokensStore.retryMintToken(root.community.id, tokenKey)
|
onRetryMintToken: communityTokensStore.retryMintToken(root.community.id, tokenKey)
|
||||||
|
|
||||||
|
@ -478,12 +480,15 @@ StatusSectionLayout {
|
||||||
Connections {
|
Connections {
|
||||||
target: mintPanel
|
target: mintPanel
|
||||||
|
|
||||||
function onAirdropCollectible(key) {
|
function onAirdropCollectible(key, addresses) {
|
||||||
// Here it is forced a navigation to the new airdrop form, like if it was clicked the header button
|
// Here it is forced a navigation to the new airdrop form, like if it was clicked the header button
|
||||||
airdropPanel.primaryHeaderButtonClicked()
|
airdropPanel.primaryHeaderButtonClicked()
|
||||||
|
|
||||||
// Force a token selection to be airdroped with default amount 1
|
// Force a token selection to be airdroped with default amount 1
|
||||||
airdropPanel.selectCollectible(key, 1)
|
airdropPanel.selectCollectible(key, 1)
|
||||||
|
|
||||||
|
// Set given addresses as recipients
|
||||||
|
airdropPanel.addAddresses(addresses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,12 +510,15 @@ StatusSectionLayout {
|
||||||
function goTo(section: int, subSection: int) {
|
function goTo(section: int, subSection: int) {
|
||||||
//find and enable section
|
//find and enable section
|
||||||
const matchingIndex = listView.model.findIndex((modelItem, index) => modelItem.id === section && modelItem.enabled)
|
const matchingIndex = listView.model.findIndex((modelItem, index) => modelItem.id === section && modelItem.enabled)
|
||||||
if(matchingIndex !== -1) {
|
|
||||||
d.currentIndex = matchingIndex
|
if(matchingIndex === -1)
|
||||||
//find and enable subsection if subSection navigation is available
|
return
|
||||||
if(d.currentItem && d.currentItem.goTo) {
|
|
||||||
d.currentItem.goTo(subSection)
|
d.currentIndex = matchingIndex
|
||||||
}
|
|
||||||
|
//find and enable subsection if subSection navigation is available
|
||||||
|
if(d.currentItem && d.currentItem.goTo) {
|
||||||
|
d.currentItem.goTo(subSection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,10 @@ StatusScrollView {
|
||||||
selectedHoldingsModel.append(entry)
|
selectedHoldingsModel.append(entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addAddresses(_addresses) {
|
||||||
|
addresses.addAddresses(_addresses)
|
||||||
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
|
@ -265,21 +269,27 @@ StatusScrollView {
|
||||||
ListModel {
|
ListModel {
|
||||||
id: addresses
|
id: addresses
|
||||||
|
|
||||||
function addAddressesFromString(addresses) {
|
function addAddresses(_addresses) {
|
||||||
const words = addresses.trim().split(/[\s+,]/)
|
|
||||||
const existing = new Set()
|
const existing = new Set()
|
||||||
|
|
||||||
for (let i = 0; i < count; i++)
|
for (let i = 0; i < count; i++)
|
||||||
existing.add(get(i).address)
|
existing.add(get(i).address)
|
||||||
|
|
||||||
words.forEach(word => {
|
_addresses.forEach(address => {
|
||||||
if (word === "" || existing.has(word))
|
if (existing.has(address))
|
||||||
return
|
return
|
||||||
|
|
||||||
const valid = Utils.isValidAddress(word)
|
const valid = Utils.isValidAddress(address)
|
||||||
append({ valid, address: word })
|
append({ valid, address })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addAddressesFromString(addressesString) {
|
||||||
|
const words = addressesString.trim().split(/[\s+,]/)
|
||||||
|
const wordsNonEmpty = words.filter(word => !!word)
|
||||||
|
|
||||||
|
addAddresses(wordsNonEmpty)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function openPopup(popup) {
|
function openPopup(popup) {
|
||||||
|
|
|
@ -69,6 +69,11 @@ StatusScrollView {
|
||||||
int chainId,
|
int chainId,
|
||||||
string accountName)
|
string accountName)
|
||||||
|
|
||||||
|
signal airdropRequested(string address)
|
||||||
|
signal generalAirdropRequested
|
||||||
|
|
||||||
|
signal remoteDestructRequested(string address)
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: d
|
id: d
|
||||||
|
|
||||||
|
@ -373,13 +378,19 @@ StatusScrollView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TokenHoldersPanel {
|
SortableTokenHoldersPanel {
|
||||||
visible: !root.preview
|
visible: !root.preview
|
||||||
tokenName: root.name
|
|
||||||
model: root.tokenOwnersModel
|
model: root.tokenOwnersModel
|
||||||
|
tokenName: root.name
|
||||||
|
showRemotelyDestructMenuItem: !root.isAssetView && root.selfDestruct
|
||||||
|
|
||||||
Layout.topMargin: Style.current.padding
|
Layout.topMargin: Style.current.padding
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
|
||||||
|
onAirdropRequested: root.airdropRequested(address)
|
||||||
|
onGeneralAirdropRequested: root.generalAirdropRequested()
|
||||||
|
onRemoteDestructRequested: root.remoteDestructRequested(address)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue