From 423882df898934eb133e6d70755d40cd3265307a Mon Sep 17 00:00:00 2001 From: emizzle Date: Wed, 7 Oct 2020 13:47:21 +1100 Subject: [PATCH] fix: 1:1 chat command transactions "intrinsic gas too low" I noticed that the 1:1 chat commands were not able to send token transactions due to "intrinsic gas too low" error. I quickly realised there there were a few components missing, which have been fixed. *feat: update the 1:1 chat commands transaction modal to allow editing of the from account and network fee* The TransactionStackGroup was updated slightly to allow manual control of back/next actions. Fixes #870. *fix: Create distinct modal transaction actions* Previously, adding `Connection`s for the `walletModel.transactionWasSent` signal in different dialogs would cause the signal to be handled in the wrong dialog. The solution was to pass a `uuid` from the requesting dialog, and include the `uuid` in the response, so that only requests that were requested from the dialog would be handled. *fix: update 1:1 translations* All the translations were not being translated for me. I noticed that they did not exist in the `.ts` translation files either. --- src/app/wallet/view.nim | 6 +- .../ChatComponents/ChatCommandModal.qml | 37 ++-- .../ChatComponents/SignTransactionModal.qml | 167 ++++++++++++++---- .../SendTransactionButton.qml | 3 +- .../TransactionComponents/StateBubble.qml | 30 ++-- .../Profile/Sections/Ens/RegisterENSModal.qml | 4 +- .../Profile/Sections/Ens/SetPubKeyModal.qml | 4 +- ui/app/AppLayouts/Wallet/SendModal.qml | 42 ++--- ui/imports/Utils.qml | 4 + ui/shared/TransactionFormGroup.qml | 4 + ui/shared/TransactionPreview.qml | 63 ++++++- ui/shared/TransactionStackView.qml | 3 +- .../status/StatusStickerPackPurchaseModal.qml | 12 +- 13 files changed, 252 insertions(+), 127 deletions(-) diff --git a/src/app/wallet/view.nim b/src/app/wallet/view.nim index 7e135b55ed..fd4bd5beac 100644 --- a/src/app/wallet/view.nim +++ b/src/app/wallet/view.nim @@ -280,18 +280,18 @@ QtObject: proc transactionSent(self: WalletView, txResult: string) {.slot.} = self.transactionWasSent(txResult) - proc sendTransaction*(self: WalletView, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string) {.slot.} = + proc sendTransaction*(self: WalletView, from_addr: string, to: string, assetAddress: string, value: string, gas: string, gasPrice: string, password: string, uuid: string) {.slot.} = let wallet = self.status.wallet if assetAddress != ZERO_ADDRESS and not assetAddress.isEmptyOrWhitespace: spawnAndSend(self, "transactionSent") do: var success: bool let response = wallet.sendTokenTransaction(from_addr, to, assetAddress, value, gas, gasPrice, password, success) - $(%* { "result": %response, "success": %success }) + $(%* { "result": %response, "success": %success, "uuid": %uuid }) else: spawnAndSend(self, "transactionSent") do: var success: bool let response = wallet.sendTransaction(from_addr, to, value, gas, gasPrice, password, success) - $(%* { "result": %response, "success": %success }) + $(%* { "result": %response, "success": %success, "uuid": %uuid }) proc getDefaultAccount*(self: WalletView): string {.slot.} = self.currentAccount.address diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml index a2cb9f5769..18837dcbc1 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/ChatCommandModal.qml @@ -44,7 +44,11 @@ ModalPopup { currency: walletModel.defaultCurrency width: stack.width //% "From account" - label: qsTrId("from-account") + label: { + return root.isRequested ? + qsTr("Receive on account") : + qsTrId("from-account") + } reset: function() { accounts = Qt.binding(function() { return walletModel.accounts }) selectedAccount = Qt.binding(function() { return walletModel.currentAccount }) @@ -54,13 +58,13 @@ ModalPopup { id: separator anchors.top: selectFromAccount.bottom anchors.topMargin: 19 + icon.rotation: root.isRequested ? -90 : 90 } RecipientSelector { id: selectRecipient accounts: walletModel.accounts contacts: profileModel.addedContacts - //% "Recipient" - label: qsTrId("recipient") + label: qsTr("From") readOnly: true anchors.top: separator.bottom anchors.topMargin: 10 @@ -114,6 +118,7 @@ ModalPopup { SVGImage { width: 16 height: 16 + visible: warningText.visible source: "../../../../img/warning.svg" anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: warningText.top @@ -122,6 +127,7 @@ ModalPopup { StyledText { id: warningText + visible: !root.isRequested //% "You need to request the recipient’s address first.\nAssets won’t be sent yet." text: qsTrId("you-need-to-request-the-recipient-s-address-first--nassets-won-t-be-sent-yet-") color: Style.current.danger @@ -139,29 +145,14 @@ ModalPopup { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - StyledButton { + StatusRoundButton { id: btnBack anchors.left: parent.left - width: 44 - height: 44 visible: !stack.isFirstGroup - label: "" - background: Rectangle { - anchors.fill: parent - border.width: 0 - radius: width / 2 - color: btnBack.hovered ? Qt.darker(btnBack.btnColor, 1.1) : btnBack.btnColor - - SVGImage { - width: 20.42 - height: 15.75 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - fillMode: Image.PreserveAspectFit - source: "../../../../img/arrow-right.svg" - rotation: 180 - } - } + icon.name: "arrow-right" + icon.width: 20 + icon.height: 16 + rotation: 180 onClicked: { stack.back() } diff --git a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml index 65238fa3b7..f44c17ccd2 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/ChatComponents/SignTransactionModal.qml @@ -24,7 +24,8 @@ ModalPopup { root.selectedAmount, selectedGasLimit, selectedGasPrice, - enteredPassword) + enteredPassword, + stack.uuid) let response = JSON.parse(responseStr) @@ -67,13 +68,14 @@ ModalPopup { anchors.fill: parent anchors.leftMargin: Style.current.padding anchors.rightMargin: Style.current.padding + initialItem: groupPreview + isLastGroup: stack.currentGroup === groupSignTx onGroupActivated: { root.title = group.headerText btnNext.text = group.footerText } TransactionFormGroup { - id: group1 - //% "Send" + id: groupSelectAcct headerText: { if(trxData.startsWith("0x095ea7b3")){ const approveData = JSON.parse(walletModel.decodeTokenApproval(selectedRecipient.address, trxData)) @@ -82,9 +84,54 @@ ModalPopup { } return qsTrId("command-button-send"); } + footerText: qsTr("Continue") + showNextBtn: false + onBackClicked: function() { + if(validate()) { + stack.pop() + } + } + AccountSelector { + id: selectFromAccount + accounts: walletModel.accounts + selectedAccount: root.selectedAccount + currency: walletModel.defaultCurrency + width: stack.width + //% "Choose account" + label: qsTrId("choose-account") + showBalanceForAssetSymbol: root.selectedAsset.symbol + minRequiredAssetBalance: parseFloat(root.selectedAmount) + reset: function() { + accounts = Qt.binding(function() { return walletModel.accounts }) + selectedAccount = Qt.binding(function() { return root.selectedAccount }) + showBalanceForAssetSymbol = Qt.binding(function() { return root.selectedAsset.symbol }) + minRequiredAssetBalance = Qt.binding(function() { return parseFloat(root.selectedAmount) }) + } + onSelectedAccountChanged: if (isValid) { gasSelector.estimateGas() } + } + RecipientSelector { + id: selectRecipient + visible: false + accounts: walletModel.accounts + contacts: profileModel.addedContacts + selectedRecipient: root.selectedRecipient + readOnly: true + reset: function() { + accounts = Qt.binding(function() { return walletModel.accounts }) + contacts = Qt.binding(function() { return profileModel.addedContacts }) + selectedRecipient = Qt.binding(function() { return root.selectedRecipient }) + } + } + } + TransactionFormGroup { + id: groupSelectGas + headerText: qsTr("Network fee") //% "Preview" footerText: qsTrId("preview") - + showNextBtn: false + onBackClicked: function() { + stack.pop() + } GasSelector { id: gasSelector anchors.topMargin: Style.current.bigPadding @@ -98,17 +145,19 @@ ModalPopup { slowestGasPrice = Qt.binding(function(){ return parseFloat(walletModel.safeLowGasPrice) }) fastestGasPrice = Qt.binding(function(){ return parseFloat(walletModel.fastestGasPrice) }) } - - function estimateGas() { - console.log("CALLING ESTIMATE GAS") - if (!(root.selectedAccount && root.selectedAccount.address && - root.selectedRecipient && root.selectedRecipient.address && + + property var estimateGas: Backpressure.debounce(gasSelector, 600, function() { + if (!(selectFromAccount.selectedAccount && selectFromAccount.selectedAccount.address && + selectRecipient.selectedRecipient && selectRecipient.selectedRecipient.address && root.selectedAsset && root.selectedAsset.address && - root.selectedAmount)) return - + root.selectedAmount)) { + selectedGasLimit = 250000 + return + } + let gasEstimate = JSON.parse(walletModel.estimateGas( - root.selectedAccount.address, - root.selectedRecipient.address, + selectFromAccount.selectedAccount.address, + selectRecipient.selectedRecipient.address, root.selectedAsset.address, root.selectedAmount, trxData)) @@ -119,7 +168,7 @@ ModalPopup { return } selectedGasLimit = gasEstimate.result - } + }) } GasValidator { id: gasValidator @@ -130,16 +179,24 @@ ModalPopup { selectedAsset: root.selectedAsset selectedGasEthValue: gasSelector.selectedGasEthValue reset: function() { + selectedAccount = Qt.binding(function() { return root.selectedAccount }) + selectedAmount = Qt.binding(function() { return parseFloat(root.selectedAmount) }) + selectedAsset = Qt.binding(function() { return root.selectedAsset }) selectedGasEthValue = Qt.binding(function() { return gasSelector.selectedGasEthValue }) } } } + TransactionFormGroup { - id: group2 + id: groupPreview //% "Transaction preview" headerText: qsTrId("transaction-preview") //% "Sign with password" footerText: qsTrId("sign-with-password") + showBackBtn: false + onNextClicked: function() { + stack.push(groupSignTx, StackView.Immediate) + } TransactionPreview { id: pvwTransaction @@ -155,6 +212,7 @@ ModalPopup { amount: { "value": root.selectedAmount, "fiatValue": root.selectedFiatAmount } currency: walletModel.defaultCurrency reset: function() { + fromAccount = Qt.binding(function() { return root.selectedAccount }) gas = Qt.binding(function() { return { "value": gasSelector.selectedGasEthValue, @@ -162,15 +220,23 @@ ModalPopup { "fiatValue": gasSelector.selectedGasFiatValue } }) + toAccount = Qt.binding(function() { return root.selectedRecipient }) + asset = Qt.binding(function() { return root.selectedAsset }) + amount = Qt.binding(function() { return { "value": root.selectedAmount, "fiatValue": root.selectedFiatAmount } }) } + onFromClicked: stack.push(groupSelectAcct, StackView.Immediate) + onGasClicked: stack.push(groupSelectGas, StackView.Immediate) } } TransactionFormGroup { - id: group3 + id: groupSignTx //% "Sign with password" headerText: qsTrId("sign-with-password") //% "Send %1 %2" footerText: qsTrId("send--1--2").arg(root.selectedAmount).arg(!!root.selectedAsset ? root.selectedAsset.symbol : "") + onBackClicked: function() { + stack.pop() + } TransactionSigner { id: transactionSigner @@ -187,30 +253,19 @@ ModalPopup { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - StyledButton { + StatusRoundButton { id: btnBack anchors.left: parent.left - width: 44 - height: 44 - visible: !stack.isFirstGroup - label: "" - background: Rectangle { - anchors.fill: parent - border.width: 0 - radius: width / 2 - color: btnBack.hovered ? Qt.darker(btnBack.btnColor, 1.1) : btnBack.btnColor - - SVGImage { - width: 20.42 - height: 15.75 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - fillMode: Image.PreserveAspectFit - source: "../../../../img/arrow-right.svg" - rotation: 180 - } - } + icon.name: "arrow-right" + icon.width: 20 + icon.height: 16 + rotation: 180 + visible: stack.currentGroup.showBackBtn + enabled: stack.currentGroup.isValid || stack.isLastGroup onClicked: { + if (typeof stack.currentGroup.onBackClicked === "function") { + return stack.currentGroup.onBackClicked() + } stack.back() } } @@ -220,6 +275,7 @@ ModalPopup { //% "Next" text: qsTrId("next") enabled: stack.currentGroup.isValid && !stack.currentGroup.isPending + visible: stack.currentGroup.showNextBtn onClicked: { const validity = stack.currentGroup.validate() if (validity.isValid && !validity.isPending) { @@ -228,10 +284,47 @@ ModalPopup { gasSelector.selectedGasPrice, transactionSigner.enteredPassword) } + if (typeof stack.currentGroup.onNextClicked === "function") { + return stack.currentGroup.onNextClicked() + } stack.next() } } } + + Connections { + target: walletModel + onTransactionWasSent: { + try { + let response = JSON.parse(txResult) + + if (response.uuid !== stack.uuid) return + + stack.currentGroup.isPending = false + + if (!response.success) { + if (response.result.includes("could not decrypt key with given password")){ + //% "Wrong password" + transactionSigner.validationError = qsTrId("wrong-password") + return + } + sendingError.text = response.result + return sendingError.open() + } + + //% "Transaction pending..." + toastMessage.title = qsTrId("ens-transaction-pending") + toastMessage.source = "../../img/loading.svg" + toastMessage.iconColor = Style.current.primary + toastMessage.iconRotates = true + toastMessage.link = `${walletModel.etherscanLink}/${response.result}` + toastMessage.open() + root.close() + } catch (e) { + console.error('Error parsing the response', e) + } + } + } } } diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml index 4688b54577..fda5ed72bc 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/SendTransactionButton.qml @@ -14,8 +14,7 @@ Item { StyledText { id: signText color: Style.current.blue - //% "Sign and send" - text: qsTrId("sign-and-send") + text: qsTr("Sign and send") horizontalAlignment: Text.AlignHCenter wrapMode: Text.WordWrap font.weight: Font.Medium diff --git a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/StateBubble.qml b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/StateBubble.qml index 2172a75c76..ee8b41d51c 100644 --- a/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/StateBubble.qml +++ b/ui/app/AppLayouts/Chat/ChatColumn/MessageComponents/TransactionComponents/StateBubble.qml @@ -55,26 +55,18 @@ Rectangle { } text: { switch (root.state) { - //% "Pending" - case Constants.pending: return qsTrId("pending") - //% "Confirmed" - case Constants.confirmed: return qsTrId("status-confirmed") - //% "Unknown token" - case Constants.unknown: return qsTrId("unknown-token") - //% "Address requested" - case Constants.addressRequested: return qsTrId("address-requested") - //% "Waiting to accept" - case Constants.transactionRequested: return qsTrId("waiting-to-accept") - //% "Address shared" - //% "Address received" - case Constants.addressReceived: return (!root.outgoing ? qsTrId("address-shared") : qsTrId("address-received")) + case Constants.pending: return qsTr("Pending") + case Constants.confirmed: return qsTr("Confirmed") + case Constants.unknown: return qsTr("Unknown token") + case Constants.addressRequested: return qsTr("Address requested") + case Constants.transactionRequested: return qsTr("Waiting to accept") + case Constants.addressReceived: return (!root.outgoing ? + qsTr("Address shared") : + qsTr("Address received")) case Constants.transactionDeclined: - //% "Transaction declined" - case Constants.declined: return qsTrId("transaction-declined") - //% "Failure" - case Constants.failure: return qsTrId("failure") - //% "Unknown state" - default: return qsTrId("unknown-state") + case Constants.declined: return qsTr("Transaction declined") + case Constants.failure: return qsTr("failure") + default: return qsTr("Unknown state") } } font.weight: Font.Medium diff --git a/ui/app/AppLayouts/Profile/Sections/Ens/RegisterENSModal.qml b/ui/app/AppLayouts/Profile/Sections/Ens/RegisterENSModal.qml index a079607a97..d5baa4cb47 100644 --- a/ui/app/AppLayouts/Profile/Sections/Ens/RegisterENSModal.qml +++ b/ui/app/AppLayouts/Profile/Sections/Ens/RegisterENSModal.qml @@ -81,7 +81,7 @@ ModalPopup { showBalanceForAssetSymbol = Qt.binding(function() { return root.asset.symbol }) minRequiredAssetBalance = Qt.binding(function() { return root.ensPrice }) } - onSelectedAccountChanged: gasSelector.estimateGas() + onSelectedAccountChanged: if (isValid) { gasSelector.estimateGas() } } RecipientSelector { id: selectRecipient @@ -90,7 +90,7 @@ ModalPopup { contacts: profileModel.addedContacts selectedRecipient: { "address": utilsModel.ensRegisterAddress, "type": RecipientSelector.Type.Address } readOnly: true - onSelectedRecipientChanged: gasSelector.estimateGas() + onSelectedRecipientChanged: if (isValid) { gasSelector.estimateGas() } } GasSelector { id: gasSelector diff --git a/ui/app/AppLayouts/Profile/Sections/Ens/SetPubKeyModal.qml b/ui/app/AppLayouts/Profile/Sections/Ens/SetPubKeyModal.qml index 891f46d41f..bdf29f09e3 100644 --- a/ui/app/AppLayouts/Profile/Sections/Ens/SetPubKeyModal.qml +++ b/ui/app/AppLayouts/Profile/Sections/Ens/SetPubKeyModal.qml @@ -85,7 +85,7 @@ ModalPopup { showBalanceForAssetSymbol = Qt.binding(function() { return "ETH" }) minRequiredAssetBalance = Qt.binding(function() { return 0 }) } - onSelectedAccountChanged: gasSelector.estimateGas() + onSelectedAccountChanged: if (isValid) { gasSelector.estimateGas() } } RecipientSelector { id: selectRecipient @@ -94,7 +94,7 @@ ModalPopup { contacts: profileModel.addedContacts selectedRecipient: { "address": utilsModel.ensRegisterAddress, "type": RecipientSelector.Type.Address } readOnly: true - onSelectedRecipientChanged: gasSelector.estimateGas() + onSelectedRecipientChanged: if (isValid) { gasSelector.estimateGas() } } GasSelector { id: gasSelector diff --git a/ui/app/AppLayouts/Wallet/SendModal.qml b/ui/app/AppLayouts/Wallet/SendModal.qml index a823b91083..e24b97dc70 100644 --- a/ui/app/AppLayouts/Wallet/SendModal.qml +++ b/ui/app/AppLayouts/Wallet/SendModal.qml @@ -35,7 +35,8 @@ ModalPopup { txtAmount.selectedAmount, gasSelector.selectedGasLimit, gasSelector.selectedGasPrice, - transactionSigner.enteredPassword) + transactionSigner.enteredPassword, + stack.uuid) } TransactionStackView { @@ -66,7 +67,7 @@ ModalPopup { accounts = Qt.binding(function() { return walletModel.accounts }) selectedAccount = Qt.binding(function() { return walletModel.currentAccount }) } - onSelectedAccountChanged: gasSelector.estimateGas() + onSelectedAccountChanged: if (isValid) { gasSelector.estimateGas() } } SeparatorWithIcon { id: separator @@ -87,7 +88,7 @@ ModalPopup { contacts = Qt.binding(function() { return profileModel.addedContacts }) selectedRecipient = {} } - onSelectedRecipientChanged: gasSelector.estimateGas() + onSelectedRecipientChanged: if (isValid) { gasSelector.estimateGas() } } } TransactionFormGroup { @@ -107,8 +108,8 @@ ModalPopup { reset: function() { selectedAccount = Qt.binding(function() { return selectFromAccount.selectedAccount }) } - onSelectedAssetChanged: gasSelector.estimateGas() - onSelectedAmountChanged: gasSelector.estimateGas() + onSelectedAssetChanged: if (isValid) { gasSelector.estimateGas() } + onSelectedAmountChanged: if (isValid) { gasSelector.estimateGas() } } GasSelector { id: gasSelector @@ -225,30 +226,14 @@ ModalPopup { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - StyledButton { + StatusRoundButton { id: btnBack anchors.left: parent.left - width: 44 - height: 44 visible: !stack.isFirstGroup - label: "" - background: Rectangle { - anchors.fill: parent - border.width: 0 - radius: width / 2 - color: btnBack.disabled ? Style.current.grey : - btnBack.hovered ? Qt.darker(btnBack.btnColor, 1.1) : btnBack.btnColor - - SVGImage { - width: 20.42 - height: 15.75 - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - fillMode: Image.PreserveAspectFit - source: "../../img/arrow-right.svg" - rotation: 180 - } - } + icon.name: "arrow-right" + icon.width: 20 + icon.height: 16 + rotation: 180 onClicked: { stack.back() } @@ -275,9 +260,12 @@ ModalPopup { target: walletModel onTransactionWasSent: { try { - stack.currentGroup.isPending = false let response = JSON.parse(txResult) + if (response.uuid !== stack.uuid) return + + stack.currentGroup.isPending = false + if (!response.success) { if (response.result.includes("could not decrypt key with given password")){ //% "Wrong password" diff --git a/ui/imports/Utils.qml b/ui/imports/Utils.qml index 385b836071..b63b546cb0 100644 --- a/ui/imports/Utils.qml +++ b/ui/imports/Utils.qml @@ -167,4 +167,8 @@ QtObject { let wordCount = countWords(text); return qsTr("%1%2 words").arg(getTick(wordCount)).arg(wordCount.toString()); } + + function uuid() { + return Date.now().toString(36) + Math.random().toString(36).substr(2, 5) + } } diff --git a/ui/shared/TransactionFormGroup.qml b/ui/shared/TransactionFormGroup.qml index 6cd7aac529..7b2a0cf10f 100644 --- a/ui/shared/TransactionFormGroup.qml +++ b/ui/shared/TransactionFormGroup.qml @@ -6,4 +6,8 @@ FormGroup { id: root property string headerText property string footerText + property bool showBackBtn: true + property bool showNextBtn: true + property var onBackClicked + property var onNextClicked } \ No newline at end of file diff --git a/ui/shared/TransactionPreview.qml b/ui/shared/TransactionPreview.qml index 30ffcf9721..74f2028b9f 100644 --- a/ui/shared/TransactionPreview.qml +++ b/ui/shared/TransactionPreview.qml @@ -15,6 +15,8 @@ Item { property var gas height: content.height property var reset: function() {} + signal fromClicked + signal gasClicked function resetInternal() { fromAccount = undefined @@ -53,15 +55,39 @@ Item { id: imgFromWallet sourceSize.height: 18 sourceSize.width: 18 - anchors.right: parent.right + anchors.right: fromArrow.visible ? fromArrow.left : parent.right + anchors.rightMargin: fromArrow.visible ? Style.current.padding : 0 anchors.verticalCenter: parent.verticalCenter fillMode: Image.PreserveAspectFit source: "../app/img/walletIcon.svg" + ColorOverlay { + anchors.fill: parent + source: parent + color: root.fromAccount ? root.fromAccount.iconColor : Style.current.blue + } } - ColorOverlay { - anchors.fill: imgFromWallet - source: imgFromWallet - color: root.fromAccount ? root.fromAccount.iconColor : Style.current.blue + SVGImage { + id: fromArrow + width: 13 + visible: typeof root.fromClicked === "function" + anchors.right: parent.right + anchors.rightMargin: 7 + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.PreserveAspectFit + source: "../app/img/caret.svg" + rotation: 270 + ColorOverlay { + anchors.fill: parent + visible: parent.visible + source: parent + color: Style.current.secondaryText + } + } + MouseArea { + anchors.fill: parent + visible: fromArrow.visible + cursorShape: Qt.PointingHandCursor + onClicked: root.fromClicked() } } } @@ -316,6 +342,7 @@ Item { id: itmNetworkFee //% "Network fee" label: qsTrId("network-fee") + visible: !!root.gas value: Item { id: networkFeeRoot anchors.fill: parent @@ -362,11 +389,35 @@ Item { height: 22 text: root.currency.toUpperCase() color: Style.current.secondaryText - anchors.right: parent.right + anchors.right: gasArrow.visible ? gasArrow.left : parent.right + anchors.rightMargin: gasArrow.visible ? Style.current.padding : 0 anchors.verticalCenter: parent.verticalCenter horizontalAlignment: Text.AlignRight verticalAlignment: Text.AlignVCenter } + SVGImage { + id: gasArrow + width: 13 + visible: typeof root.gasClicked === "function" + anchors.right: parent.right + anchors.rightMargin: 7 + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.PreserveAspectFit + source: "../app/img/caret.svg" + rotation: 270 + ColorOverlay { + anchors.fill: parent + visible: parent.visible + source: parent + color: Style.current.secondaryText + } + } + MouseArea { + anchors.fill: parent + visible: gasArrow.visible + cursorShape: Qt.PointingHandCursor + onClicked: root.gasClicked() + } } } } diff --git a/ui/shared/TransactionStackView.qml b/ui/shared/TransactionStackView.qml index ec9d2b6f6a..af146aebac 100644 --- a/ui/shared/TransactionStackView.qml +++ b/ui/shared/TransactionStackView.qml @@ -10,13 +10,14 @@ StackView { property bool isFirstGroup: currentIdx === 0 signal groupActivated(Item group) property alias currentGroup: root.currentItem + readonly property string uuid: Utils.uuid() + property var next: function() { if (groups && groups.length <= currentIdx + 1) { return } const group = groups[++currentIdx] this.push(group, StackView.Immediate) - } property var back: function() { if (currentIdx <= 0) { diff --git a/ui/shared/status/StatusStickerPackPurchaseModal.qml b/ui/shared/status/StatusStickerPackPurchaseModal.qml index b98ab33beb..ee892f5e58 100644 --- a/ui/shared/status/StatusStickerPackPurchaseModal.qml +++ b/ui/shared/status/StatusStickerPackPurchaseModal.qml @@ -85,7 +85,7 @@ ModalPopup { showBalanceForAssetSymbol = Qt.binding(function() { return root.asset.symbol }) minRequiredAssetBalance = Qt.binding(function() { return root.packPrice }) } - onSelectedAccountChanged: gasSelector.estimateGas() + onSelectedAccountChanged: if (isValid) { gasSelector.estimateGas() } } RecipientSelector { id: selectRecipient @@ -94,7 +94,7 @@ ModalPopup { contacts: profileModel.addedContacts selectedRecipient: { "address": utilsModel.stickerMarketAddress, "type": RecipientSelector.Type.Address } readOnly: true - onSelectedRecipientChanged: gasSelector.estimateGas() + onSelectedRecipientChanged: if (isValid) { gasSelector.estimateGas() } } GasSelector { id: gasSelector @@ -196,11 +196,13 @@ ModalPopup { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - StyledButton { + StatusRoundButton { id: btnBack anchors.left: parent.left - //% "Back" - label: qsTrId("back") + icon.name: "arrow-right" + icon.width: 20 + icon.height: 16 + rotation: 180 onClicked: { if (stack.isFirstGroup) { return root.close()