From 25ca0811099ad3485e47155bc23916da270a5604 Mon Sep 17 00:00:00 2001 From: rating89us <45968869+rating89us@users.noreply.github.com> Date: Sat, 17 Oct 2020 11:57:37 +0200 Subject: [PATCH] transfer: new TxConfirmationDialog --- components/TxConfirmationDialog.qml | 466 ++++++++++++++++++++++++++++ main.qml | 155 ++++----- qml.qrc | 1 + 3 files changed, 530 insertions(+), 92 deletions(-) create mode 100644 components/TxConfirmationDialog.qml diff --git a/components/TxConfirmationDialog.qml b/components/TxConfirmationDialog.qml new file mode 100644 index 00000000..1d0a21e9 --- /dev/null +++ b/components/TxConfirmationDialog.qml @@ -0,0 +1,466 @@ +// Copyright (c) 2014-2020, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import QtQuick 2.9 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.1 + +import "../components" as MoneroComponents +import FontAwesome 1.0 + +Rectangle { + id: root + x: parent.width/2 - root.width/2 + y: parent.height/2 - root.height/2 + // TODO: implement without hardcoding sizes + width: 580 + height: 400 + color: MoneroComponents.Style.blackTheme ? "black" : "white" + visible: false + radius: 10 + border.color: MoneroComponents.Style.blackTheme ? Qt.rgba(255, 255, 255, 0.25) : Qt.rgba(0, 0, 0, 0.25) + border.width: 1 + focus: true + Keys.enabled: true + Keys.onEscapePressed: { + root.close() + root.clearFields() + root.rejected() + } + Keys.onEnterPressed: { + if (root.state == "default") { + root.close() + root.accepted() + } else if (root.state == "error") { + root.close() + root.clearFields() + root.rejected() + } + } + Keys.onReturnPressed: { + if (root.state == "default") { + root.close() + root.accepted() + } else if (root.state == "error") { + root.close() + root.clearFields() + root.rejected() + } + } + KeyNavigation.tab: confirmButton + + property var transactionAmount: "" + property var transactionAddress: "" + property var transactionDescription: "" + property var transactionFee: "" + property var transactionPriority: "" + property bool sweepUnmixable: false + property alias errorText: errorText + property alias confirmButton: confirmButton + property alias backButton: backButton + property alias bottomText: bottomText + property alias bottomTextAnimation: bottomTextAnimation + + state: "default" + states: [ + State { + // waiting for user action, show tx details + back and confirm buttons + name: "default"; + when: errorText.text == "" && bottomText.text == "" + PropertyChanges { target: errorText; visible: false } + PropertyChanges { target: txAmountText; visible: root.transactionAmount !== "(all)" || (root.transactionAmount === "(all)" && currentWallet.isHwBacked() === true) } + PropertyChanges { target: txAmountBusyIndicator; visible: !txAmountText.visible } + PropertyChanges { target: txFiatAmountText; visible: txAmountText.visible && persistentSettings.fiatPriceEnabled && root.transactionAmount !== "(all)" } + PropertyChanges { target: txDetails; visible: true } + PropertyChanges { target: bottom; visible: true } + PropertyChanges { target: bottomMessage; visible: false } + PropertyChanges { target: buttons; visible: true } + PropertyChanges { target: backButton; visible: true; primary: false } + PropertyChanges { target: confirmButton; visible: true } + }, State { + // error message being displayed, show only back button + name: "error"; + when: errorText.text !== "" + PropertyChanges { target: dialogTitle; text: "Error" } + PropertyChanges { target: errorText; visible: true } + PropertyChanges { target: txAmountText; visible: false } + PropertyChanges { target: txAmountBusyIndicator; visible: false } + PropertyChanges { target: txFiatAmountText; visible: false } + PropertyChanges { target: txDetails; visible: false } + PropertyChanges { target: bottom; visible: true } + PropertyChanges { target: bottomMessage; visible: false } + PropertyChanges { target: buttons; visible: true } + PropertyChanges { target: backButton; visible: true; primary: true } + PropertyChanges { target: confirmButton; visible: false } + }, State { + // creating or sending transaction, show tx details and don't show any button + name: "bottomText"; + when: errorText.text == "" && bottomText.text !== "" + PropertyChanges { target: errorText; visible: false } + PropertyChanges { target: txAmountText; visible: root.transactionAmount !== "(all)" || (root.transactionAmount === "(all)" && currentWallet.isHwBacked() === true) } + PropertyChanges { target: txAmountBusyIndicator; visible: !txAmountText.visible } + PropertyChanges { target: txFiatAmountText; visible: txAmountText.visible && persistentSettings.fiatPriceEnabled && root.transactionAmount !== "(all)" } + PropertyChanges { target: txDetails; visible: true } + PropertyChanges { target: bottom; visible: true } + PropertyChanges { target: bottomMessage; visible: true } + PropertyChanges { target: buttons; visible: false } + } + ] + + // same signals as Dialog has + signal accepted() + signal rejected() + + function open() { + root.visible = true; + + //clean previous error message + errorText.text = ""; + root.forceActiveFocus() + } + + function close() { + root.visible = false; + } + + function clearFields() { + root.transactionAmount = ""; + root.transactionAddress = ""; + root.transactionDescription = ""; + root.transactionFee = ""; + root.transactionPriority = ""; + root.sweepUnmixable = false; + } + + function showFiatConversion(valueXMR) { + const fiatFee = fiatApiConvertToFiat(valueXMR); + return "%1 %2".arg(fiatFee < 0.01 ? "<0.01" : "~" + fiatFee).arg(fiatApiCurrencySymbol()); + } + + ColumnLayout { + spacing: 10 + anchors.fill: parent + anchors.margins: 25 + + RowLayout { + Layout.topMargin: 10 + Layout.fillWidth: true + + MoneroComponents.Label { + id: dialogTitle + Layout.fillWidth: true + fontSize: 18 + fontFamily: "Arial" + horizontalAlignment: Text.AlignHCenter + text: { + if (appWindow.viewOnly) { + return qsTr("Create transaction file") + translationManager.emptyString; + } else if (root.sweepUnmixable) { + return qsTr("Sweep unmixable outputs") + translationManager.emptyString; + } else { + return qsTr("Confirm send") + translationManager.emptyString; + } + } + } + } + + Text { + id: errorText + Layout.fillWidth: true + Layout.fillHeight: true + color: MoneroComponents.Style.defaultFontColor + wrapMode: Text.Wrap + font.pixelSize: 15 + } + + ColumnLayout { + spacing: 0 + Layout.fillWidth: true + Layout.preferredHeight: 71 + + BusyIndicator { + id: txAmountBusyIndicator + Layout.fillWidth: true + Layout.alignment : Qt.AlignTop | Qt.AlignLeft + running: root.transactionAmount == "(all)" + } + + Text { + id: txAmountText + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + font.pixelSize: root.transactionAmount == "(all)" && currentWallet.isHwBacked() === true ? 32 : 42 + color: MoneroComponents.Style.defaultFontColor + text: { + if (root.transactionAmount == "(all)" && currentWallet.isHwBacked() === true) { + return qsTr("All unlocked balance") + translationManager.emptyString; + } else { + return root.transactionAmount + " XMR " + translationManager.emptyString; + } + } + } + + Text { + id: txFiatAmountText + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + font.pixelSize: 20 + color: MoneroComponents.Style.buttonSecondaryTextColor + text: showFiatConversion(transactionAmount) + translationManager.emptyString + } + } + + GridLayout { + columns: 2 + id: txDetails + Layout.fillWidth: true + columnSpacing: 15 + rowSpacing: 16 + + ColumnLayout { + Layout.fillWidth: true + Layout.alignment : Qt.AlignTop | Qt.AlignLeft + + Text { + Layout.fillWidth: true + color: MoneroComponents.Style.dimmedFontColor + text: qsTr("From") + ":" + translationManager.emptyString + font.pixelSize: 15 + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 16 + + Text { + Layout.fillWidth: true + font.pixelSize: 15 + color: MoneroComponents.Style.defaultFontColor + text: { + if (currentWallet) { + var walletTitle = function() { + if (currentWallet.isLedger()) { + return "Ledger"; + } else if (currentWallet.isTrezor()) { + return "Trezor"; + } else { + return qsTr("My wallet"); + } + } + var walletName = appWindow.walletName; + if (appWindow.currentWallet.numSubaddressAccounts() > 1) { + var currentSubaddressAccount = currentWallet.currentSubaddressAccount; + var currentAccountLabel = currentWallet.getSubaddressLabel(currentWallet.currentSubaddressAccount, 0); + return walletTitle() + " (" + walletName + ")" + "
" + qsTr("Account #") + currentSubaddressAccount + (currentAccountLabel !== "" ? " (" + currentAccountLabel + ")" : "") + translationManager.emptyString; + } else { + return walletTitle() + " (" + walletName + ")" + translationManager.emptyString; + } + } else { + return ""; + } + } + } + } + + ColumnLayout { + Layout.fillWidth: true + Layout.alignment : Qt.AlignTop | Qt.AlignLeft + + Text { + Layout.fillWidth: true + font.pixelSize: 15 + color: MoneroComponents.Style.dimmedFontColor + text: qsTr("To") + ":" + translationManager.emptyString + } + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 16 + + Text { + Layout.fillWidth: true + font.pixelSize: 15 + font.family: MoneroComponents.Style.fontRegular.name + textFormat: Text.RichText + wrapMode: Text.Wrap + color: MoneroComponents.Style.defaultFontColor + text: { + if (root.transactionAddress) { + const addressBookName = currentWallet ? currentWallet.addressBook.getDescription(root.transactionAddress) : null; + var fulladdress = root.transactionAddress; + var spacedaddress = fulladdress.match(/.{1,4}/g); + var spacedaddress = spacedaddress.join(' '); + if (!addressBookName) { + return qsTr("Monero address") + "
" + spacedaddress + translationManager.emptyString; + } else { + return FontAwesome.addressBook + " " + addressBookName + "
" + spacedaddress; + } + } else { + return ""; + } + } + } + } + + ColumnLayout { + Layout.fillWidth: true + Layout.alignment : Qt.AlignTop | Qt.AlignLeft + + Text { + Layout.fillWidth: true + color: MoneroComponents.Style.dimmedFontColor + text: qsTr("Fee") + ":" + translationManager.emptyString + font.pixelSize: 15 + } + } + + RowLayout { + Layout.fillWidth: true + spacing: 16 + + Text { + color: MoneroComponents.Style.defaultFontColor + font.pixelSize: 15 + text: { + if (currentWallet) { + if (!root.transactionFee) { + if (currentWallet.isHwBacked() === true) { + return qsTr("See on device") + translationManager.emptyString; + } else { + return qsTr("Calculating fee") + "..." + translationManager.emptyString; + } + } else { + return root.transactionFee + " XMR" + } + } else { + return ""; + } + } + } + + Text { + Layout.fillWidth: true + Layout.leftMargin: 8 + color: MoneroComponents.Style.buttonSecondaryTextColor + visible: persistentSettings.fiatPriceEnabled && root.transactionFee + font.pixelSize: 15 + text: showFiatConversion(root.transactionFee) + } + } + } + + ColumnLayout { + id: bottom + Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter + Layout.fillWidth: true + + RowLayout { + id: bottomMessage + Layout.fillWidth: true + Layout.preferredHeight: 50 + + BusyIndicator { + visible: !bottomTextAnimation.running + running: !bottomTextAnimation.running + scale: .5 + } + + Text { + id: bottomText + color: MoneroComponents.Style.defaultFontColor + text: "" + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.Wrap + font.pixelSize: 17 + opacity: 1 + + SequentialAnimation{ + id:bottomTextAnimation + running: false + loops: Animation.Infinite + alwaysRunToEnd: true + NumberAnimation { target: bottomText; property: "opacity"; to: 0; duration: 500} + NumberAnimation { target: bottomText; property: "opacity"; to: 1; duration: 500} + } + } + } + + RowLayout { + id: buttons + spacing: 70 + Layout.fillWidth: true + Layout.preferredHeight: 50 + + MoneroComponents.StandardButton { + id: backButton + text: qsTr("Back") + translationManager.emptyString; + width: 200 + focus: false + primary: false + KeyNavigation.tab: confirmButton + Keys.enabled: backButton.visible + Keys.onReturnPressed: backButton.onClicked + Keys.onEnterPressed: backButton.onClicked + Keys.onEscapePressed: { + root.close() + root.clearFields() + root.rejected() + } + onClicked: { + root.close() + root.clearFields() + root.rejected() + } + } + + MoneroComponents.StandardButton { + id: confirmButton + text: qsTr("Confirm") + translationManager.emptyString; + rightIcon: "qrc:///images/rightArrow.png" + width: 200 + focus: false + KeyNavigation.tab: backButton + Keys.enabled: confirmButton.visible + Keys.onReturnPressed: confirmButton.onClicked + Keys.onEnterPressed: confirmButton.onClicked + Keys.onEscapePressed: { + root.close() + root.clearFields() + root.rejected() + } + onClicked: { + root.close() + root.accepted() + } + } + } + } + } +} diff --git a/main.qml b/main.qml index c849939c..b5f8dcd3 100644 --- a/main.qml +++ b/main.qml @@ -65,7 +65,6 @@ ApplicationWindow { property var currentWallet; property bool disconnected: currentWallet ? currentWallet.disconnected : false property var transaction; - property var transactionDescription; property var walletPassword property int restoreHeight:0 property bool daemonSynced: false @@ -508,16 +507,30 @@ ApplicationWindow { } function onDeviceButtonRequest(code){ - prevSplashText = splash.messageText; - splashDisplayedBeforeButtonRequest = splash.visible; - appWindow.showProcessingSplash(qsTr("Please proceed to the device...")); + if (txConfirmationPopup.visible) { + txConfirmationPopup.bottomTextAnimation.running = true + if (!txConfirmationPopup.errorText.visible) { + txConfirmationPopup.bottomText.text = qsTr("Please confirm transaction on the device...") + translationManager.emptyString; + } else { + txConfirmationPopup.bottomText.text = qsTr("Please proceed to the device...") + translationManager.emptyString; + } + } else { + prevSplashText = splash.messageText; + splashDisplayedBeforeButtonRequest = splash.visible; + appWindow.showProcessingSplash(qsTr("Please proceed to the device...")); + } } function onDeviceButtonPressed(){ - if (splashDisplayedBeforeButtonRequest){ - appWindow.showProcessingSplash(prevSplashText); + if (txConfirmationPopup.visible) { + txConfirmationPopup.bottomTextAnimation.running = false; + txConfirmationPopup.bottomText.text = qsTr("Signing transaction in the device...") + translationManager.emptyString; } else { - hideProcessingSplash(); + if (splashDisplayedBeforeButtonRequest){ + appWindow.showProcessingSplash(prevSplashText); + } else { + hideProcessingSplash(); + } } } @@ -811,51 +824,33 @@ ApplicationWindow { function onTransactionCreated(pendingTransaction,address,paymentId,mixinCount){ console.log("Transaction created"); - hideProcessingSplash(); + txConfirmationPopup.bottomText.text = ""; transaction = pendingTransaction; // validate address; if (transaction.status !== PendingTransaction.Status_Ok) { console.error("Can't create transaction: ", transaction.errorString); - informationPopup.title = qsTr("Error") + translationManager.emptyString; - if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion) - informationPopup.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString - else - informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString - informationPopup.icon = StandardIcon.Critical - informationPopup.onCloseCallback = null - informationPopup.open(); + if (currentWallet.connected() == Wallet.ConnectionStatus_WrongVersion) { + txConfirmationPopup.errorText.text = qsTr("Can't create transaction: Wrong daemon version: ") + transaction.errorString + } else { + txConfirmationPopup.errorText.text = qsTr("Can't create transaction: ") + transaction.errorString + } // deleting transaction object, we don't want memleaks currentWallet.disposeTransaction(transaction); } else if (transaction.txCount == 0) { - informationPopup.title = qsTr("Error") + translationManager.emptyString - informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString - informationPopup.icon = StandardIcon.Information - informationPopup.onCloseCallback = null - informationPopup.open() + console.error("Can't create transaction: ", transaction.errorString); + txConfirmationPopup.errorText.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString // deleting transaction object, we don't want memleaks currentWallet.disposeTransaction(transaction); } else { console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount) + ", fee: " + walletManager.displayAmount(transaction.fee)); - // here we show confirmation popup; - transactionConfirmationPopup.title = qsTr("Please confirm transaction:\n") + translationManager.emptyString; - transactionConfirmationPopup.text = ""; - transactionConfirmationPopup.text += (address === "" ? "" : (qsTr("Address: ") + address)); - transactionConfirmationPopup.text += (paymentId === "" ? "" : (qsTr("\nPayment ID: ") + paymentId)); - transactionConfirmationPopup.text += qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount); - transactionConfirmationPopup.text += qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee); - transactionConfirmationPopup.text += qsTr("\nRingsize: ") + (mixinCount + 1); - transactionConfirmationPopup.text += qsTr("\n\nNumber of transactions: ") + transaction.txCount - transactionConfirmationPopup.text += (transactionDescription === "" ? "" : (qsTr("\nDescription: ") + transactionDescription)) - for (var i = 0; i < transaction.subaddrIndices.length; ++i){ - transactionConfirmationPopup.text += qsTr("\nSpending address index: ") + transaction.subaddrIndices[i]; - } - - transactionConfirmationPopup.text += translationManager.emptyString; - transactionConfirmationPopup.icon = StandardIcon.Question - transactionConfirmationPopup.open() + // here we update txConfirmationPopup + txConfirmationPopup.transactionAmount = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.amount)); + txConfirmationPopup.transactionFee = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.fee)); + txConfirmationPopup.confirmButton.text = viewOnly ? qsTr("Save as file") : qsTr("Confirm") + translationManager.emptyString; + txConfirmationPopup.confirmButton.rightIcon = viewOnly ? "" : "qrc:///images/rightArrow.png" } } @@ -869,12 +864,12 @@ ApplicationWindow { ", mixins: ", mixinCount, ", priority: ", priority, ", description: ", description); - - var splashMsg = qsTr("Creating transaction..."); - splashMsg += appWindow.currentWallet.isLedger() ? qsTr("\n\nPlease check your hardware wallet –\nyour input may be required.") : ""; - showProcessingSplash(splashMsg); - - transactionDescription = description; + txConfirmationPopup.bottomTextAnimation.running = false + txConfirmationPopup.bottomText.text = qsTr("Creating transaction...") + translationManager.emptyString; + txConfirmationPopup.transactionAddress = address; + txConfirmationPopup.transactionAmount = Utils.removeTrailingZeros(amount); + txConfirmationPopup.transactionPriority = priority; + txConfirmationPopup.transactionDescription = description; // validate amount; if (amount !== "(all)") { @@ -882,31 +877,21 @@ ApplicationWindow { console.log("integer amount: ", amountxmr); console.log("integer unlocked", currentWallet.unlockedBalance()) if (amountxmr <= 0) { - hideProcessingSplash() - informationPopup.title = qsTr("Error") + translationManager.emptyString; - informationPopup.text = qsTr("Amount is wrong: expected number from %1 to %2") - .arg(walletManager.displayAmount(0)) - .arg(walletManager.displayAmount(currentWallet.unlockedBalance())) - + translationManager.emptyString - - informationPopup.icon = StandardIcon.Critical - informationPopup.onCloseCallback = null - informationPopup.open() + txConfirmationPopup.errorText.text = qsTr("Amount is wrong: expected number from %1 to %2") + .arg(walletManager.displayAmount(0)) + .arg(walletManager.displayAmount(currentWallet.unlockedBalance())) + + translationManager.emptyString; return; } else if (amountxmr > currentWallet.unlockedBalance()) { - hideProcessingSplash() - informationPopup.title = qsTr("Error") + translationManager.emptyString; - informationPopup.text = qsTr("Insufficient funds. Unlocked balance: %1") - .arg(walletManager.displayAmount(currentWallet.unlockedBalance())) - + translationManager.emptyString - - informationPopup.icon = StandardIcon.Critical - informationPopup.onCloseCallback = null - informationPopup.open() + txConfirmationPopup.errorText.text = qsTr("Insufficient funds. Unlocked balance: %1") + .arg(walletManager.displayAmount(currentWallet.unlockedBalance())) + + translationManager.emptyString; return; } } + txConfirmationPopup.open(); + if (amount === "(all)") currentWallet.createTransactionAllAsync(address, paymentId, mixinCount, priority); else @@ -934,40 +919,27 @@ ApplicationWindow { function handleSweepUnmixable() { console.log("Creating transaction: ") + txConfirmationPopup.sweepUnmixable = true; transaction = currentWallet.createSweepUnmixableTransaction(); if (transaction.status !== PendingTransaction.Status_Ok) { console.error("Can't create transaction: ", transaction.errorString); - informationPopup.title = qsTr("Error") + translationManager.emptyString; - informationPopup.text = qsTr("Can't create transaction: ") + transaction.errorString - informationPopup.icon = StandardIcon.Critical - informationPopup.onCloseCallback = null - informationPopup.open(); + txConfirmationPopup.errorText.text = qsTr("Can't create transaction: ") + transaction.errorString + translationManager.emptyString // deleting transaction object, we don't want memleaks currentWallet.disposeTransaction(transaction); } else if (transaction.txCount == 0) { - informationPopup.title = qsTr("Error") + translationManager.emptyString - informationPopup.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString - informationPopup.icon = StandardIcon.Information - informationPopup.onCloseCallback = null - informationPopup.open() + console.error("No unmixable outputs to sweep"); + txConfirmationPopup.errorText.text = qsTr("No unmixable outputs to sweep") + translationManager.emptyString // deleting transaction object, we don't want memleaks currentWallet.disposeTransaction(transaction); } else { console.log("Transaction created, amount: " + walletManager.displayAmount(transaction.amount) + ", fee: " + walletManager.displayAmount(transaction.fee)); - - // here we show confirmation popup; - - transactionConfirmationPopup.title = qsTr("Confirmation") + translationManager.emptyString - transactionConfirmationPopup.text = qsTr("Please confirm transaction:\n") - + qsTr("\n\nAmount: ") + walletManager.displayAmount(transaction.amount) - + qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee) - + translationManager.emptyString - transactionConfirmationPopup.icon = StandardIcon.Question - transactionConfirmationPopup.open() + txConfirmationPopup.transactionAmount = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.amount)); + txConfirmationPopup.transactionFee = Utils.removeTrailingZeros(walletManager.displayAmount(transaction.fee)); // committing transaction } + txConfirmationPopup.open(); } // called after user confirms transaction @@ -985,13 +957,10 @@ ApplicationWindow { // Store to file transaction.setFilename(path); } - - appWindow.showProcessingSplash(qsTr("Sending transaction ...")); currentWallet.commitTransactionAsync(transaction); } function onTransactionCommitted(success, transaction, txid) { - hideProcessingSplash(); if (!success) { console.log("Error committing transaction: " + transaction.errorString); informationPopup.title = qsTr("Error") + translationManager.emptyString @@ -1000,13 +969,14 @@ ApplicationWindow { informationPopup.onCloseCallback = null; informationPopup.open(); } else { - if (transactionDescription.length > 0) { + if (txConfirmationPopup.transactionDescription.length > 0) { for (var i = 0; i < txid.length; ++i) - currentWallet.setUserNote(txid[i], transactionDescription); + currentWallet.setUserNote(txid[i], txConfirmationPopup.transactionDescription); } // Clear tx fields middlePanel.transferView.clearFields() + txConfirmationPopup.clearFields() successfulTxPopup.open(txid) } currentWallet.refresh() @@ -1458,10 +1428,11 @@ ApplicationWindow { } } - // Confrirmation aka question dialog - StandardDialog { + // Transaction confirmation popup + TxConfirmationDialog { + // dynamically change onclose handler + id: txConfirmationPopup z: parent.z + 1 - id: transactionConfirmationPopup onAccepted: { var handleAccepted = function() { // Save transaction to file if view only wallet @@ -1767,7 +1738,7 @@ ApplicationWindow { anchors.fill: blurredArea source: blurredArea radius: 64 - visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible || successfulTxPopup.visible + visible: passwordDialog.visible || inputDialog.visible || splash.visible || updateDialog.visible || devicePassphraseDialog.visible || txConfirmationPopup.visible || successfulTxPopup.visible } diff --git a/qml.qrc b/qml.qrc index 4e722891..31754983 100644 --- a/qml.qrc +++ b/qml.qrc @@ -243,5 +243,6 @@ images/success.png images/success@2x.png components/SuccessfulTxDialog.qml + components/TxConfirmationDialog.qml