From 02134c4fc664334be07036d7511c89382376e480 Mon Sep 17 00:00:00 2001
From: xiphon <xiphon@protonmail.com>
Date: Fri, 30 Nov 2018 03:51:03 +0000
Subject: [PATCH] transfer: paste Payment URL to fill the payment form fields

---
 clipboardAdapter.cpp              |  4 +++
 clipboardAdapter.h                |  1 +
 components/LineEditMulti.qml      | 46 ++++++++++++++++++++-----------
 pages/Transfer.qml                | 12 ++++++++
 src/libwalletqt/WalletManager.cpp | 26 ++++++++++++++++-
 src/libwalletqt/WalletManager.h   |  4 ++-
 6 files changed, 75 insertions(+), 18 deletions(-)

diff --git a/clipboardAdapter.cpp b/clipboardAdapter.cpp
index f1920937..b558936a 100644
--- a/clipboardAdapter.cpp
+++ b/clipboardAdapter.cpp
@@ -38,3 +38,7 @@ void clipboardAdapter::setText(const QString &text) {
     m_pClipboard->setText(text, QClipboard::Clipboard);
     m_pClipboard->setText(text, QClipboard::Selection);
 }
+
+QString clipboardAdapter::text() const {
+    return m_pClipboard->text();
+}
diff --git a/clipboardAdapter.h b/clipboardAdapter.h
index 9d9f7c22..415a7240 100644
--- a/clipboardAdapter.h
+++ b/clipboardAdapter.h
@@ -39,6 +39,7 @@ class clipboardAdapter : public QObject
 public:
     explicit clipboardAdapter(QObject *parent = 0);
     Q_INVOKABLE void setText(const QString &text);
+    Q_INVOKABLE QString text() const;
 
 private:
     QClipboard *m_pClipboard;
diff --git a/components/LineEditMulti.qml b/components/LineEditMulti.qml
index 87cee6d4..63b2dee2 100644
--- a/components/LineEditMulti.qml
+++ b/components/LineEditMulti.qml
@@ -74,6 +74,10 @@ ColumnLayout {
     property bool mouseSelection: true
     property alias readOnly: input.readOnly
     property bool copyButton: false
+    property bool pasteButton: false
+    property var onPaste: function(clipboardText) {
+        item.text = clipboardText;
+    }
     property bool showingHeader: true
     property var wrapMode: Text.NoWrap
     property alias addressValidation: input.addressValidation
@@ -109,25 +113,35 @@ ColumnLayout {
             }
         }
 
-        MoneroComponents.LabelButton {
-            id: labelButton
-            onClicked: labelButtonClicked()
-            visible: labelButtonVisible
-        }
+        RowLayout {
+            anchors.right: parent.right
+            spacing: 16 * scaleRatio
 
-        MoneroComponents.LabelButton {
-            id: copyButtonId
-            visible: copyButton && input.text !== ""
-            text: qsTr("Copy")
-            anchors.right: labelButton.visible ? inputLabel.right : parent.right
-            anchors.rightMargin: labelButton.visible? 4 : 0
-            onClicked: {
-                if (input.text.length > 0) {
-                    console.log("Copied to clipboard");
-                    clipboard.setText(input.text);
-                    appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
+            MoneroComponents.LabelButton {
+                id: labelButton
+                onClicked: labelButtonClicked()
+                visible: labelButtonVisible
+            }
+
+            MoneroComponents.LabelButton {
+                id: copyButtonId
+                visible: copyButton && input.text !== ""
+                text: qsTr("Copy")
+                onClicked: {
+                    if (input.text.length > 0) {
+                        console.log("Copied to clipboard");
+                        clipboard.setText(input.text);
+                        appWindow.showStatusMessage(qsTr("Copied to clipboard"), 3);
+                    }
                 }
             }
+
+            MoneroComponents.LabelButton {
+                id: pasteButtonId
+                onClicked: item.onPaste(clipboard.text())
+                text: qsTr("Paste")
+                visible: pasteButton
+            }
         }
     }
 
diff --git a/pages/Transfer.qml b/pages/Transfer.qml
index f543c1f2..3207e432 100644
--- a/pages/Transfer.qml
+++ b/pages/Transfer.qml
@@ -215,6 +215,18 @@ Rectangle {
               wrapMode: Text.WrapAnywhere
               addressValidation: true
               onInputLabelLinkActivated: { appWindow.showPageRequest("AddressBook") }
+              pasteButton: true
+              onPaste: function(clipboardText) {
+                  const parsed = walletManager.parse_uri_to_object(clipboardText);
+                  if (!parsed.error) {
+                    addressLine.text = parsed.address;
+                    paymentIdLine.text = parsed.payment_id;
+                    amountLine.text = parsed.amount;
+                    descriptionLine.text = parsed.tx_description;
+                  } else {
+                     addressLine.text = clipboardText; 
+                  }
+              }
           }
 
           StandardButton {
diff --git a/src/libwalletqt/WalletManager.cpp b/src/libwalletqt/WalletManager.cpp
index 355527ad..777cdef7 100644
--- a/src/libwalletqt/WalletManager.cpp
+++ b/src/libwalletqt/WalletManager.cpp
@@ -296,13 +296,37 @@ QString WalletManager::resolveOpenAlias(const QString &address) const
     res = std::string(dnssec_valid ? "true" : "false") + "|" + res;
     return QString::fromStdString(res);
 }
-bool WalletManager::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error)
+bool WalletManager::parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const
 {
     if (m_currentWallet)
         return m_currentWallet->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error);
     return false;
 }
 
+QVariantMap WalletManager::parse_uri_to_object(const QString &uri) const
+{
+    QString address;
+    QString payment_id;
+    uint64_t amount;
+    QString tx_description;
+    QString recipient_name;
+    QVector<QString> unknown_parameters;
+    QString error;
+
+    QVariantMap result;
+    if (this->parse_uri(uri, address, payment_id, amount, tx_description, recipient_name, unknown_parameters, error)) {
+        result.insert("address", address);
+        result.insert("payment_id", payment_id);
+        result.insert("amount", this->displayAmount(amount));
+        result.insert("tx_description", tx_description);
+        result.insert("recipient_name", recipient_name);
+    } else {
+        result.insert("error", error);
+    }
+    
+    return result;
+}
+
 void WalletManager::setLogLevel(int logLevel)
 {
     Monero::WalletManagerFactory::setLogLevel(logLevel);
diff --git a/src/libwalletqt/WalletManager.h b/src/libwalletqt/WalletManager.h
index 75626928..cefbd49f 100644
--- a/src/libwalletqt/WalletManager.h
+++ b/src/libwalletqt/WalletManager.h
@@ -1,6 +1,7 @@
 #ifndef WALLETMANAGER_H
 #define WALLETMANAGER_H
 
+#include <QVariant>
 #include <QObject>
 #include <QUrl>
 #include <wallet/api/wallet2_api.h>
@@ -141,7 +142,8 @@ public:
 #endif
 
     Q_INVOKABLE QString resolveOpenAlias(const QString &address) const;
-    Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error);
+    Q_INVOKABLE bool parse_uri(const QString &uri, QString &address, QString &payment_id, uint64_t &amount, QString &tx_description, QString &recipient_name, QVector<QString> &unknown_parameters, QString &error) const;
+    Q_INVOKABLE QVariantMap parse_uri_to_object(const QString &uri) const;
     Q_INVOKABLE bool saveQrCode(const QString &, const QString &) const;
     Q_INVOKABLE void checkUpdatesAsync(const QString &software, const QString &subdir) const;
     Q_INVOKABLE QString checkUpdates(const QString &software, const QString &subdir) const;