PaymentRequestDialog

This commit is contained in:
tobtoht 2021-10-01 19:10:46 +02:00
parent 3767e736c2
commit e512e539b6
No known key found for this signature in database
GPG key ID: 1CADD27F41F45C3C
11 changed files with 368 additions and 1 deletions

View file

@ -7,6 +7,7 @@
#include <QMenu> #include <QMenu>
#include <QMessageBox> #include <QMessageBox>
#include "dialog/PaymentRequestDialog.h"
#include "dialog/QrCodeDialog.h" #include "dialog/QrCodeDialog.h"
#include "model/ModelUtils.h" #include "model/ModelUtils.h"
#include "utils/Icons.h" #include "utils/Icons.h"
@ -60,6 +61,8 @@ ReceiveWidget::ReceiveWidget(QSharedPointer<AppContext> ctx, QWidget *parent)
connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses); connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses);
connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses); connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses);
connect(ui->btn_createPaymentRequest, &QPushButton::clicked, this, &ReceiveWidget::createPaymentRequest);
} }
void ReceiveWidget::setSearchbarVisible(bool visible) { void ReceiveWidget::setSearchbarVisible(bool visible) {
@ -118,6 +121,18 @@ void ReceiveWidget::showContextMenu(const QPoint &point) {
menu->popup(ui->addresses->viewport()->mapToGlobal(point)); menu->popup(ui->addresses->viewport()->mapToGlobal(point));
} }
void ReceiveWidget::createPaymentRequest() {
QModelIndex index = ui->addresses->currentIndex();
if (!index.isValid()) {
return;
}
QString address = index.model()->data(index.siblingAtColumn(SubaddressModel::Address), Qt::UserRole).toString();
PaymentRequestDialog dialog{this, m_ctx, address};
dialog.exec();
}
void ReceiveWidget::onShowTransactions() { void ReceiveWidget::onShowTransactions() {
QModelIndex index = ui->addresses->currentIndex(); QModelIndex index = ui->addresses->currentIndex();
if (!index.isValid()) { if (!index.isValid()) {
@ -190,6 +205,7 @@ void ReceiveWidget::updateQrCode(){
QModelIndex index = ui->addresses->currentIndex(); QModelIndex index = ui->addresses->currentIndex();
if (!index.isValid()) { if (!index.isValid()) {
ui->qrCode->clear(); ui->qrCode->clear();
ui->btn_createPaymentRequest->hide();
return; return;
} }
@ -199,6 +215,7 @@ void ReceiveWidget::updateQrCode(){
int width = ui->qrCode->width() - 4; int width = ui->qrCode->width() - 4;
if (qrc.isValid()) { if (qrc.isValid()) {
ui->qrCode->setPixmap(qrc.toPixmap(1).scaled(width, width, Qt::KeepAspectRatio)); ui->qrCode->setPixmap(qrc.toPixmap(1).scaled(width, width, Qt::KeepAspectRatio));
ui->btn_createPaymentRequest->show();
} }
} }

View file

@ -39,6 +39,7 @@ public slots:
void setShowHiddenAddresses(bool show); void setShowHiddenAddresses(bool show);
void setSearchFilter(const QString &filter); void setSearchFilter(const QString &filter);
void onShowTransactions(); void onShowTransactions();
void createPaymentRequest();
signals: signals:
void showTransactions(const QString& address); void showTransactions(const QString& address);

View file

@ -69,6 +69,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QPushButton" name="btn_createPaymentRequest">
<property name="text">
<string>Payment Request</string>
</property>
</widget>
</item>
<item> <item>
<spacer name="verticalSpacer_4"> <spacer name="verticalSpacer_4">
<property name="orientation"> <property name="orientation">

View file

@ -0,0 +1,82 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
#include "PaymentRequestDialog.h"
#include "ui_PaymentRequestDialog.h"
#include <QClipboard>
#include <QFileDialog>
#include <QMessageBox>
#include <QRegExpValidator>
#include "WalletManager.h"
PaymentRequestDialog::PaymentRequestDialog(QWidget *parent, QSharedPointer<AppContext> ctx, QString address)
: QDialog(parent)
, ui(new Ui::PaymentRequestDialog)
, m_ctx(std::move(ctx))
, m_address(std::move(address))
{
ui->setupUi(this);
QString amount_rx = R"(^\d{0,8}[\.]\d{0,12}|(all)$)";
QRegExp rx;
rx.setPattern(amount_rx);
QValidator *validator = new QRegExpValidator(rx, this);
ui->line_amountXMR->setValidator(validator);
connect(ui->line_amountXMR, &QLineEdit::textChanged, this, &PaymentRequestDialog::updatePaymentRequest);
connect(ui->line_description, &QLineEdit::textChanged, this, &PaymentRequestDialog::updatePaymentRequest);
connect(ui->line_recipient, &QLineEdit::textChanged, this, &PaymentRequestDialog::updatePaymentRequest);
connect(ui->btn_copyLink, &QPushButton::clicked, this, &PaymentRequestDialog::copyLink);
connect(ui->btn_copyImage, &QPushButton::clicked, this, &PaymentRequestDialog::copyImage);
connect(ui->btn_saveImage, &QPushButton::clicked, this, &PaymentRequestDialog::saveImage);
this->updatePaymentRequest();
ui->line_amountXMR->setFocus();
this->adjustSize();
}
void PaymentRequestDialog::updatePaymentRequest() {
QString description = ui->line_description->text();
QString recipient = ui->line_recipient->text();
quint64 amount = WalletManager::amountFromString(ui->line_amountXMR->text());
QString uri = m_ctx->wallet->make_uri(m_address, amount, description, recipient);
ui->line_paymentRequestUri->setText(uri);
ui->line_paymentRequestUri->setCursorPosition(0);
// TODO: memory leak, cba to refactor now
m_qrCode = new QrCode(uri, QrCode::Version::AUTO, QrCode::ErrorCorrectionLevel::MEDIUM);
if (m_qrCode->isValid()) {
ui->qrWidget->setQrCode(m_qrCode);
}
}
void PaymentRequestDialog::copyLink() {
Utils::copyToClipboard(ui->line_paymentRequestUri->text());
QMessageBox::information(this, "Information", "Payment request link copied to clipboard.");
}
void PaymentRequestDialog::copyImage() {
QApplication::clipboard()->setPixmap(m_qrCode->toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio));
QMessageBox::information(this, "Information", "QR code copied to clipboard.");
}
void PaymentRequestDialog::saveImage() {
QString filename = QFileDialog::getSaveFileName(this, "Select where to save file", QDir::current().filePath("qrcode.png"));
if (filename.isEmpty()) {
return;
}
QFile file(filename);
file.open(QIODevice::WriteOnly);
m_qrCode->toPixmap(1).scaled(500, 500, Qt::KeepAspectRatio).save(&file, "PNG");
QMessageBox::information(this, "Information", "QR code saved to file");
}
PaymentRequestDialog::~PaymentRequestDialog() = default;

View file

@ -0,0 +1,37 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
#ifndef FEATHER_PAYMENTREQUESTDIALOG_H
#define FEATHER_PAYMENTREQUESTDIALOG_H
#include <QDialog>
#include "appcontext.h"
#include "qrcode/QrCode.h"
namespace Ui {
class PaymentRequestDialog;
}
class PaymentRequestDialog : public QDialog
{
Q_OBJECT
public:
explicit PaymentRequestDialog(QWidget *parent, QSharedPointer<AppContext> ctx, QString address);
~PaymentRequestDialog() override;
private slots:
void updatePaymentRequest();
void copyLink();
void copyImage();
void saveImage();
private:
QScopedPointer<Ui::PaymentRequestDialog> ui;
QSharedPointer<AppContext> m_ctx;
QString m_address;
QrCode *m_qrCode;
};
#endif //FEATHER_PAYMENTREQUESTDIALOG_H

View file

@ -0,0 +1,203 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PaymentRequestDialog</class>
<widget class="QDialog" name="PaymentRequestDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>658</width>
<height>761</height>
</rect>
</property>
<property name="windowTitle">
<string>Create Payment Request</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QrCodeWidget" name="qrWidget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="line_paymentRequestUri">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Amount:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLineEdit" name="line_amountXMR">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>XMR</string>
</property>
</widget>
</item>
<item>
<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>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Description:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="line_description"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Your name:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="line_recipient"/>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btn_copyLink">
<property name="text">
<string>Copy Link</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_copyImage">
<property name="text">
<string>Copy Image</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_saveImage">
<property name="text">
<string>Save Image</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QrCodeWidget</class>
<extends>QWidget</extends>
<header>widgets/QrCodeWidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PaymentRequestDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PaymentRequestDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -1150,6 +1150,14 @@ QVariantMap Wallet::parse_uri_to_object(const QString &uri) const
return result; return result;
} }
QString Wallet::make_uri(const QString &address, quint64 &amount, const QString &description,
const QString &recipient) const
{
std::string error;
std::string uri = m_walletImpl->make_uri(address.toStdString(), "", amount, description.toStdString(), recipient.toStdString(), error);
return QString::fromStdString(uri);
}
bool Wallet::rescanSpent() bool Wallet::rescanSpent()
{ {
QMutexLocker locker(&m_asyncMutex); QMutexLocker locker(&m_asyncMutex);

View file

@ -390,6 +390,8 @@ public:
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; 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;
QVariantMap parse_uri_to_object(const QString &uri) const; QVariantMap parse_uri_to_object(const QString &uri) const;
QString make_uri(const QString &address, quint64 &amount, const QString &description, const QString &recipient) const;
//! Namespace your cacheAttribute keys to avoid collisions //! Namespace your cacheAttribute keys to avoid collisions
bool setCacheAttribute(const QString &key, const QString &val); bool setCacheAttribute(const QString &key, const QString &val);
QString getCacheAttribute(const QString &key) const; QString getCacheAttribute(const QString &key) const;

View file

@ -58,3 +58,11 @@ void QrCodeWidget::paintEvent(QPaintEvent *event) {
} }
} }
} }
bool QrCodeWidget::hasHeightForWidth() const {
return true;
}
int QrCodeWidget::heightForWidth(int w) const {
return w;
}

View file

@ -18,6 +18,8 @@ public:
protected: protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
int heightForWidth(int w) const override;
bool hasHeightForWidth() const override;
private: private:
QrCode *m_qrcode = nullptr; QrCode *m_qrcode = nullptr;