]> Nutra Git (v1) - gamesguru/feather.git/commitdiff
status/balance and HW backed wallet fixes
authorgg <chown_tee@proton.me>
Thu, 15 Jan 2026 05:45:28 +0000 (00:45 -0500)
committergg <chown_tee@proton.me>
Thu, 15 Jan 2026 05:45:28 +0000 (00:45 -0500)
src/MainWindow.cpp
src/MainWindow.h
src/SettingsDialog.cpp
src/libwalletqt/Wallet.cpp
src/libwalletqt/Wallet.h
src/widgets/TickerWidget.cpp

index 4ea0a9a41e69e7b2e1d7303c84b4653b504aec02..a1323e7ec015d0b09138aec245eb2beaa001d9a5 100644 (file)
@@ -766,6 +766,16 @@ void MainWindow::onWalletOpened() {
     connect(m_wallet->coins(), &Coins::descriptionChanged, [this] {
         m_wallet->history()->refresh();
     });
+
+    connect(m_wallet->coins(), &Coins::refreshStarted, [this]{
+        m_coinsRefreshing = true;
+        this->updateNetStats();
+    });
+
+    connect(m_wallet->coins(), &Coins::refreshFinished, [this]{
+        m_coinsRefreshing = false;
+        this->updateNetStats();
+    });
     // Vice versa
     connect(m_wallet->transactionHistoryModel(), &TransactionHistoryModel::transactionDescriptionChanged, [this] {
         m_wallet->coins()->refresh();
@@ -854,6 +864,18 @@ void MainWindow::updateStatusToolTip() {
     if (m_wallet && m_wallet->lastSyncTime().isValid()) {
         toolTip += QString("\nWallet synced: %1").arg(Utils::timeAgo(m_wallet->lastSyncTime()));
     }
+
+    if (m_wallet) {
+        qint64 nextRefresh = m_wallet->secondsUntilNextRefresh();
+        if (nextRefresh > 0) {
+            toolTip += QString("\nNext sync attempt in: %1s").arg(nextRefresh);
+        } else if (nextRefresh == 0) {
+            toolTip += "\nSync attempt in progress...";
+        } else if (nextRefresh == -2) {
+            toolTip += "\nHardware wallet disconnected";
+        }
+    }
+
     m_statusLabelBalance->setToolTip(toolTip);
 
     this->updateSyncStatusToolTip();
@@ -888,7 +910,9 @@ void MainWindow::updateSyncStatusToolTip() {
 
     if (lastSync.isValid()) {
         qint64 secsSinceSync = lastSync.secsTo(QDateTime::currentDateTime());
-        blocksBehindEstimated = secsSinceSync / 120; // ~2 min per block
+        if (secsSinceSync > 0) {
+            blocksBehindEstimated = secsSinceSync / 120; // ~2 min per block
+        }
     }
 
     quint64 blocksBehind = std::max(blocksBehindActual, blocksBehindEstimated);
@@ -1079,10 +1103,12 @@ void MainWindow::onConnectionStatusChanged(int status)
                 // Estimate blocks behind based on time since last sync
                 if (m_wallet && m_wallet->lastSyncTime().isValid()) {
                     qint64 secsSinceLastSync = m_wallet->lastSyncTime().secsTo(QDateTime::currentDateTime());
-                    quint64 estimatedBlocksBehind = secsSinceLastSync / 120; // ~2 min per block
-                    if (estimatedBlocksBehind > 0) {
-                        statusStr = tr("~%1 blocks behind").arg(QLocale().toString(estimatedBlocksBehind));
-                        break;
+                    if (secsSinceLastSync > 0) {
+                        quint64 estimatedBlocksBehind = secsSinceLastSync / 120; // ~2 min per block
+                        if (estimatedBlocksBehind > 0) {
+                            statusStr = tr("~%1 blocks behind").arg(QLocale().toString(estimatedBlocksBehind));
+                            break;
+                        }
                     }
                 }
                 statusStr = "Disconnected";
@@ -1897,7 +1923,7 @@ void MainWindow::onWalletPassphraseNeeded(bool on_device) {
 
 void MainWindow::updateNetStats() {
     if (!m_wallet || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected
-                       || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized)
+                       || (m_wallet->connectionStatus() == Wallet::ConnectionStatus_Synchronized && !m_coinsRefreshing))
     {
         m_statusLabelNetStats->hide();
         return;
index f161ff058418d69b6c1ded312b9a1760806cd667..4df669919da23973138b4a51cadee54960627c14 100644 (file)
@@ -263,6 +263,7 @@ private:
 
     QString m_statusText;
     int m_statusDots;
+    bool m_coinsRefreshing = false;
     bool m_constructingTransaction = false;
     bool m_statusOverrideActive = false;
     bool m_showDeviceError = false;
index dd6bea50a260126844c3eac8d2dfa2d962478b8e..fa25f1ac7ab12d1f899428e2a44b2ffc53db62ca 100644 (file)
@@ -178,6 +178,14 @@ void Settings::setupNetworkTab() {
     // Proxy
     connect(ui->proxyWidget, &NetworkProxyWidget::proxySettingsChanged, this, &Settings::onProxySettingsChanged);
 
+    // Offline mode
+    ui->checkBox_offlineMode->setChecked(conf()->get(Config::offlineMode).toBool());
+    connect(ui->checkBox_offlineMode, &QCheckBox::toggled, [this](bool checked){
+        conf()->set(Config::offlineMode, checked);
+        this->enableWebsocket(!checked && !conf()->get(Config::disableWebsocket).toBool());
+        emit offlineMode(checked);
+    });
+
     // Websocket
     // [Obtain third-party data]
     ui->checkBox_enableWebsocket->setChecked(!conf()->get(Config::disableWebsocket).toBool());
index 9dc59e5a55afb1cd26c99367aa4341eafe5f5b6c..6a171476d3fe03d56ef06361e79c3cbccfd9304f 100644 (file)
@@ -55,6 +55,7 @@ Wallet::Wallet(Monero::Wallet *wallet, QObject *parent)
         , m_useSSL(true)
         , m_coins(new Coins(this, wallet->getWallet(), this))
         , m_storeTimer(new QTimer(this))
+        , m_lastRefreshTime(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count())
 {
     m_walletListener = new WalletListenerImpl(this);
     m_walletImpl->setListener(m_walletListener);
@@ -541,6 +542,7 @@ void Wallet::startRefreshThread()
                         qInfo() << "Calling m_walletImpl->refresh(). Wallet height:" << walletHeight << "Daemon height:" << daemonHeight << "Target:" << targetHeight;
                         m_walletImpl->refresh();
                     }
+                    m_lastRefreshTime = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
                     last = std::chrono::steady_clock::now();
                 }
             }
@@ -586,6 +588,26 @@ quint64 Wallet::blockChainHeight() const {
     return m_wallet2->get_blockchain_current_height();
 }
 
+qint64 Wallet::secondsUntilNextRefresh() const {
+    if (m_syncPaused || !m_refreshEnabled) {
+        return -1;
+    }
+
+    if (this->isHwBacked() && !this->isDeviceConnected()) {
+        return -2;
+    }
+
+    auto now = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
+    auto elapsed = std::chrono::microseconds(now - m_lastRefreshTime.load());
+    auto interval = std::chrono::seconds(m_refreshInterval);
+
+    if (elapsed >= interval) {
+        return 0;
+    }
+
+    return std::chrono::duration_cast<std::chrono::seconds>(interval - elapsed).count();
+}
+
 quint64 Wallet::daemonBlockChainHeight() const {
     return m_daemonBlockChainHeight;
 }
index c37cc5d7d37db949f48a08c17136f8350b5f5485..366dd8858742f7769f44745d7eb2afa8c0b0cd81 100644 (file)
@@ -15,6 +15,7 @@
 #include "rows/TxBacklogEntry.h"
 
 #include <set>
+#include <atomic>
 
 class WalletListenerImpl;
 
@@ -140,6 +141,7 @@ public:
 
     QDateTime lastSyncTime() const;
     void setRefreshInterval(int seconds);
+    qint64 secondsUntilNextRefresh() const;
 
     //! return true if deterministic keys
     bool isDeterministic() const;
@@ -520,7 +522,7 @@ private:
     Coins *m_coins;
     CoinsModel *m_coinsModel;
 
-    int m_refreshInterval = 10;
+    std::atomic<int> m_refreshInterval{10};
 
     QMutex m_asyncMutex;
     QString m_daemonUsername;
@@ -542,6 +544,7 @@ private:
     std::atomic<quint64> m_stopHeight{0};
     std::atomic<bool> m_rangeSyncActive{false};
     std::atomic<bool> m_syncPaused{false};
+    std::atomic<int64_t> m_lastRefreshTime{0};
 };
 
 #endif // FEATHER_WALLET_H
index 2276c1a470da1d9462462ae0ece0b2ddf807a251..11403b666d0ac5dee04f611f9ababa33564e5546 100644 (file)
@@ -66,14 +66,16 @@ BalanceTickerWidget::BalanceTickerWidget(QWidget *parent, Wallet *wallet, bool t
     this->setPercentageVisible(false);
 
     connect(m_wallet, &Wallet::balanceUpdated, this, &BalanceTickerWidget::updateDisplay);
+    connect(m_wallet, &Wallet::connectionStatusChanged, this, &BalanceTickerWidget::updateDisplay);
     connect(&appData()->prices, &Prices::fiatPricesUpdated, this, &BalanceTickerWidget::updateDisplay);
     connect(&appData()->prices, &Prices::cryptoPricesUpdated, this, &BalanceTickerWidget::updateDisplay);
 }
 
 void BalanceTickerWidget::updateDisplay() {
-    double balance = (m_totalBalance ? m_wallet->balanceAll() : m_wallet->balance()) / constants::cdiv;
+    double balance = (m_totalBalance ? m_wallet->balanceAll() : m_wallet->balance());
+    double balanceAmount = balance / constants::cdiv;
     QString fiatCurrency = conf()->get(Config::preferredFiatCurrency).toString();
-    double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance);
+    double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balanceAmount);
 
     bool isCacheValid = appData()->prices.lastUpdateTime.isValid();
     bool isCacheFresh = isCacheValid && appData()->prices.lastUpdateTime.secsTo(QDateTime::currentDateTime()) < 3600;
@@ -81,7 +83,7 @@ void BalanceTickerWidget::updateDisplay() {
     bool hasXmrPrice = appData()->prices.markets.contains("XMR");
     bool hasFiatRate = fiatCurrency == "USD" || appData()->prices.rates.contains(fiatCurrency);
 
-    if (balanceFiatAmount == 0.0 || !isCacheValid) {
+    if (balance > 0 && (balanceFiatAmount == 0.0 || !isCacheValid)) {
         if (conf()->get(Config::offlineMode).toBool() || conf()->get(Config::disableWebsocket).toBool() || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) {
             this->setDisplayText("offline");
         } else if (!hasXmrPrice || !hasFiatRate) {