diff --git a/storybook/pages/SendModalFooterPage.qml b/storybook/pages/SendModalFooterPage.qml new file mode 100644 index 0000000000..3d1414e58e --- /dev/null +++ b/storybook/pages/SendModalFooterPage.qml @@ -0,0 +1,56 @@ +import QtQuick 2.14 +import QtQuick.Controls 2.14 + +import StatusQ.Core.Theme 0.1 + +import Storybook 1.0 + +import AppLayouts.Wallet.views 1.0 + +SplitView { + orientation: Qt.Vertical + Logs { id: logs } + + Rectangle { + SplitView.fillHeight: true + SplitView.fillWidth: true + color: Theme.palette.indirectColor1 + + SendModalFooter { + id: footer + anchors.centerIn: parent + width: 595 + + loading: loadingCheckbox.checked + + onReviewSendClicked: console.log("review send clicked") + } + } + + LogsAndControlsPanel { + id: logsAndControlsPanel + + SplitView.minimumHeight: 100 + SplitView.preferredHeight: 200 + + logsView.logText: logs.logText + + Column { + CheckBox { + id: loadingCheckbox + text: "loading" + } + + Button { + text: "set fees values" + onClicked: { + loadingCheckbox.checked = false + footer.estimateTime = "~60s" + footer.estimatedFees = "1.45 EUR" + } + } + } + } +} + +// category: Views diff --git a/storybook/pages/SimpleSendModalPage.qml b/storybook/pages/SimpleSendModalPage.qml index daf9e3d9ff..829e785b03 100644 --- a/storybook/pages/SimpleSendModalPage.qml +++ b/storybook/pages/SimpleSendModalPage.qml @@ -60,6 +60,12 @@ SplitView { }) } } + + property var setFees: Backpressure.debounce(root, 1500, function () { + simpleSend.estimatedTime = "~60s" + simpleSend.estimatedFiatFees = "1.45 EUR" + simpleSend.estimatedCryptoFees = "0.0007 ETH" + }) } PopupBackground { @@ -87,7 +93,6 @@ SplitView { modal: false closePolicy: Popup.CloseOnEscape - feesLoading: feesLoadingCheckbox.checked interactive: interactiveCheckbox.checked accountsModel: d.walletAccountsModel @@ -116,6 +121,12 @@ SplitView { } }) + onFetchFees: { + console.log("Fetch fees...") + d.setFees() + } + onReviewSendClicked: console.log("Review send clicked") + Binding on selectedAccountAddress { value: accountsCombobox.currentValue ?? "" } @@ -491,11 +502,6 @@ SplitView { checked: true } - CheckBox { - id: feesLoadingCheckbox - text: "Fees loading" - } - Text { text: "Select an accounts" } diff --git a/storybook/pages/SimpleTransactionsFeesPage.qml b/storybook/pages/SimpleTransactionsFeesPage.qml index a4fedd476f..0f1c38304c 100644 --- a/storybook/pages/SimpleTransactionsFeesPage.qml +++ b/storybook/pages/SimpleTransactionsFeesPage.qml @@ -20,6 +20,8 @@ SplitView { anchors.centerIn: parent width: 400 + cryptoFees: qsTr("0.0007 ETH") + fiatFees: qsTr("1.45 EUR") loading: loadingCheckbox.checked } } diff --git a/ui/app/AppLayouts/Wallet/panels/RecipientSelectorPanel.qml b/ui/app/AppLayouts/Wallet/panels/RecipientSelectorPanel.qml index d1e18c44de..d7b5f3dd81 100644 --- a/ui/app/AppLayouts/Wallet/panels/RecipientSelectorPanel.qml +++ b/ui/app/AppLayouts/Wallet/panels/RecipientSelectorPanel.qml @@ -9,7 +9,7 @@ import StatusQ.Controls 0.1 import StatusQ.Components 0.1 import shared.controls 1.0 as SharedControls -// TODO: remove all files and dependecies with this location once old send modal is removed +// TODO: remove all files and dependencies with this location once old send modal is removed import shared.popups.send.controls 1.0 import shared.popups.send 1.0 diff --git a/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml b/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml index 82eae04f45..c21f5400fd 100644 --- a/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml +++ b/ui/app/AppLayouts/Wallet/panels/SimpleTransactionsFees.qml @@ -11,13 +11,18 @@ Control { id: root /** property to set fees in fiat along with fiat symbol **/ - property alias cryptoFees: cryptoFeesText.text + property string cryptoFees /** property to set fees in crypto along with crypto symbol **/ - property alias fiatFees: fiatFeesText.text - + property string fiatFees /** property to set loading state in the fees component **/ property bool loading + QtObject { + id: d + + readonly property string loadingText: "----------" + } + implicitHeight: 64 padding: Theme.padding @@ -63,7 +68,8 @@ Control { lineHeightMode: Text.FixedHeight lineHeight: 22 - text: qsTr("0.0007 ETH") + text: !!root.cryptoFees ? root.cryptoFees: + d.loadingText } } StatusTextWithLoadingState { @@ -76,7 +82,8 @@ Control { lineHeightMode: Text.FixedHeight lineHeight: 22 - text: qsTr("1.45 EUR") + text: !!root.fiatFees ? root.fiatFees: + d.loadingText } } } diff --git a/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml b/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml index b0ece3bd18..41dd282232 100644 --- a/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml +++ b/ui/app/AppLayouts/Wallet/popups/simpleSend/SimpleSendModal.qml @@ -80,9 +80,14 @@ StatusDialog { required property var fnFormatCurrencyAmount /** input property to decide if send modal is interactive or prefilled **/ - property bool interactive - /** input property to decide if fees are loading **/ - property bool feesLoading + property bool interactive: true + + /** input property to set estimated time **/ + property string estimatedTime + /** input property to set estimated fees in fiat **/ + property string estimatedFiatFees + /** input property to set estimated fees in crypto **/ + property string estimatedCryptoFees /** property to set and expose currently selected account **/ property string selectedAccountAddress @@ -100,11 +105,18 @@ StatusDialog { /** TODO: replace with new and improved recipient selector StatusDateRangePicker TBD under https://github.com/status-im/status-desktop/issues/16916 **/ property alias selectedRecipientAddress: recipientsPanel.selectedRecipientAddress + /** Input function to resolve Ens Name **/ required property var fnResolveENS + /** Output function to set resolved ens name values **/ function ensNameResolved(resolvedPubKey, resolvedAddress, uuid) { recipientsPanel.ensNameResolved(resolvedPubKey, resolvedAddress, uuid) } + /** Output signal to request signing of the transaction **/ + signal reviewSendClicked() + /** Output signal to request fetching fees **/ + signal fetchFees() + QtObject { id: d @@ -162,6 +174,10 @@ StatusDialog { } }) + readonly property var debounceSetSelectedAmount: Backpressure.debounce(root, 1500, function() { + root.selectedAmount = amountToSend.text + }) + readonly property bool isCollectibleSelected: { if(!selectedTokenEntry) return false @@ -180,11 +196,43 @@ StatusDialog { return WalletUtils.calculateMaxSafeSendAmount(maxCryptoBalance, d.selectedCryptoTokenSymbol) } - readonly property bool allValuesFilled: !!root.selectedAccountAddress && - root.selectedChainId !== 0 && - !!root.selectedTokenKey && - !!root.selectedRecipientAddress && - !!root.selectedAmount + function allValuesFilledCorrectly() { + return !!root.selectedAccountAddress && + root.selectedChainId !== 0 && + !!root.selectedTokenKey && + !!root.selectedRecipientAddress && + !!root.selectedAmount && + !amountToSend.markAsInvalid && + amountToSend.valid + } + + // handle multiple property changes from single changed signal + property var combinedPropertyChangedHandler: [ + root.selectedAccountAddress, + root.selectedChainId, + root.selectedTokenKey, + root.selectedRecipientAddress, + root.selectedAmount, + amountToSend.markAsInvalid, + amountToSend.valid] + onCombinedPropertyChangedHandlerChanged: Qt.callLater(() => d.fetchFees()) + + function resetFees() { + root.estimatedCryptoFees = "" + root.estimatedFiatFees = "" + root.estimatedTime = "" + } + + function fetchFees() { + resetFees() + if(allValuesFilledCorrectly()) { + root.fetchFees() + } + } + + readonly property bool feesIsLoading: !root.estimatedCryptoFees && + !root.estimatedFiatFees && + !root.estimatedTime } width: 556 @@ -198,9 +246,6 @@ StatusDialog { } // Bindings needed for exposing and setting raw values from AmountToSend - Binding on selectedAmount { - value: amountToSend.text - } onSelectedAmountChanged: { if(!!selectedAmount && amountToSend.text !== root.selectedAmount) { amountToSend.setValue(root.selectedAmount) @@ -343,6 +388,8 @@ StatusDialog { visible: !!root.selectedTokenKey && !d.isCollectibleSelected onVisibleChanged: if(visible) forceActiveFocus() + onTextChanged: d.debounceSetSelectedAmount() + bottomRightComponent: MaxSendButton { id: maxButton @@ -414,20 +461,24 @@ StatusDialog { SimpleTransactionsFees { Layout.fillWidth: true - loading: root.feesLoading + cryptoFees: root.estimatedCryptoFees + fiatFees: root.estimatedFiatFees + loading: d.feesIsLoading && d.allValuesFilledCorrectly() } - visible: d.allValuesFilled + visible: d.allValuesFilledCorrectly() } } } } - // TODO:: move to new location and rework if needed - footer: TransactionModalFooter { - width: parent.width - pending: false - nextButtonText: qsTr("Review Send") - maxFiatFees: "..." - totalTimeEstimate: "..." + footer: SendModalFooter { + width: root.width + + estimateTime: root.estimatedTime + estimatedFees: root.estimatedFiatFees + + loading: d.feesIsLoading && d.allValuesFilledCorrectly() + + onReviewSendClicked: root.reviewSendClicked() } } diff --git a/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml b/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml new file mode 100644 index 0000000000..dbe8027ae4 --- /dev/null +++ b/ui/app/AppLayouts/Wallet/views/SendModalFooter.qml @@ -0,0 +1,95 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 +import QtQml.Models 2.15 + +import StatusQ.Controls 0.1 +import StatusQ.Core 0.1 +import StatusQ.Core.Theme 0.1 +import StatusQ.Popups.Dialog 0.1 + +StatusDialogFooter { + id: root + + /** property to set loading state **/ + property bool loading + /** property to set estimated time **/ + property string estimateTime + /** property to set estimates fees in fiat **/ + property string estimatedFees + + // Signal to propogate Send clicked + signal reviewSendClicked() + + implicitHeight: 82 + spacing: Theme.bigPadding + color: Theme.palette.baseColor3 + dropShadowEnabled: true + + QtObject { + id: d + + readonly property string emptyText: "--" + readonly property string loadingText: "----------" + } + + leftButtons: ObjectModel { + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + Layout.leftMargin: Theme.padding + + spacing: 0 + + StatusBaseText { + color: Theme.palette.directColor5 + text: qsTr("Est time") + } + StatusTextWithLoadingState { + id: estimatedTime + + customColor: !!root.estimateTime ? Theme.palette.directColor1: + Theme.palette.directColor5 + loading: root.loading + + text: !!root.estimateTime ? root.estimateTime: + root.loading ? d.loadingText : d.emptyText + } + } + ColumnLayout { + Layout.alignment: Qt.AlignVCenter + + spacing: 0 + + StatusBaseText { + color: Theme.palette.directColor5 + text: qsTr("Est fees") + } + StatusTextWithLoadingState { + id: estimatedFees + + customColor: !!root.estimatedFees ? Theme.palette.directColor1: + Theme.palette.directColor5 + loading: root.loading + + text: !!root.estimatedFees ? root.estimatedFees: + loading ? d.loadingText : d.emptyText + } + } + } + + rightButtons: ObjectModel { + StatusButton { + objectName: "transactionModalFooterButton" + + Layout.rightMargin: Theme.padding + + disabledColor: Theme.palette.directColor8 + enabled: !!root.estimateTime && + !!root.estimatedFees && + !root.loading + + text: qsTr("Review Send") + + onClicked: root.reviewSendClicked() + } + } +} diff --git a/ui/app/AppLayouts/Wallet/views/qmldir b/ui/app/AppLayouts/Wallet/views/qmldir index 54c55397ed..12ef9ae06c 100644 --- a/ui/app/AppLayouts/Wallet/views/qmldir +++ b/ui/app/AppLayouts/Wallet/views/qmldir @@ -7,3 +7,4 @@ TokenSelectorCollectibleDelegate 1.0 TokenSelectorCollectibleDelegate.qml TokenSelectorSectionDelegate 1.0 TokenSelectorSectionDelegate.qml AccountContextMenu 1.0 AccountContextMenu.qml RecipientView 1.0 RecipientView.qml +SendModalFooter 1.0 SendModalFooter.qml diff --git a/ui/app/mainui/AppMain.qml b/ui/app/mainui/AppMain.qml index 13933e7e14..da9bf720fb 100644 --- a/ui/app/mainui/AppMain.qml +++ b/ui/app/mainui/AppMain.qml @@ -671,6 +671,11 @@ Item { fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) { return appMain.currencyStore.formatCurrencyAmount(amount, symbol) } + // TODO remove this call to mainModule under #16919 + fnResolveENS: function(ensName, uuid) { + mainModule.resolveENS(name, uuid) + } + savedAddressesModel: WalletStores.RootStore.savedAddresses recentRecipientsModel: appMain.transactionStore.tempActivityController1Model @@ -678,6 +683,8 @@ Item { // It's requested from many nested places, so as a workaround we use // Global to shorten the path via global signal. Global.sendToRecipientRequested.connect(sendToRecipient) + // TODO remove this call to mainModule under #16919 + mainModule.resolvedENS.connect(ensNameResolved) } } diff --git a/ui/app/mainui/SendModalHandler.qml b/ui/app/mainui/SendModalHandler.qml index b69c1346ff..b207f190b8 100644 --- a/ui/app/mainui/SendModalHandler.qml +++ b/ui/app/mainui/SendModalHandler.qml @@ -88,9 +88,15 @@ QtObject { required property var showCommunityAssetsInSend /** required function to format currency amount to locale string **/ required property var fnFormatCurrencyAmount + required property var savedAddressesModel required property var recentRecipientsModel + /** required function to resolve an ens name **/ + required property var fnResolveENS + /** required signal to receive resolved ens name address **/ + signal ensNameResolved(string resolvedPubKey, string resolvedAddress, string uuid) + function openSend(params = {}) { // TODO remove once simple send is feature complete let sendModalCmp = root.simpleSendEnabled ? simpleSendModalComponent: sendModalComponent @@ -228,6 +234,7 @@ QtObject { currentCurrency: root.currentCurrency fnFormatCurrencyAmount: root.fnFormatCurrencyAmount + fnResolveENS: root.fnResolveENS onClosed: destroy() @@ -259,6 +266,10 @@ QtObject { } } } + + Component.onCompleted: { + root.ensNameResolved.connect(ensNameResolved) + } } } diff --git a/ui/imports/shared/popups/send/views/AmountToSend.qml b/ui/imports/shared/popups/send/views/AmountToSend.qml index 2e29b5a448..c9041fc59b 100644 --- a/ui/imports/shared/popups/send/views/AmountToSend.qml +++ b/ui/imports/shared/popups/send/views/AmountToSend.qml @@ -229,7 +229,7 @@ Control { objectName: "amountToSend_textField" - implicitHeight: 44 + Layout.preferredHeight: 44 padding: 0 background: null @@ -240,7 +240,7 @@ Control { : Theme.palette.dangerColor1 placeholderText: { - if (!d.fiatMode || root.fiatDecimalPlaces === 0) + if (!d.fiatMode || root.fiatDecimalPlaces === 0 || !!text) return "0" return "0" + root.decimalPoint