Răsfoiți Sursa

add check for updates

Le Tan 4 ani în urmă
părinte
comite
0f1be2883a

+ 1 - 1
libs/vtextedit

@@ -1 +1 @@
-Subproject commit f17e9bf898d86c2990b5831dea45673c3269030b
+Subproject commit 392c0e218f5981b4fc6566512103b6149f714931

+ 13 - 0
src/core/coreconfig.cpp

@@ -57,6 +57,8 @@ void CoreConfig::init(const QJsonObject &p_app,
 
     m_recoverLastSessionOnStartEnabled = READBOOL(QStringLiteral("recover_last_session_on_start"));
 
+    m_checkForUpdatesOnStartEnabled = READBOOL(QStringLiteral("check_for_updates_on_start"));
+
     m_historyMaxCount = READINT(QStringLiteral("history_max_count"));
     if (m_historyMaxCount < 0) {
         m_historyMaxCount = 100;
@@ -72,6 +74,7 @@ QJsonObject CoreConfig::toJson() const
     obj[QStringLiteral("toolbar_icon_size")] = m_toolBarIconSize;
     obj[QStringLiteral("docks_tabbar_icon_size")] = m_docksTabBarIconSize;
     obj[QStringLiteral("recover_last_session_on_start")] = m_recoverLastSessionOnStartEnabled;
+    obj[QStringLiteral("check_for_updates_on_start")] = m_checkForUpdatesOnStartEnabled;
     obj[QStringLiteral("history_max_count")] = m_historyMaxCount;
     return obj;
 }
@@ -186,6 +189,16 @@ void CoreConfig::setRecoverLastSessionOnStartEnabled(bool p_enabled)
     updateConfig(m_recoverLastSessionOnStartEnabled, p_enabled, this);
 }
 
+bool CoreConfig::isCheckForUpdatesOnStartEnabled() const
+{
+    return m_checkForUpdatesOnStartEnabled;
+}
+
+void CoreConfig::setCheckForUpdatesOnStartEnabled(bool p_enabled)
+{
+    updateConfig(m_checkForUpdatesOnStartEnabled, p_enabled, this);
+}
+
 int CoreConfig::getHistoryMaxCount() const
 {
     return m_historyMaxCount;

+ 5 - 0
src/core/coreconfig.h

@@ -97,6 +97,9 @@ namespace vnotex
         bool isRecoverLastSessionOnStartEnabled() const;
         void setRecoverLastSessionOnStartEnabled(bool p_enabled);
 
+        bool isCheckForUpdatesOnStartEnabled() const;
+        void setCheckForUpdatesOnStartEnabled(bool p_enabled);
+
         int getHistoryMaxCount() const;
 
     private:
@@ -128,6 +131,8 @@ namespace vnotex
         // Whether recover last session on start.
         bool m_recoverLastSessionOnStartEnabled = true;
 
+        bool m_checkForUpdatesOnStartEnabled = true;
+
         // Max count of the history items for each notebook and session config.
         int m_historyMaxCount = 100;
 

+ 1 - 0
src/data/core/vnotex.json

@@ -70,6 +70,7 @@
             }
         },
         "recover_last_session_on_start" : true,
+        "check_for_updates_on_start" : true,
         "//comment" : "Max count of the history items for each notebook and session config",
         "history_max_count" : 100
     },

+ 14 - 0
src/widgets/dialogs/settings/generalpage.cpp

@@ -79,6 +79,16 @@ void GeneralPage::setupUI()
         connect(m_recoverLastSessionCheckBox, &QCheckBox::stateChanged,
                 this, &GeneralPage::pageIsChanged);
     }
+
+    {
+        const QString label(tr("Check for updates on start"));
+        m_checkForUpdatesCheckBox = WidgetsFactory::createCheckBox(label, this);
+        m_checkForUpdatesCheckBox->setToolTip(tr("Check for updates on start of VNote"));
+        mainLayout->addRow(m_checkForUpdatesCheckBox);
+        addSearchItem(label, m_checkForUpdatesCheckBox->toolTip(), m_checkForUpdatesCheckBox);
+        connect(m_checkForUpdatesCheckBox, &QCheckBox::stateChanged,
+                this, &GeneralPage::pageIsChanged);
+    }
 }
 
 void GeneralPage::loadInternal()
@@ -104,6 +114,8 @@ void GeneralPage::loadInternal()
     }
 
     m_recoverLastSessionCheckBox->setChecked(coreConfig.isRecoverLastSessionOnStartEnabled());
+
+    m_checkForUpdatesCheckBox->setChecked(coreConfig.isCheckForUpdatesOnStartEnabled());
 }
 
 bool GeneralPage::saveInternal()
@@ -128,6 +140,8 @@ bool GeneralPage::saveInternal()
 
     coreConfig.setRecoverLastSessionOnStartEnabled(m_recoverLastSessionCheckBox->isChecked());
 
+    coreConfig.setCheckForUpdatesOnStartEnabled(m_checkForUpdatesCheckBox->isChecked());
+
     return true;
 }
 

+ 2 - 0
src/widgets/dialogs/settings/generalpage.h

@@ -31,6 +31,8 @@ namespace vnotex
         QCheckBox *m_systemTrayCheckBox = nullptr;
 
         QCheckBox *m_recoverLastSessionCheckBox = nullptr;
+
+        QCheckBox *m_checkForUpdatesCheckBox = nullptr;
     };
 }
 

+ 104 - 0
src/widgets/dialogs/updater.cpp

@@ -0,0 +1,104 @@
+#include "updater.h"
+
+#include <QHBoxLayout>
+#include <QFormLayout>
+#include <QTimer>
+#include <QLabel>
+#include <QApplication>
+#include <QPushButton>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QJsonObject>
+#include <QPointer>
+
+#include <widgets/widgetsfactory.h>
+#include <utils/widgetutils.h>
+#include <utils/utils.h>
+#include <vtextedit/networkutils.h>
+
+using namespace vnotex;
+
+Updater::Updater(QWidget *p_parent)
+    : Dialog(p_parent)
+{
+    setupUI();
+}
+
+void Updater::setupUI()
+{
+    auto mainWidget = new QWidget(this);
+    setCentralWidget(mainWidget);
+
+    auto mainLayout = WidgetsFactory::createFormLayout(mainWidget);
+
+    mainLayout->addRow(tr("Version:"), new QLabel(qApp->applicationVersion(), mainWidget));
+
+    m_latestVersionLabel = new QLabel(tr("Fetching information..."), mainWidget);
+    mainLayout->addRow(tr("Latest version:"), m_latestVersionLabel);
+
+    setDialogButtonBox(QDialogButtonBox::Ok);
+
+    {
+        auto btnBox = getDialogButtonBox();
+        auto viewBtn = btnBox->addButton(tr("View Releases"), QDialogButtonBox::AcceptRole);
+        connect(viewBtn, &QPushButton::clicked,
+                this, [this]() {
+                    WidgetUtils::openUrlByDesktop(QUrl("https://github.com/vnotex/vnote/releases"));
+                });
+    }
+
+    setWindowTitle(tr("Check for Updates"));
+}
+
+void Updater::showEvent(QShowEvent *p_event)
+{
+    Dialog::showEvent(p_event);
+
+    QTimer::singleShot(1000, this, &Updater::start);
+}
+
+void Updater::start()
+{
+    checkForUpdates(this, [this](bool p_hasUpdate, const QString &p_version, const QString &p_errMsg) {
+                Q_UNUSED(p_hasUpdate);
+                if (p_version.isEmpty()) {
+                    setInformationText(tr("Failed to fetch information (%1).").arg(p_errMsg), InformationLevel::Warning);
+                    m_latestVersionLabel->setText("");
+                } else {
+                    clearInformationText();
+                    m_latestVersionLabel->setText(p_version);
+                }
+            });
+}
+
+void Updater::checkForUpdates(QObject *p_receiver, const std::function<void(bool, const QString &, const QString &)> &p_callback)
+{
+    QPointer<QObject> receiver(p_receiver);
+
+    // Will delete it in the callback.
+    auto mgr = new QNetworkAccessManager();
+    connect(mgr, &QNetworkAccessManager::finished,
+            mgr, [mgr, receiver, p_callback](QNetworkReply *p_reply) {
+                bool hasUpdate = false;
+                QString version;
+                QString errMsg;
+                if (p_reply->error() != QNetworkReply::NoError) {
+                    errMsg = vte::NetworkUtils::networkErrorStr(p_reply->error());
+                } else {
+                    auto obj = Utils::fromJsonString(p_reply->readAll());
+                    version = obj["tag_name"].toString();
+                    if (version.startsWith('v')) {
+                        version = version.mid(1);
+                    }
+                    hasUpdate = version != qApp->applicationVersion();
+                }
+
+                if (receiver) {
+                    p_callback(hasUpdate, version, errMsg);
+                }
+                p_reply->deleteLater();
+                mgr->deleteLater();
+            });
+
+    mgr->get(vte::NetworkUtils::networkRequest(QUrl("https://api.github.com/repos/vnotex/vnote/releases/latest")));
+}

+ 34 - 0
src/widgets/dialogs/updater.h

@@ -0,0 +1,34 @@
+#ifndef UPDATER_H
+#define UPDATER_H
+
+#include "dialog.h"
+
+#include <functional>
+
+class QLabel;
+
+namespace vnotex
+{
+    class Updater : public Dialog
+    {
+        Q_OBJECT
+    public:
+        explicit Updater(QWidget *p_parent = nullptr);
+
+        // Callback(hasUpdate, VersionOnSuccess, errMsg).
+        static void checkForUpdates(QObject *p_receiver, const std::function<void(bool, const QString &, const QString &)> &p_callback);
+
+    protected:
+        void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
+
+    private slots:
+        void start();
+
+    private:
+        void setupUI();
+
+        QLabel *m_latestVersionLabel = nullptr;
+    };
+}
+
+#endif // UPDATER_H

+ 16 - 0
src/widgets/mainwindow.cpp

@@ -51,6 +51,7 @@
 #include <utils/docsutils.h>
 #include <utils/iconutils.h>
 #include <core/thememgr.h>
+#include "dialogs/updater.h"
 
 using namespace vnotex;
 
@@ -122,6 +123,10 @@ void MainWindow::kickOffOnStart(const QStringList &p_paths)
                 emit VNoteX::getInst().openFileRequested(file, paras);
             }
         }
+
+        if (ConfigMgr::getInst().getCoreConfig().isCheckForUpdatesOnStartEnabled()) {
+            QTimer::singleShot(5 * 60 * 1000, this, &MainWindow::checkForUpdates);
+        }
     });
 }
 
@@ -937,3 +942,14 @@ QDockWidget *MainWindow::createDockWidget(DockIndex p_dockIndex, const QString &
     m_docks.push_back(dock);
     return dock;
 }
+
+void MainWindow::checkForUpdates()
+{
+    Updater::checkForUpdates(this, [this](bool p_hasUpdate, const QString &p_version, const QString &p_errMsg) {
+                if (p_version.isEmpty()) {
+                    statusBar()->showMessage(tr("Failed to check for updates (%1)").arg(p_errMsg), 3000);
+                } else if (p_hasUpdate) {
+                    statusBar()->showMessage(tr("Updates available: %1").arg(p_version));
+                }
+            });
+}

+ 2 - 0
src/widgets/mainwindow.h

@@ -169,6 +169,8 @@ namespace vnotex
 
         QDockWidget *createDockWidget(DockIndex p_dockIndex, const QString &p_title, QWidget *p_parent);
 
+        void checkForUpdates();
+
         ToolBarHelper m_toolBarHelper;
 
         StatusBarHelper m_statusBarHelper;

+ 9 - 1
src/widgets/toolbarhelper.cpp

@@ -25,6 +25,7 @@
 #include "propertydefs.h"
 #include "dialogs/settings/settingsdialog.h"
 #include "messageboxhelper.h"
+#include "dialogs/updater.h"
 
 using namespace vnotex;
 
@@ -511,7 +512,7 @@ QToolBar *ToolBarHelper::setupSettingsToolBar(MainWindow *p_win, QToolBar *p_too
                             WidgetUtils::openUrlByDesktop(QUrl("https://vnotex.github.io/vnote"));
                         });
 
-        menu->addAction(MainWindow::tr("Feedback And Discussions"),
+        menu->addAction(MainWindow::tr("Feedback and Discussions"),
                         menu,
                         []() {
                             WidgetUtils::openUrlByDesktop(QUrl("https://github.com/vnotex/vnote/discussions"));
@@ -519,6 +520,13 @@ QToolBar *ToolBarHelper::setupSettingsToolBar(MainWindow *p_win, QToolBar *p_too
 
         menu->addSeparator();
 
+        menu->addAction(MainWindow::tr("Check for Updates"),
+                        menu,
+                        [p_win]() {
+                            Updater updater(p_win);
+                            updater.exec();
+                        });
+
         menu->addAction(MainWindow::tr("About"),
                         menu,
                         [p_win]() {

+ 2 - 0
src/widgets/widgets.pri

@@ -33,6 +33,7 @@ SOURCES += \
     $$PWD/dialogs/snippetpropertiesdialog.cpp \
     $$PWD/dialogs/sortdialog.cpp \
     $$PWD/dialogs/tableinsertdialog.cpp \
+    $$PWD/dialogs/updater.cpp \
     $$PWD/dragdropareaindicator.cpp \
     $$PWD/editors/editormarkdownvieweradapter.cpp \
     $$PWD/editors/graphhelper.cpp \
@@ -147,6 +148,7 @@ HEADERS += \
     $$PWD/dialogs/snippetpropertiesdialog.h \
     $$PWD/dialogs/sortdialog.h \
     $$PWD/dialogs/tableinsertdialog.h \
+    $$PWD/dialogs/updater.h \
     $$PWD/dragdropareaindicator.h \
     $$PWD/editors/editormarkdownvieweradapter.h \
     $$PWD/editors/graphhelper.h \