From 05c50fdb7f0493e93624f1d4cc437d8be8131ab0 Mon Sep 17 00:00:00 2001 From: "James C. Owens" Date: Sat, 10 Feb 2024 20:00:59 -0500 Subject: [PATCH] Implement custom upgrade notification dialog box --- src/Makefile.qt.include | 4 ++ src/gridcoin/upgrade.cpp | 50 ++++++++++-------- src/gridcoin/upgrade.h | 10 +++- src/node/ui_interface.cpp | 2 +- src/node/ui_interface.h | 2 +- src/noui.cpp | 2 +- src/qt/CMakeLists.txt | 1 + src/qt/bitcoin.cpp | 6 +-- src/qt/bitcoingui.cpp | 17 ++++--- src/qt/bitcoingui.h | 5 +- src/qt/forms/updatedialog.ui | 98 ++++++++++++++++++++++++++++++++++++ src/qt/updatedialog.cpp | 55 ++++++++++++++++++++ src/qt/updatedialog.h | 32 ++++++++++++ src/qt/upgradeqt.cpp | 3 +- src/wallet/diagnose.h | 5 +- 15 files changed, 252 insertions(+), 40 deletions(-) create mode 100644 src/qt/forms/updatedialog.ui create mode 100644 src/qt/updatedialog.cpp create mode 100644 src/qt/updatedialog.h diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index 6e67219bec..ffc7dad3cb 100755 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -106,6 +106,7 @@ QT_FORMS_UI = \ qt/forms/sendcoinsentry.ui \ qt/forms/signverifymessagedialog.ui \ qt/forms/transactiondescdialog.ui \ + qt/forms/updatedialog.ui \ qt/forms/voting/additionalfieldstableview.ui \ qt/forms/voting/pollcard.ui \ qt/forms/voting/pollcardview.ui \ @@ -171,6 +172,7 @@ QT_MOC_CPP = \ qt/moc_transactionfilterproxy.cpp \ qt/moc_transactiontablemodel.cpp \ qt/moc_transactionview.cpp \ + qt/moc_updatedialog.cpp \ qt/moc_walletmodel.cpp \ qt/researcher/moc_projecttablemodel.cpp \ qt/researcher/moc_researchermodel.cpp \ @@ -298,6 +300,7 @@ GRIDCOINRESEARCH_QT_H = \ qt/transactionrecord.h \ qt/transactiontablemodel.h \ qt/transactionview.h \ + qt/updatedialog.h \ qt/upgradeqt.h \ qt/voting/additionalfieldstableview.h \ qt/voting/additionalfieldstablemodel.h \ @@ -388,6 +391,7 @@ GRIDCOINRESEARCH_QT_CPP = \ qt/transactiontablemodel.cpp \ qt/transactionview.cpp \ qt/upgradeqt.cpp \ + qt/updatedialog.cpp \ qt/voting/additionalfieldstableview.cpp \ qt/voting/additionalfieldstablemodel.cpp \ qt/voting/poll_types.cpp \ diff --git a/src/gridcoin/upgrade.cpp b/src/gridcoin/upgrade.cpp index aa45fe12bd..513efb4f42 100644 --- a/src/gridcoin/upgrade.cpp +++ b/src/gridcoin/upgrade.cpp @@ -34,10 +34,13 @@ void Upgrade::ScheduledUpdateCheck() { std::string VersionResponse = ""; - CheckForLatestUpdate(VersionResponse); + Upgrade::UpgradeType upgrade_type {Upgrade::UpgradeType::Unknown}; + + CheckForLatestUpdate(VersionResponse, upgrade_type); } -bool Upgrade::CheckForLatestUpdate(std::string& client_message_out, bool ui_dialog, bool snapshotrequest) +bool Upgrade::CheckForLatestUpdate(std::string& client_message_out, Upgrade::UpgradeType& upgrade_type, + bool ui_dialog, bool snapshotrequest) { // If testnet skip this || If the user changes this to disable while wallet running just drop out of here now. // (Need a way to remove items from scheduler.) @@ -95,14 +98,18 @@ bool Upgrade::CheckForLatestUpdate(std::string& client_message_out, bool ui_dial } GithubReleaseTypeData = ToLower(GithubReleaseTypeData); - if (GithubReleaseTypeData.find("leisure") != std::string::npos) + if (GithubReleaseTypeData.find("leisure") != std::string::npos) { GithubReleaseType = _("leisure"); - - else if (GithubReleaseTypeData.find("mandatory") != std::string::npos) + upgrade_type = Upgrade::UpgradeType::Leisure; + } else if (GithubReleaseTypeData.find("mandatory") != std::string::npos) { GithubReleaseType = _("mandatory"); - - else + // This will be confirmed below by also checking the second position version. If not incremented, then it will + // be set to unknown. + upgrade_type = Upgrade::UpgradeType::Mandatory; + } else { GithubReleaseType = _("unknown"); + upgrade_type = Upgrade::UpgradeType::Unknown; + } // Parse version data std::vector GithubVersion; @@ -139,23 +146,24 @@ bool Upgrade::CheckForLatestUpdate(std::string& client_message_out, bool ui_dial if (github_version > LocalVersion[x]) { NewVersion = true; - if (x < 2) - { + + if (x < 2 && upgrade_type == Upgrade::UpgradeType::Mandatory) { NewMandatory = true; + } else { + upgrade_type = Upgrade::UpgradeType::Unknown; } + break; } } - } - catch (std::exception& ex) - { + } catch (std::exception& ex) { error("%s: Exception occurred checking client version against GitHub version (%s)", __func__, ToString(ex.what())); return false; } - if (!NewVersion) return NewVersion; + if (!NewVersion) return false; // New version was found client_message_out = _("Local version: ") + strprintf("%d.%d.%d.%d", CLIENT_VERSION_MAJOR, CLIENT_VERSION_MINOR, @@ -164,19 +172,20 @@ bool Upgrade::CheckForLatestUpdate(std::string& client_message_out, bool ui_dial client_message_out.append(_("This update is ") + GithubReleaseType + "\r\n\r\n"); // For snapshot requests we will handle things differently after this point - if (snapshotrequest && NewMandatory) - return NewVersion; + if (snapshotrequest && NewMandatory) return true; - if (NewMandatory) + if (NewMandatory) { client_message_out.append(_("WARNING: A mandatory release is available. Please upgrade as soon as possible.") + "\n"); + } std::string ChangeLog = GithubReleaseBody; - if (ui_dialog) - uiInterface.UpdateMessageBox(client_message_out, ChangeLog); + if (ui_dialog) { + uiInterface.UpdateMessageBox(client_message_out, static_cast(upgrade_type), ChangeLog); + } - return NewVersion; + return true; } void Upgrade::SnapshotMain() @@ -188,8 +197,9 @@ void Upgrade::SnapshotMain() // Verify a mandatory release is not available before we continue to snapshot download. std::string VersionResponse = ""; + Upgrade::UpgradeType upgrade_type {Upgrade::UpgradeType::Unknown}; - if (CheckForLatestUpdate(VersionResponse, false, true)) + if (CheckForLatestUpdate(VersionResponse, upgrade_type, false, true)) { std::cout << this->ResetBlockchainMessages(UpdateAvailable) << std::endl; std::cout << this->ResetBlockchainMessages(GithubResponse) << std::endl; diff --git a/src/gridcoin/upgrade.h b/src/gridcoin/upgrade.h index daa1efba8f..4486894748 100644 --- a/src/gridcoin/upgrade.h +++ b/src/gridcoin/upgrade.h @@ -125,6 +125,13 @@ class Upgrade GithubResponse }; + enum UpgradeType { + Unknown, + Leisure, + Mandatory, + Testnet + }; + //! //! \brief Scheduler call to CheckForLatestUpdate //! @@ -133,7 +140,8 @@ class Upgrade //! //! \brief Check for latest updates on GitHub. //! - static bool CheckForLatestUpdate(std::string& client_message_out, bool ui_dialog = true, bool snapshotrequest = false); + static bool CheckForLatestUpdate(std::string& client_message_out, UpgradeType& upgrade_type, + bool ui_dialog = true, bool snapshotrequest = false); //! //! \brief Function that will be threaded to download snapshot diff --git a/src/node/ui_interface.cpp b/src/node/ui_interface.cpp index c412d77269..297d64997a 100644 --- a/src/node/ui_interface.cpp +++ b/src/node/ui_interface.cpp @@ -67,7 +67,7 @@ ADD_SIGNALS_IMPL_WRAPPER(UpdateMessageBox); ADD_SIGNALS_IMPL_WRAPPER(RwSettingsUpdated); void CClientUIInterface::ThreadSafeMessageBox(const std::string& message, const std::string& caption, int style) { return g_ui_signals.ThreadSafeMessageBox(message, caption, style); } -void CClientUIInterface::UpdateMessageBox(const std::string& version, const std::string& message) { return g_ui_signals.UpdateMessageBox(version, message); } +void CClientUIInterface::UpdateMessageBox(const std::string& version, const int& update_type, const std::string& message) { return g_ui_signals.UpdateMessageBox(version, update_type, message); } bool CClientUIInterface::ThreadSafeAskFee(int64_t nFeeRequired, const std::string& strCaption) { return g_ui_signals.ThreadSafeAskFee(nFeeRequired, strCaption).value_or(false); } bool CClientUIInterface::ThreadSafeAskQuestion(std::string caption, std::string body) { return g_ui_signals.ThreadSafeAskQuestion(caption, body).value_or(false); } void CClientUIInterface::ThreadSafeHandleURI(const std::string& strURI) { return g_ui_signals.ThreadSafeHandleURI(strURI); } diff --git a/src/node/ui_interface.h b/src/node/ui_interface.h index a0917c573a..6a2aa852be 100644 --- a/src/node/ui_interface.h +++ b/src/node/ui_interface.h @@ -88,7 +88,7 @@ class CClientUIInterface ADD_SIGNALS_DECL_WRAPPER(ThreadSafeMessageBox, void, const std::string& message, const std::string& caption, int style); /** Update notification message box. */ - ADD_SIGNALS_DECL_WRAPPER(UpdateMessageBox, void, const std::string& version, const std::string& message); + ADD_SIGNALS_DECL_WRAPPER(UpdateMessageBox, void, const std::string& version, const int& update_type, const std::string& message); /** Ask the user whether they want to pay a fee or not. */ ADD_SIGNALS_DECL_WRAPPER(ThreadSafeAskFee, bool, int64_t nFeeRequired, const std::string& strCaption); diff --git a/src/noui.cpp b/src/noui.cpp index 033b04df56..188b7f8bba 100644 --- a/src/noui.cpp +++ b/src/noui.cpp @@ -21,7 +21,7 @@ static bool noui_ThreadSafeAskFee(int64_t nFeeRequired, const std::string& strCa return true; } -static int noui_UpdateMessageBox(const std::string& version, const std::string& message) +static int noui_UpdateMessageBox(const std::string& version, const int& upgrade_type, const std::string& message) { std::string caption = _("Gridcoin Update Available"); diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index b62d55953b..26f345e0c2 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -71,6 +71,7 @@ add_library(gridcoinqt STATIC transactionrecord.cpp transactiontablemodel.cpp transactionview.cpp + upgradedialog.cpp upgradeqt.cpp voting/additionalfieldstableview.cpp voting/additionalfieldstablemodel.cpp diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 82bd5a8ab1..24028b6be3 100755 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -192,16 +192,16 @@ static void InitMessage(const std::string &message) } } -static void UpdateMessageBox(const std::string& version, const std::string& message) +static void UpdateMessageBox(const std::string& version, const int& update_version, const std::string& message) { std::string caption = _("Gridcoin Update Available"); if (guiref) { - std::string guiaddition = version + _("Click \"Show Details\" to view changes in latest update."); QMetaObject::invokeMethod(guiref, "update", Qt::QueuedConnection, Q_ARG(QString, QString::fromStdString(caption)), - Q_ARG(QString, QString::fromStdString(guiaddition)), + Q_ARG(QString, QString::fromStdString(version)), + Q_ARG(int, update_version), Q_ARG(QString, QString::fromStdString(message))); } diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index aa7c86315f..09e3595340 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -45,6 +45,7 @@ #include "upgradeqt.h" #include "voting/votingmodel.h" #include "voting/polltablemodel.h" +#include "updatedialog.h" #ifdef Q_OS_MAC #include "macdockiconhandler.h" @@ -1159,22 +1160,22 @@ void BitcoinGUI::error(const QString &title, const QString &message, bool modal) } } -void BitcoinGUI::update(const QString &title, const QString& version, const QString &message) +void BitcoinGUI::update(const QString &title, const QString& version, const int& upgrade_type, const QString &message) { // Create our own message box; A dialog can go here in future for qt if we choose - updateMessageDialog.reset(new QMessageBox); + updateMessageDialog.reset(new UpdateDialog); updateMessageDialog->setWindowTitle(title); - updateMessageDialog->setText(version); - updateMessageDialog->setDetailedText(message); - updateMessageDialog->setIcon(QMessageBox::Information); - updateMessageDialog->setStandardButtons(QMessageBox::Ok); + updateMessageDialog->setVersion(version); + updateMessageDialog->setUpgradeType(static_cast(upgrade_type)); + updateMessageDialog->setDetails(message); updateMessageDialog->setModal(false); - connect(updateMessageDialog.get(), &QMessageBox::finished, [this](int) { updateMessageDialog.reset(); }); + + connect(updateMessageDialog.get(), &QDialog::finished, this, [this]() { updateMessageDialog.reset(); }); + // Due to slight delay in gui load this could appear behind the gui ui // The only other option available would make the message box stay on top of all applications - QTimer::singleShot(5000, updateMessageDialog.get(), [this]() { updateMessageDialog->show(); }); } diff --git a/src/qt/bitcoingui.h b/src/qt/bitcoingui.h index 5b1413cbbf..e1934f8348 100644 --- a/src/qt/bitcoingui.h +++ b/src/qt/bitcoingui.h @@ -32,6 +32,7 @@ class Notificator; class RPCConsole; class DiagnosticsDialog; class ClickLabel; +class UpdateDialog; QT_BEGIN_NAMESPACE class QLabel; @@ -110,7 +111,7 @@ class BitcoinGUI : public QMainWindow TransactionView *transactionView; VotingPage *votingPage; SignVerifyMessageDialog *signVerifyMessageDialog; - std::unique_ptr updateMessageDialog; + std::unique_ptr updateMessageDialog; QLabel *statusbarAlertsLabel; QLabel *labelEncryptionIcon; @@ -205,7 +206,7 @@ public slots: void setEncryptionStatus(int status); /** Notify the user if there is an update available */ - void update(const QString& title, const QString& version, const QString& message); + void update(const QString& title, const QString& version, const int& upgrade_type, const QString& message); /** Notify the user of an error in the network or transaction handling code. */ void error(const QString &title, const QString &message, bool modal); diff --git a/src/qt/forms/updatedialog.ui b/src/qt/forms/updatedialog.ui new file mode 100644 index 0000000000..d713ec8b28 --- /dev/null +++ b/src/qt/forms/updatedialog.ui @@ -0,0 +1,98 @@ + + + UpdateDialog + + + + 0 + 0 + 609 + 430 + + + + Dialog + + + + + + + + icon + + + + + + + version + + + + + + + + + false + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + + changelog + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + UpdateDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UpdateDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/qt/updatedialog.cpp b/src/qt/updatedialog.cpp new file mode 100644 index 0000000000..adde5b5ae0 --- /dev/null +++ b/src/qt/updatedialog.cpp @@ -0,0 +1,55 @@ +// Copyright (c) 2014-2024 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#include "updatedialog.h" +#include "qicon.h" +#include "qstyle.h" +#include "qt/decoration.h" + +#include "ui_updatedialog.h" + +UpdateDialog::UpdateDialog(QWidget* parent) + : QDialog(parent) + , ui(new Ui::UpdateDialog) +{ + ui->setupUi(this); + + resize(GRC::ScaleSize(this, width(), height())); +} + +UpdateDialog::~UpdateDialog() +{ + delete ui; +} + +void UpdateDialog::setVersion(QString version) +{ + ui->versionData->setText(version); +} + +void UpdateDialog::setDetails(QString message) +{ + ui->versionDetails->setText(message); +} + +void UpdateDialog::setUpgradeType(GRC::Upgrade::UpgradeType upgrade_type) +{ + QIcon info_icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxInformation); + QIcon warning_icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxWarning); + QIcon unkown_icon = QApplication::style()->standardIcon(QStyle::SP_MessageBoxQuestion); + + switch (upgrade_type) { + case GRC::Upgrade::UpgradeType::Mandatory: + ui->infoIcon->setPixmap(GRC::ScaleIcon(this, warning_icon, 48)); + break; + case GRC::Upgrade::UpgradeType::Leisure: + [[fallthrough]]; + case GRC::Upgrade::UpgradeType::Testnet: + ui->infoIcon->setPixmap(GRC::ScaleIcon(this, info_icon, 48)); + break; + case GRC::Upgrade::Unknown: + ui->infoIcon->setPixmap(GRC::ScaleIcon(this, unkown_icon, 48)); + break; + } +} diff --git a/src/qt/updatedialog.h b/src/qt/updatedialog.h new file mode 100644 index 0000000000..7987b706f7 --- /dev/null +++ b/src/qt/updatedialog.h @@ -0,0 +1,32 @@ +// Copyright (c) 2014-2024 The Gridcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or https://opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_QT_UPDATEDIALOG_H +#define BITCOIN_QT_UPDATEDIALOG_H + +#include "gridcoin/upgrade.h" +#include + +namespace Ui { +class UpdateDialog; +} + +class UpdateDialog : public QDialog +{ + Q_OBJECT + +public: + explicit UpdateDialog(QWidget* parent = nullptr); + ~UpdateDialog(); + + void setVersion(QString version); + void setDetails(QString message); + void setUpgradeType(GRC::Upgrade::UpgradeType upgrade_type); + +private: + Ui::UpdateDialog *ui; + +}; + +#endif // BITCOIN_QT_UPDATEDIALOG_H diff --git a/src/qt/upgradeqt.cpp b/src/qt/upgradeqt.cpp index 6bbfd9519d..06a9c490d6 100644 --- a/src/qt/upgradeqt.cpp +++ b/src/qt/upgradeqt.cpp @@ -41,8 +41,9 @@ bool UpgradeQt::SnapshotMain(QApplication& SnapshotApp) // Verify a mandatory release is not available before we continue to snapshot download. std::string VersionResponse = ""; + Upgrade::UpgradeType upgrade_type {Upgrade::UpgradeType::Unknown}; - if (UpgradeMain.CheckForLatestUpdate(VersionResponse, false, true)) + if (UpgradeMain.CheckForLatestUpdate(VersionResponse, upgrade_type, false, true)) { ErrorMsg(UpgradeMain.ResetBlockchainMessages(Upgrade::UpdateAvailable), UpgradeMain.ResetBlockchainMessages(Upgrade::GithubResponse) + "\r\n" + VersionResponse); diff --git a/src/wallet/diagnose.h b/src/wallet/diagnose.h index f931fc45e1..d09856ca82 100644 --- a/src/wallet/diagnose.h +++ b/src/wallet/diagnose.h @@ -403,14 +403,15 @@ class CheckClientVersion : public Diagnose m_results_tip_arg.clear(); std::string client_message; + GRC::Upgrade::UpgradeType upgrade_type {GRC::Upgrade::UpgradeType::Unknown}; - if (g_UpdateChecker->CheckForLatestUpdate(client_message, false) + if (g_UpdateChecker->CheckForLatestUpdate(client_message, upgrade_type, false) && client_message.find("mandatory") != std::string::npos) { m_results_tip = _("There is a new mandatory version available and you should upgrade as soon as possible to " "ensure your wallet remains in consensus with the network."); m_results = Diagnose::FAIL; - } else if (g_UpdateChecker->CheckForLatestUpdate(client_message, false) + } else if (g_UpdateChecker->CheckForLatestUpdate(client_message, upgrade_type, false) && client_message.find("mandatory") == std::string::npos) { m_results_tip = _("There is a new leisure version available and you should upgrade as soon as practical."); m_results = Diagnose::WARNING;