]> Nutra Git (v2) - gamesguru/feather.git/commitdiff
add history widget and mempool scanning config
authorgg <chown_tee@proton.me>
Sun, 18 Jan 2026 20:54:47 +0000 (15:54 -0500)
committergg <chown_tee@proton.me>
Sun, 18 Jan 2026 20:54:47 +0000 (15:54 -0500)
src/HistoryWidget.cpp
src/HistoryWidget.h
src/MainWindow.cpp
src/MainWindow.h
src/libwalletqt/Wallet.cpp
src/libwalletqt/Wallet.h
src/utils/config.cpp
src/utils/config.h

index 6f2433b77a9b20d5077d28956b02400178c2b049..09aa843b326ad1a89c777806e3004585779a82e3 100644 (file)
 #include "utils/Icons.h"
 #include "WebsocketNotifier.h"
 
+#include <QClipboard>
+#include <QJsonObject>
+#include <QJsonDocument>
+#include <QJsonArray>
+
 HistoryWidget::HistoryWidget(Wallet *wallet, QWidget *parent)
         : QWidget(parent)
         , ui(new Ui::HistoryWidget)
@@ -33,6 +38,7 @@ HistoryWidget::HistoryWidget(Wallet *wallet, QWidget *parent)
     m_copyMenu->addAction("Date", this, [this]{copy(copyField::Date);});
     m_copyMenu->addAction("Description", this, [this]{copy(copyField::Description);});
     m_copyMenu->addAction("Amount", this, [this]{copy(copyField::Amount);});
+    m_copyMenu->addAction("Row as JSON", this, [this]{copy(copyField::JSON);});
 
     ui->history->setContextMenuPolicy(Qt::CustomContextMenu);
     connect(ui->history, &QTreeView::customContextMenuRequested, this, &HistoryWidget::showContextMenu);
@@ -204,6 +210,30 @@ void HistoryWidget::copy(copyField field) {
                                                                      conf()->get(Config::timeFormat).toString()));
             case copyField::Amount:
                 return WalletManager::displayAmount(abs(tx.balanceDelta));
+            case copyField::JSON: {
+                QJsonObject obj;
+                obj.insert("txid", tx.hash);
+                obj.insert("amount", static_cast<double>(tx.amount));
+                obj.insert("fee", static_cast<double>(tx.fee));
+                obj.insert("height", static_cast<double>(tx.blockHeight));
+                obj.insert("timestamp", tx.timestamp.toSecsSinceEpoch());
+                obj.insert("direction", tx.direction == TransactionRow::Direction_In ? "in" : "out");
+                obj.insert("payment_id", tx.paymentId);
+                obj.insert("description", tx.description);
+                obj.insert("confirmations", static_cast<double>(tx.confirmations));
+                obj.insert("failed", tx.failed);
+                obj.insert("pending", tx.pending);
+                obj.insert("coinbase", tx.coinbase);
+                obj.insert("label", tx.label);
+
+                QJsonArray subaddrIndices;
+                for (const auto &idx : tx.subaddrIndex) subaddrIndices.append(static_cast<int>(idx));
+                obj.insert("subaddr_index", subaddrIndices);
+                obj.insert("subaddr_account", static_cast<int>(tx.subaddrAccount));
+
+                QJsonDocument doc(obj);
+                return QString::fromUtf8(doc.toJson(QJsonDocument::Indented));
+            }
             default:
                 return QString("");
         }
index d9d982632505b2a6dd7fa7e48ed7a73f22ee605f..f619a1262da2c790f63db83c2880370371be2434 100644 (file)
@@ -48,7 +48,8 @@ private:
         TxID = 0,
         Description,
         Date,
-        Amount
+        Amount,
+        JSON
     };
 
     void copy(copyField field);
index 5f0dc0a7b6e9e78d4da4bf36813357719a5fc764..f0f0258b8d14c34c538b412c955b89898523262a 100644 (file)
@@ -235,6 +235,15 @@ void MainWindow::initStatusBar() {
     m_actionPauseSync->setChecked(conf()->get(Config::syncPaused).toBool());
     m_statusLabelStatus->addAction(m_actionPauseSync);
 
+    m_actionScanMempoolWhenPaused = new QAction(tr("Scan mempool when paused"), this);
+    m_actionScanMempoolWhenPaused->setCheckable(true);
+    m_actionScanMempoolWhenPaused->setChecked(conf()->get(Config::scanMempoolWhenPaused).toBool());
+    m_statusLabelStatus->addAction(m_actionScanMempoolWhenPaused);
+
+    connect(m_actionScanMempoolWhenPaused, &QAction::toggled, this, [](bool checked) {
+        conf()->set(Config::scanMempoolWhenPaused, checked);
+    });
+
     m_actionEnableWebsocket = new QAction(tr("Enable Websocket"), this);
     m_actionEnableWebsocket->setCheckable(true);
     m_actionEnableWebsocket->setChecked(!conf()->get(Config::disableWebsocket).toBool());
index 5164c147486d233e1d5c9d755d98286126e51d43..51d44c9c47d4fb04fe4c4d778dc94c3c0ee9a4d7 100644 (file)
@@ -240,6 +240,7 @@ private:
     QPointer<QAction> m_updateNetworkInfoAction;
     QPointer<QAction> m_actionEnableWebsocket;
     QPointer<QAction> m_actionPauseSync;
+    QPointer<QAction> m_actionScanMempoolWhenPaused;
 
     QDateTime m_lastSyncStatusUpdate;
     QDateTime m_lastNetInfoUpdate;
index 5f9e2eb1e5d56e473e278babb5bde2a27cee07ec..a6fef448f647ecf4dd21d77e6ad960ef442046fd 100644 (file)
@@ -5,6 +5,7 @@
 
 #include <chrono>
 #include <thread>
+#include <tuple>
 
 #include "AddressBook.h"
 #include "Coins.h"
@@ -561,9 +562,6 @@ void Wallet::startRefreshThread()
                     // Don't call refresh function if we don't have the daemon and target height
                     // We do this to prevent to UI from getting confused about the amount of blocks that are still remaining
                     if (haveHeights) {
-                        // Prevent background network usage when sync is paused
-                        if (m_syncPaused)
-                            continue;
 
                         QMutexLocker locker(&m_asyncMutex);
 
@@ -576,6 +574,19 @@ void Wallet::startRefreshThread()
                         quint64 walletHeight = m_walletImpl->blockChainHeight();
                         m_walletImpl->refresh();
                     }
+
+                    // Scan mempool if paused
+                    // Low-bandwidth query if user has enabled it
+                    if (m_syncPaused) {
+                        if (m_refreshNow || conf()->get(Config::scanMempoolWhenPaused).toBool()) {
+                            scanMempool();
+                            m_refreshNow = false;
+                        } else {
+                            std::this_thread::sleep_for(std::chrono::milliseconds(250));
+                        }
+                        last = std::chrono::steady_clock::now();
+                        continue;
+                    }
                 }
             }
 
@@ -1688,6 +1699,19 @@ void Wallet::getTxPoolStatsAsync() {
     });
 }
 
+void Wallet::scanMempool() {
+    QMutexLocker locker(&m_asyncMutex);
+    try {
+        std::vector<std::tuple<cryptonote::transaction, crypto::hash, bool>> process_txs;
+        m_wallet2->update_pool_state(process_txs, false, false);
+        if (!process_txs.empty()) {
+            m_wallet2->process_pool_state(process_txs);
+        }
+    } catch (const std::exception &e) {
+        qWarning() << "Failed to scan mempool:" << e.what();
+    }
+}
+
 Wallet::~Wallet()
 {
     qDebug() << "~Wallet: Closing wallet" << QThread::currentThreadId();
index 366dd8858742f7769f44745d7eb2afa8c0b0cd81..690966540a9f954501ed467fbe8237b5fa09ab53 100644 (file)
@@ -494,6 +494,7 @@ private:
     void onTransactionCreated(Monero::PendingTransaction *mtx, const QVector<QString> &address);
 
 private:
+    void scanMempool();
     friend class WalletManager;
     friend class WalletListenerImpl;
 
index ae6cade9f830538d245b489a89b70deec21da3f2..c6720fa4e871f09072fcdb7e01a9b331d32a6c5a 100644 (file)
@@ -132,6 +132,7 @@ static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
         {Config::torManagedPort, {QS("torManagedPort"), "19450"}},
         {Config::useLocalTor, {QS("useLocalTor"), false}},
         {Config::initSyncThreshold, {QS("initSyncThreshold"), 360}},
+        {Config::scanMempoolWhenPaused, {QS("scanMempoolWhenPaused"), false}},
 
         {Config::enabledPlugins, {QS("enabledPlugins"), QStringList{"tickers", "crowdfunding", "revuo", "calc"}}},
         {Config::restartRequired, {QS("restartRequired"), false}},
index b739359b05f6e47909f882df97308c4431201baa..d43935b01d6bc125bfa39dd1a2b77d2e5cae5dd7 100644 (file)
@@ -150,6 +150,7 @@ public:
         lastNetInfoUpdate,
         lastSyncTimestamp,
         lastPriceUpdateTimestamp,
+        scanMempoolWhenPaused,
     };
 
     enum PrivacyLevel {