monero-gui/pages/Transfer.qml

799 lines
32 KiB
QML
Raw Normal View History

// Copyright (c) 2014-2019, The Monero Project
2015-04-01 08:56:05 +00: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 01:17:29 +00:00
import QtQuick 2.9
2016-12-17 15:57:42 +00:00
import QtQuick.Layouts 1.1
import QtQuick.Dialogs 1.2
2017-12-06 13:09:37 +00: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 21:53:07 +00:00
import "../components"
import "../components" as MoneroComponents
import "." 1.0
import "../js/TxUtils.js" as TxUtils
2014-07-07 17:08:30 +00:00
2016-06-27 12:45:48 +00:00
2014-07-07 17:08:30 +00:00
Rectangle {
2016-08-23 13:07:52 +00:00
id: root
signal paymentClicked(string address, string paymentId, string amount, int mixinCount,
int priority, string description)
signal sweepUnmixableClicked()
2017-11-25 21:53:07 +00:00
color: "transparent"
2019-05-07 05:19:40 +00:00
property alias transferHeight1: pageRoot.height
property alias transferHeight2: advancedLayout.height
property int mixin: 10 // (ring size 11)
property string warningContent: ""
property string sendButtonWarning: ""
property string startLinkText: qsTr("<style type='text/css'>a {text-decoration: none; color: #FF6C3C; font-size: 14px;}</style><font size='2'> (</font><a href='#'>Start daemon</a><font size='2'>)</font>") + translationManager.emptyString
2017-02-27 21:05:28 +00:00
property bool showAdvanced: false
// @TODO: remove after pid removal hardfork
property bool warningLongPidTransfer: false
property bool warningLongPidDescription: descriptionLine.text.match(/^[0-9a-f]{64}$/i)
2014-07-10 22:18:36 +00:00
2017-12-06 13:09:37 +00:00
Clipboard { id: clipboard }
2017-11-25 21:53:07 +00:00
2016-12-17 15:57:42 +00: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 04:36:08 +00:00
function updateFromQrCode(address, payment_id, amount, tx_description, recipient_name) {
console.log("updateFromQrCode")
addressLine.text = address
setPaymentId(payment_id);
2017-01-31 04:36:08 +00:00
amountLine.text = amount
setDescription(recipient_name + " " + tx_description);
2017-01-31 04:36:08 +00: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 != "";
}
function isLongPidService(text) {
// @TODO: remove after pid removal hardfork
return text.length == 95 &&
[ "44tLjmXrQNrWJ5NBsEj2R77ZBEgDa3fEe9GLpSf2FRmhexPvfYDUAB7EXX1Hdb3aMQ9FLqdJ56yaAhiXoRsceGJCRS3Jxkn", // Binance
"4AQ3ZREb53FMYKBmpPn7BD7hphPk6G1ceinQX6gefAvhFJsNbeFsGwebZWCNxoJAbZhD9cjetBAqmLhfXmcNLBpPMsBL6yM", // KuCoin
"47YzEcMrU2S42UitURo7ukUDaSaL485Z1QbmFgq1vSs5g3JesL4rChwWf2uWk1va99JAaRxt65jhX9uAqQnjeFM44ckgZtp", // AnycoinDirect
"4BCeEPhodgPMbPWFN1dPwhWXdRX8q4mhhdZdA1dtSMLTLCEYvAj9QXjXAfF7CugEbmfBhgkqHbdgK9b2wKA6nqRZQCgvCDm", // Bitfinex
"463tWEBn5XZJSxLU6uLQnQ2iY9xuNcDbjLSjkn3XAXHCbLrTTErJrBWYgHJQyrCwkNgYvyV3z8zctJLPCZy24jvb3NiTcTJ" // Bittrex
].indexOf(text) > -1
}
2017-02-04 13:44:30 +00:00
function clearFields() {
addressLine.text = ""
setPaymentId("");
2017-02-04 13:44:30 +00:00
amountLine.text = ""
root.sendButtonWarning = ""
setDescription("");
priorityDropdown.currentIndex = 0
updatePriorityDropdown()
2017-02-04 13:44:30 +00:00
}
2016-12-17 15:57:42 +00:00
// Information dialog
StandardDialog {
// dynamically change onclose handler
property var onCloseCallback
id: oaPopup
cancelVisible: false
onAccepted: {
if (onCloseCallback) {
onCloseCallback()
}
}
}
2017-08-08 09:10:44 +00:00
ColumnLayout {
id: pageRoot
2019-09-05 22:11:12 +00:00
anchors.margins: 20
2019-04-25 19:09:23 +00:00
anchors.topMargin: 40
2017-12-06 13:09:37 +00:00
2017-01-12 19:53:27 +00:00
anchors.left: parent.left
2017-12-06 13:09:37 +00:00
anchors.top: parent.top
2017-01-12 19:53:27 +00:00
anchors.right: parent.right
2017-08-08 09:10:44 +00:00
2019-04-25 19:09:23 +00:00
spacing: 30
RowLayout {
visible: root.warningContent !== ""
MoneroComponents.WarningBox {
text: warningContent
onLinkActivated: {
appWindow.startDaemon(appWindow.persistentSettings.daemonFlags);
}
}
}
2019-09-06 13:52:45 +00: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 09:10:44 +00:00
GridLayout {
2019-09-05 22:11:12 +00:00
columns: appWindow.walletMode < 2 ? 1 : 2
2017-08-08 09:10:44 +00:00
Layout.fillWidth: true
2017-12-08 23:01:10 +00:00
columnSpacing: 32
2017-12-06 13:09:37 +00:00
2017-08-08 09:10:44 +00:00
ColumnLayout {
Layout.fillWidth: true
2019-04-25 19:09:23 +00:00
Layout.minimumWidth: 200
2017-02-27 21:05:28 +00:00
// Amount input
LineEdit {
id: amountLine
Layout.fillWidth: true
inlineIcon: true
labelText: qsTr("<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
Amount <font size='2'> ( </font> <a href='#'>Change account</a><font size='2'> )</font>")
+ translationManager.emptyString
2019-11-24 23:57:59 +00:00
copyButton: !isNaN(amountLine.text) && persistentSettings.fiatPriceEnabled
copyButtonText: fiatApiCurrencySymbol() + " ~" + fiatApiConvertToFiat(amountLine.text)
copyButtonEnabled: false
onLabelLinkActivated: {
middlePanel.accountView.selectAndSend = true;
appWindow.showPageRequest("Account")
}
placeholderText: "0.00"
2019-04-25 19:09:23 +00:00
width: 100
fontBold: true
inlineButtonText: qsTr("All") + translationManager.emptyString
inlineButton.onClicked: amountLine.text = "(all)"
onTextChanged: {
2019-12-05 10:13:29 +00: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;
}
}
}
validator: RegExpValidator {
regExp: /^(\d{1,8})?([\.]\d{1,12})?$/
2017-08-08 09:10:44 +00:00
}
2017-02-27 21:05:28 +00:00
}
2017-08-08 09:10:44 +00:00
}
2017-02-27 21:05:28 +00:00
2017-08-08 09:10:44 +00:00
ColumnLayout {
2019-02-25 01:45:06 +00:00
visible: appWindow.walletMode >= 2
2017-08-08 09:10:44 +00:00
Layout.fillWidth: true
Label {
id: transactionPriority
2019-04-25 19:09:23 +00:00
Layout.topMargin: 12
2017-08-08 09:10:44 +00:00
text: qsTr("Transaction priority") + translationManager.emptyString
fontBold: false
2019-04-25 19:09:23 +00:00
fontSize: 16
2017-08-08 09:10:44 +00: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 21:53:07 +00:00
2017-08-08 09:10:44 +00:00
// Priorites after v5
ListModel {
id: priorityModelV5
ListElement { column1: qsTr("Automatic") ; column2: ""; priority: 0}
2019-10-13 17:07:52 +00:00
ListElement { column1: qsTr("Slow (x0.2 fee)") ; column2: ""; priority: 1}
ListElement { column1: qsTr("Normal (x1 fee)") ; column2: ""; priority: 2 }
2017-08-08 09:10:44 +00:00
ListElement { column1: qsTr("Fast (x5 fee)") ; column2: ""; priority: 3 }
2019-10-13 17:07:52 +00:00
ListElement { column1: qsTr("Fastest (x200 fee)") ; column2: ""; priority: 4 }
2017-08-08 09:10:44 +00:00
}
StandardDropdown {
Layout.fillWidth: true
id: priorityDropdown
2019-04-25 19:09:23 +00:00
Layout.topMargin: 5
currentIndex: 0
2017-08-08 09:10:44 +00:00
}
}
// Make sure dropdown is on top
z: parent.z + 1
2017-02-27 21:05:28 +00:00
}
2017-12-06 13:09:37 +00:00
// recipient address input
RowLayout {
id: addressLineRow
2017-08-08 09:10:44 +00:00
Layout.fillWidth: true
2017-11-25 21:53:07 +00:00
LineEditMulti {
2017-12-08 23:01:10 +00:00
id: addressLine
spacing: 0
fontBold: true
2018-03-21 22:56:53 +00:00
labelText: qsTr("<style type='text/css'>a {text-decoration: none; color: #858585; font-size: 14px;}</style>\
Address <font size='2'> ( </font> <a href='#'>Address book</a><font size='2'> )</font>")
2017-12-08 23:01:10 +00:00
+ 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
onInputLabelLinkActivated: {
middlePanel.addressBookView.selectAndSend = true;
appWindow.showPageRequest("AddressBook");
}
pasteButton: 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);
}
2019-09-28 02:00:51 +00:00
warningLongPidTransfer = isLongPidService(text);
}
inlineButton.text: FontAwesome.qrcode
inlineButton.fontPixelSize: 22
inlineButton.fontFamily: FontAwesome.fontFamily
inlineButton.textColor: MoneroComponents.Style.defaultFontColor
inlineButton.buttonColor: MoneroComponents.Style.orange
inlineButton.onClicked: {
2017-12-06 13:09:37 +00:00
cameraUi.state = "Capture"
cameraUi.qrcode_decoded.connect(updateFromQrCode)
}
inlineButtonVisible : appWindow.qrScannerEnabled && !addressLine.text
2017-08-08 09:10:44 +00:00
}
2017-12-06 13:09:37 +00:00
}
2017-02-27 21:05:28 +00:00
2018-04-22 01:48:31 +00:00
StandardButton {
id: resolveButton
2019-04-25 19:09:23 +00:00
width: 80
2018-04-22 01:48:31 +00:00
text: qsTr("Resolve") + translationManager.emptyString
visible: TxUtils.isValidOpenAliasAddress(addressLine.text)
enabled : visible
2018-04-22 01:48:31 +00: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 01:48:31 +00: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 01:48:31 +00: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 09:10:44 +00:00
}
2017-02-27 21:05:28 +00:00
ColumnLayout {
2019-09-28 02:00:51 +00:00
visible: paymentIdCheckbox.checked
// @TODO: remove after pid removal hardfork
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 02:00:51 +00:00
readOnly: true
Layout.fillWidth: true
wrapMode: Text.WrapAnywhere
addressValidation: false
visible: paymentIdCheckbox.checked
}
2017-08-08 09:10:44 +00:00
}
2017-12-06 13:09:37 +00:00
}
2017-02-27 21:05:28 +00:00
MoneroComponents.WarningBox {
// @TODO: remove after pid removal hardfork
id: paymentIdWarningBox
2019-09-28 02:00:51 +00: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;
visible: warningLongPidTransfer || paymentIdCheckbox.checked
}
MoneroComponents.WarningBox {
id: sendButtonWarningBox
text: root.sendButtonWarning
visible: root.sendButtonWarning !== ""
}
2017-12-06 13:09:37 +00:00
RowLayout {
2017-03-08 19:54:11 +00:00
StandardButton {
id: sendButton
2019-04-11 01:17:29 +00:00
rightIcon: "qrc:///images/rightArrow.png"
rightIconInactive: "qrc:///images/rightArrowInactive.png"
2019-04-25 19:09:23 +00:00
Layout.topMargin: 4
2017-03-08 19:54:11 +00:00
text: qsTr("Send") + translationManager.emptyString
enabled: {
updateSendButton()
}
2017-03-08 19:54:11 +00:00
onClicked: {
console.log("Transfer: paymentClicked")
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
2017-03-08 19:54:11 +00: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 19:54:11 +00:00
}
2017-02-27 21:05:28 +00:00
}
}
2017-03-08 19:54:11 +00:00
2018-03-05 16:19:45 +00:00
function checkInformation(amount, address, payment_id, nettype) {
2017-08-08 09:10:44 +00:00
address = address.trim()
payment_id = payment_id.trim()
var amount_ok = amount.length > 0
2018-03-05 16:19:45 +00:00
var address_ok = walletManager.addressValid(address, nettype)
var payment_id_ok = payment_id.length == 0 || (payment_id.length == 64 && walletManager.paymentIdValid(payment_id))
2018-03-05 16:19:45 +00:00
var ipid = walletManager.paymentIdFromAddress(address, nettype)
2017-08-08 09:10:44 +00:00
if (ipid.length > 0 && payment_id.length > 0)
payment_id_ok = false
addressLine.error = !address_ok
amountLine.error = !amount_ok
paymentIdLine.error = !payment_id_ok
return amount_ok && address_ok && payment_id_ok
}
2017-03-08 19:54:11 +00:00
2017-01-12 19:53:27 +00:00
} // pageRoot
2017-01-12 19:53:27 +00:00
ColumnLayout {
2019-05-07 05:19:40 +00:00
id: advancedLayout
2017-01-12 19:53:27 +00:00
anchors.top: pageRoot.bottom
anchors.left: parent.left
anchors.right: parent.right
2019-09-05 22:11:12 +00:00
anchors.margins: 20
2019-04-25 19:09:23 +00:00
anchors.topMargin: 32
spacing: 26
2017-01-12 19:53:27 +00:00
enabled: !viewOnly || pageRoot.enabled
RowLayout {
2019-01-14 00:02:44 +00:00
visible: appWindow.walletMode >= 2
CheckBox2 {
2017-02-27 21:05:28 +00:00
id: showAdvancedCheckbox
checked: persistentSettings.transferShowAdvanced
onClicked: {
persistentSettings.transferShowAdvanced = !persistentSettings.transferShowAdvanced
}
text: qsTr("Advanced options") + translationManager.emptyString
2017-01-12 19:53:27 +00:00
}
}
2017-04-03 16:51:55 +00:00
GridLayout {
2019-01-14 00:02:44 +00:00
visible: persistentSettings.transferShowAdvanced && appWindow.walletMode >= 2
2019-09-05 22:11:12 +00:00
columns: 6
2017-04-03 16:51:55 +00:00
2017-01-12 19:53:27 +00:00
StandardButton {
id: sweepUnmixableButton
2017-02-27 22:02:33 +00:00
text: qsTr("Sweep Unmixable") + translationManager.emptyString
2017-01-12 19:53:27 +00:00
enabled : pageRoot.enabled
small: true
2017-01-12 19:53:27 +00:00
onClicked: {
console.log("Transfer: sweepUnmixableClicked")
root.sweepUnmixableClicked()
}
}
StandardButton {
id: saveTxButton
2017-03-28 23:15:55 +00:00
text: qsTr("Create tx file") + translationManager.emptyString
2017-01-12 19:53:27 +00:00
visible: appWindow.viewOnly
2018-03-05 16:19:45 +00:00
enabled: pageRoot.checkInformation(amountLine.text, addressLine.text, paymentIdLine.text, appWindow.persistentSettings.nettype)
small: true
2017-01-12 19:53:27 +00:00
onClicked: {
console.log("Transfer: saveTx Clicked")
var priority = priorityModelV5.get(priorityDropdown.currentIndex).priority
2017-01-12 19:53:27 +00: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 19:53:27 +00:00
}
}
StandardButton {
id: signTxButton
2017-03-19 02:57:48 +00:00
text: qsTr("Sign tx file") + translationManager.emptyString
small: true
2017-01-12 19:53:27 +00:00
visible: !appWindow.viewOnly
onClicked: {
console.log("Transfer: sign tx clicked")
signTxDialog.open();
}
}
StandardButton {
id: submitTxButton
2017-03-19 02:57:48 +00:00
text: qsTr("Submit tx file") + translationManager.emptyString
small: true
2017-01-12 19:53:27 +00:00
visible: appWindow.viewOnly
enabled: pageRoot.enabled
onClicked: {
console.log("Transfer: submit tx clicked")
submitTxDialog.open();
}
}
2018-05-14 21:43:52 +00: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
visible: appWindow.viewOnly && walletManager.isDaemonLocal(appWindow.currentDaemonAddress)
enabled: pageRoot.enabled
onClicked: {
console.log("Transfer: import key images clicked")
importKeyImagesDialog.open();
}
}
2017-01-12 19:53:27 +00:00
}
}
//SignTxDialog
FileDialog {
id: signTxDialog
title: qsTr("Please choose a file") + translationManager.emptyString
2017-01-12 19:53:27 +00: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 19:53:27 +00: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 19:53:27 +00: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 22:53:29 +00:00
informationPopup.text = qsTr("Monero sent successfully") + translationManager.emptyString
2017-01-12 19:53:27 +00:00
informationPopup.icon = StandardIcon.Information
informationPopup.onCloseCallback = null
informationPopup.open();
}
}
onRejected: {
console.log("Canceled")
}
}
2018-05-14 21:43:52 +00: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 00:02:44 +00:00
var messageNotConnected = qsTr("Wallet is not connected to daemon.");
if(appWindow.walletMode >= 2) messageNotConnected += root.startLinkText;
pageRoot.enabled = true;
if(typeof currentWallet === "undefined") {
2019-01-14 00:02:44 +00:00
root.warningContent = messageNotConnected;
return;
}
if (currentWallet.viewOnly) {
// warningText.text = qsTr("Wallet is view only.")
2017-01-12 19:53:27 +00:00
//return;
}
//pageRoot.enabled = false;
switch (currentWallet.connected()) {
case Wallet.ConnectionStatus_Disconnected:
2019-01-14 00:02:44 +00: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 00:02:44 +00:00
root.warningContent = qsTr("Waiting on daemon synchronization to finish.")
} else {
// everything OK, enable transfer page
2017-08-08 09:10:44 +00:00
// Light wallet is always ready
pageRoot.enabled = true;
root.warningContent = "";
}
}
}
2016-12-10 01:01:04 +00: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 01:01:04 +00:00
}
function updateSendButton(){
// reset message
root.sendButtonWarning = "";
// Currently opened wallet is not view-only
if(appWindow.viewOnly){
root.sendButtonWarning = 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;
return false;
}
// There are sufficient unlocked funds available
if(parseFloat(amountLine.text) > parseFloat(middlePanel.unlockedBalanceText)){
root.sendButtonWarning = qsTr("Amount is more than unlocked balance.") + translationManager.emptyString;
return false;
}
// There is no warning box displayed
if(root.warningContent !== ""){
return false;
}
// The transactional information is correct
if(!pageRoot.checkInformation(amountLine.text, addressLine.text, paymentIdLine.text, appWindow.persistentSettings.nettype)){
if(amountLine.text && addressLine.text)
root.sendButtonWarning = qsTr("Transaction information is incorrect.") + translationManager.emptyString;
return false;
}
2019-09-28 02:00:51 +00:00
if (paymentIdWarningBox.visible) {
return false;
}
return true;
}
2014-07-07 17:08:30 +00:00
}