diff --git a/storybook/pages/EditAirdropViewPage.qml b/storybook/pages/EditAirdropViewPage.qml index 546fbf356e..7df780c6e1 100644 --- a/storybook/pages/EditAirdropViewPage.qml +++ b/storybook/pages/EditAirdropViewPage.qml @@ -252,6 +252,23 @@ SplitView { assetsModel: AssetsModel {} collectiblesModel: CollectiblesModel {} membersModel: members + + accountsModel: ListModel { + ListElement { + name: "Test account" + emoji: "πŸ˜‹" + address: "0x7F47C2e18a4BBf5487E6fb082eC2D9Ab0E6d7240" + color: "red" + } + + ListElement { + name: "Another account - generated" + emoji: "πŸš—" + address: "0x7F47C2e98a4BBf5487E6fb082eC2D9Ab0E6d8888" + color: "blue" + } + } + communityDetails: QtObject { readonly property string name: "Socks" readonly property string id: "SOCKS" @@ -262,13 +279,15 @@ SplitView { onAirdropClicked: { logs.logEvent("EditAirdropView::airdropClicked", - ["airdropTokens", "addresses", "membersPubKeys"], + ["airdropTokens", "addresses", + "membersPubKeys", "feeAccountAddress"], arguments) } onAirdropFeesRequested: { logs.logEvent("EditAirdropView::airdropFeesRequested", - ["contractKeysAndAmounts", "addresses"], + ["contractKeysAndAmounts", "addresses", + "feeAccountAddress"], arguments) feesCalculationTimer.requestMockedFees(contractKeysAndAmounts) diff --git a/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml b/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml index 94bfa1845a..6defdb27fb 100644 --- a/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml +++ b/ui/app/AppLayouts/Communities/panels/AirdropsSettingsPanel.qml @@ -30,6 +30,7 @@ StackView { required property var collectiblesModel required property var membersModel + required property var accountsModel // JS object specifing fees for the airdrop operation, should be set to // provide response to airdropFeesRequested signal. @@ -39,8 +40,10 @@ StackView { property int viewWidth: 560 // by design property string previousPageName: depth > 1 ? qsTr("Airdrops") : "" - signal airdropClicked(var airdropTokens, var addresses, var membersPubKeys) - signal airdropFeesRequested(var contractKeysAndAmounts, var addresses) + signal airdropClicked(var airdropTokens, var addresses, var membersPubKeys, + string feeAccountAddress) + signal airdropFeesRequested(var contractKeysAndAmounts, var addresses, + string feeAccountAddress) signal navigateToMintTokenSettings(bool isAssetType) function navigateBack() { @@ -135,6 +138,7 @@ StackView { assetsModel: root.assetsModel collectiblesModel: root.collectiblesModel membersModel: root.membersModel + accountsModel: root.accountsModel Binding on airdropFees { value: root.airdropFees diff --git a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml index bf4ccf65be..63c94c2e03 100644 --- a/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml +++ b/ui/app/AppLayouts/Communities/views/CommunitySettingsView.qml @@ -495,8 +495,31 @@ StatusSectionLayout { return chatContentModule.usersModule.model } - onAirdropClicked: communityTokensStore.airdrop(root.community.id, - airdropTokens, addresses) + accountsModel: SortFilterProxyModel { + sourceModel: root.rootStore.accounts + proxyRoles: [ + ExpressionRole { + name: "color" + + function getColor(colorId) { + return Utils.getColorForId(colorId) + } + + // Direct call for singleton function is not handled properly by + // SortFilterProxyModel that's why helper function is used instead. + expression: { return getColor(model.colorId) } + } + ] + filters: ValueFilter { + roleName: "walletType" + value: Constants.watchWalletType + inverted: true + } + } + + onAirdropClicked: communityTokensStore.airdrop( + root.community.id, airdropTokens, addresses, + feeAccountAddress) onNavigateToMintTokenSettings: { root.goTo(Constants.CommunitySettingsSections.MintTokens) @@ -505,7 +528,8 @@ StatusSectionLayout { onAirdropFeesRequested: communityTokensStore.computeAirdropFee( - root.community.id, contractKeysAndAmounts, addresses) + root.community.id, contractKeysAndAmounts, addresses, + feeAccountAddress) } } diff --git a/ui/app/AppLayouts/Communities/views/EditAirdropView.qml b/ui/app/AppLayouts/Communities/views/EditAirdropView.qml index b417907593..0977a64e3e 100644 --- a/ui/app/AppLayouts/Communities/views/EditAirdropView.qml +++ b/ui/app/AppLayouts/Communities/views/EditAirdropView.qml @@ -32,6 +32,9 @@ StatusScrollView { // Community members model: required property var membersModel + // A model containing accounts from which the fee can be paid: + required property var accountsModel + // JS object specifing fees for the airdrop operation, should be set to // provide response to airdropFeesRequested signal. // @@ -75,9 +78,11 @@ StatusScrollView { airdropRecipientsSelector.count > 0 && airdropRecipientsSelector.valid - signal airdropClicked(var airdropTokens, var addresses, var membersPubKeys) + signal airdropClicked(var airdropTokens, var addresses, var membersPubKeys, + string feeAccountAddress) - signal airdropFeesRequested(var contractKeysAndAmounts, var addresses) + signal airdropFeesRequested(var contractKeysAndAmounts, var addresses, + string feeAccountAddress) signal navigateToMintTokenSettings(bool isAssetType) @@ -169,6 +174,7 @@ StatusScrollView { readonly property int totalRevision: holdingsModelTracker.revision + addressesModelTracker.revision + membersModelTracker.revision + + feesBox.accountsSelector.currentIndex + (d.showFees ? 1 : 0) onTotalRevisionChanged: Qt.callLater(() => d.resetFees()) @@ -209,8 +215,7 @@ StatusScrollView { airdropTokens.forEach(entry => { feesModel.append({ contractUniqueKey: entry.contractUniqueKey, - title: qsTr("Airdropping %1 %2 on %3") - .arg(entry.amount * addresses.count) + title: qsTr("Airdrop %1 on %2") .arg(entry.symbol) .arg(entry.networkText), feeText: "" @@ -230,7 +235,11 @@ StatusScrollView { const addressesArray = ModelUtils.modelToArray( addresses, ["address"]).map(e => e.address) - airdropFeesRequested(contractKeysAndAmounts, addressesArray) + const accountItem = ModelUtils.get(root.accountsModel, + feesBox.accountIndex) + + airdropFeesRequested(contractKeysAndAmounts, addressesArray, + accountItem.address) } function resetFees() { @@ -583,11 +592,19 @@ StatusScrollView { SequenceColumnLayout.Separator {} FeesBox { + id: feesBox + + readonly property int accountIndex: accountsSelector.currentIndex + Layout.fillWidth: true model: feesModel + accountsSelector.model: root.accountsModel + totalFeeText: d.totalFee placeholderText: qsTr("Add valid β€œWhat” and β€œTo” values to see fees") + + accountErrorText: d.feesError } WarningPanel { @@ -602,15 +619,6 @@ StatusScrollView { recipientsCountInstantiator.maximumRecipientsCount < airdropRecipientsSelector.count } - WarningPanel { - Layout.fillWidth: true - Layout.topMargin: Style.current.padding - - text: d.feesError - - visible: !notEnoughTokensWarning.visible && d.showFees && d.feesError - } - StatusButton { Layout.preferredHeight: 44 Layout.alignment: Qt.AlignHCenter @@ -620,6 +628,10 @@ StatusScrollView { enabled: root.isFullyFilled && !d.isFeeLoading && d.feesError === "" onClicked: { + const accountItem = ModelUtils.get(root.accountsModel, + feesBox.accountIndex) + feesPopup.accountAddress = accountItem.address + feesPopup.accountName = accountItem.name feesPopup.open() } } @@ -627,6 +639,8 @@ StatusScrollView { SignMultiTokenTransactionsPopup { id: feesPopup + property string accountAddress + destroyOnClose: false model: feesModel @@ -655,7 +669,8 @@ StatusScrollView { const pubKeys = [...selectedKeysFilter.keys] - root.airdropClicked(airdropTokens, addresses_, pubKeys) + root.airdropClicked(airdropTokens, addresses_, pubKeys, + accountAddress) } } } diff --git a/ui/imports/shared/stores/CommunityTokensStore.qml b/ui/imports/shared/stores/CommunityTokensStore.qml index 18da8f7caa..a9fa2b73b5 100644 --- a/ui/imports/shared/stores/CommunityTokensStore.qml +++ b/ui/imports/shared/stores/CommunityTokensStore.qml @@ -116,11 +116,13 @@ QtObject { } // Airdrop tokens: - function airdrop(communityId, airdropTokens, addresses) { + function airdrop(communityId, airdropTokens, addresses, feeAccountAddress) { + // TODO: Take `feeAccountAddress` into account for the airdrop communityTokensModuleInst.airdropTokens(communityId, JSON.stringify(airdropTokens), JSON.stringify(addresses)) } - function computeAirdropFee(communityId, contractKeysAndAmounts, addresses) { + function computeAirdropFee(communityId, contractKeysAndAmounts, addresses, feeAccountAddress) { + // TODO: Take `feeAccountAddress` into account when calculating fee communityTokensModuleInst.computeAirdropFee( communityId, JSON.stringify(contractKeysAndAmounts), JSON.stringify(addresses))