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:
Michał Cieślak 2023-06-05 15:49:36 +02:00 committed by Michał
parent 99ad85047d
commit 8102600c5b
5 changed files with 83 additions and 20 deletions

View File

@ -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)
}
} }
} }
} }

View File

@ -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)
} }
} }
} }

View File

@ -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)
} }
} }
} }

View File

@ -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) {

View File

@ -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)
} }
} }
} }