diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -103,6 +103,8 @@ /** Disconnect core signals from GUI client */ void unsubscribeFromCoreSignals(); + bool isPrivacyModeActivated() const; + /** * Get the tray icon status. * Some systems have not "system tray" or "notification area" available. @@ -165,6 +167,7 @@ QAction *m_close_wallet_action{nullptr}; QAction *m_wallet_selector_label_action = nullptr; QAction *m_wallet_selector_action = nullptr; + QAction *m_mask_values_action{nullptr}; QLabel *m_wallet_selector_label = nullptr; QComboBox *m_wallet_selector = nullptr; @@ -218,6 +221,7 @@ void receivedURI(const QString &uri); /** Signal raised when RPC console shown */ void consoleShown(RPCConsole *console); + void setPrivacy(bool privacy); public Q_SLOTS: /** Set number of connections shown in the UI */ diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -400,6 +400,13 @@ "command-line options") .arg(PACKAGE_NAME)); + m_mask_values_action = new QAction(tr("&Mask values"), this); + m_mask_values_action->setShortcut( + QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_M)); + m_mask_values_action->setStatusTip( + tr("Mask the values in the Overview tab")); + m_mask_values_action->setCheckable(true); + connect(quitAction, &QAction::triggered, qApp, QApplication::quit); connect(aboutAction, &QAction::triggered, this, &BitcoinGUI::aboutClicked); connect(aboutQtAction, &QAction::triggered, qApp, QApplication::aboutQt); @@ -489,6 +496,9 @@ &QObject::deleteLater); activity->create(); }); + + connect(m_mask_values_action, &QAction::toggled, this, + &BitcoinGUI::setPrivacy); } #endif // ENABLE_WALLET @@ -530,6 +540,8 @@ settings->addAction(encryptWalletAction); settings->addAction(changePassphraseAction); settings->addSeparator(); + settings->addAction(m_mask_values_action); + settings->addSeparator(); } settings->addAction(optionsAction); @@ -1555,6 +1567,11 @@ m_handler_question->disconnect(); } +bool BitcoinGUI::isPrivacyModeActivated() const { + assert(m_mask_values_action); + return m_mask_values_action->isChecked(); +} + UnitDisplayStatusBarControl::UnitDisplayStatusBarControl( const PlatformStyle *platformStyle) : optionsModel(nullptr), menu(nullptr) { diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -6,8 +6,8 @@ 0 0 - 596 - 342 + 798 + 318 @@ -118,6 +118,7 @@ + Monospace 75 true @@ -129,7 +130,7 @@ Unconfirmed transactions to watch-only addresses - 0.000 000 00 BCH + 0.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -143,6 +144,7 @@ + Monospace 75 true @@ -154,7 +156,7 @@ Total of transactions that have yet to be confirmed, and do not yet count toward the spendable balance - 0.000 000 00 BCH + 0.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -168,6 +170,7 @@ + Monospace 75 true @@ -179,7 +182,7 @@ Mined balance in watch-only addresses that has not yet matured - 0.000 000 00 BCH + 0.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -226,6 +229,7 @@ + Monospace 75 true @@ -237,7 +241,7 @@ Mined balance that has not yet matured - 0.000 000 00 BCH + 0.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -271,6 +275,7 @@ + Monospace 75 true @@ -282,7 +287,7 @@ Your current total balance - 0.000 000 00 BCH + 21 000 000 000 000.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -296,6 +301,7 @@ + Monospace 75 true @@ -307,7 +313,7 @@ Current total balance in watch-only addresses - 0.000 000 00 BCH + 21 000 000 000 000.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -338,6 +344,7 @@ + Monospace 75 true @@ -349,7 +356,7 @@ Your current spendable balance - 0.000 000 00 BCH + 21 000 000 000 000.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -363,6 +370,7 @@ + Monospace 75 true @@ -374,7 +382,7 @@ Your current balance in watch-only addresses - 0.000 000 00 BCH + 21 000 000 000 000.00 XEC Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter diff --git a/src/qt/overviewpage.h b/src/qt/overviewpage.h --- a/src/qt/overviewpage.h +++ b/src/qt/overviewpage.h @@ -39,6 +39,7 @@ public Q_SLOTS: void setBalance(const interfaces::WalletBalances &balances); + void setPrivacy(bool privacy); Q_SIGNALS: void transactionClicked(const QModelIndex &index); @@ -49,6 +50,7 @@ ClientModel *clientModel; WalletModel *walletModel; interfaces::WalletBalances m_balances; + bool m_privacy{false}; TxViewDelegate *txdelegate; std::unique_ptr filter; diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -16,7 +16,9 @@ #include #include +#include #include +#include #define DECORATION_SIZE 54 #define NUM_ITEMS 5 @@ -158,6 +160,23 @@ Q_EMIT outOfSyncWarningClicked(); } +void OverviewPage::setPrivacy(bool privacy) { + m_privacy = privacy; + if (m_balances.balance != -Amount::satoshi()) { + setBalance(m_balances); + } + + ui->listTransactions->setVisible(!m_privacy); + + const QString status_tip = + m_privacy ? tr("Privacy mode activated for the Overview tab. To unmask " + "the values, uncheck Settings->Mask values.") + : ""; + setStatusTip(status_tip); + QStatusTipEvent event(status_tip); + QApplication::sendEvent(this, &event); +} + OverviewPage::~OverviewPage() { delete ui; } @@ -167,65 +186,66 @@ m_balances = balances; if (walletModel->wallet().isLegacy()) { if (walletModel->wallet().privateKeysDisabled()) { - ui->labelBalance->setText(BitcoinUnits::formatWithUnit( - unit, balances.watch_only_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit( - unit, balances.unconfirmed_watch_only_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelImmature->setText(BitcoinUnits::formatWithUnit( - unit, balances.immature_watch_only_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelTotal->setText(BitcoinUnits::formatWithUnit( + ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.watch_only_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.unconfirmed_watch_only_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.immature_watch_only_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy( unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, - false, BitcoinUnits::separatorAlways)); + BitcoinUnits::separatorAlways, m_privacy)); } else { - ui->labelBalance->setText(BitcoinUnits::formatWithUnit( - unit, balances.balance, false, BitcoinUnits::separatorAlways)); - ui->labelUnconfirmed->setText(BitcoinUnits::formatWithUnit( - unit, balances.unconfirmed_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelImmature->setText(BitcoinUnits::formatWithUnit( - unit, balances.immature_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelTotal->setText(BitcoinUnits::formatWithUnit( + ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.balance, BitcoinUnits::separatorAlways, + m_privacy)); + ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.unconfirmed_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.immature_balance, BitcoinUnits::separatorAlways, + m_privacy)); + ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy( unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, - false, BitcoinUnits::separatorAlways)); - ui->labelWatchAvailable->setText(BitcoinUnits::formatWithUnit( - unit, balances.watch_only_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelWatchPending->setText(BitcoinUnits::formatWithUnit( - unit, balances.unconfirmed_watch_only_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelWatchImmature->setText(BitcoinUnits::formatWithUnit( - unit, balances.immature_watch_only_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelWatchTotal->setText(BitcoinUnits::formatWithUnit( + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelWatchAvailable->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.watch_only_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelWatchPending->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.unconfirmed_watch_only_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelWatchImmature->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.immature_watch_only_balance, + BitcoinUnits::separatorAlways, m_privacy)); + ui->labelWatchTotal->setText(BitcoinUnits::formatWithPrivacy( unit, balances.watch_only_balance + balances.unconfirmed_watch_only_balance + balances.immature_watch_only_balance, - false, BitcoinUnits::separatorAlways)); + BitcoinUnits::separatorAlways, m_privacy)); } } else { - ui->labelBalance->setText(BitcoinUnits::formatWithUnit( - unit, balances.balance, false, BitcoinUnits::separatorAlways)); - ui->labelUnconfirmed->setText( - BitcoinUnits::formatWithUnit(unit, balances.unconfirmed_balance, - false, BitcoinUnits::separatorAlways)); - ui->labelImmature->setText( - BitcoinUnits::formatWithUnit(unit, balances.immature_balance, false, - BitcoinUnits::separatorAlways)); - ui->labelTotal->setText(BitcoinUnits::formatWithUnit( + ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.balance, BitcoinUnits::separatorAlways, m_privacy)); + ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.unconfirmed_balance, BitcoinUnits::separatorAlways, + m_privacy)); + ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy( + unit, balances.immature_balance, BitcoinUnits::separatorAlways, + m_privacy)); + ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy( unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, - false, BitcoinUnits::separatorAlways)); + BitcoinUnits::separatorAlways, m_privacy)); } // only show immature (newly mined) balance if it's non-zero, so as not to diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -188,7 +188,7 @@ OverviewPage overviewPage(platformStyle.get()); overviewPage.setWalletModel(&walletModel); QLabel *balanceLabel = overviewPage.findChild("labelBalance"); - QString balanceText = balanceLabel->text(); + QString balanceText = balanceLabel->text().trimmed(); int unit = walletModel.getOptionsModel()->getDisplayUnit(); Amount balance = walletModel.wallet().getBalance(); QString balanceComparison = BitcoinUnits::formatWithUnit( diff --git a/src/qt/walletframe.cpp b/src/qt/walletframe.cpp --- a/src/qt/walletframe.cpp +++ b/src/qt/walletframe.cpp @@ -50,6 +50,7 @@ WalletView *walletView = new WalletView(platformStyle, walletModel, this); walletView->setClientModel(clientModel); walletView->showOutOfSyncWarning(bOutOfSync); + walletView->setPrivacy(gui->isPrivacyModeActivated()); WalletView *current_wallet_view = currentWalletView(); if (current_wallet_view) { @@ -77,6 +78,7 @@ &BitcoinGUI::incomingTransaction); connect(walletView, &WalletView::hdEnabledStatusChanged, gui, &BitcoinGUI::updateWalletStatus); + connect(gui, &BitcoinGUI::setPrivacy, walletView, &WalletView::setPrivacy); return true; } diff --git a/src/qt/walletview.h b/src/qt/walletview.h --- a/src/qt/walletview.h +++ b/src/qt/walletview.h @@ -121,6 +121,7 @@ void requestedSyncWarningInfo(); Q_SIGNALS: + void setPrivacy(bool privacy); void transactionClicked(); void coinsSent(); /** Fired when a message should be reported to the user */ diff --git a/src/qt/walletview.cpp b/src/qt/walletview.cpp --- a/src/qt/walletview.cpp +++ b/src/qt/walletview.cpp @@ -99,6 +99,8 @@ // Pass through messages from transactionView connect(transactionView, &TransactionView::message, this, &WalletView::message); + connect(this, &WalletView::setPrivacy, overviewPage, + &OverviewPage::setPrivacy); // Set the model properly. setWalletModel(walletModel);