diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ad3f6e9..c8cae11 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -224,6 +224,15 @@ void MainWindow::initWidgets() { connect(ui->btn_resetCoinControl, &QPushButton::clicked, [this]{ m_ctx->setSelectedInputs({}); }); + + m_walletUnlockWidget = new WalletUnlockWidget(this); + m_walletUnlockWidget->setWalletName(this->walletName()); + ui->walletUnlockLayout->addWidget(m_walletUnlockWidget); + + connect(m_walletUnlockWidget, &WalletUnlockWidget::closeWallet, this, &MainWindow::close); + connect(m_walletUnlockWidget, &WalletUnlockWidget::unlockWallet, this, &MainWindow::unlockWallet); + + ui->stackedWidget->setCurrentIndex(0); } void MainWindow::initMenu() { @@ -231,6 +240,7 @@ void MainWindow::initMenu() { // [File] connect(ui->actionOpen, &QAction::triggered, this, &MainWindow::menuOpenClicked); connect(ui->actionNew_Restore, &QAction::triggered, this, &MainWindow::menuNewRestoreClicked); + connect(ui->actionLock, &QAction::triggered, this, &MainWindow::lockWallet); connect(ui->actionClose, &QAction::triggered, this, &MainWindow::menuWalletCloseClicked); // Close current wallet connect(ui->actionQuit, &QAction::triggered, this, &MainWindow::menuQuitClicked); // Quit application connect(ui->actionSettings, &QAction::triggered, this, &MainWindow::menuSettingsClicked); @@ -352,6 +362,7 @@ void MainWindow::initMenu() { ui->actionRefresh_tabs->setShortcut(QKeySequence("Ctrl+R")); ui->actionOpen->setShortcut(QKeySequence("Ctrl+O")); ui->actionNew_Restore->setShortcut(QKeySequence("Ctrl+N")); + ui->actionLock->setShortcut(QKeySequence("Ctrl+L")); ui->actionClose->setShortcut(QKeySequence("Ctrl+W")); ui->actionShow_debug_info->setShortcut(QKeySequence("Ctrl+D")); ui->actionSettings->setShortcut(QKeySequence("Ctrl+Alt+S")); @@ -1655,6 +1666,16 @@ void MainWindow::userActivity() { m_userLastActive = QDateTime::currentSecsSinceEpoch(); } +void MainWindow::closeQDialogChildren(QObject *object) { + for (QObject *child : object->children()) { + if (auto *childDlg = dynamic_cast(child)) { + qDebug() << "Closing dialog: " << childDlg->objectName(); + childDlg->close(); + } + this->closeQDialogChildren(child); + } +} + void MainWindow::checkUserActivity() { if (!config()->get(Config::inactivityLockEnabled).toBool()) { return; @@ -1665,34 +1686,56 @@ void MainWindow::checkUserActivity() { } if ((m_userLastActive + (config()->get(Config::inactivityLockTimeout).toInt()*60)) < QDateTime::currentSecsSinceEpoch()) { - m_checkUserActivity.stop(); qInfo() << "Locking wallet for inactivity"; - ui->tabWidget->hide(); - this->statusBar()->hide(); - this->menuBar()->hide(); - if (!this->verifyPassword(false)) { - this->setEnabled(false); - this->close(); - // This doesn't close the wallet immediately. - // FIXME -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - do { -#endif - QApplication::processEvents(); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - // Because running it a single time is apparently not enough. - // TODO: Qt bug? Need proper fix for this. - } while (QApplication::hasPendingEvents()); -#endif - } else { - ui->tabWidget->show(); - this->statusBar()->show(); - this->menuBar()->show(); - m_checkUserActivity.start(); - } + this->lockWallet(); } } +void MainWindow::lockWallet() { + if (m_locked) { + return; + } + + if (m_constructingTransaction) { + QMessageBox::warning(this, "Lock wallet", "Unable to lock wallet during transaction construction"); + return; + } + m_walletUnlockWidget->reset(); + + // Close all open QDialogs + this->closeQDialogChildren(this); + + ui->tabWidget->hide(); + this->statusBar()->hide(); + this->menuBar()->hide(); + ui->stackedWidget->setCurrentIndex(1); + + m_checkUserActivity.stop(); + + m_locked = true; +} + +void MainWindow::unlockWallet(const QString &password) { + if (!m_locked) { + return; + } + + if (password != m_ctx->wallet->getPassword()) { + m_walletUnlockWidget->incorrectPassword(); + return; + } + m_walletUnlockWidget->reset(); + + ui->tabWidget->show(); + this->statusBar()->show(); + this->menuBar()->show(); + ui->stackedWidget->setCurrentIndex(0); + + m_checkUserActivity.start(); + + m_locked = false; +} + void MainWindow::toggleSearchbar(bool visible) { config()->set(Config::showSearchbar, visible); diff --git a/src/MainWindow.h b/src/MainWindow.h index 5d9fe57..5525f13 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -34,6 +34,7 @@ #include "widgets/CCSWidget.h" #include "widgets/RedditWidget.h" #include "widgets/TickerWidget.h" +#include "widgets/WalletUnlockWidget.h" #include "wizard/WalletWizard.h" #include "ContactsWidget.h" @@ -221,6 +222,9 @@ private: void fillSendTab(const QString &address, const QString &description); void userActivity(); void checkUserActivity(); + void lockWallet(); + void unlockWallet(const QString &password); + void closeQDialogChildren(QObject *object); QIcon hardwareDevicePairedIcon(); QIcon hardwareDeviceUnpairedIcon(); @@ -233,6 +237,7 @@ private: SplashDialog *m_splashDialog = nullptr; AccountSwitcherDialog *m_accountSwitcherDialog = nullptr; + WalletUnlockWidget *m_walletUnlockWidget = nullptr; #ifdef HAS_XMRIG XMRigWidget *m_xmrig = nullptr; #endif @@ -277,6 +282,7 @@ private: QTimer m_txTimer; bool cleanedUp = false; + bool m_locked = false; bool m_criticalWarningShown = false; EventFilter *m_eventFilter = nullptr; diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 513a251..fa9799d 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -40,290 +40,13 @@ 12 - - + + - 0 + 1 - - - 16 - 16 - - - - - - :/assets/images/tab_home.png:/assets/images/tab_home.png - - - Home - - - - 5 - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - Qt::Horizontal - - - - - - - 0 - - - true - - - - CCS - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - Bounties - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - /r/Monero - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - Revuo - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - - - - - - :/assets/images/history.png:/assets/images/history.png - - - History - - - - 9 - - - - - - - - - - 0 - 0 - - - - - :/assets/images/tab_send.png:/assets/images/tab_send.png - - - Send - - - - 11 - - - 11 - - - - - 0 - - - - - - - - 0 - 0 - - - - Qt::Horizontal - - - - - - - - - - - - :/assets/images/coins.png:/assets/images/coins.png - - - Receive - - - - - - - - - - - :/assets/images/tab_coins.png:/assets/images/tab_coins.png - - - Coins - - - - - - - - - - - :/assets/images/gnome-calc.png:/assets/images/gnome-calc.png - - - Calc - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - :/assets/images/update.png:/assets/images/update.png - - - Exchange - - + + 0 @@ -337,19 +60,289 @@ 0 - + 0 - + + + 16 + 16 + + + - :/assets/images/localMonero_logo.png:/assets/images/localMonero_logo.png + :/assets/images/tab_home.png:/assets/images/tab_home.png - LocalMonero + Home - + + + 5 + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Horizontal + + + + + + + 0 + + + true + + + + CCS + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Bounties + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + /r/Monero + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + Revuo + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + :/assets/images/history.png:/assets/images/history.png + + + History + + + + 9 + + + + + + + + + + 0 + 0 + + + + + :/assets/images/tab_send.png:/assets/images/tab_send.png + + + Send + + + + 11 + + + 11 + + + + + 0 + + + + + + + + 0 + 0 + + + + Qt::Horizontal + + + + + + + + + + + + :/assets/images/coins.png:/assets/images/coins.png + + + Receive + + + + + + + + + + + :/assets/images/tab_coins.png:/assets/images/tab_coins.png + + + Coins + + + + + + + + + + + :/assets/images/gnome-calc.png:/assets/images/gnome-calc.png + + + Calc + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + :/assets/images/update.png:/assets/images/update.png + + + Exchange + + 0 @@ -363,69 +356,118 @@ 0 - + + + 0 + + + + + :/assets/images/localMonero_logo.png:/assets/images/localMonero_logo.png + + + LocalMonero + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + + + :/assets/images/mining.png:/assets/images/mining.png + + + Mining + + + + - - - - - - :/assets/images/mining.png:/assets/images/mining.png - - - Mining - - - - + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + 0 + + + + + Coin control active: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + Reset + + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - - - Coin control active: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 0 - 0 - - - - Reset - - - - @@ -452,6 +494,7 @@ + @@ -894,6 +937,11 @@ Documentation + + + Lock wallet + + diff --git a/src/widgets/WalletUnlockWidget.cpp b/src/widgets/WalletUnlockWidget.cpp new file mode 100644 index 0000000..9fa0a7d --- /dev/null +++ b/src/widgets/WalletUnlockWidget.cpp @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-FileCopyrightText: 2020-2023 The Monero Project + +#include "WalletUnlockWidget.h" +#include "ui_WalletUnlockWidget.h" + +#include +#include + +WalletUnlockWidget::WalletUnlockWidget(QWidget *parent) + : QWidget(parent) + , ui(new Ui::WalletUnlockWidget) +{ + ui->setupUi(this); + this->reset(); + + ui->buttonBox->button(QDialogButtonBox::Ok)->setAutoDefault(true); + + connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &WalletUnlockWidget::tryUnlock); + connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &WalletUnlockWidget::closeWallet); +} + +void WalletUnlockWidget::setWalletName(const QString &walletName) { + ui->label_fileName->setText(walletName); +} + +void WalletUnlockWidget::reset() { + ui->label_incorrectPassword->hide(); + ui->line_password->setText(""); + ui->line_password->setFocus(); +} + +void WalletUnlockWidget::incorrectPassword() { + ui->label_incorrectPassword->show(); + ui->line_password->clear(); +} + +void WalletUnlockWidget::tryUnlock() { + emit unlockWallet(ui->line_password->text()); +} + +void WalletUnlockWidget::keyPressEvent(QKeyEvent *e) { + switch (e->key()) { + case Qt::Key_Enter: + case Qt::Key_Return: + ui->buttonBox->accepted(); + e->ignore(); + break; + case Qt::Key_Escape: + ui->buttonBox->rejected(); + e->ignore(); + break; + default: + e->ignore(); + } +} + +WalletUnlockWidget::~WalletUnlockWidget() = default; \ No newline at end of file diff --git a/src/widgets/WalletUnlockWidget.h b/src/widgets/WalletUnlockWidget.h new file mode 100644 index 0000000..99bd551 --- /dev/null +++ b/src/widgets/WalletUnlockWidget.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: BSD-3-Clause +// SPDX-FileCopyrightText: 2020-2023 The Monero Project + +#ifndef FEATHER_WALLETUNLOCKWIDGET_H +#define FEATHER_WALLETUNLOCKWIDGET_H + +#include +#include + +namespace Ui { + class WalletUnlockWidget; +} + +class WalletUnlockWidget : public QWidget +{ +Q_OBJECT + +public: + explicit WalletUnlockWidget(QWidget *parent = nullptr); + ~WalletUnlockWidget(); + + void setWalletName(const QString &walletName); + void reset(); + void incorrectPassword(); + +signals: + void unlockWallet(const QString &password); + void closeWallet(); + +private slots: + void tryUnlock(); + +protected: + void keyPressEvent(QKeyEvent* e) override; + +private: + QScopedPointer ui; +}; + +#endif //FEATHER_WALLETUNLOCKWIDGET_H diff --git a/src/widgets/WalletUnlockWidget.ui b/src/widgets/WalletUnlockWidget.ui new file mode 100644 index 0000000..fe445ff --- /dev/null +++ b/src/widgets/WalletUnlockWidget.ui @@ -0,0 +1,175 @@ + + + WalletUnlockWidget + + + + 0 + 0 + 918 + 255 + + + + Form + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + 500 + 0 + + + + + 700 + 16777215 + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 0 + + + + + + + + + 12 + 75 + true + + + + Unlock Wallet + + + + + + + filename.keys + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + Enter Password: + + + + + + + <html><head/><body><p><span style=" font-weight:600; color:#a40000;">Incorrect password, try again.</span></p></body></html> + + + + + + + QLineEdit::Password + + + + + + + + + Qt::StrongFocus + + + QDialogButtonBox::Close|QDialogButtonBox::Ok + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 0 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::MinimumExpanding + + + + 0 + 0 + + + + + + + + + + +