diff --git a/libs/vtextedit b/libs/vtextedit index f17e9bf8..392c0e21 160000 --- a/libs/vtextedit +++ b/libs/vtextedit @@ -1 +1 @@ -Subproject commit f17e9bf898d86c2990b5831dea45673c3269030b +Subproject commit 392c0e218f5981b4fc6566512103b6149f714931 diff --git a/src/core/coreconfig.cpp b/src/core/coreconfig.cpp index b7271ca8..c6b94b93 100644 --- a/src/core/coreconfig.cpp +++ b/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; diff --git a/src/core/coreconfig.h b/src/core/coreconfig.h index d1d03d2a..a330cd27 100644 --- a/src/core/coreconfig.h +++ b/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; diff --git a/src/data/core/vnotex.json b/src/data/core/vnotex.json index eca78743..93495ab9 100644 --- a/src/data/core/vnotex.json +++ b/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 }, diff --git a/src/widgets/dialogs/settings/generalpage.cpp b/src/widgets/dialogs/settings/generalpage.cpp index 88d7d696..35956d87 100644 --- a/src/widgets/dialogs/settings/generalpage.cpp +++ b/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; } diff --git a/src/widgets/dialogs/settings/generalpage.h b/src/widgets/dialogs/settings/generalpage.h index 9990b74c..c48fc3cc 100644 --- a/src/widgets/dialogs/settings/generalpage.h +++ b/src/widgets/dialogs/settings/generalpage.h @@ -31,6 +31,8 @@ namespace vnotex QCheckBox *m_systemTrayCheckBox = nullptr; QCheckBox *m_recoverLastSessionCheckBox = nullptr; + + QCheckBox *m_checkForUpdatesCheckBox = nullptr; }; } diff --git a/src/widgets/dialogs/updater.cpp b/src/widgets/dialogs/updater.cpp new file mode 100644 index 00000000..71e1e572 --- /dev/null +++ b/src/widgets/dialogs/updater.cpp @@ -0,0 +1,104 @@ +#include "updater.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +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 &p_callback) +{ + QPointer 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"))); +} diff --git a/src/widgets/dialogs/updater.h b/src/widgets/dialogs/updater.h new file mode 100644 index 00000000..8b14d35a --- /dev/null +++ b/src/widgets/dialogs/updater.h @@ -0,0 +1,34 @@ +#ifndef UPDATER_H +#define UPDATER_H + +#include "dialog.h" + +#include + +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 &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 diff --git a/src/widgets/mainwindow.cpp b/src/widgets/mainwindow.cpp index 7ce9ac8f..a8036db9 100644 --- a/src/widgets/mainwindow.cpp +++ b/src/widgets/mainwindow.cpp @@ -51,6 +51,7 @@ #include #include #include +#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)); + } + }); +} diff --git a/src/widgets/mainwindow.h b/src/widgets/mainwindow.h index 4e710cff..b7fabe1a 100644 --- a/src/widgets/mainwindow.h +++ b/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; diff --git a/src/widgets/toolbarhelper.cpp b/src/widgets/toolbarhelper.cpp index ddbdd479..20154926 100644 --- a/src/widgets/toolbarhelper.cpp +++ b/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]() { diff --git a/src/widgets/widgets.pri b/src/widgets/widgets.pri index e7683163..11e8b3ef 100644 --- a/src/widgets/widgets.pri +++ b/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 \