1
mirror of https://github.com/monero-project/monero-gui synced 2024-11-30 08:40:03 +01:00
monero-gui/pages/Transfer.qml

809 lines
32 KiB
QML
Raw Normal View History

// Copyright (c) 2014-2019, The Monero Project
2015-04-01 10:56:05 +02:00
//
// 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.
2019-04-11 03:17:29 +02:00
import QtQuick 2.9
import QtQuick.Controls 1.4
2016-12-17 16:57:42 +01:00
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
2017-12-06 14:09:37 +01:00
import moneroComponents.Clipboard 1.0
import moneroComponents.PendingTransaction 1.0
import moneroComponents.Wallet 1.0
import moneroComponents.NetworkType 1.0
import FontAwesome 1.0
2017-11-25 22:53:07 +01:00
import "../components"
import "../components" as MoneroComponents
import "." 1.0
import "../js/TxUtils.js" as TxUtils
import "../js/Utils.js" as Utils
2014-07-07 19:08:30 +02:00
2016-06-27 14:45:48 +02:00
2014-07-07 19:08:30 +02:00
Rectangle {
2016-08-23 15:07:52 +02:00
id: root
signal paymentClicked(string address, string paymentId, string amount, int mixinCount,
int priority, string description)
signal sweepUnmixableClicked()
2017-11-25 22:53:07 +01:00
color: "transparent"
2019-05-07 07:19:40 +02:00
property alias transferHeight1: pageRoot.height
property alias transferHeight2: advancedLayout.height
property int mixin: 10 // (ring size 11)
property string warningContent: ""
property string sendButtonWarning: {
// Currently opened wallet is not view-only
if (appWindow.viewOnly) {
return qsTr("Wallet is view-only and sends are not possible. Unless key images are imported, " +
"the balance reflects only incoming but not outgoing transactions.") + translationManager.emptyString;
}
// There are sufficient unlocked funds available
if (walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()) {
return qsTr("Amount is more than unlocked balance.") + translationManager.emptyString;
}
if (addressLine.text)
{
// Address is valid
if (!TxUtils.checkAddress(addressLine.text, appWindow.persistentSettings.nettype)) {
return qsTr("Address is invalid.") + translationManager.emptyString;
}
// Amount is nonzero
if (!amountLine.text || parseFloat(amountLine.text) <= 0) {
return qsTr("Enter an amount.") + translationManager.emptyString;
}
}
return "";
}
property string startLinkText: "<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 14px;}</style><a href='#'>(%1)</a>".arg(qsTr("Start daemon")) + translationManager.emptyString
property bool warningLongPidDescription: descriptionLine.text.match(/^[0-9a-f]{64}$/i)
2014-07-11 00:18:36 +02:00
2017-12-06 14:09:37 +01:00
Clipboard { id: clipboard }
2017-11-25 22:53:07 +01:00
2016-12-17 16:57:42 +01:00
function oa_message(text) {
oaPopup.title = qsTr("OpenAlias error") + translationManager.emptyString
oaPopup.text = text
oaPopup.icon = StandardIcon.Information
oaPopup.onCloseCallback = null
oaPopup.open()
}
2017-01-31 05:36:08 +01:00
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
console.log("updateFromQrCode")
addressLine.text = address
setPaymentId(payment_id);
2017-01-31 05:36:08 +01:00
amountLine.text = amount
setDescription(recipient_name + " " + tx_description);
2017-01-31 05:36:08 +01:00
cameraUi.qrcode_decoded.disconnect(updateFromQrCode)
}
function setDescription(value) {
descriptionLine.text = value;
descriptionCheckbox.checked = descriptionLine.text != "";
}
function setPaymentId(value) {
paymentIdLine.text = value;
paymentIdCheckbox.checked = paymentIdLine.text != "";
}
2017-02-04 14:44:30 +01:00
function clearFields() {
addressLine.text = ""
setPaymentId("");
2017-02-04 14:44:30 +01:00
amountLine.text = ""
setDescription("");
priorityDropdown.currentIndex = 0
updatePriorityDropdown()
2017-02-04 14:44:30 +01:00
}
2016-12-17 16:57:42 +01:00
// Information dialog
StandardDialog {
// dynamically change onclose handler
property var onCloseCallback
id: oaPopup
cancelVisible: false
onAccepted: {
if (onCloseCallback) {
onCloseCallback()
}
}
}
2017-08-08 11:10:44 +02:00
ColumnLayout {
id: pageRoot
2019-09-06 00:11:12 +02:00
anchors.margins: 20
2019-04-25 21:09:23 +02:00
anchors.topMargin: 40
2017-12-06 14:09:37 +01:00
2017-01-12 20:53:27 +01:00
anchors.left: parent.left
2017-12-06 14:09:37 +01:00
anchors.top: parent.top
2017-01-12 20:53:27 +01:00
anchors.right: parent.right
2017-08-08 11:10:44 +02:00
2019-04-25 21:09:23 +02:00
spacing: 30
RowLayout {
visible: root.warningContent !== ""
MoneroComponents.WarningBox {
text: warningContent
onLinkActivated: {
appWindow.startDaemon(appWindow.persistentSettings.daemonFlags);
}
}
}
2019-09-06 15:52:45 +02:00
RowLayout {
visible: leftPanel.minutesToUnlock !== ""
MoneroComponents.WarningBox {
text: qsTr("Spendable funds: %1 XMR. Please wait ~%2 minutes for your whole balance to become spendable.").arg(leftPanel.balanceUnlockedString).arg(leftPanel.minutesToUnlock)
}
}
2017-08-08 11:10:44 +02:00
GridLayout {
2019-09-06 00:11:12 +02:00
columns: appWindow.walletMode < 2 ? 1 : 2
2017-08-08 11:10:44 +02:00
Layout.fillWidth: true
2017-12-09 00:01:10 +01:00
columnSpacing: 32
2017-12-06 14:09:37 +01:00
2017-08-08 11:10:44 +02:00
ColumnLayout {
Layout.fillWidth: true
2019-04-25 21:09:23 +02:00
Layout.minimumWidth: 200
2017-02-27 22:05:28 +01:00
// Amount input
LineEdit {
id: amountLine
Layout.fillWidth: true
inlineIcon: true
labelText: "<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
%1 <a href='#'>(%2)</a>".arg(qsTr("Amount")).arg(qsTr("Change account"))
+ translationManager.emptyString
2019-11-25 00:57:59 +01:00
copyButton: !isNaN(amountLine.text) && persistentSettings.fiatPriceEnabled
copyButtonText: "~%1 %2".arg(fiatApiConvertToFiat(amountLine.text)).arg(fiatApiCurrencySymbol())
copyButtonEnabled: false
onLabelLinkActivated: {
middlePanel.accountView.selectAndSend = true;
appWindow.showPageRequest("Account")
}
placeholderText: "0.00"
2019-04-25 21:09:23 +02:00
width: 100
fontBold: true
inlineButtonText: qsTr("All") + translationManager.emptyString
inlineButton.onClicked: amountLine.text = "(all)"
onTextChanged: {
2019-12-05 11:13:29 +01:00
const match = amountLine.text.match(/^0+(\d.*)/);
if (match) {
const cursorPosition = amountLine.cursorPosition;
amountLine.text = match[1];
amountLine.cursorPosition = Math.max(cursorPosition, 1) - 1;
} else if(amountLine.text.indexOf('.') === 0){
amountLine.text = '0' + amountLine.text;
if (amountLine.text.length > 2) {
amountLine.cursorPosition = 1;
}
}
2019-12-19 01:16:00 +01:00
amountLine.error = walletManager.amountFromString(amountLine.text) > appWindow.getUnlockedBalance()
}
validator: RegExpValidator {
regExp: /^(\d{1,8})?([\.]\d{1,12})?$/
2017-08-08 11:10:44 +02:00
}
2017-02-27 22:05:28 +01:00
}
MoneroComponents.TextPlain {
id: feeLabel
Layout.alignment: Qt.AlignRight
Layout.topMargin: 12
font.family: MoneroComponents.Style.fontRegular.name
font.pixelSize: 14
color: MoneroComponents.Style.defaultFontColor
property bool estimating: false
property var estimatedFee: null
property string estimatedFeeFiat: {
if (!persistentSettings.fiatPriceEnabled || estimatedFee == null) {
return "";
}
const fiatFee = fiatApiConvertToFiat(estimatedFee);
return " (%1 %3)".arg(fiatFee < 0.01 ? "<0.01" : "~" + fiatFee).arg(fiatApiCurrencySymbol());
}
property var fee: {
estimatedFee = null;
estimating = sendButton.enabled;
if (!sendButton.enabled) {
return;
}
currentWallet.estimateTransactionFeeAsync(
addressLine.text,
walletManager.amountFromString(amountLine.text),
priorityModelV5.get(priorityDropdown.currentIndex).priority,
function (amount) {
estimatedFee = Utils.removeTrailingZeros(amount);
estimating = false;
});
}
text: {
if (!sendButton.enabled || estimatedFee == null) {
return ""
}
return "%1: ~%2 XMR".arg(qsTr("Fee")).arg(estimatedFee) +
estimatedFeeFiat +
translationManager.emptyString;
}
BusyIndicator {
anchors.right: parent.right
running: feeLabel.estimating
height: parent.height
}
}
2017-08-08 11:10:44 +02:00
}
2017-02-27 22:05:28 +01:00
2017-08-08 11:10:44 +02:00
ColumnLayout {
2019-02-25 02:45:06 +01:00
visible: appWindow.walletMode >= 2
Layout.alignment: Qt.AlignTop
2017-08-08 11:10:44 +02:00
Label {
id: transactionPriority
Layout.topMargin: 0
2017-08-08 11:10:44 +02:00
text: qsTr("Transaction priority") + translationManager.emptyString
fontBold: false
2019-04-25 21:09:23 +02:00
fontSize: 16
2017-08-08 11:10:44 +02:00
}
// Note: workaround for translations in listElements
// ListElement: cannot use script for property value, so
// code like this wont work:
// ListElement { column1: qsTr("LOW") + translationManager.emptyString ; column2: ""; priority: PendingTransaction.Priority_Low }
// For translations to work, the strings need to be listed in
// the file components/StandardDropdown.qml too.
2017-11-25 22:53:07 +01:00
2017-08-08 11:10:44 +02:00
// Priorites after v5
ListModel {
id: priorityModelV5
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
2019-10-13 19:07:52 +02:00
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
2017-08-08 11:10:44 +02:00
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
2019-10-13 19:07:52 +02:00
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
2017-08-08 11:10:44 +02:00
}
StandardDropdown {
Layout.preferredWidth: 200
2017-08-08 11:10:44 +02:00
id: priorityDropdown
2019-04-25 21:09:23 +02:00
Layout.topMargin: 5
currentIndex: 0
2017-08-08 11:10:44 +02:00
}
}
2017-02-27 22:05:28 +01:00
}
2017-12-06 14:09:37 +01:00
// recipient address input
RowLayout {
id: addressLineRow
2017-08-08 11:10:44 +02:00
Layout.fillWidth: true
2017-11-25 22:53:07 +01:00
LineEditMulti {
2017-12-09 00:01:10 +01:00
id: addressLine
spacing: 0
inputPaddingRight: inlineButtonVisible && inlineButton2Visible ? 100 : 60
fontBold: true
labelText: qsTr("Address") + translationManager.emptyString
labelButtonText: qsTr("Resolve") + translationManager.emptyString
placeholderText: {
if(persistentSettings.nettype == NetworkType.MAINNET){
return "4.. / 8.. / OpenAlias";
} else if (persistentSettings.nettype == NetworkType.STAGENET){
return "5.. / 7..";
} else if(persistentSettings.nettype == NetworkType.TESTNET){
return "9.. / B..";
}
}
wrapMode: Text.WrapAnywhere
addressValidation: true
onTextChanged: {
const parsed = walletManager.parse_uri_to_object(text);
if (!parsed.error) {
addressLine.text = parsed.address;
setPaymentId(parsed.payment_id);
amountLine.text = parsed.amount;
setDescription(parsed.tx_description);
}
}
inlineButton.text: FontAwesome.addressBook
inlineButton.buttonHeight: 30
inlineButton.fontPixelSize: 22
inlineButton.fontFamily: FontAwesome.fontFamily
inlineButton.textColor: MoneroComponents.Style.defaultFontColor
inlineButton.onClicked: {
middlePanel.addressBookView.selectAndSend = true;
appWindow.showPageRequest("AddressBook");
}
inlineButtonVisible: true
inlineButton2.text: FontAwesome.qrcode
inlineButton2.buttonHeight: 30
inlineButton2.fontPixelSize: 22
inlineButton2.fontFamily: FontAwesome.fontFamily
inlineButton2.textColor: MoneroComponents.Style.defaultFontColor
inlineButton2.onClicked: {
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
2017-12-06 14:09:37 +01:00
}
inlineButton2Visible: appWindow.qrScannerEnabled
2017-08-08 11:10:44 +02:00
}
2017-12-06 14:09:37 +01:00
}
2017-02-27 22:05:28 +01:00
2018-04-22 03:48:31 +02:00
StandardButton {
id: resolveButton
2019-04-25 21:09:23 +02:00
width: 80
2018-04-22 03:48:31 +02:00
text: qsTr("Resolve") + translationManager.emptyString
visible: TxUtils.isValidOpenAliasAddress(addressLine.text)
enabled : visible
2018-04-22 03:48:31 +02:00
onClicked: {
var result = walletManager.resolveOpenAlias(addressLine.text)
if (result) {
var parts = result.split("|")
if (parts.length == 2) {
var address_ok = walletManager.addressValid(parts[1], appWindow.persistentSettings.nettype)
2018-04-22 03:48:31 +02:00
if (parts[0] === "true") {
if (address_ok) {
// prepend openalias to description
descriptionLine.text = descriptionLine.text ? addressLine.text + " " + descriptionLine.text : addressLine.text
descriptionCheckbox.checked = true
2018-04-22 03:48:31 +02:00
addressLine.text = parts[1]
}
else
oa_message(qsTr("No valid address found at this OpenAlias address"))
}
else if (parts[0] === "false") {
if (address_ok) {
addressLine.text = parts[1]
oa_message(qsTr("Address found, but the DNSSEC signatures could not be verified, so this address may be spoofed"))
}
else
{
oa_message(qsTr("No valid address found at this OpenAlias address, but the DNSSEC signatures could not be verified, so this may be spoofed"))
}
}
else {
oa_message(qsTr("Internal error"))
}
}
else {
oa_message(qsTr("Internal error"))
}
}
else {
oa_message(qsTr("No address found"))
}
}
}
MoneroComponents.WarningBox {
text: qsTr("Description field contents match long payment ID format. \
Please don't paste long payment ID into description field, your funds might be lost.") + translationManager.emptyString;
visible: warningLongPidDescription
}
ColumnLayout {
spacing: 15
ColumnLayout {
CheckBox {
id: descriptionCheckbox
border: false
checkedIcon: FontAwesome.minusCircle
uncheckedIcon: FontAwesome.plusCircle
fontAwesomeIcons: true
fontSize: descriptionLine.labelFontSize
iconOnTheLeft: true
Layout.fillWidth: true
text: qsTr("Add description") + translationManager.emptyString
onClicked: {
if (!descriptionCheckbox.checked) {
descriptionLine.text = "";
}
}
}
LineEditMulti {
id: descriptionLine
placeholderText: qsTr("Saved to local wallet history") + translationManager.emptyString
Layout.fillWidth: true
visible: descriptionCheckbox.checked
}
2017-08-08 11:10:44 +02:00
}
2017-02-27 22:05:28 +01:00
ColumnLayout {
2019-09-28 04:00:51 +02:00
visible: paymentIdCheckbox.checked
CheckBox {
id: paymentIdCheckbox
border: false
checkedIcon: FontAwesome.minusCircle
uncheckedIcon: FontAwesome.plusCircle
fontAwesomeIcons: true
fontSize: paymentIdLine.labelFontSize
iconOnTheLeft: true
Layout.fillWidth: true
text: qsTr("Add payment ID") + translationManager.emptyString
onClicked: {
if (!paymentIdCheckbox.checked) {
paymentIdLine.text = "";
}
}
}
// payment id input
LineEditMulti {
id: paymentIdLine
fontBold: true
placeholderText: qsTr("64 hexadecimal characters") + translationManager.emptyString
2019-09-28 04:00:51 +02:00
readOnly: true
Layout.fillWidth: true
wrapMode: Text.WrapAnywhere
addressValidation: false
visible: paymentIdCheckbox.checked
2019-12-19 13:47:19 +01:00
error: paymentIdCheckbox.checked
}
2017-08-08 11:10:44 +02:00
}
2017-12-06 14:09:37 +01:00
}
2017-02-27 22:05:28 +01:00
MoneroComponents.WarningBox {
id: paymentIdWarningBox
2019-09-28 04:00:51 +02:00
text: qsTr("Long payment IDs are obsolete. \
Long payment IDs were not encrypted on the blockchain and would harm your privacy. \
If the party you're sending to still requires a long payment ID, please notify them.") + translationManager.emptyString;
2019-12-19 13:47:19 +01:00
visible: paymentIdCheckbox.checked || warningLongPidDescription
}
MoneroComponents.WarningBox {
id: sendButtonWarningBox
text: root.sendButtonWarning
visible: root.sendButtonWarning !== ""
}
2017-12-06 14:09:37 +01:00
RowLayout {
2017-03-08 20:54:11 +01:00
StandardButton {
id: sendButton
2019-04-11 03:17:29 +02:00
rightIcon: "qrc:///images/rightArrow.png"
rightIconInactive: "qrc:///images/rightArrowInactive.png"
2019-04-25 21:09:23 +02:00
Layout.topMargin: 4
2017-03-08 20:54:11 +01:00
text: qsTr("Send") + translationManager.emptyString
enabled: !sendButtonWarningBox.visible && !warningContent && addressLine.text && !paymentIdWarningBox.visible
2017-03-08 20:54:11 +01:00
onClicked: {
console.log("Transfer: paymentClicked")
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
2017-03-08 20:54:11 +01:00
console.log("priority: " + priority)
console.log("amount: " + amountLine.text)
addressLine.text = addressLine.text.trim()
setPaymentId(paymentIdLine.text.trim());
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, root.mixin, priority, descriptionLine.text)
2017-03-08 20:54:11 +01:00
}
2017-02-27 22:05:28 +01:00
}
}
2017-03-08 20:54:11 +01:00
2019-12-19 01:16:00 +01:00
function checkInformation(amount, address, nettype) {
return amount.length > 0 && walletManager.amountFromString(amountLine.text) <= appWindow.getUnlockedBalance() && TxUtils.checkAddress(address, nettype)
2017-08-08 11:10:44 +02:00
}
2017-03-08 20:54:11 +01:00
2017-01-12 20:53:27 +01:00
} // pageRoot
2017-01-12 20:53:27 +01:00
ColumnLayout {
2019-05-07 07:19:40 +02:00
id: advancedLayout
2017-01-12 20:53:27 +01:00
anchors.top: pageRoot.bottom
anchors.left: parent.left
anchors.right: parent.right
2019-09-06 00:11:12 +02:00
anchors.margins: 20
2019-04-25 21:09:23 +02:00
anchors.topMargin: 32
spacing: 26
2017-01-12 20:53:27 +01:00
enabled: !viewOnly || pageRoot.enabled
RowLayout {
2019-01-14 01:02:44 +01:00
visible: appWindow.walletMode >= 2
CheckBox2 {
2017-02-27 22:05:28 +01:00
id: showAdvancedCheckbox
checked: persistentSettings.transferShowAdvanced
onClicked: {
persistentSettings.transferShowAdvanced = !persistentSettings.transferShowAdvanced
}
text: qsTr("Advanced options") + translationManager.emptyString
2017-01-12 20:53:27 +01:00
}
}
2017-04-03 18:51:55 +02:00
GridLayout {
2019-01-14 01:02:44 +01:00
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
2019-09-06 00:11:12 +02:00
columns: 6
2017-04-03 18:51:55 +02:00
2017-01-12 20:53:27 +01:00
StandardButton {
id: sweepUnmixableButton
2017-02-27 23:02:33 +01:00
text: qsTr("Sweep Unmixable") + translationManager.emptyString
2017-01-12 20:53:27 +01:00
enabled : pageRoot.enabled
small: true
2017-01-12 20:53:27 +01:00
onClicked: {
console.log("Transfer: sweepUnmixableClicked")
root.sweepUnmixableClicked()
}
}
StandardButton {
id: saveTxButton
2017-03-29 01:15:55 +02:00
text: qsTr("Create tx file") + translationManager.emptyString
2017-01-12 20:53:27 +01:00
visible: appWindow.viewOnly
2019-12-19 01:16:00 +01:00
enabled: pageRoot.checkInformation(amountLine.text, addressLine.text, appWindow.persistentSettings.nettype)
small: true
2017-01-12 20:53:27 +01:00
onClicked: {
console.log("Transfer: saveTx Clicked")
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
2017-01-12 20:53:27 +01:00
console.log("priority: " + priority)
console.log("amount: " + amountLine.text)
addressLine.text = addressLine.text.trim()
setPaymentId(paymentIdLine.text.trim());
root.paymentClicked(addressLine.text, paymentIdLine.text, amountLine.text, root.mixin, priority, descriptionLine.text)
2017-01-12 20:53:27 +01:00
}
}
StandardButton {
id: signTxButton
2017-03-19 03:57:48 +01:00
text: qsTr("Sign tx file") + translationManager.emptyString
small: true
2017-01-12 20:53:27 +01:00
visible: !appWindow.viewOnly
onClicked: {
console.log("Transfer: sign tx clicked")
signTxDialog.open();
}
}
StandardButton {
id: submitTxButton
2017-03-19 03:57:48 +01:00
text: qsTr("Submit tx file") + translationManager.emptyString
small: true
2017-01-12 20:53:27 +01:00
visible: appWindow.viewOnly
enabled: pageRoot.enabled
onClicked: {
console.log("Transfer: submit tx clicked")
submitTxDialog.open();
}
}
2018-05-14 23:43:52 +02:00
StandardButton {
id: exportKeyImagesButton
text: qsTr("Export key images") + translationManager.emptyString
small: true
visible: !appWindow.viewOnly
enabled: pageRoot.enabled
onClicked: {
console.log("Transfer: export key images clicked")
exportKeyImagesDialog.open();
}
}
StandardButton {
id: importKeyImagesButton
text: qsTr("Import key images") + translationManager.emptyString
small: true
enabled: appWindow.viewOnly && appWindow.isTrustedDaemon()
2018-05-14 23:43:52 +02:00
onClicked: {
console.log("Transfer: import key images clicked")
importKeyImagesDialog.open();
}
}
2017-01-12 20:53:27 +01:00
}
}
//SignTxDialog
FileDialog {
id: signTxDialog
title: qsTr("Please choose a file") + translationManager.emptyString
2017-01-12 20:53:27 +01:00
folder: "file://" +moneroAccountsDir
nameFilters: [ "Unsigned transfers (*)"]
onAccepted: {
var path = walletManager.urlToLocalPath(fileUrl);
// Load the unsigned tx from file
var transaction = currentWallet.loadTxFile(path);
if (transaction.status !== PendingTransaction.Status_Ok) {
console.error("Can't load unsigned transaction: ", transaction.errorString);
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Can't load unsigned transaction: ") + transaction.errorString
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
// deleting transaction object, we don't want memleaks
transaction.destroy();
} else {
confirmationDialog.text = qsTr("\nNumber of transactions: ") + transaction.txCount
for (var i = 0; i < transaction.txCount; ++i) {
confirmationDialog.text += qsTr("\nTransaction #%1").arg(i+1)
+qsTr("\nRecipient: ") + transaction.recipientAddress[i]
+ (transaction.paymentId[i] == "" ? "" : qsTr("\n\payment ID: ") + transaction.paymentId[i])
+ qsTr("\nAmount: ") + walletManager.displayAmount(transaction.amount(i))
+ qsTr("\nFee: ") + walletManager.displayAmount(transaction.fee(i))
+ qsTr("\nRingsize: ") + (transaction.mixin(i)+1)
2017-01-12 20:53:27 +01:00
// TODO: add descriptions to unsigned_tx_set?
// + (transactionDescription === "" ? "" : (qsTr("\n\nDescription: ") + transactionDescription))
+ translationManager.emptyString
if (i > 0) {
confirmationDialog.text += "\n\n"
}
}
console.log(transaction.confirmationMessage);
// Show confirmation dialog
confirmationDialog.title = qsTr("Confirmation") + translationManager.emptyString
confirmationDialog.icon = StandardIcon.Question
confirmationDialog.onAcceptedCallback = function() {
transaction.sign(path+"_signed");
transaction.destroy();
};
confirmationDialog.onRejectedCallback = transaction.destroy;
confirmationDialog.open()
}
}
onRejected: {
// File dialog closed
console.log("Canceled")
}
}
//SignTxDialog
FileDialog {
id: submitTxDialog
title: qsTr("Please choose a file") + translationManager.emptyString
2017-01-12 20:53:27 +01:00
folder: "file://" +moneroAccountsDir
nameFilters: [ "signed transfers (*)"]
onAccepted: {
if(!currentWallet.submitTxFile(walletManager.urlToLocalPath(fileUrl))){
informationPopup.title = qsTr("Error") + translationManager.emptyString;
informationPopup.text = qsTr("Can't submit transaction: ") + currentWallet.errorString
informationPopup.icon = StandardIcon.Critical
informationPopup.onCloseCallback = null
informationPopup.open();
} else {
informationPopup.title = qsTr("Information") + translationManager.emptyString
2018-03-23 23:53:29 +01:00
informationPopup.text = qsTr("Monero sent successfully") + translationManager.emptyString
2017-01-12 20:53:27 +01:00
informationPopup.icon = StandardIcon.Information
informationPopup.onCloseCallback = null
informationPopup.open();
}
}
onRejected: {
console.log("Canceled")
}
}
2018-05-14 23:43:52 +02:00
//ExportKeyImagesDialog
FileDialog {
id: exportKeyImagesDialog
selectMultiple: false
selectExisting: false
onAccepted: {
console.log(walletManager.urlToLocalPath(exportKeyImagesDialog.fileUrl))
currentWallet.exportKeyImages(walletManager.urlToLocalPath(exportKeyImagesDialog.fileUrl));
}
onRejected: {
console.log("Canceled");
}
}
//ImportKeyImagesDialog
FileDialog {
id: importKeyImagesDialog
selectMultiple: false
selectExisting: true
title: qsTr("Please choose a file") + translationManager.emptyString
onAccepted: {
console.log(walletManager.urlToLocalPath(importKeyImagesDialog.fileUrl))
currentWallet.importKeyImages(walletManager.urlToLocalPath(importKeyImagesDialog.fileUrl));
}
onRejected: {
console.log("Canceled");
}
}
Component.onCompleted: {
//Disable password page until enabled by updateStatus
pageRoot.enabled = false
}
// fires on every page load
function onPageCompleted() {
console.log("transfer page loaded")
updateStatus();
updatePriorityDropdown()
}
function updatePriorityDropdown() {
priorityDropdown.dataModel = priorityModelV5;
priorityDropdown.update()
}
//TODO: Add daemon sync status
//TODO: enable send page when we're connected and daemon is synced
function updateStatus() {
2019-01-14 01:02:44 +01:00
var messageNotConnected = qsTr("Wallet is not connected to daemon.");
if(appWindow.walletMode >= 2 && !persistentSettings.useRemoteNode) messageNotConnected += root.startLinkText;
pageRoot.enabled = true;
if(typeof currentWallet === "undefined") {
2019-01-14 01:02:44 +01:00
root.warningContent = messageNotConnected;
return;
}
if (currentWallet.viewOnly) {
// warningText.text = qsTr("Wallet is view only.")
2017-01-12 20:53:27 +01:00
//return;
}
//pageRoot.enabled = false;
switch (currentWallet.connected()) {
case Wallet.ConnectionStatus_Connecting:
case Wallet.ConnectionStatus_Disconnected:
2019-01-14 01:02:44 +01:00
root.warningContent = messageNotConnected;
break
case Wallet.ConnectionStatus_WrongVersion:
root.warningContent = qsTr("Connected daemon is not compatible with GUI. \n" +
"Please upgrade or connect to another daemon")
break
default:
if(!appWindow.daemonSynced){
2019-01-14 01:02:44 +01:00
root.warningContent = qsTr("Waiting on daemon synchronization to finish.")
} else {
// everything OK, enable transfer page
2017-08-08 11:10:44 +02:00
// Light wallet is always ready
pageRoot.enabled = true;
root.warningContent = "";
}
}
}
2016-12-10 02:01:04 +01:00
// Popuplate fields from addressbook.
function sendTo(address, paymentId, description, amount){
middlePanel.state = 'Transfer';
if(typeof address !== 'undefined')
addressLine.text = address
if(typeof paymentId !== 'undefined')
setPaymentId(paymentId);
if(typeof description !== 'undefined')
setDescription(description);
if(typeof amount !== 'undefined')
amountLine.text = amount;
2016-12-10 02:01:04 +01:00
}
2014-07-07 19:08:30 +02:00
}