diff --git a/src/ReceiveWidget.cpp b/src/ReceiveWidget.cpp index 477e51c..f583af4 100644 --- a/src/ReceiveWidget.cpp +++ b/src/ReceiveWidget.cpp @@ -7,6 +7,7 @@ #include #include +#include "dialog/PaymentRequestDialog.h" #include "dialog/QrCodeDialog.h" #include "model/ModelUtils.h" #include "utils/Icons.h" @@ -60,6 +61,8 @@ ReceiveWidget::ReceiveWidget(QSharedPointer ctx, QWidget *parent) connect(ui->check_showUsed, &QCheckBox::clicked, this, &ReceiveWidget::setShowUsedAddresses); connect(ui->check_showHidden, &QCheckBox::clicked, this, &ReceiveWidget::setShowHiddenAddresses); + + connect(ui->btn_createPaymentRequest, &QPushButton::clicked, this, &ReceiveWidget::createPaymentRequest); } void ReceiveWidget::setSearchbarVisible(bool visible) { @@ -118,6 +121,18 @@ void ReceiveWidget::showContextMenu(const QPoint &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() { QModelIndex index = ui->addresses->currentIndex(); if (!index.isValid()) { @@ -190,6 +205,7 @@ void ReceiveWidget::updateQrCode(){ QModelIndex index = ui->addresses->currentIndex(); if (!index.isValid()) { ui->qrCode->clear(); + ui->btn_createPaymentRequest->hide(); return; } @@ -199,6 +215,7 @@ void ReceiveWidget::updateQrCode(){ int width = ui->qrCode->width() - 4; if (qrc.isValid()) { ui->qrCode->setPixmap(qrc.toPixmap(1).scaled(width, width, Qt::KeepAspectRatio)); + ui->btn_createPaymentRequest->show(); } } diff --git a/src/ReceiveWidget.h b/src/ReceiveWidget.h index 23ee78b..e01f93f 100644 --- a/src/ReceiveWidget.h +++ b/src/ReceiveWidget.h @@ -39,6 +39,7 @@ public slots: void setShowHiddenAddresses(bool show); void setSearchFilter(const QString &filter); void onShowTransactions(); + void createPaymentRequest(); signals: void showTransactions(const QString& address); diff --git a/src/ReceiveWidget.ui b/src/ReceiveWidget.ui index 0d42081..b84ed58 100644 --- a/src/ReceiveWidget.ui +++ b/src/ReceiveWidget.ui @@ -69,6 +69,13 @@ + + + + Payment Request + + + diff --git a/src/SendWidget.cpp b/src/SendWidget.cpp index b460a08..92f9a34 100644 --- a/src/SendWidget.cpp +++ b/src/SendWidget.cpp @@ -26,7 +26,7 @@ SendWidget::SendWidget(QSharedPointer ctx, QWidget *parent) QString amount_rx = R"(^\d{0,8}[\.,]\d{0,12}|(all)$)"; QRegExp rx; rx.setPattern(amount_rx); - QValidator *validator = new QRegExpValidator(rx, this); + QValidator *validator = new QRegExpValidator(rx, this); ui->lineAmount->setValidator(validator); connect(m_ctx.get(), &AppContext::initiateTransaction, this, &SendWidget::onInitiateTransaction); diff --git a/src/dialog/PaymentRequestDialog.cpp b/src/dialog/PaymentRequestDialog.cpp new file mode 100644 index 0000000..4cf38ee --- /dev/null +++ b/src/dialog/PaymentRequestDialog.cpp @@ -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 +#include +#include +#include + +#include "WalletManager.h" + +PaymentRequestDialog::PaymentRequestDialog(QWidget *parent, QSharedPointer 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; \ No newline at end of file diff --git a/src/dialog/PaymentRequestDialog.h b/src/dialog/PaymentRequestDialog.h new file mode 100644 index 0000000..c109d0a --- /dev/null +++ b/src/dialog/PaymentRequestDialog.h @@ -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 + +#include "appcontext.h" +#include "qrcode/QrCode.h" + +namespace Ui { + class PaymentRequestDialog; +} + +class PaymentRequestDialog : public QDialog +{ + Q_OBJECT + +public: + explicit PaymentRequestDialog(QWidget *parent, QSharedPointer ctx, QString address); + ~PaymentRequestDialog() override; + +private slots: + void updatePaymentRequest(); + void copyLink(); + void copyImage(); + void saveImage(); + +private: + QScopedPointer ui; + QSharedPointer m_ctx; + QString m_address; + QrCode *m_qrCode; +}; + +#endif //FEATHER_PAYMENTREQUESTDIALOG_H diff --git a/src/dialog/PaymentRequestDialog.ui b/src/dialog/PaymentRequestDialog.ui new file mode 100644 index 0000000..5b4dac2 --- /dev/null +++ b/src/dialog/PaymentRequestDialog.ui @@ -0,0 +1,203 @@ + + + PaymentRequestDialog + + + + 0 + 0 + 658 + 761 + + + + Create Payment Request + + + + + + + 0 + 0 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + + + + + + Amount: + + + + + + + + + + + + 0 + 0 + + + + + + + + XMR + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Description: + + + + + + + + + + Your name: + + + + + + + + + + + + + + Copy Link + + + + + + + Copy Image + + + + + + + Save Image + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + QrCodeWidget + QWidget +
widgets/QrCodeWidget.h
+ 1 +
+
+ + + + buttonBox + accepted() + PaymentRequestDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + PaymentRequestDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +
diff --git a/src/libwalletqt/Wallet.cpp b/src/libwalletqt/Wallet.cpp index f0dd9f3..ea1d844 100644 --- a/src/libwalletqt/Wallet.cpp +++ b/src/libwalletqt/Wallet.cpp @@ -1150,6 +1150,14 @@ QVariantMap Wallet::parse_uri_to_object(const QString &uri) const 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() { QMutexLocker locker(&m_asyncMutex); diff --git a/src/libwalletqt/Wallet.h b/src/libwalletqt/Wallet.h index 1e41945..f54e8c7 100644 --- a/src/libwalletqt/Wallet.h +++ b/src/libwalletqt/Wallet.h @@ -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 &unknown_parameters, QString &error) 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 bool setCacheAttribute(const QString &key, const QString &val); QString getCacheAttribute(const QString &key) const; diff --git a/src/widgets/QrCodeWidget.cpp b/src/widgets/QrCodeWidget.cpp index e82902b..ffc17af 100644 --- a/src/widgets/QrCodeWidget.cpp +++ b/src/widgets/QrCodeWidget.cpp @@ -57,4 +57,12 @@ void QrCodeWidget::paintEvent(QPaintEvent *event) { } } } +} + +bool QrCodeWidget::hasHeightForWidth() const { + return true; +} + +int QrCodeWidget::heightForWidth(int w) const { + return w; } \ No newline at end of file diff --git a/src/widgets/QrCodeWidget.h b/src/widgets/QrCodeWidget.h index 855936e..f86c81d 100644 --- a/src/widgets/QrCodeWidget.h +++ b/src/widgets/QrCodeWidget.h @@ -18,6 +18,8 @@ public: protected: void paintEvent(QPaintEvent *event) override; + int heightForWidth(int w) const override; + bool hasHeightForWidth() const override; private: QrCode *m_qrcode = nullptr;