diff --git a/ui/app/AppLayouts/Wallet/ReceiveModal.qml b/ui/app/AppLayouts/Wallet/ReceiveModal.qml index 5bb1b100ad..cf8c67d86c 100644 --- a/ui/app/AppLayouts/Wallet/ReceiveModal.qml +++ b/ui/app/AppLayouts/Wallet/ReceiveModal.qml @@ -46,6 +46,8 @@ ModalPopup { anchors.topMargin: Style.current.padding anchors.horizontalCenter: parent.horizontalCenter width: 240 + dropdownWidth: parent.width - (Style.current.padding * 2) + dropdownAlignment: Select.MenuAlignment.Center } Input { diff --git a/ui/app/AppLayouts/Wallet/SendModal.qml b/ui/app/AppLayouts/Wallet/SendModal.qml index ec31c28e67..cb4bf20041 100644 --- a/ui/app/AppLayouts/Wallet/SendModal.qml +++ b/ui/app/AppLayouts/Wallet/SendModal.qml @@ -1,5 +1,6 @@ import QtQuick 2.13 import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.13 import "../../../imports" import "../../../shared" import "./components" @@ -9,10 +10,10 @@ ModalPopup { //% "Send" title: qsTrId("command-button-send") - height: 600 + height: 700 onOpened: { - sendModalContent.amountInput.text = "" + sendModalContent.amountInput.selectedAmount = "" sendModalContent.passwordInput.text = "" sendModalContent.amountInput.forceActiveFocus(Qt.MouseFocusReason) } @@ -24,15 +25,41 @@ ModalPopup { } } - footer: StyledButton { + footer: Item { anchors.top: parent.top + anchors.left: parent.left anchors.right: parent.right - anchors.rightMargin: Style.current.padding - //% "Send" - label: qsTrId("command-button-send") - - onClicked: { - sendModalContent.send() + StyledButton { + id: btnBack + anchors.left: parent.left + label: qsTr("Back") + visible: !btnPreview.visible + onClicked: { + btnPreview.visible = true + sendModalContent.showInputs() + } + } + StyledButton { + id: btnPreview + anchors.right: parent.right + label: qsTr("Preview") + onClicked: { + if (!sendModalContent.validate()) { + return + } + visible = false + sendModalContent.showPreview() + } + } + StyledButton { + id: btnSend + anchors.right: parent.right + visible: !btnPreview.visible + //% "Send" + label: qsTrId("command-button-send") + onClicked: { + sendModalContent.send() + } } } } diff --git a/ui/app/AppLayouts/Wallet/components/SendModalContent.qml b/ui/app/AppLayouts/Wallet/components/SendModalContent.qml index 6cc2f32f64..04f54872f5 100644 --- a/ui/app/AppLayouts/Wallet/components/SendModalContent.qml +++ b/ui/app/AppLayouts/Wallet/components/SendModalContent.qml @@ -11,8 +11,6 @@ Item { property alias passwordInput: txtPassword property string passwordValidationError: "" - property string toValidationError: "" - property string amountValidationError: "" function send() { if (!validate()) { @@ -20,7 +18,7 @@ Item { } let result = walletModel.onSendTransaction(selectFromAccount.selectedAccount.address, selectRecipient.selectedRecipient, - selectAsset.selectedAsset.address, + txtAmount.selectedAsset.address, txtAmount.text, txtPassword.text) @@ -47,7 +45,17 @@ Item { passwordValidationError = "" } - return passwordValidationError === "" && toValidationError === "" && amountValidationError === "" && isRecipientValid && isAssetAndAmountValid + return passwordValidationError === "" && isRecipientValid && isAssetAndAmountValid + } + + function showPreview() { + pvwTransaction.visible = true + txtAmount.visible = selectFromAccount.visible = selectRecipient.visible = txtPassword.visible = gasSelector.visible = false + } + + function showInputs() { + pvwTransaction.visible = false + txtAmount.visible = selectFromAccount.visible = selectRecipient.visible = txtPassword.visible = gasSelector.visible = true } anchors.left: parent.left @@ -58,6 +66,9 @@ Item { title: "Error sending the transaction" icon: StandardIcon.Critical standardButtons: StandardButton.Ok + onAccepted: { + sendModalContent.showInputs() + } } MessageDialog { id: sendingSuccess @@ -67,6 +78,7 @@ Item { standardButtons: StandardButton.Ok onAccepted: { closePopup() + sendModalContent.showInputs() } } @@ -87,20 +99,21 @@ Item { anchors.topMargin: Style.current.padding anchors.left: parent.left anchors.right: parent.right + label: qsTr("From account") onSelectedAccountChanged: { txtAmount.selectedAccount = selectFromAccount.selectedAccount } } GasSelector { - id: gasSelector - anchors.top: selectFromAccount.bottom - anchors.topMargin: Style.current.bigPadding - slowestGasPrice: parseFloat(walletModel.safeLowGasPrice) - fastestGasPrice: parseFloat(walletModel.fastestGasPrice) - getGasEthValue: walletModel.getGasEthValue - getFiatValue: walletModel.getFiatValue - defaultCurrency: walletModel.defaultCurrency + id: gasSelector + anchors.top: selectFromAccount.bottom + anchors.topMargin: Style.current.bigPadding + slowestGasPrice: parseFloat(walletModel.safeLowGasPrice) + fastestGasPrice: parseFloat(walletModel.fastestGasPrice) + getGasEthValue: walletModel.getGasEthValue + getFiatValue: walletModel.getFiatValue + defaultCurrency: walletModel.defaultCurrency } RecipientSelector { @@ -114,6 +127,23 @@ Item { anchors.right: parent.right } + TransactionPreview { + id: pvwTransaction + visible: false + anchors.left: parent.left + anchors.right: parent.right + fromAccount: selectFromAccount.selectedAccount + gas: { + const value = walletModel.getGasEthValue(gasSelector.selectedGasPrice, gasSelector.selectedGasLimit) + const fiatValue = walletModel.getFiatValue(value, "ETH", walletModel.defaultCurrency) + return { value, "symbol": "ETH", fiatValue } + } + toAccount: selectRecipient.selectedRecipient + asset: txtAmount.selectedAsset + amount: { "value": txtAmount.selectedAmount, "fiatValue": txtAmount.selectedFiatAmount } + currency: walletModel.defaultCurrency + } + Input { id: txtPassword //% "Password" @@ -125,6 +155,7 @@ Item { textField.echoMode: TextInput.Password validationError: passwordValidationError } + } /*##^## diff --git a/ui/imports/Utils.qml b/ui/imports/Utils.qml index b79a0073ae..5478979a44 100644 --- a/ui/imports/Utils.qml +++ b/ui/imports/Utils.qml @@ -69,4 +69,15 @@ QtObject { function isValidAddress(inputValue) { return /0x[a-fA-F0-9]{40}/.test(inputValue) } + + /** + * Removes trailing zeros from a string-representation of a number. Throws + * if parameter is not a string + */ + function stripTrailingZeros(strNumber) { + if (!(typeof strNumber === "string")) { + throw "must be a string" + } + return strNumber.replace(/(\.[0-9]*[1-9])0+$|\.0*$/,'$1') + } } diff --git a/ui/nim-status-client.pro b/ui/nim-status-client.pro index 4664176059..eac56d108c 100644 --- a/ui/nim-status-client.pro +++ b/ui/nim-status-client.pro @@ -313,6 +313,7 @@ DISTFILES += \ shared/AddButton.qml \ shared/IconButton.qml \ shared/Input.qml \ + shared/LabelValueRow.qml \ shared/ModalPopup.qml \ shared/NotificationWindow.qml \ shared/PopupMenu.qml \ @@ -332,6 +333,7 @@ DISTFILES += \ shared/StyledTextField.qml \ shared/SVGImage.qml \ shared/TextWithLabel.qml \ + shared/TransactionPreview.qml \ shared/img/check.svg \ shared/img/close.svg \ shared/img/loading.png \ diff --git a/ui/shared/AccountSelector.qml b/ui/shared/AccountSelector.qml index a5214795a1..5f76129e60 100644 --- a/ui/shared/AccountSelector.qml +++ b/ui/shared/AccountSelector.qml @@ -20,6 +20,7 @@ Item { // nothing will be displayed property string showAssetBalance: "" property int dropdownWidth: width + property alias dropdownAlignment: select.menuAlignment Repeater { visible: showAssetBalance !== "" @@ -71,11 +72,10 @@ Item { id: selectedTextField text: selectedAccount.name elide: Text.ElideRight - anchors.right: parent.right - anchors.rightMargin: Style.current.bigPadding anchors.left: selectedIconImg.right anchors.leftMargin: 8 anchors.verticalCenter: parent.verticalCenter + width: select.contentWidth - (Style.current.padding + selectedIconImg.width + anchors.leftMargin) font.pixelSize: 15 verticalAlignment: Text.AlignVCenter height: 22 @@ -143,15 +143,17 @@ Item { id: column anchors.left: iconImg.right anchors.leftMargin: 14 + anchors.right: txtFiatBalance.left + anchors.rightMargin: 8 anchors.verticalCenter: parent.verticalCenter StyledText { id: accountName text: name elide: Text.ElideRight - anchors.right: parent.right - anchors.left: parent.left font.pixelSize: 15 + anchors.left: parent.left + anchors.right: parent.right height: 22 } @@ -166,6 +168,7 @@ Item { } } StyledText { + id: txtFiatBalance anchors.right: fiatCurrencySymbol.left anchors.rightMargin: 4 anchors.verticalCenter: parent.verticalCenter diff --git a/ui/shared/AssetAndAmountInput.qml b/ui/shared/AssetAndAmountInput.qml index 360fe39a29..c7b703ef9c 100644 --- a/ui/shared/AssetAndAmountInput.qml +++ b/ui/shared/AssetAndAmountInput.qml @@ -9,11 +9,10 @@ Item { property string greaterThan0ErrorMessage: qsTr("Must be greater than 0") //% "This needs to be a number" property string invalidInputErrorMessage: qsTrId("this-needs-to-be-a-number") - //% "You need to enter an amount" - property string noInputErrorMessage: qsTrId("you-need-to-enter-an-amount") + property string noInputErrorMessage: qsTr("Please enter an amount") property string defaultCurrency: "USD" - property string fiatBalance: "0.00" - property alias text: inputAmount.text + property alias selectedFiatAmount: txtFiatBalance.text + property alias selectedAmount: inputAmount.text property var selectedAccount property alias selectedAsset: selectAsset.selectedAsset property var getFiatValue: function () {} @@ -62,7 +61,7 @@ Item { if (!selectAsset.selectedAsset) { return } - txtBalance.text = selectAsset.selectedAsset.value + txtBalance.text = Utils.stripTrailingZeros(selectAsset.selectedAsset.value) } Item { @@ -83,7 +82,7 @@ Item { StyledText { id: txtBalance property bool hovered: false - text: selectAsset.selectedAsset ? selectAsset.selectedAsset.value : "0.00" + text: selectAsset.selectedAsset ? Utils.stripTrailingZeros(selectAsset.selectedAsset.value) : "0.00" anchors.right: parent.right font.weight: Font.Medium font.pixelSize: 13 @@ -146,7 +145,7 @@ Item { anchors.right: parent.right anchors.rightMargin: Style.current.smallPadding onSelectedAssetChanged: { - txtBalance.text = selectAsset.selectedAsset.value + txtBalance.text = Utils.stripTrailingZeros(selectAsset.selectedAsset.value) if (inputAmount.text === "" || isNan(inputAmount.text)) { return } @@ -168,7 +167,7 @@ Item { font.weight: Font.Medium font.pixelSize: 12 inputMethodHints: Qt.ImhFormattedNumbersOnly - text: root.fiatBalance + text: "0.00" selectByMouse: true background: Rectangle { color: Style.current.transparent diff --git a/ui/shared/ContactSelector.qml b/ui/shared/ContactSelector.qml index f096032e2f..5c3e2c345c 100644 --- a/ui/shared/ContactSelector.qml +++ b/ui/shared/ContactSelector.qml @@ -28,6 +28,7 @@ Item { select.select.border.width = 0 validationErrorText.visible = false } + return isValid } Select { diff --git a/ui/shared/GasSelector.qml b/ui/shared/GasSelector.qml index 41bea01f85..5c60b59bdd 100644 --- a/ui/shared/GasSelector.qml +++ b/ui/shared/GasSelector.qml @@ -23,9 +23,13 @@ Item { } function updateGasEthValue() { + // causes error on application load without this null check + if (!inputGasPrice || !inputGasLimit) { + return + } let ethValue = root.getGasEthValue(inputGasPrice.text, inputGasLimit.text) let fiatValue = root.getFiatValue(ethValue, "ETH", root.defaultCurrency) - let summary = ethValue + " ETH ~" + fiatValue + " " + root.defaultCurrency.toUpperCase() + let summary = Utils.stripTrailingZeros(ethValue) + " ETH ~" + fiatValue + " " + root.defaultCurrency.toUpperCase() labelGasPriceSummary.text = summary labelGasPriceSummaryAdvanced.text = summary } diff --git a/ui/shared/LabelValueRow.qml b/ui/shared/LabelValueRow.qml new file mode 100644 index 0000000000..5b432dc274 --- /dev/null +++ b/ui/shared/LabelValueRow.qml @@ -0,0 +1,32 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.13 +import "../imports" + +Item { + id: itmFrom + property alias label: txtLabel.text + property alias value: itmValue.children + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + Layout.preferredWidth: parent.width + width: parent.width + height: 52 + + StyledText { + id: txtLabel + font.pixelSize: 15 + height: parent.height + anchors.left: parent.left + anchors.leftMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + verticalAlignment: Text.AlignVCenter + width: 105 + } + Item { + id: itmValue + anchors.left: txtLabel.right + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + height: parent.height + } +} \ No newline at end of file diff --git a/ui/shared/RecipientSelector.qml b/ui/shared/RecipientSelector.qml index 2ea823930f..996b1d04c6 100644 --- a/ui/shared/RecipientSelector.qml +++ b/ui/shared/RecipientSelector.qml @@ -18,6 +18,12 @@ Item { height: (readOnly ? inpReadOnly.height : inpAddress.height) + txtLabel.height readonly property string addressValidationError: qsTr("Invalid ethereum address") + enum Type { + Address, + Contact, + Account + } + function validate() { let isValid = true if (readOnly) { @@ -97,7 +103,7 @@ Item { if (root.readOnly) { return } - root.selectedRecipient = { address: selectedAddress } + root.selectedRecipient = { address: selectedAddress, type: RecipientSelector.Type.Address } } } @@ -115,7 +121,8 @@ Item { return } if(selectedContact && selectedContact.address) { - root.selectedRecipient = { name: selectedContact.name, address: selectedContact.address } + const { address, name, alias, isContact, identicon, ensVerified } = selectedContact + root.selectedRecipient = { address, name, alias, isContact, identicon, ensVerified, type: RecipientSelector.Type.Contact } } } } @@ -134,7 +141,8 @@ Item { if (root.readOnly) { return } - root.selectedRecipient = { address: selectedAccount.address } + const { address, name, iconColor, assets, fiatBalance } = selectedAccount + root.selectedRecipient = { address, name, iconColor, assets, fiatBalance, type: RecipientSelector.Type.Account } } } AddressSourceSelector { @@ -149,21 +157,31 @@ Item { if (root.readOnly) { return } + let address, name switch (selectedSource) { case "Address": inpAddress.visible = true selContact.visible = selAccount.visible = false root.height = Qt.binding(function() { return inpAddress.height + txtLabel.height }) + root.selectedRecipient = { address: inpAddress.selectedAddress, type: RecipientSelector.Type.Address } break; case "Contact": selContact.visible = true inpAddress.visible = selAccount.visible = false root.height = Qt.binding(function() { return selContact.height + txtLabel.height }) + let { alias, isContact, identicon, ensVerified } = selContact.selectedContact + address = selContact.selectedContact.address + name = selContact.selectedContact.name + root.selectedRecipient = { address, name, alias, isContact, identicon, ensVerified, type: RecipientSelector.Type.Contact } break; case "My account": selAccount.visible = true inpAddress.visible = selContact.visible = false root.height = Qt.binding(function() { return selAccount.height + txtLabel.height }) + const { iconColor, assets, fiatBalance } = selAccount.selectedAccount + address = selAccount.selectedAccount.address + name = selAccount.selectedAccount.name + root.selectedRecipient = { address, name, iconColor, assets, fiatBalance, type: RecipientSelector.Type.Account } break; } } diff --git a/ui/shared/Select.qml b/ui/shared/Select.qml index 82c6b515d0..ace4705a05 100644 --- a/ui/shared/Select.qml +++ b/ui/shared/Select.qml @@ -7,7 +7,8 @@ import "../imports" Item { enum MenuAlignment { Left, - Right + Right, + Center } property string label: "" readonly property bool hasLabel: label !== "" @@ -18,9 +19,11 @@ Item { property color bgColorHover: bgColor property alias selectedItemView: selectedItemContainer.children property int caretRightMargin: Style.current.padding + property int caretLeftMargin: 8 property alias select: inputRectangle property int menuAlignment: Select.MenuAlignment.Right property Item zeroItemsView: Item {} + property int contentWidth: inputRectangle.width - (caret.width + caretRightMargin + caretLeftMargin) anchors.left: parent.left anchors.right: parent.right @@ -147,7 +150,17 @@ Item { selectMenu.close() } else { const rightOffset = inputRectangle.width - selectMenu.width - const offset = root.menuAlignment === Select.MenuAlignment.Left ? 0 : rightOffset + let offset = rightOffset + switch (root.menuAlignment) { + case Select.MenuAlignment.Left: + offset = 0 + break + case Select.MenuAlignment.Right: + offset = rightOffset + break + case Select.MenuAlignment.Center: + offset = rightOffset / 2 + } selectMenu.popup(inputRectangle.x + offset, inputRectangle.y + inputRectangle.height + 8) } } diff --git a/ui/shared/TransactionPreview.qml b/ui/shared/TransactionPreview.qml new file mode 100644 index 0000000000..29e6f2ef76 --- /dev/null +++ b/ui/shared/TransactionPreview.qml @@ -0,0 +1,361 @@ +import QtQuick 2.13 +import QtQuick.Controls 2.13 +import QtQuick.Layouts 1.13 +import QtGraphicalEffects 1.13 +import "../imports" + +Item { + id: root + property var fromAccount: ({}) + property var toAccount: ({ type: "" }) + property var asset: ({ name: "", symbol: "" }) + property var amount: ({ value: "", fiatValue: "", currency: "" }) + property string currency: "USD" + property var gas: ({ value: "", symbol: "", fiatValue: "" }) + height: itmFrom.height + + Column { + anchors.left: parent.left + anchors.right: parent.right + + LabelValueRow { + id: itmFrom + label: qsTr("From") + value: Item { + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + + StyledText { + font.pixelSize: 15 + height: 22 + text: root.fromAccount.name + elide: Text.ElideRight + anchors.left: parent.left + anchors.right: imgFromWallet.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + SVGImage { + id: imgFromWallet + sourceSize.height: 18 + sourceSize.width: 18 + anchors.right: parent.right + anchors.rightMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.PreserveAspectFit + source: "../app/img/walletIcon.svg" + } + ColorOverlay { + anchors.fill: imgFromWallet + source: imgFromWallet + color: fromAccount.iconColor + } + } + } + LabelValueRow { + id: itmTo + property var props: { "primaryText": "replace1", "secondaryText": "me1" } + label: qsTr("Recipient") + states: [ + State { + name: "Address" + when: root.toAccount.type === RecipientSelector.Type.Address + PropertyChanges { + target: txtToPrimary + text: root.toAccount.address + elide: Text.ElideMiddle + anchors.leftMargin: 190 + } + PropertyChanges { + target: txtToSecondary + width: 0 + } + }, + State { + name: "Contact" + when: root.toAccount.type === RecipientSelector.Type.Contact && !!root.toAccount.address + PropertyChanges { + target: metSecondary + text: root.toAccount.ensVerified ? root.toAccount.alias : root.toAccount.address + } + PropertyChanges { + target: txtToSecondary + anchors.rightMargin: Style.current.padding + idtToContact.width + 8 + width: metSecondary.elidedWidth + text: metSecondary.elidedText + } + PropertyChanges { + target: idtToContact + source: root.toAccount.identicon + visible: true + } + PropertyChanges { + target: txtToPrimary + text: Utils.removeStatusEns(root.toAccount.name) + } + }, + State { + name: "Account" + when: root.toAccount.type === RecipientSelector.Type.Account && !!root.toAccount.address + PropertyChanges { + target: metSecondary + text: root.toAccount.address + } + PropertyChanges { + target: txtToSecondary + anchors.rightMargin: Style.current.padding + imgToWallet.width + 8 + text: metSecondary.elidedText + width: metSecondary.elidedWidth + } + PropertyChanges { + target: imgToWallet + visible: true + } + PropertyChanges { + target: ovlToWallet + visible: true + color: root.toAccount.iconColor + } + PropertyChanges { + target: txtToPrimary + text: root.toAccount.name + } + } + ] + value: Item { + id: recipientRoot + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + + StyledText { + id: txtToPrimary + font.pixelSize: 15 + height: 22 + anchors.left: parent.left + anchors.right: txtToSeparator.left + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + StyledText { + id: txtToSeparator + font.pixelSize: 15 + height: 22 + text: " • " + visible: txtToSecondary.visible && txtToSecondary.width > 0 + color: Style.current.secondaryText + anchors.right: txtToSecondary.left + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + StyledText { + id: txtToSecondary + visible: true + font.pixelSize: 15 + height: 22 + color: Style.current.secondaryText + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + TextMetrics { + id: metSecondary + elideWidth: 102 + elide: Text.ElideMiddle + } + SVGImage { + id: imgToWallet + visible: false + sourceSize.height: 18 + sourceSize.width: 18 + anchors.right: parent.right + anchors.rightMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.PreserveAspectFit + source: "../app/img/walletIcon.svg" + } + ColorOverlay { + id: ovlToWallet + anchors.fill: imgToWallet + visible: false + source: imgToWallet + } + Identicon { + id: idtToContact + visible: false + anchors.right: parent.right + anchors.rightMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + width: 32 + height: 32 + } + } + } + LabelValueRow { + id: itmAsset + label: qsTr("Asset") + value: Item { + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + + StyledText { + font.pixelSize: 15 + height: 22 + text: (root.asset && root.asset.name) ? root.asset.name : "" + anchors.left: parent.left + anchors.right: txtAssetSymbol.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + StyledText { + id: txtAssetSymbol + font.pixelSize: 15 + height: 22 + text: (root.asset && root.asset.symbol) ? root.asset.symbol : "" + color: Style.current.secondaryText + anchors.right: imgAsset.left + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + Image { + id: imgAsset + sourceSize.height: 32 + sourceSize.width: 32 + anchors.right: parent.right + anchors.rightMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + fillMode: Image.PreserveAspectFit + source: "../app/img/tokens/" + ((root.asset && root.asset.symbol) ? root.asset.symbol : "ETH") + ".png" + onStatusChanged: { + if (status == Image.Error) { + source = "../app/img/tokens/0-native.png" + } + } + } + } + } + LabelValueRow { + id: itmAmount + label: qsTr("Amount") + value: Item { + id: amountRoot + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + + StyledText { + font.pixelSize: 15 + height: 22 + text: root.amount.value ? Utils.stripTrailingZeros(root.amount.value) : "" + anchors.left: parent.left + anchors.right: txtAmountSymbol.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + StyledText { + id: txtAmountSymbol + font.pixelSize: 15 + height: 22 + text: ((root.asset && root.asset.symbol) ? root.asset.symbol : "") + " •" + color: Style.current.secondaryText + anchors.right: txtAmountFiat.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + StyledText { + id: txtAmountFiat + font.pixelSize: 15 + height: 22 + text: "~" + (root.amount.fiatValue ? root.amount.fiatValue : "0.00") + anchors.right: txtAmountCurrency.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + StyledText { + id: txtAmountCurrency + font.pixelSize: 15 + height: 22 + text: root.currency.toUpperCase() + color: Style.current.secondaryText + anchors.right: parent.right + anchors.rightMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + } + } + LabelValueRow { + id: itmNetworkFee + label: qsTr("Network fee") + value: Item { + id: networkFeeRoot + anchors.fill: parent + anchors.verticalCenter: parent.verticalCenter + + StyledText { + font.pixelSize: 15 + height: 22 + text: (root.gas && root.gas.value) ? Utils.stripTrailingZeros(root.gas.value) : "" + anchors.left: parent.left + anchors.right: txtFeeSymbol.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + StyledText { + id: txtFeeSymbol + font.pixelSize: 15 + height: 22 + text: ((root.gas && root.gas.symbol) ? root.gas.symbol : "") + " •" + color: Style.current.secondaryText + anchors.right: txtFeeFiat.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + StyledText { + id: txtFeeFiat + font.pixelSize: 15 + height: 22 + text: "~" + ((root.gas && root.gas.fiatValue) ? root.gas.fiatValue : "0.00") + anchors.right: txtFeeCurrency.left + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + StyledText { + id: txtFeeCurrency + font.pixelSize: 15 + height: 22 + text: root.currency.toUpperCase() + color: Style.current.secondaryText + anchors.right: parent.right + anchors.rightMargin: Style.current.padding + anchors.verticalCenter: parent.verticalCenter + horizontalAlignment: Text.AlignRight + verticalAlignment: Text.AlignVCenter + } + } + } + } +}