diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 252b639..dd2d110 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -405,6 +405,9 @@ void MainWindow::initOffline() { connect(ui->btn_help, &QPushButton::clicked, [this] { windowManager()->showDocs(this, "offline_tx_signing"); }); + connect(ui->btn_viewOnlyDetails, &QPushButton::clicked, [this] { + this->showViewOnlyDialog(); + }); connect(ui->btn_checkAddress, &QPushButton::clicked, [this]{ AddressCheckerIndexDialog dialog{m_wallet, this}; dialog.exec(); diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 477e9f2..e9b390e 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -403,6 +403,13 @@ + + + + View-only details + + + diff --git a/src/dialog/URDialog.cpp b/src/dialog/URDialog.cpp index 37444c6..370f968 100644 --- a/src/dialog/URDialog.cpp +++ b/src/dialog/URDialog.cpp @@ -8,12 +8,29 @@ #include "utils/Utils.h" -URDialog::URDialog(QWidget *parent) +URDialog::URDialog(QWidget *parent, const QString &data, bool scanOnly) : WindowModalDialog(parent) , ui(new Ui::URDialog) { ui->setupUi(this); + if (!data.isEmpty()) { + ui->btn_loadFile->setVisible(false); + ui->btn_loadClipboard->setVisible(false); + ui->tabWidget->setTabVisible(1, false); + + QScreen *currentScreen = QApplication::screenAt(this->geometry().center()); + if (!currentScreen) { + currentScreen = QApplication::primaryScreen(); + } + int availableHeight = currentScreen->availableGeometry().height() - 200; + this->resize(availableHeight, availableHeight); + + std::string d = data.toStdString(); + ui->widgetUR->setData("xmr-viewonly", d); + return; + } + connect(ui->btn_loadFile, &QPushButton::clicked, [this]{ QString fn = QFileDialog::getOpenFileName(this, "Load file", QDir::homePath(), "All Files (*)"); if (fn.isEmpty()) { @@ -41,7 +58,7 @@ URDialog::URDialog(QWidget *parent) std::string data = qdata.toStdString(); - ui->widgetUR->setData("ana", data); + ui->widgetUR->setData("any", data); }); connect(ui->tabWidget, &QTabWidget::currentChanged, [this](int index){ @@ -51,44 +68,76 @@ URDialog::URDialog(QWidget *parent) }); connect(ui->widgetScanner, &QrCodeScanWidget::finished, [this](bool success){ - if (!success) { + if (!success) { Utils::showError(this, "Unable to scan UR"); ui->widgetScanner->reset(); return; - } + } - if (ui->radio_clipboard->isChecked()) { - Utils::copyToClipboard(QString::fromStdString(ui->widgetScanner->getURData())); - Utils::showInfo(this, "Data copied to clipboard"); - } - else if (ui->radio_file->isChecked()) { - QString fn = QFileDialog::getSaveFileName(this, "Save to file", QDir::homePath(), "ur_data"); - if (fn.isEmpty()) { - ui->widgetScanner->reset(); - return; - } + if (ui->widgetScanner->getURType() == "xmr-viewonly") { + QRegularExpression viewOnlyDetails( + "Secret view key: (?[0-9a-f]{64})\nAddress: (?
\\w+)\nRestore height: (?\\d+)\nWallet name: (?\\w+)\n", + QRegularExpression::CaseInsensitiveOption | QRegularExpression::DotMatchesEverythingOption); + QString data = QString::fromStdString(ui->widgetScanner->getURData()); + QRegularExpressionMatch match = viewOnlyDetails.match(data); - QFile file{fn}; - if (!file.open(QIODevice::WriteOnly)) { - Utils::showError(this, "Failed to save file", QString("Could not open file %1 for writing").arg(fn)); - ui->widgetScanner->reset(); - return; - } + if (!match.hasMatch()) { + Utils::showError(this, "Unable to load view-only details", "Unexpected data"); + return; + } - std::string data = ui->widgetScanner->getURData(); - file.write(data.data(), data.size()); - file.close(); - - Utils::showInfo(this, "Successfully saved data to file"); - } - - ui->widgetScanner->reset(); + m_viewOnlyDetails.address = match.captured("address"); + m_viewOnlyDetails.key = match.captured("key").toLower(); + m_viewOnlyDetails.restoreHeight = match.captured("restoreheight").toInt(); + m_viewOnlyDetails.walletName = QString("%1_view_only").arg(match.captured("walletname")); + + this->accept(); + } + + if (ui->radio_clipboard->isChecked()) { + Utils::copyToClipboard(QString::fromStdString(ui->widgetScanner->getURData())); + Utils::showInfo(this, "Data copied to clipboard"); + } + else if (ui->radio_file->isChecked()) { + QString fn = QFileDialog::getSaveFileName(this, "Save to file", QDir::homePath(), "ur_data"); + if (fn.isEmpty()) { + ui->widgetScanner->reset(); + return; + } + + QFile file{fn}; + if (!file.open(QIODevice::WriteOnly)) { + Utils::showError(this, "Failed to save file", QString("Could not open file %1 for writing").arg(fn)); + ui->widgetScanner->reset(); + return; + } + + std::string data = ui->widgetScanner->getURData(); + file.write(data.data(), data.size()); + file.close(); + + Utils::showInfo(this, "Successfully saved data to file"); + } + + ui->widgetScanner->reset(); }); + if (scanOnly) { + ui->tabWidget->setCurrentIndex(1); + ui->tabWidget->setTabVisible(0, false); + ui->radio_clipboard->setVisible(false); + ui->radio_file->setVisible(false); + return; + } + ui->radio_file->setChecked(true); ui->tabWidget->setCurrentIndex(0); this->resize(600, 700); } +ViewOnlyDetails URDialog::getViewOnlyDetails() { + return m_viewOnlyDetails; +} + URDialog::~URDialog() = default; \ No newline at end of file diff --git a/src/dialog/URDialog.h b/src/dialog/URDialog.h index d7d871b..85aa965 100644 --- a/src/dialog/URDialog.h +++ b/src/dialog/URDialog.h @@ -12,16 +12,26 @@ namespace Ui { class URDialog; } +struct ViewOnlyDetails { + QString address; + QString key; + int restoreHeight = 0; + QString walletName; +}; + class URDialog : public WindowModalDialog { Q_OBJECT public: - explicit URDialog(QWidget *parent = nullptr); + explicit URDialog(QWidget *parent, const QString &data = "", bool scanOnly = false); ~URDialog() override; + ViewOnlyDetails getViewOnlyDetails(); + private: QScopedPointer ui; + ViewOnlyDetails m_viewOnlyDetails; }; diff --git a/src/dialog/ViewOnlyDialog.cpp b/src/dialog/ViewOnlyDialog.cpp index 1ea4549..364f6c4 100644 --- a/src/dialog/ViewOnlyDialog.cpp +++ b/src/dialog/ViewOnlyDialog.cpp @@ -8,6 +8,7 @@ #include #include +#include "URDialog.h" #include "utils/Utils.h" ViewOnlyDialog::ViewOnlyDialog(Wallet *wallet, QWidget *parent) @@ -23,6 +24,10 @@ ViewOnlyDialog::ViewOnlyDialog(Wallet *wallet, QWidget *parent) connect(ui->btn_Copy, &QPushButton::clicked, this, &ViewOnlyDialog::copyToClipboard); connect(ui->btn_Save, &QPushButton::clicked, this, &ViewOnlyDialog::onWriteViewOnlyWallet); + connect(ui->btn_transmitOverUR, &QPushButton::clicked, [this] { + URDialog dialog{this, this->toString()}; + dialog.exec(); + }); if (m_wallet->viewOnly()) { ui->btn_Save->setEnabled(false); @@ -52,12 +57,17 @@ void ViewOnlyDialog::onWriteViewOnlyWallet(){ QMessageBox::information(this, "Information", "View-only wallet successfully written to disk."); } -void ViewOnlyDialog::copyToClipboard() { - QString text = ""; - text += QString("Address: %1\n").arg(ui->label_primaryAddress->text()); +QString ViewOnlyDialog::toString() { + QString text; text += QString("Secret view key: %1\n").arg(ui->label_secretViewKey->text()); + text += QString("Address: %1\n").arg(ui->label_primaryAddress->text()); text += QString("Restore height: %1\n").arg(ui->label_restoreHeight->text()); - Utils::copyToClipboard(text); + text += QString("Wallet name: %1\n").arg(m_wallet->walletName()); + return text; +} + +void ViewOnlyDialog::copyToClipboard() { + Utils::copyToClipboard(this->toString()); } ViewOnlyDialog::~ViewOnlyDialog() = default; diff --git a/src/dialog/ViewOnlyDialog.h b/src/dialog/ViewOnlyDialog.h index 08de238..1ba44db 100644 --- a/src/dialog/ViewOnlyDialog.h +++ b/src/dialog/ViewOnlyDialog.h @@ -25,6 +25,7 @@ private slots: void onWriteViewOnlyWallet(); private: + QString toString(); void copyToClipboard(); QScopedPointer ui; diff --git a/src/dialog/ViewOnlyDialog.ui b/src/dialog/ViewOnlyDialog.ui index 2cdcdb8..a09d9da 100644 --- a/src/dialog/ViewOnlyDialog.ui +++ b/src/dialog/ViewOnlyDialog.ui @@ -7,7 +7,7 @@ 0 0 659 - 254 + 260 @@ -15,13 +15,13 @@ - + - Restore height + Secret view key - + - + TextLabel @@ -53,13 +53,13 @@ - + - Secret view key + Restore height - + - + TextLabel @@ -87,6 +87,13 @@ + + + + Transmit over UR + + + diff --git a/src/qrcode/scanner/QrCodeScanWidget.cpp b/src/qrcode/scanner/QrCodeScanWidget.cpp index 0c9b6e2..39edf2d 100644 --- a/src/qrcode/scanner/QrCodeScanWidget.cpp +++ b/src/qrcode/scanner/QrCodeScanWidget.cpp @@ -233,6 +233,14 @@ std::string QrCodeScanWidget::getURData() { return data; } +std::string QrCodeScanWidget::getURType() { + if (!m_decoder.is_success()) { + return ""; + } + + return m_decoder.expected_type().value_or(""); +} + QString QrCodeScanWidget::getURError() { if (!m_decoder.is_failure()) { return {}; diff --git a/src/qrcode/scanner/QrCodeScanWidget.h b/src/qrcode/scanner/QrCodeScanWidget.h index 8c8b86f..a239ba4 100644 --- a/src/qrcode/scanner/QrCodeScanWidget.h +++ b/src/qrcode/scanner/QrCodeScanWidget.h @@ -29,6 +29,7 @@ public: QString decodedString = ""; std::string getURData(); + std::string getURType(); QString getURError(); void startCapture(bool scan_ur = false); diff --git a/src/wizard/PageSetRestoreHeight.cpp b/src/wizard/PageSetRestoreHeight.cpp index 55d02ac..22eafba 100644 --- a/src/wizard/PageSetRestoreHeight.cpp +++ b/src/wizard/PageSetRestoreHeight.cpp @@ -50,6 +50,12 @@ void PageSetRestoreHeight::initializePage() { ui->line_creationDate->setText(creationDate.toString("yyyy-MM-dd")); this->onCreationDateEdited(); } + + if (m_fields->restoreHeight > 0) { + ui->line_restoreHeight->setText(QString::number(m_fields->restoreHeight)); + this->onRestoreHeightEdited(); + this->completeChanged(); + } } void PageSetRestoreHeight::onCreationDateEdited() { diff --git a/src/wizard/PageWalletFile.cpp b/src/wizard/PageWalletFile.cpp index 6acc60c..83a70c4 100644 --- a/src/wizard/PageWalletFile.cpp +++ b/src/wizard/PageWalletFile.cpp @@ -42,6 +42,10 @@ void PageWalletFile::initializePage() { ui->line_walletName->setText(this->defaultWalletName()); ui->check_defaultWalletDirectory->setVisible(false); ui->check_defaultWalletDirectory->setChecked(false); + + if (!m_fields->walletName.isEmpty()) { + ui->line_walletName->setText(m_fields->walletName); + } } bool PageWalletFile::validateWidgets(){ diff --git a/src/wizard/PageWalletRestoreKeys.cpp b/src/wizard/PageWalletRestoreKeys.cpp index 4ae5739..ba69415 100644 --- a/src/wizard/PageWalletRestoreKeys.cpp +++ b/src/wizard/PageWalletRestoreKeys.cpp @@ -11,6 +11,7 @@ #include "WalletWizard.h" #include "constants.h" +#include "dialog/URDialog.h" #include "libwalletqt/WalletManager.h" PageWalletRestoreKeys::PageWalletRestoreKeys(WizardFields *fields, QWidget *parent) @@ -41,6 +42,17 @@ PageWalletRestoreKeys::PageWalletRestoreKeys(WizardFields *fields, QWidget *pare connect(ui->btnOptions, &QPushButton::clicked, this, &PageWalletRestoreKeys::onOptionsClicked); connect(ui->combo_walletType, &QComboBox::currentTextChanged, this, &PageWalletRestoreKeys::showInputLines); + connect(ui->btn_scanUR, &QPushButton::clicked, [this] { + URDialog dialog{this, "", true}; + dialog.exec(); + ViewOnlyDetails details = dialog.getViewOnlyDetails(); + ui->line_address->setText(details.address); + ui->line_address->setCursorPosition(0); + ui->line_viewkey->setText(details.key); + ui->line_viewkey->setCursorPosition(0); + m_fields->restoreHeight = details.restoreHeight; + m_fields->walletName = details.walletName; + }); } void PageWalletRestoreKeys::initializePage() { diff --git a/src/wizard/PageWalletRestoreKeys.ui b/src/wizard/PageWalletRestoreKeys.ui index 21b9f05..716c06f 100644 --- a/src/wizard/PageWalletRestoreKeys.ui +++ b/src/wizard/PageWalletRestoreKeys.ui @@ -215,6 +215,13 @@ + + + + Scan UR + + +