]> Nutra Git (v2) - gamesguru/feather.git/commitdiff
wip
authorgg <chown_tee@proton.me>
Tue, 13 Jan 2026 08:21:40 +0000 (03:21 -0500)
committergg <chown_tee@proton.me>
Tue, 13 Jan 2026 08:21:40 +0000 (03:21 -0500)
.github/workflows/linux.yml
src/CMakeLists.txt
src/MainWindow.cpp
src/WindowManager.cpp
src/utils/Utils.cpp
src/utils/Utils.h
src/widgets/TickerWidget.cpp

index af5a983469799fc1b17ba78791a1aaf04771d5fc..7fbddf400fc12a61dd3e84cef8cc2056cfa1e430 100644 (file)
@@ -97,4 +97,4 @@ jobs:
         run: cmake --build build
 
       - name: Validate Version
-        run: ./build/bin/feather --version
+        run: ./build/bin/feather --version | grep "Feather Wallet"
index 9031e1443f60a9632d320a254685a4a761f41f00..1dcfc99077d80ff305708b6e92477b9bccd97e45 100644 (file)
@@ -369,6 +369,14 @@ else()
 
     if (UNIX AND NOT APPLE)
         install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/feather.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME "feather.png")
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/48x48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps RENAME "feather.png")
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/64x64.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/64x64/apps RENAME "feather.png")
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/96x96.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/96x96/apps RENAME "feather.png")
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/128x128.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/128x128/apps RENAME "feather.png")
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/256x256.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/256x256/apps RENAME "feather.png")
+        install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/512x512.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/512x512/apps RENAME "feather.png")
+
         install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME "FeatherWallet.png")
         install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/48x48.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/48x48/apps RENAME "FeatherWallet.png")
         install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/images/appicons/64x64.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/64x64/apps RENAME "FeatherWallet.png")
index 1b5a0d89e8f371f86b446c55a49f8ad61c643fcc..ee26762fd3855cc202b1014909fa6673f1d88263 100644 (file)
@@ -9,6 +9,7 @@
 #include <QMessageBox>
 #include <QClipboard>
 #include <QLocale>
+#include <QHBoxLayout>
 #include <QCheckBox>
 #include <QFormLayout>
 #include <QSpinBox>
@@ -157,17 +158,24 @@ void MainWindow::initStatusBar() {
     m_statusUpdateAvailable->hide();
     this->statusBar()->addPermanentWidget(m_statusUpdateAvailable);
 
+    QWidget *balanceContainer = new QWidget(this);
+    QHBoxLayout *balanceLayout = new QHBoxLayout(balanceContainer);
+    balanceLayout->setContentsMargins(0, 0, 0, 0);
+    balanceLayout->setSpacing(0);
+
     QLabel *balancePrefix = new QLabel("Balance:", this);
-    this->statusBar()->addPermanentWidget(balancePrefix);
+    balanceLayout->addWidget(balancePrefix);
 
     m_statusLabelBalance = new QLabel(this);
     m_statusLabelBalance->setText("0");
     m_statusLabelBalance->setTextInteractionFlags(Qt::TextSelectableByMouse);
     m_statusLabelBalance->setContextMenuPolicy(Qt::ActionsContextMenu);
-    this->statusBar()->addPermanentWidget(m_statusLabelBalance);
+    balanceLayout->addWidget(m_statusLabelBalance);
 
     m_statusLabelBalanceSuffix = new QLabel("XMR", this);
-    this->statusBar()->addPermanentWidget(m_statusLabelBalanceSuffix);
+    balanceLayout->addWidget(m_statusLabelBalanceSuffix);
+
+    this->statusBar()->addPermanentWidget(balanceContainer);
 
     QAction *copyBalanceAction = new QAction(tr("Copy"), this);
     connect(copyBalanceAction, &QAction::triggered, this, [this](){
@@ -910,10 +918,10 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) {
     if (conf()->get(Config::balanceShowFiat).toBool() && !hide) {
         QString fiatCurrency = conf()->get(Config::preferredFiatCurrency).toString();
         double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance / constants::cdiv);
-        bool isCacheFresh = appData()->prices.lastUpdateTime.isValid() &&
-                            appData()->prices.lastUpdateTime.secsTo(QDateTime::currentDateTime()) < 3600;
+        bool isCacheValid = appData()->prices.lastUpdateTime.isValid();
+        bool isCacheFresh = isCacheValid && appData()->prices.lastUpdateTime.secsTo(QDateTime::currentDateTime()) < 3; // TODO: 3600
 
-        if (balance > 0 && (balanceFiatAmount == 0.0 || !isCacheFresh)) {
+        if (balance > 0 && (balanceFiatAmount == 0.0 || !isCacheValid)) {
             if (conf()->get(Config::offlineMode).toBool() || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) {
                 suffixStr += " (offline)";
             } else if (!appData()->prices.markets.contains("XMR")) {
@@ -922,12 +930,18 @@ void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) {
                 suffixStr += " (unknown)";
             }
         } else {
-            suffixStr += QString(" (%1)").arg(Utils::amountToCurrencyString(balanceFiatAmount, fiatCurrency));
+            QString approx = isCacheFresh ? "" : "~ ";
+            suffixStr += QString(" (%1%2)").arg(approx, Utils::amountToCurrencyString(balanceFiatAmount, fiatCurrency));
         }
     }
 
-    m_statusLabelBalance->setToolTip("Click for details");
+    QString toolTip = "Click for details";
+    if (appData()->prices.lastUpdateTime.isValid()) {
+        toolTip += QString("\nLast updated: %1").arg(Utils::timeAgo(appData()->prices.lastUpdateTime));
+    }
+    m_statusLabelBalance->setToolTip(toolTip);
     m_statusLabelBalance->setText(valueStr);
+    m_statusLabelBalanceSuffix->setToolTip(toolTip);
     m_statusLabelBalanceSuffix->setText(suffixStr);
 }
 
index b15cd315c64c7f8ad0a6f852f6abbf1e6e95cb3b..2417e61fad371a72882028f1f05153cb17e0179c 100644 (file)
@@ -51,7 +51,7 @@ WindowManager::WindowManager(QObject *parent)
         if (reason == QSystemTrayIcon::Trigger) {
             if (conf()->get(Config::trayLeftClickTogglesFocus).toBool()) {
                 for (const auto &window : m_windows) {
-                    if (window->isVisible()) {
+                    if (window->isVisible() && window->isActiveWindow()) {
                         window->hide();
                     } else {
                         window->show();
@@ -737,7 +737,7 @@ void WindowManager::onProxySettingsChanged() {
         getNetworkSocks5()->setProxy(proxy);
     }
 
-    qInfo() << "Proxy: " << proxy.hostName() << " " << proxy.port();
+    qDebug() << "Proxy: " << proxy.hostName() << " " << proxy.port();
 
     // Switch websocket to new proxy and update URL
     websocketNotifier()->websocketClient->stop();
index 323c4dda10f050e443107e888dd8362aeac41d4f..12f05c5a5a17275ab3c8e46d840420d7853d40dd 100644 (file)
@@ -619,6 +619,32 @@ QFont relativeFont(int delta) {
     return font;
 }
 
+QString timeAgo(const QDateTime &dt) {
+    qint64 diff = dt.secsTo(QDateTime::currentDateTime());
+
+    if (diff < 0) return "in the future";
+    if (diff < 60) return QString("%1 second%2 ago").arg(diff).arg(diff == 1 ? "" : "s");
+
+    diff /= 60; // minutes
+    if (diff < 60) return QString("%1 minute%2 ago").arg(diff).arg(diff == 1 ? "" : "s");
+
+    qint64 minutes = diff % 60;
+    diff /= 60; // hours
+    if (diff < 24) {
+        if (minutes > 0)
+            return QString("%1 hour%2 %3 minute%4 ago").arg(diff).arg(diff == 1 ? "" : "s").arg(minutes).arg(minutes == 1 ? "" : "s");
+        return QString("%1 hour%2 ago").arg(diff).arg(diff == 1 ? "" : "s");
+    }
+
+    diff /= 24; // days
+    if (diff < 30) return QString("%1 day%2 ago").arg(diff).arg(diff == 1 ? "" : "s");
+
+    diff /= 30; // months (approx)
+    if (diff < 12) return QString("%1 month%2 ago").arg(diff).arg(diff == 1 ? "" : "s");
+
+    return QString("%1 year%2 ago").arg(diff / 12).arg((diff / 12) == 1 ? "" : "s");
+}
+
 bool isLocalUrl(const QUrl &url) {
     QRegularExpression localNetwork(R"((^127\.)|(^10\.)|(^172\.1[6-9]\.)|(^172\.2[0-9]\.)|(^172\.3[0-1]\.)|(^192\.168\.))");
     return (localNetwork.match(url.host()).hasMatch() || url.host() == "localhost");
index 3a750aa9956ff678f471f56c32bc89ec98609c81..ae2467dfc121eb414e95fe5908dfefd17fb00975 100644 (file)
@@ -98,6 +98,7 @@ namespace Utils
 
     QFont getMonospaceFont();
     QFont relativeFont(int delta);
+    QString timeAgo(const QDateTime &dt);
 
     void applicationLogHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg);
     QString barrayToString(const QByteArray &data);
index 75b5cfe66d52ba1f874dcd258df3895c8d5612e5..f6f525ab8b7a9aa4588e620523db91da6767182a 100644 (file)
@@ -74,9 +74,22 @@ void BalanceTickerWidget::updateDisplay() {
     double balance = (m_totalBalance ? m_wallet->balanceAll() : m_wallet->balance()) / constants::cdiv;
     QString fiatCurrency = conf()->get(Config::preferredFiatCurrency).toString();
     double balanceFiatAmount = appData()->prices.convert("XMR", fiatCurrency, balance);
-    if (balanceFiatAmount < 0)
-        return;
-    this->setFiatText(balanceFiatAmount, fiatCurrency);
+
+    bool isCacheValid = appData()->prices.lastUpdateTime.isValid();
+    bool isCacheFresh = isCacheValid && appData()->prices.lastUpdateTime.secsTo(QDateTime::currentDateTime()) < 3600;
+
+    if (balanceFiatAmount == 0.0 || !isCacheValid) {
+        if (conf()->get(Config::offlineMode).toBool() || m_wallet->connectionStatus() == Wallet::ConnectionStatus_Disconnected) {
+            this->setDisplayText("offline");
+        } else if (!appData()->prices.markets.contains("XMR")) {
+            this->setDisplayText("connecting");
+        } else {
+            this->setDisplayText("unknown");
+        }
+    } else {
+        QString approx = isCacheFresh ? "" : "~ ";
+        this->setDisplayText(approx + Utils::amountToCurrencyString(balanceFiatAmount, fiatCurrency));
+    }
 }
 
 // PriceTickerWidget