Pay payment requests
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
<qresource prefix="/icons">
|
<qresource prefix="/icons">
|
||||||
<file>res/connected.gif</file>
|
<file>res/connected.gif</file>
|
||||||
<file>res/loading.gif</file>
|
<file>res/loading.gif</file>
|
||||||
|
<file>res/paymentreq.gif</file>
|
||||||
<file>res/icon.ico</file>
|
<file>res/icon.ico</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
<qresource prefix="/img">
|
<qresource prefix="/img">
|
||||||
|
|||||||
BIN
res/paymentreq.gif
Normal file
BIN
res/paymentreq.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
@@ -804,12 +804,6 @@ void MainWindow::payZcashURI(QString uri) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error to display if something goes wrong.
|
|
||||||
auto payZcashURIError = [=] (QString errorDetail = "") {
|
|
||||||
QMessageBox::critical(this, tr("Error paying zcash URI"),
|
|
||||||
tr("URI should be of the form 'zcash:<addr>?amt=x&memo=y") + "\n" + errorDetail);
|
|
||||||
};
|
|
||||||
|
|
||||||
// If there was no URI passed, ask the user for one.
|
// If there was no URI passed, ask the user for one.
|
||||||
if (uri.isEmpty()) {
|
if (uri.isEmpty()) {
|
||||||
uri = QInputDialog::getText(this, tr("Paste Zcash URI"),
|
uri = QInputDialog::getText(this, tr("Paste Zcash URI"),
|
||||||
@@ -820,70 +814,21 @@ void MainWindow::payZcashURI(QString uri) {
|
|||||||
if (uri.isEmpty())
|
if (uri.isEmpty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// URI should be of the form zcash://address?amt=x&memo=y
|
|
||||||
if (!uri.startsWith("zcash:")) {
|
|
||||||
payZcashURIError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract the address
|
// Extract the address
|
||||||
qDebug() << "Recieved URI " << uri;
|
qDebug() << "Recieved URI " << uri;
|
||||||
uri = uri.right(uri.length() - QString("zcash:").length());
|
PaymentURI paymentInfo = Settings::parseURI(uri);
|
||||||
|
if (!paymentInfo.error.isEmpty()) {
|
||||||
QRegExp re("([a-zA-Z0-9]+)");
|
QMessageBox::critical(this, tr("Error paying zcash URI"),
|
||||||
int pos;
|
tr("URI should be of the form 'zcash:<addr>?amt=x&memo=y") + "\n" + paymentInfo.error);
|
||||||
if ( (pos = re.indexIn(uri)) == -1 ) {
|
|
||||||
payZcashURIError();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString addr = re.cap(1);
|
|
||||||
if (!Settings::isValidAddress(addr)) {
|
|
||||||
payZcashURIError(tr("Could not understand address"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uri = uri.right(uri.length() - addr.length());
|
|
||||||
|
|
||||||
double amount = 0.0;
|
|
||||||
QString memo = "";
|
|
||||||
|
|
||||||
if (!uri.isEmpty()) {
|
|
||||||
uri = uri.right(uri.length() - 1); // Eat the "?"
|
|
||||||
|
|
||||||
QStringList args = uri.split("&");
|
|
||||||
for (QString arg: args) {
|
|
||||||
QStringList kv = arg.split("=");
|
|
||||||
if (kv.length() != 2) {
|
|
||||||
payZcashURIError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (kv[0].toLower() == "amt" || kv[0].toLower() == "amount") {
|
|
||||||
amount = kv[1].toDouble();
|
|
||||||
} else if (kv[0].toLower() == "memo" || kv[0].toLower() == "message" || kv[0].toLower() == "msg") {
|
|
||||||
memo = kv[1];
|
|
||||||
// Test if this is hex
|
|
||||||
|
|
||||||
QRegularExpression hexMatcher("^[0-9A-F]+$",
|
|
||||||
QRegularExpression::CaseInsensitiveOption);
|
|
||||||
QRegularExpressionMatch match = hexMatcher.match(memo);
|
|
||||||
if (match.hasMatch()) {
|
|
||||||
// Encoded as hex, convert to string
|
|
||||||
memo = QByteArray::fromHex(memo.toUtf8());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
payZcashURIError(tr("Unknown field in URI:") + kv[0]);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now, set the fields on the send tab
|
// Now, set the fields on the send tab
|
||||||
removeExtraAddresses();
|
removeExtraAddresses();
|
||||||
ui->Address1->setText(addr);
|
ui->Address1->setText(paymentInfo.addr);
|
||||||
ui->Address1->setCursorPosition(0);
|
ui->Address1->setCursorPosition(0);
|
||||||
ui->Amount1->setText(QString::number(amount));
|
ui->Amount1->setText(Settings::getDecimalString(paymentInfo.amt.toDouble()));
|
||||||
ui->MemoTxt1->setText(memo);
|
ui->MemoTxt1->setText(paymentInfo.memo);
|
||||||
|
|
||||||
// And switch to the send tab.
|
// And switch to the send tab.
|
||||||
ui->tabWidget->setCurrentIndex(1);
|
ui->tabWidget->setCurrentIndex(1);
|
||||||
@@ -891,7 +836,7 @@ void MainWindow::payZcashURI(QString uri) {
|
|||||||
|
|
||||||
// And click the send button if the amount is > 0, to validate everything. If everything is OK, it will show the confirm box
|
// And click the send button if the amount is > 0, to validate everything. If everything is OK, it will show the confirm box
|
||||||
// else, show the error message;
|
// else, show the error message;
|
||||||
if (amount > 0) {
|
if (paymentInfo.amt > 0) {
|
||||||
sendButton();
|
sendButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1214,6 +1159,14 @@ void MainWindow::setupTransactionsTab() {
|
|||||||
QDesktopServices::openUrl(QUrl(url));
|
QDesktopServices::openUrl(QUrl(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Payment Request
|
||||||
|
if (!memo.isEmpty() && memo.startsWith("zcash:")) {
|
||||||
|
menu.addAction(tr("View Payment Request"), [=] () {
|
||||||
|
RequestDialog::showPaymentConfirmation(this, memo);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// View Memo
|
||||||
if (!memo.isEmpty()) {
|
if (!memo.isEmpty()) {
|
||||||
menu.addAction(tr("View Memo"), [=] () {
|
menu.addAction(tr("View Memo"), [=] () {
|
||||||
QMessageBox mb(QMessageBox::Information, tr("Memo"), memo, QMessageBox::Ok, this);
|
QMessageBox mb(QMessageBox::Information, tr("Memo"), memo, QMessageBox::Ok, this);
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
#include "ui_requestdialog.h"
|
#include "ui_requestdialog.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "addressbook.h"
|
#include "addressbook.h"
|
||||||
|
#include "mainwindow.h"
|
||||||
|
#include "rpc.h"
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
|
||||||
RequestDialog::RequestDialog(QWidget *parent) :
|
RequestDialog::RequestDialog(QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
@@ -15,6 +19,51 @@ RequestDialog::~RequestDialog()
|
|||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RequestDialog::setupDialog(QDialog* d, Ui_RequestDialog* req) {
|
||||||
|
req->setupUi(d);
|
||||||
|
Settings::saveRestore(d);
|
||||||
|
|
||||||
|
// Setup
|
||||||
|
req->txtMemo->setLenDisplayLabel(req->lblMemoLen);
|
||||||
|
req->lblAmount->setText(req->lblAmount->text() + Settings::getTokenName());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static method that shows an incoming payment request and prompts the user to pay it
|
||||||
|
void RequestDialog::showPaymentConfirmation(MainWindow* main, QString paymentURI) {
|
||||||
|
PaymentURI payInfo = Settings::parseURI(paymentURI);
|
||||||
|
if (!payInfo.error.isEmpty()) {
|
||||||
|
QMessageBox::critical(main, tr("Error paying zcash URI"),
|
||||||
|
tr("URI should be of the form 'zcash:<addr>?amt=x&memo=y") + "\n" + payInfo.error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDialog d(main);
|
||||||
|
Ui_RequestDialog req;
|
||||||
|
setupDialog(&d, &req);
|
||||||
|
|
||||||
|
// In the view mode, all fields are read-only
|
||||||
|
req.txtAmount->setReadOnly(true);
|
||||||
|
req.txtFrom->setReadOnly(true);
|
||||||
|
req.txtMemo->setReadOnly(true);
|
||||||
|
|
||||||
|
// Payment is "to"
|
||||||
|
req.lblAddress->setText(tr("Pay To"));
|
||||||
|
|
||||||
|
// No Addressbook
|
||||||
|
req.btnAddressBook->setVisible(false);
|
||||||
|
|
||||||
|
req.txtFrom->setText(payInfo.addr);
|
||||||
|
req.txtMemo->setPlainText(payInfo.memo);
|
||||||
|
req.txtAmount->setText(payInfo.amt);
|
||||||
|
req.txtAmountUSD->setText(Settings::getUSDFormat(req.txtAmount->text().toDouble()));
|
||||||
|
|
||||||
|
req.buttonBox->button(QDialogButtonBox::Ok)->setText(tr("Pay"));
|
||||||
|
|
||||||
|
if (d.exec() == QDialog::Accepted) {
|
||||||
|
main->payZcashURI(paymentURI);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Static method that shows the request dialog
|
// Static method that shows the request dialog
|
||||||
void RequestDialog::showRequestZcash(MainWindow* main) {
|
void RequestDialog::showRequestZcash(MainWindow* main) {
|
||||||
QDialog d(main);
|
QDialog d(main);
|
||||||
@@ -55,9 +104,15 @@ void RequestDialog::showRequestZcash(MainWindow* main) {
|
|||||||
|
|
||||||
if (d.exec() == QDialog::Accepted) {
|
if (d.exec() == QDialog::Accepted) {
|
||||||
// Construct a zcash Payment URI with the data and pay it immediately.
|
// Construct a zcash Payment URI with the data and pay it immediately.
|
||||||
QString paymentURI = "zcash:" + AddressBook::addressFromAddressLabel(req.txtFrom->text())
|
QString memoURI = "zcash:" + main->getRPC()->getDefaultSaplingAddress()
|
||||||
+ "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble())
|
+ "?amt=" + Settings::getDecimalString(req.txtAmount->text().toDouble())
|
||||||
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
|
+ "&memo=" + QUrl::toPercentEncoding(req.txtMemo->toPlainText());
|
||||||
main->payZcashURI(paymentURI);
|
|
||||||
|
QString sendURI = "zcash:" + AddressBook::addressFromAddressLabel(req.txtFrom->text())
|
||||||
|
+ "?amt=0.0001"
|
||||||
|
+ "&memo=" + QUrl::toPercentEncoding(memoURI);
|
||||||
|
|
||||||
|
qDebug() << "Paying " << sendURI;
|
||||||
|
main->payZcashURI(sendURI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
#include "ui_requestdialog.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RequestDialog;
|
class RequestDialog;
|
||||||
@@ -17,7 +18,8 @@ public:
|
|||||||
~RequestDialog();
|
~RequestDialog();
|
||||||
|
|
||||||
static void showRequestZcash(MainWindow* main);
|
static void showRequestZcash(MainWindow* main);
|
||||||
|
static void showPaymentConfirmation(MainWindow* main, QString paymentURI);
|
||||||
|
static void setupDialog(QDialog* d, Ui_RequestDialog* req);
|
||||||
private:
|
private:
|
||||||
Ui::RequestDialog *ui;
|
Ui::RequestDialog *ui;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,41 +6,41 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>714</width>
|
<width>1052</width>
|
||||||
<height>524</height>
|
<height>509</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string>Dialog</string>
|
<string>Payment Request</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item row="8" column="1" colspan="3">
|
<item row="8" column="1" colspan="3">
|
||||||
<widget class="MemoEdit" name="txtMemo"/>
|
<widget class="MemoEdit" name="txtMemo"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="10" column="0">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
<item row="5" column="1" colspan="3">
|
<item row="5" column="1" colspan="3">
|
||||||
<widget class="QLineEdit" name="txtAmount">
|
<widget class="QLineEdit" name="txtAmount">
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
<property name="placeholderText">
|
<property name="placeholderText">
|
||||||
<string>Amount</string>
|
<string>Amount</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2" colspan="2">
|
<item row="13" column="2" colspan="2">
|
||||||
<widget class="QLabel" name="lblSaplingWarning">
|
|
||||||
<property name="styleSheet">
|
|
||||||
<string notr="true">color: red;</string>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string/>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="11" column="2" colspan="2">
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
@@ -67,8 +67,38 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="3">
|
<item row="1" column="1" colspan="3">
|
||||||
|
<widget class="QLineEdit" name="txtFrom">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>z address</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="lblAddress">
|
||||||
|
<property name="text">
|
||||||
|
<string>Request From</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1" colspan="3">
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnAddressBook">
|
||||||
|
<property name="text">
|
||||||
|
<string>AddressBook</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<spacer name="horizontalSpacer">
|
<spacer name="horizontalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
@@ -82,35 +112,25 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="btnAddressBook">
|
|
||||||
<property name="text">
|
|
||||||
<string>AddressBook</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" colspan="3">
|
<item row="0" column="1" colspan="3">
|
||||||
<widget class="QLineEdit" name="txtFrom">
|
<widget class="QLabel" name="lblSaplingWarning">
|
||||||
<property name="sizePolicy">
|
<property name="styleSheet">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
<string notr="true">color: red;</string>
|
||||||
<horstretch>0</horstretch>
|
</property>
|
||||||
<verstretch>0</verstretch>
|
<property name="text">
|
||||||
</sizepolicy>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
</property>
|
|
||||||
<property name="placeholderText">
|
|
||||||
<string>z address</string>
|
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item row="7" column="1">
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Request From</string>
|
<string/>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -120,24 +140,37 @@
|
|||||||
<string>Amount USD</string>
|
<string>Amount USD</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="alignment">
|
<property name="alignment">
|
||||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="5" column="0">
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="lblAmount">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Amount in ZEC</string>
|
<string>Amount in </string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="10" column="0" colspan="4">
|
<item row="12" column="0" colspan="4">
|
||||||
<widget class="Line" name="line">
|
<widget class="Line" name="line">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Horizontal</enum>
|
<enum>Qt::Horizontal</enum>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="10" column="3">
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
@@ -147,6 +180,11 @@
|
|||||||
<header>memoedit.h</header>
|
<header>memoedit.h</header>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>txtFrom</tabstop>
|
||||||
|
<tabstop>txtAmount</tabstop>
|
||||||
|
<tabstop>txtMemo</tabstop>
|
||||||
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections>
|
<connections>
|
||||||
<connection>
|
<connection>
|
||||||
|
|||||||
@@ -161,10 +161,7 @@ void Settings::saveRestore(QDialog* d) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString Settings::getUSDFormat(double bal) {
|
QString Settings::getUSDFormat(double bal) {
|
||||||
if (!Settings::getInstance()->isTestnet() && Settings::getInstance()->getZECPrice() > 0)
|
return "$" + QLocale(QLocale::English).toString(bal * Settings::getInstance()->getZECPrice(), 'f', 2);
|
||||||
return "$" + QLocale(QLocale::English).toString(bal * Settings::getInstance()->getZECPrice(), 'f', 2);
|
|
||||||
else
|
|
||||||
return QString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Settings::getDecimalString(double amt) {
|
QString Settings::getDecimalString(double amt) {
|
||||||
@@ -289,4 +286,60 @@ bool Settings::isValidAddress(QString addr) {
|
|||||||
ztsexp.exactMatch(addr) || zsexp.exactMatch(addr);
|
ztsexp.exactMatch(addr) || zsexp.exactMatch(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get a pretty string representation of this Payment URI
|
||||||
|
QString Settings::paymentURIPretty(PaymentURI uri) {
|
||||||
|
return QString() + "Payment Request\n" + "Pay: " + uri.addr + "\nAmount: " + getZECDisplayFormat(uri.amt.toDouble())
|
||||||
|
+ "\nMemo:" + QUrl::fromPercentEncoding(uri.memo.toUtf8());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse a payment URI string into its components
|
||||||
|
PaymentURI Settings::parseURI(QString uri) {
|
||||||
|
PaymentURI ans;
|
||||||
|
|
||||||
|
if (!uri.startsWith("zcash:")) {
|
||||||
|
ans.error = "Not a zcash payment URI";
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
uri = uri.right(uri.length() - QString("zcash:").length());
|
||||||
|
|
||||||
|
QRegExp re("([a-zA-Z0-9]+)");
|
||||||
|
int pos;
|
||||||
|
if ( (pos = re.indexIn(uri)) == -1 ) {
|
||||||
|
ans.error = "Couldn't find an address";
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
ans.addr = re.cap(1);
|
||||||
|
if (!Settings::isValidAddress(ans.addr)) {
|
||||||
|
ans.error = "Could not understand address";
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
uri = uri.right(uri.length() - ans.addr.length());
|
||||||
|
|
||||||
|
if (!uri.isEmpty()) {
|
||||||
|
uri = uri.right(uri.length() - 1); // Eat the "?"
|
||||||
|
|
||||||
|
QStringList args = uri.split("&");
|
||||||
|
for (QString arg: args) {
|
||||||
|
QStringList kv = arg.split("=");
|
||||||
|
if (kv.length() != 2) {
|
||||||
|
ans.error = "No value argument was seen";
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (kv[0].toLower() == "amt" || kv[0].toLower() == "amount") {
|
||||||
|
ans.amt = kv[1];
|
||||||
|
} else if (kv[0].toLower() == "memo" || kv[0].toLower() == "message" || kv[0].toLower() == "msg") {
|
||||||
|
ans.memo = QUrl::fromPercentEncoding(kv[1].toUtf8());
|
||||||
|
} else {
|
||||||
|
ans.error = "Unknown field in URI:" + kv[0];
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
|
||||||
const QString Settings::labelRegExp("[a-zA-Z0-9\\-_]{0,40}");
|
const QString Settings::labelRegExp("[a-zA-Z0-9\\-_]{0,40}");
|
||||||
|
|||||||
@@ -13,6 +13,15 @@ struct Config {
|
|||||||
struct ToFields;
|
struct ToFields;
|
||||||
struct Tx;
|
struct Tx;
|
||||||
|
|
||||||
|
struct PaymentURI {
|
||||||
|
QString addr;
|
||||||
|
QString amt;
|
||||||
|
QString memo;
|
||||||
|
|
||||||
|
// Any errors are stored here
|
||||||
|
QString error;
|
||||||
|
};
|
||||||
|
|
||||||
class Settings
|
class Settings
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -68,6 +77,9 @@ public:
|
|||||||
|
|
||||||
static void saveRestore(QDialog* d);
|
static void saveRestore(QDialog* d);
|
||||||
|
|
||||||
|
static PaymentURI parseURI(QString paymentURI);
|
||||||
|
static QString paymentURIPretty(PaymentURI);
|
||||||
|
|
||||||
static bool isZAddress(QString addr);
|
static bool isZAddress(QString addr);
|
||||||
static bool isTAddress(QString addr);
|
static bool isTAddress(QString addr);
|
||||||
|
|
||||||
|
|||||||
@@ -138,8 +138,14 @@ void TxTableModel::updateAllData() {
|
|||||||
|
|
||||||
if (role == Qt::ToolTipRole) {
|
if (role == Qt::ToolTipRole) {
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case 0: return modeldata->at(index.row()).type +
|
case 0: {
|
||||||
(dat.memo.isEmpty() ? "" : " tx memo: \"" + dat.memo + "\"");
|
if (dat.memo.startsWith("zcash:")) {
|
||||||
|
return Settings::paymentURIPretty(Settings::parseURI(dat.memo));
|
||||||
|
} else {
|
||||||
|
return modeldata->at(index.row()).type +
|
||||||
|
(dat.memo.isEmpty() ? "" : " tx memo: \"" + dat.memo + "\"");
|
||||||
|
}
|
||||||
|
}
|
||||||
case 1: {
|
case 1: {
|
||||||
auto addr = modeldata->at(index.row()).address;
|
auto addr = modeldata->at(index.row()).address;
|
||||||
if (addr.trimmed().isEmpty())
|
if (addr.trimmed().isEmpty())
|
||||||
@@ -154,9 +160,15 @@ void TxTableModel::updateAllData() {
|
|||||||
|
|
||||||
if (role == Qt::DecorationRole && index.column() == 0) {
|
if (role == Qt::DecorationRole && index.column() == 0) {
|
||||||
if (!dat.memo.isEmpty()) {
|
if (!dat.memo.isEmpty()) {
|
||||||
// Return the info pixmap to indicate memo
|
// If the memo is a Payment URI, then show a payment request icon
|
||||||
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
if (dat.memo.startsWith("zcash:")) {
|
||||||
return QVariant(icon.pixmap(16, 16));
|
QIcon icon(":/icons/res/paymentreq.gif");
|
||||||
|
return QVariant(icon.pixmap(16, 16));
|
||||||
|
} else {
|
||||||
|
// Return the info pixmap to indicate memo
|
||||||
|
QIcon icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation);
|
||||||
|
return QVariant(icon.pixmap(16, 16));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Empty pixmap to make it align
|
// Empty pixmap to make it align
|
||||||
QPixmap p(16, 16);
|
QPixmap p(16, 16);
|
||||||
|
|||||||
Reference in New Issue
Block a user