From 6549ca4e1d83a16d51957ff4326084928aa02d4e Mon Sep 17 00:00:00 2001 From: dsc Date: Fri, 14 May 2021 01:44:42 +0200 Subject: [PATCH] Warn when there is a new version available --- CMakeLists.txt | 4 +- cmake/config-wowlet.h.cmake | 1 + src/appcontext.cpp | 8 +++ src/appcontext.h | 4 +- src/assets.qrc | 1 + src/assets/images/pls_update.jpg | Bin 0 -> 31180 bytes src/dialog/updatedialog.cpp | 44 +++++++++++++ src/dialog/updatedialog.h | 31 +++++++++ src/dialog/updatedialog.ui | 108 +++++++++++++++++++++++++++++++ src/mainwindow.cpp | 27 ++++++++ src/mainwindow.h | 5 ++ src/mainwindow.ui | 9 ++- src/utils/config.cpp | 1 + src/utils/config.h | 3 +- src/utils/utils.cpp | 10 +++ src/utils/utils.h | 1 + 16 files changed, 252 insertions(+), 5 deletions(-) create mode 100644 src/assets/images/pls_update.jpg create mode 100644 src/dialog/updatedialog.cpp create mode 100644 src/dialog/updatedialog.h create mode 100644 src/dialog/updatedialog.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index b1a1e5c..71096d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ project(wowlet) message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}") set(THREADS_PREFER_PTHREAD_FLAG ON) -set(VERSION_MAJOR "0") -set(VERSION_MINOR "2") +set(VERSION_MAJOR "2") +set(VERSION_MINOR "0") set(VERSION_REVISION "0") set(VERSION "beta-2") diff --git a/cmake/config-wowlet.h.cmake b/cmake/config-wowlet.h.cmake index 1790145..cd8681e 100644 --- a/cmake/config-wowlet.h.cmake +++ b/cmake/config-wowlet.h.cmake @@ -3,6 +3,7 @@ #define WOWLET_VERSION "@VERSION@" #define WOWLET_BRANCH "@WOWLET_BRANCH@" +#define WOWLET_VERSION_SEMVER "@VERSION_MAJOR@.@VERSION_MINOR@.@VERSION_REVISION@" #define MONERO_VERSION "@MONERO_VERSION@" #define MONERO_BRANCH "@MONERO_BRANCH@" diff --git a/src/appcontext.cpp b/src/appcontext.cpp index 122e5d9..c185181 100644 --- a/src/appcontext.cpp +++ b/src/appcontext.cpp @@ -6,6 +6,7 @@ #include "appcontext.h" #include "globals.h" +#include "config-wowlet.h" // libwalletqt #include "libwalletqt/TransactionHistory.h" @@ -457,6 +458,13 @@ void AppContext::onWSMessage(const QJsonObject &msg) { auto txFiatHistory_data = msg.value("data").toObject(); AppContext::txFiatHistory->onWSData(txFiatHistory_data); } + else if(cmd == "wowlet_releases") { + versionPending = msg.value("data").toObject(); + auto version_str = versionPending.value("version").toString(); + + if(Utils::versionOutdated(WOWLET_VERSION_SEMVER, version_str)) + emit versionOutdated(version_str, versionPending); + } #if defined(HAS_OPENVR) else if(cmd == "requestPIN") { auto pin = msg.value("data").toString(); diff --git a/src/appcontext.h b/src/appcontext.h index 6419c40..b07444a 100644 --- a/src/appcontext.h +++ b/src/appcontext.h @@ -45,6 +45,7 @@ public: bool isMac = false; bool isWindows = false; bool isDebug = false; + static bool isQML; bool androidDebug = false; // Donation config @@ -105,7 +106,7 @@ public: static QMap txDescriptionCache; static QMap txCache; static TxFiatHistory *txFiatHistory; - static bool isQML; + QJsonObject versionPending; // libwalletqt bool refreshed = false; @@ -219,6 +220,7 @@ signals: void initiateTransaction(); void endTransaction(); void setTitle(const QString &title); // set window title + void versionOutdated(QString version_string, QJsonObject data); private: WalletKeysFilesModel *m_walletKeysFilesModel; diff --git a/src/assets.qrc b/src/assets.qrc index 596a774..da545e3 100644 --- a/src/assets.qrc +++ b/src/assets.qrc @@ -186,6 +186,7 @@ assets/images/seal.png assets/images/seed.png assets/images/speaker.png + assets/images/pls_update.jpg assets/images/status_connected_fork.png assets/images/status_connected.png assets/images/status_connected_proxy_fork.png diff --git a/src/assets/images/pls_update.jpg b/src/assets/images/pls_update.jpg new file mode 100644 index 0000000000000000000000000000000000000000..be276abfea3b406230e8d9fe1fa606ad0e3680fd GIT binary patch literal 31180 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 SzY|S=_=c%|Vvd^Opa0o!3f->& literal 0 HcmV?d00001 diff --git a/src/dialog/updatedialog.cpp b/src/dialog/updatedialog.cpp new file mode 100644 index 0000000..a089aa0 --- /dev/null +++ b/src/dialog/updatedialog.cpp @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#include +#include "updatedialog.h" +#include "ui_updatedialog.h" + +#include "config-wowlet.h" + +UpdateDialog::UpdateDialog(AppContext *ctx, QWidget *parent) : + QDialog(parent), + ctx(ctx), + ui(new Ui::UpdateDialog) { + ui->setupUi(this); + this->setWindowIcon(QIcon("://assets/images/appicons/64x64.png")); + + auto version_str = ctx->versionPending.value("version").toString(); + + QPixmap p(":assets/images/pls_update.jpg"); + ui->label_image->setPixmap(p.scaled(320, 320, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + + ui->info_label->setText("Current version: " + QString(WOWLET_VERSION_SEMVER) + "\n" + "New version: " + version_str); + + ui->label_download->setText("Download: git.wownero.com"); + ui->label_download->setTextInteractionFlags(Qt::TextBrowserInteraction); + ui->label_download->setOpenExternalLinks(true); + + // checkbox + connect(ui->checkbox_ignore, &QCheckBox::clicked, this, &UpdateDialog::checkboxIgnoreWarning); + + this->adjustSize(); +} + +void UpdateDialog::checkboxIgnoreWarning(bool checked) { + if(checked) + config()->set(Config::ignoreUpdateWarning, WOWLET_VERSION_SEMVER); + else + config()->set(Config::ignoreUpdateWarning, ""); +} + +UpdateDialog::~UpdateDialog() { + delete ui; +} diff --git a/src/dialog/updatedialog.h b/src/dialog/updatedialog.h new file mode 100644 index 0000000..9ec1725 --- /dev/null +++ b/src/dialog/updatedialog.h @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. + +#ifndef WOWLET_UPDATEDIALOG_H +#define WOWLET_UPDATEDIALOG_H + +#include +#include "appcontext.h" + +namespace Ui { + class UpdateDialog; +} + +class UpdateDialog : public QDialog +{ +Q_OBJECT + +public: + explicit UpdateDialog(AppContext *ctx, QWidget *parent = nullptr); + ~UpdateDialog() override; + +private slots: + void checkboxIgnoreWarning(bool checked); + +private: + AppContext *ctx = nullptr; + Ui::UpdateDialog *ui; +}; + + +#endif //WOWLET_UPDATEDIALOG_H diff --git a/src/dialog/updatedialog.ui b/src/dialog/updatedialog.ui new file mode 100644 index 0000000..efccab4 --- /dev/null +++ b/src/dialog/updatedialog.ui @@ -0,0 +1,108 @@ + + + UpdateDialog + + + + 0 + 0 + 349 + 189 + + + + Pls update + + + + + + image + + + + + + + info_label + + + + + + + download_label + + + Qt::RichText + + + + + + + Ignore for now + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + UpdateDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + UpdateDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index b09b812..110b78e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -19,11 +19,13 @@ #include "dialog/viewonlydialog.h" #include "dialog/broadcasttxdialog.h" #include "dialog/tximportdialog.h" +#include "dialog/updatedialog.h" #include "dialog/passworddialog.h" #include "dialog/balancedialog.h" #include "dialog/WalletCacheDebugDialog.h" #include "ui_mainwindow.h" #include "globals.h" +#include "config-wowlet.h" #include "utils/ColorScheme.h" // libwalletqt @@ -39,6 +41,8 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) : pMainWindow = this; ui->setupUi(this); + ui->label_outdated->setVisible(false); + m_windowSettings = new Settings(this); m_aboutDialog = new AboutDialog(this); m_windowCalc = new CalcWindow(this); @@ -337,6 +341,9 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) : // window title connect(m_ctx, &AppContext::setTitle, this, &QMainWindow::setWindowTitle); + // Version warning + connect(m_ctx, &AppContext::versionOutdated, this, &MainWindow::onVersionWarning); + // init touchbar #ifdef Q_OS_MAC m_touchbar = new KDMacTouchBar(this); @@ -428,6 +435,7 @@ void MainWindow::initMenu() { connect(ui->actionSeed, &QAction::triggered, this, &MainWindow::showSeedDialog); connect(ui->actionPassword, &QAction::triggered, this, &MainWindow::showPasswordDialog); connect(ui->actionKeys, &QAction::triggered, this, &MainWindow::showKeysDialog); + connect(this, &MainWindow::updateDialog, this, &MainWindow::showUpdateDialog); connect(ui->actionViewOnly, &QAction::triggered, this, &MainWindow::showViewOnlyDialog); connect(ui->actionStore_wallet, &QAction::triggered, [this]{ m_ctx->currentWallet->store(); @@ -632,6 +640,8 @@ void MainWindow::onWalletOpened(Wallet *wallet) { this->updatePasswordIcon(); m_updateBytes.start(100); + + if(m_showUpdateWarning == 1) emit updateDialog(); } void MainWindow::onBalanceUpdated(quint64 balance, quint64 spendable) { @@ -886,6 +896,12 @@ void MainWindow::updatePasswordIcon() { m_statusBtnPassword->setIcon(icon); } +void MainWindow::onVersionWarning(QString current_string, QJsonObject version_data) { + if(m_showUpdateWarning != -1) + m_showUpdateWarning = 1; + ui->label_outdated->setVisible(true); +} + void MainWindow::showRestoreHeightDialog() { // settings custom restore height is only available for 25 word seeds auto seed = m_ctx->currentWallet->getCacheAttribute("wowlet.seed"); @@ -911,6 +927,17 @@ void MainWindow::showRestoreHeightDialog() { }); } +void MainWindow::showUpdateDialog() { + if(config()->get(Config::ignoreUpdateWarning).toString() == WOWLET_VERSION_SEMVER) { + m_showUpdateWarning = -1; + return; + } + + auto *dialog = new UpdateDialog(m_ctx, this); + dialog->show(); + m_showUpdateWarning = -1; +} + void MainWindow::showKeysDialog() { auto *dialog = new KeysDialog(m_ctx, this); dialog->exec(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 62e33e0..3e22fac 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -38,6 +38,7 @@ #include "dialog/verifyproofdialog.h" #include "dialog/seeddialog.h" #include "dialog/passwordchangedialog.h" +#include "dialog/updatedialog.h" #include "dialog/keysdialog.h" #include "dialog/aboutdialog.h" #include "dialog/restoredialog.h" @@ -115,6 +116,7 @@ public slots: void showSendScreen(const CCSEntry &entry); void suchDonate(const QString address); void skinChanged(const QString &skinName); + void onVersionWarning(QString current_string, QJsonObject data); void menuTorClicked(); void onBlockchainSync(int height, int target); void onRefreshSync(int height, int target); @@ -158,6 +160,7 @@ public slots: void onUpdateXMRWidget(); signals: + void updateDialog(); void closed(); private: @@ -173,6 +176,7 @@ private: void saveGeo(); void restoreGeo(); void showDebugInfo(); + void showUpdateDialog(); void showNodeExhaustedMessage(); void showWSNodeExhaustedMessage(); void createUnsignedTxDialog(UnsignedTransaction *tx); @@ -236,6 +240,7 @@ private: bool m_constructingTransaction = false; bool m_statusOverrideActive = false; QTimer m_txTimer; + int m_showUpdateWarning = 0; private slots: void menuToggleTabVisible(const QString &key); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 20d9d21..574c282 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -7,7 +7,7 @@ 0 0 1156 - 502 + 506 @@ -86,6 +86,13 @@ + + + + Warning: outdated wowlet version + + + diff --git a/src/utils/config.cpp b/src/utils/config.cpp index 0aff663..c58cdd7 100644 --- a/src/utils/config.cpp +++ b/src/utils/config.cpp @@ -48,6 +48,7 @@ static const QHash configStrings = { {Config::hideBalance, {QS("hideBalance"), false}}, {Config::hideFiatBalance, {QS("hideFiatBalance"), false}}, {Config::redditFrontend, {QS("redditFrontend"), "old.reddit.com"}}, + {Config::ignoreUpdateWarning, {QS("ignoreUpdateWarning"), ""}}, {Config::showHistorySyncNotice, {QS("showHistorySyncNotice"), true}} }; diff --git a/src/utils/config.h b/src/utils/config.h index d5df478..639baab 100644 --- a/src/utils/config.h +++ b/src/utils/config.h @@ -50,7 +50,8 @@ public: hideBalance, hideFiatBalance, redditFrontend, - showHistorySyncNotice + showHistorySyncNotice, + ignoreUpdateWarning }; ~Config() override; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index ca9aee9..80adea7 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -434,6 +434,16 @@ int Utils::maxLength(const QVector &array) { return maxLength; } +bool Utils::versionOutdated(const QString ¤t_version, const QString &newest_version) { + // True when major or minor version changed + auto cver = current_version.split('.'); + auto nver = newest_version.split('.'); + int cverlist[] = {cver.at(0).toInt(), cver.at(1).toInt()}; + int nverlist[] = {nver.at(0).toInt(), nver.at(1).toInt()}; + if(cverlist[0] < nverlist[0] || cverlist[1] < nverlist[1]) return true; + return false; +} + QString Utils::balanceFormat(quint64 balance) { QString str = QString::number(balance / globals::cdiv, 'f', 4); diff --git a/src/utils/utils.h b/src/utils/utils.h index 444e6f8..a156213 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -81,6 +81,7 @@ public: static QMap localeCache; static QString balanceFormat(quint64 balance); static QTextCharFormat addressTextFormat(const SubaddressIndex &index); + static bool versionOutdated(const QString ¤t_version, const QString &newest_version); template static QString QtEnumToString (const QEnum value) {