diff --git a/doc/release-notes-911.md b/doc/release-notes-911.md new file mode 100644 index 00000000000..2b923a18ddb --- /dev/null +++ b/doc/release-notes-911.md @@ -0,0 +1,4 @@ +GUI Changes +--- + +The Overview page now displays a "On hold:" balance row showing funds that would be spent if wallet transactions currently outside the mempool were to confirm. This row is only shown when non-mempool wallet transactions are present. diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 767c618ff4c..bea182e6f31 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -93,9 +93,6 @@ QString BitcoinUnits::format(Unit unit, const CAmount& nIn, bool fPlus, Separato qint64 n_abs = (n > 0 ? n : -n); qint64 quotient = n_abs / coin; QString quotient_str = QString::number(quotient); - if (justify) { - quotient_str = quotient_str.rightJustified(MAX_DIGITS_BTC - num_decimals, ' '); - } // Use SI-style thin space separators as these are locale independent and can't be // confused with the decimal marker. @@ -110,6 +107,13 @@ QString BitcoinUnits::format(Unit unit, const CAmount& nIn, bool fPlus, Separato else if (fPlus && n > 0) quotient_str.insert(0, '+'); + // Right-justify after the sign is prepended, so that the sign stays + // adjacent to the most significant digit rather than being separated + // from it by the justification padding. + if (justify) { + quotient_str = quotient_str.rightJustified(MAX_DIGITS_BTC - num_decimals, ' '); + } + if (num_decimals > 0) { qint64 remainder = n_abs % coin; QString remainder_str = QString::number(remainder).rightJustified(num_decimals, '0'); @@ -142,7 +146,6 @@ QString BitcoinUnits::formatHtmlWithUnit(Unit unit, const CAmount& amount, bool QString BitcoinUnits::formatWithPrivacy(Unit unit, const CAmount& amount, SeparatorStyle separators, bool privacy) { - assert(amount >= 0); QString value; if (privacy) { value = format(unit, 0, false, separators, true).replace('0', '#'); diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index f44c26ef32f..5afa845a46e 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -130,14 +130,14 @@ - + Qt::Horizontal - + Total: @@ -183,7 +183,33 @@ - + + + + IBeamCursor + + + Balance for wallet transactions that currently don't fit node's mempool policies + + + 0.00000000 BTC + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + + + + + On hold: + + + + IBeamCursor diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index f2efbe9222c..fe407d1ae08 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -190,13 +190,22 @@ void OverviewPage::setBalance(const interfaces::WalletBalances& balances) ui->labelBalance->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); ui->labelUnconfirmed->setText(BitcoinUnits::formatWithPrivacy(unit, balances.unconfirmed_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); ui->labelImmature->setText(BitcoinUnits::formatWithPrivacy(unit, balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); - ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); + ui->labelNonMempool->setText(BitcoinUnits::formatWithPrivacy(unit, balances.nonmempool_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); + ui->labelNonMempool->setStyleSheet("QLabel { color: " + COLOR_NEGATIVE.name() + "; }"); + ui->labelTotal->setText(BitcoinUnits::formatWithPrivacy(unit, balances.balance + balances.unconfirmed_balance + balances.immature_balance + balances.nonmempool_balance, BitcoinUnits::SeparatorStyle::ALWAYS, m_privacy)); // only show immature (newly mined) balance if it's non-zero, so as not to complicate things // for the non-mining users bool showImmature = balances.immature_balance != 0; ui->labelImmature->setVisible(showImmature); ui->labelImmatureText->setVisible(showImmature); + + // likewise for non-mempool balances + Assert(balances.nonmempool_balance <= 0); + bool showNonMempool = balances.nonmempool_balance < 0; + + ui->labelNonMempool->setVisible(showNonMempool); + ui->labelNonMempoolText->setVisible(showNonMempool); } void OverviewPage::setClientModel(ClientModel *model) @@ -296,5 +305,6 @@ void OverviewPage::setMonospacedFont(const QFont& f) ui->labelBalance->setFont(f); ui->labelUnconfirmed->setFont(f); ui->labelImmature->setFont(f); + ui->labelNonMempool->setFont(f); ui->labelTotal->setFont(f); } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index af620b67382..83b9f0d29a8 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -297,7 +297,21 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr& wallet) OverviewPage overviewPage(platformStyle.get()); overviewPage.setWalletModel(&walletModel); walletModel.pollBalanceChanged(); // Manual balance polling update - CompareBalance(walletModel, walletModel.wallet().getBalance(), overviewPage.findChild("labelBalance")); + CompareBalance(walletModel, walletModel.wallet().getBalances().balance, overviewPage.findChild("labelBalance")); + + // Test non-mempool balance display + overviewPage.show(); + interfaces::WalletBalances nonmempool_balances; + nonmempool_balances.balance = walletModel.wallet().getBalances().balance; + nonmempool_balances.nonmempool_balance = -50000; + overviewPage.setBalance(nonmempool_balances); + QVERIFY(overviewPage.findChild("labelNonMempool")->isVisible()); + QVERIFY(overviewPage.findChild("labelNonMempoolText")->isVisible()); + CompareBalance(walletModel, -50000, overviewPage.findChild("labelNonMempool")); + nonmempool_balances.nonmempool_balance = 0; + overviewPage.setBalance(nonmempool_balances); + QVERIFY(!overviewPage.findChild("labelNonMempool")->isVisible()); + QVERIFY(!overviewPage.findChild("labelNonMempoolText")->isVisible()); // Check Request Payment button ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get()); diff --git a/src/wallet/interfaces.cpp b/src/wallet/interfaces.cpp index 9f9876da303..bb45560690b 100644 --- a/src/wallet/interfaces.cpp +++ b/src/wallet/interfaces.cpp @@ -374,7 +374,7 @@ class WalletImpl : public Wallet } WalletBalances getBalances() override { - const auto bal = GetBalance(*m_wallet); + const auto bal = GetBalance(*m_wallet, /*min_depth=*/0, /*avoid_reuse=*/true, /*include_nonmempool=*/true); WalletBalances result; result.balance = bal.m_mine_trusted; result.unconfirmed_balance = bal.m_mine_untrusted_pending;