feat(@desktop/wallet): Implements the Send Modal Footer required for simple send

fixes #16918
This commit is contained in:
Khushboo Mehta 2024-12-08 00:45:20 +01:00
parent 77003fb052
commit 16e67a2137
11 changed files with 270 additions and 34 deletions

View File

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

View File

@ -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 { PopupBackground {
@ -87,7 +93,6 @@ SplitView {
modal: false modal: false
closePolicy: Popup.CloseOnEscape closePolicy: Popup.CloseOnEscape
feesLoading: feesLoadingCheckbox.checked
interactive: interactiveCheckbox.checked interactive: interactiveCheckbox.checked
accountsModel: d.walletAccountsModel accountsModel: d.walletAccountsModel
@ -116,6 +121,12 @@ SplitView {
} }
}) })
onFetchFees: {
console.log("Fetch fees...")
d.setFees()
}
onReviewSendClicked: console.log("Review send clicked")
Binding on selectedAccountAddress { Binding on selectedAccountAddress {
value: accountsCombobox.currentValue ?? "" value: accountsCombobox.currentValue ?? ""
} }
@ -491,11 +502,6 @@ SplitView {
checked: true checked: true
} }
CheckBox {
id: feesLoadingCheckbox
text: "Fees loading"
}
Text { Text {
text: "Select an accounts" text: "Select an accounts"
} }

View File

@ -20,6 +20,8 @@ SplitView {
anchors.centerIn: parent anchors.centerIn: parent
width: 400 width: 400
cryptoFees: qsTr("0.0007 ETH")
fiatFees: qsTr("1.45 EUR")
loading: loadingCheckbox.checked loading: loadingCheckbox.checked
} }
} }

View File

@ -9,7 +9,7 @@ import StatusQ.Controls 0.1
import StatusQ.Components 0.1 import StatusQ.Components 0.1
import shared.controls 1.0 as SharedControls 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.controls 1.0
import shared.popups.send 1.0 import shared.popups.send 1.0

View File

@ -11,13 +11,18 @@ Control {
id: root id: root
/** property to set fees in fiat along with fiat symbol **/ /** 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 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 to set loading state in the fees component **/
property bool loading property bool loading
QtObject {
id: d
readonly property string loadingText: "----------"
}
implicitHeight: 64 implicitHeight: 64
padding: Theme.padding padding: Theme.padding
@ -63,7 +68,8 @@ Control {
lineHeightMode: Text.FixedHeight lineHeightMode: Text.FixedHeight
lineHeight: 22 lineHeight: 22
text: qsTr("0.0007 ETH") text: !!root.cryptoFees ? root.cryptoFees:
d.loadingText
} }
} }
StatusTextWithLoadingState { StatusTextWithLoadingState {
@ -76,7 +82,8 @@ Control {
lineHeightMode: Text.FixedHeight lineHeightMode: Text.FixedHeight
lineHeight: 22 lineHeight: 22
text: qsTr("1.45 EUR") text: !!root.fiatFees ? root.fiatFees:
d.loadingText
} }
} }
} }

View File

@ -80,9 +80,14 @@ StatusDialog {
required property var fnFormatCurrencyAmount required property var fnFormatCurrencyAmount
/** input property to decide if send modal is interactive or prefilled **/ /** input property to decide if send modal is interactive or prefilled **/
property bool interactive property bool interactive: true
/** input property to decide if fees are loading **/
property bool feesLoading /** 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 to set and expose currently selected account **/
property string selectedAccountAddress property string selectedAccountAddress
@ -100,11 +105,18 @@ StatusDialog {
/** TODO: replace with new and improved recipient selector StatusDateRangePicker /** TODO: replace with new and improved recipient selector StatusDateRangePicker
TBD under https://github.com/status-im/status-desktop/issues/16916 **/ TBD under https://github.com/status-im/status-desktop/issues/16916 **/
property alias selectedRecipientAddress: recipientsPanel.selectedRecipientAddress property alias selectedRecipientAddress: recipientsPanel.selectedRecipientAddress
/** Input function to resolve Ens Name **/
required property var fnResolveENS required property var fnResolveENS
/** Output function to set resolved ens name values **/
function ensNameResolved(resolvedPubKey, resolvedAddress, uuid) { function ensNameResolved(resolvedPubKey, resolvedAddress, uuid) {
recipientsPanel.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 { QtObject {
id: d id: d
@ -162,6 +174,10 @@ StatusDialog {
} }
}) })
readonly property var debounceSetSelectedAmount: Backpressure.debounce(root, 1500, function() {
root.selectedAmount = amountToSend.text
})
readonly property bool isCollectibleSelected: { readonly property bool isCollectibleSelected: {
if(!selectedTokenEntry) if(!selectedTokenEntry)
return false return false
@ -180,11 +196,43 @@ StatusDialog {
return WalletUtils.calculateMaxSafeSendAmount(maxCryptoBalance, d.selectedCryptoTokenSymbol) return WalletUtils.calculateMaxSafeSendAmount(maxCryptoBalance, d.selectedCryptoTokenSymbol)
} }
readonly property bool allValuesFilled: !!root.selectedAccountAddress && function allValuesFilledCorrectly() {
return !!root.selectedAccountAddress &&
root.selectedChainId !== 0 && root.selectedChainId !== 0 &&
!!root.selectedTokenKey && !!root.selectedTokenKey &&
!!root.selectedRecipientAddress && !!root.selectedRecipientAddress &&
!!root.selectedAmount !!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 width: 556
@ -198,9 +246,6 @@ StatusDialog {
} }
// Bindings needed for exposing and setting raw values from AmountToSend // Bindings needed for exposing and setting raw values from AmountToSend
Binding on selectedAmount {
value: amountToSend.text
}
onSelectedAmountChanged: { onSelectedAmountChanged: {
if(!!selectedAmount && amountToSend.text !== root.selectedAmount) { if(!!selectedAmount && amountToSend.text !== root.selectedAmount) {
amountToSend.setValue(root.selectedAmount) amountToSend.setValue(root.selectedAmount)
@ -343,6 +388,8 @@ StatusDialog {
visible: !!root.selectedTokenKey && !d.isCollectibleSelected visible: !!root.selectedTokenKey && !d.isCollectibleSelected
onVisibleChanged: if(visible) forceActiveFocus() onVisibleChanged: if(visible) forceActiveFocus()
onTextChanged: d.debounceSetSelectedAmount()
bottomRightComponent: MaxSendButton { bottomRightComponent: MaxSendButton {
id: maxButton id: maxButton
@ -414,20 +461,24 @@ StatusDialog {
SimpleTransactionsFees { SimpleTransactionsFees {
Layout.fillWidth: true 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: SendModalFooter {
footer: TransactionModalFooter { width: root.width
width: parent.width
pending: false estimateTime: root.estimatedTime
nextButtonText: qsTr("Review Send") estimatedFees: root.estimatedFiatFees
maxFiatFees: "..."
totalTimeEstimate: "..." loading: d.feesIsLoading && d.allValuesFilledCorrectly()
onReviewSendClicked: root.reviewSendClicked()
} }
} }

View File

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

View File

@ -7,3 +7,4 @@ TokenSelectorCollectibleDelegate 1.0 TokenSelectorCollectibleDelegate.qml
TokenSelectorSectionDelegate 1.0 TokenSelectorSectionDelegate.qml TokenSelectorSectionDelegate 1.0 TokenSelectorSectionDelegate.qml
AccountContextMenu 1.0 AccountContextMenu.qml AccountContextMenu 1.0 AccountContextMenu.qml
RecipientView 1.0 RecipientView.qml RecipientView 1.0 RecipientView.qml
SendModalFooter 1.0 SendModalFooter.qml

View File

@ -671,6 +671,11 @@ Item {
fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) { fnFormatCurrencyAmount: function(amount, symbol, options = null, locale = null) {
return appMain.currencyStore.formatCurrencyAmount(amount, symbol) 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 savedAddressesModel: WalletStores.RootStore.savedAddresses
recentRecipientsModel: appMain.transactionStore.tempActivityController1Model recentRecipientsModel: appMain.transactionStore.tempActivityController1Model
@ -678,6 +683,8 @@ Item {
// It's requested from many nested places, so as a workaround we use // It's requested from many nested places, so as a workaround we use
// Global to shorten the path via global signal. // Global to shorten the path via global signal.
Global.sendToRecipientRequested.connect(sendToRecipient) Global.sendToRecipientRequested.connect(sendToRecipient)
// TODO remove this call to mainModule under #16919
mainModule.resolvedENS.connect(ensNameResolved)
} }
} }

View File

@ -88,9 +88,15 @@ QtObject {
required property var showCommunityAssetsInSend required property var showCommunityAssetsInSend
/** required function to format currency amount to locale string **/ /** required function to format currency amount to locale string **/
required property var fnFormatCurrencyAmount required property var fnFormatCurrencyAmount
required property var savedAddressesModel required property var savedAddressesModel
required property var recentRecipientsModel 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 = {}) { function openSend(params = {}) {
// TODO remove once simple send is feature complete // TODO remove once simple send is feature complete
let sendModalCmp = root.simpleSendEnabled ? simpleSendModalComponent: sendModalComponent let sendModalCmp = root.simpleSendEnabled ? simpleSendModalComponent: sendModalComponent
@ -228,6 +234,7 @@ QtObject {
currentCurrency: root.currentCurrency currentCurrency: root.currentCurrency
fnFormatCurrencyAmount: root.fnFormatCurrencyAmount fnFormatCurrencyAmount: root.fnFormatCurrencyAmount
fnResolveENS: root.fnResolveENS
onClosed: destroy() onClosed: destroy()
@ -259,6 +266,10 @@ QtObject {
} }
} }
} }
Component.onCompleted: {
root.ensNameResolved.connect(ensNameResolved)
}
} }
} }

View File

@ -229,7 +229,7 @@ Control {
objectName: "amountToSend_textField" objectName: "amountToSend_textField"
implicitHeight: 44 Layout.preferredHeight: 44
padding: 0 padding: 0
background: null background: null
@ -240,7 +240,7 @@ Control {
: Theme.palette.dangerColor1 : Theme.palette.dangerColor1
placeholderText: { placeholderText: {
if (!d.fiatMode || root.fiatDecimalPlaces === 0) if (!d.fiatMode || root.fiatDecimalPlaces === 0 || !!text)
return "0" return "0"
return "0" + root.decimalPoint return "0" + root.decimalPoint