help-menu: add update check

This commit is contained in:
Le Tan 2017-06-22 23:12:54 +08:00
parent 707814909a
commit 34afc2731d
5 changed files with 252 additions and 9 deletions

164
src/dialog/vupdater.cpp Normal file
View File

@ -0,0 +1,164 @@
#include "vupdater.h"
#include <QtWidgets>
#include <QJsonDocument>
#include <QJsonObject>
#include <QTimer>
#include "vconfigmanager.h"
#include "vdownloader.h"
extern VConfigManager vconfig;
VUpdater::VUpdater(QWidget *p_parent)
: QDialog(p_parent)
{
setupUI();
}
void VUpdater::setupUI()
{
QImage img(":/resources/icons/vnote.svg");
QSize imgSize(128, 128);
QLabel *imgLabel = new QLabel();
imgLabel->setPixmap(QPixmap::fromImage(img.scaled(imgSize)));
m_versionLabel = new QLabel(tr("Current Version: v%1")
.arg(vconfig.c_version));
m_proLabel = new QLabel(tr("Checking for updates..."));
m_proLabel->setOpenExternalLinks(true);
m_proBar = new QProgressBar();
m_proBar->setTextVisible(false);
m_descriptionTb = new QTextBrowser();
m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok);
connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
QVBoxLayout *verLayout = new QVBoxLayout();
verLayout->addStretch();
verLayout->addWidget(m_versionLabel);
verLayout->addStretch();
verLayout->addWidget(m_proLabel);
verLayout->addWidget(m_proBar);
QHBoxLayout *topLayout = new QHBoxLayout();
topLayout->addWidget(imgLabel);
topLayout->addLayout(verLayout);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addLayout(topLayout);
mainLayout->addWidget(m_descriptionTb, 1);
mainLayout->addWidget(m_btnBox);
m_proLabel->hide();
m_proBar->hide();
m_descriptionTb->hide();
setLayout(mainLayout);
mainLayout->setSizeConstraint(QLayout::SetFixedSize);
setWindowTitle(tr("VNote Update"));
}
void VUpdater::showEvent(QShowEvent *p_event)
{
Q_UNUSED(p_event);
QDialog::showEvent(p_event);
QTimer *timer = new QTimer(this);
timer->setSingleShot(true);
timer->setInterval(1000);
connect(timer, &QTimer::timeout,
this, [this]() {
this->checkUpdates();
});
timer->start();
}
void VUpdater::checkUpdates()
{
// Change UI.
m_proLabel->setText(tr("Checking for updates..."));
m_proLabel->show();
m_proBar->setEnabled(true);
m_proBar->setMinimum(0);
m_proBar->setMaximum(100);
m_proBar->reset();
m_proBar->show();
QString url("https://api.github.com/repos/tamlok/vnote/releases/latest");
VDownloader *downloader = new VDownloader(this);
connect(downloader, &VDownloader::downloadFinished,
this, &VUpdater::parseResult);
downloader->download(url);
m_proBar->setValue(20);
}
// Return if @p_latestVersion is newer than p_curVersion.
// They are both in format xx.xx
bool isNewerVersion(const QString &p_curVersion, const QString &p_latestVersion)
{
QStringList curList = p_curVersion.split('.', QString::SkipEmptyParts);
QStringList latestList = p_latestVersion.split('.', QString::SkipEmptyParts);
if (curList.size() != 2 || latestList.size() != 2) {
return false;
}
int a = curList[0].toInt();
int b = curList[1].toInt();
int c = latestList[0].toInt();
int d = latestList[1].toInt();
if (a > c) {
return false;
} else if (a < c) {
return true;
} else {
return d > b;
}
}
void VUpdater::parseResult(const QByteArray &p_data)
{
m_proBar->setValue(40);
QJsonDocument jsonDoc = QJsonDocument::fromJson(p_data);
QJsonObject json = jsonDoc.object();
if (jsonDoc.isNull() || json.empty()) {
m_proBar->setEnabled(false);
m_proLabel->setText(tr(":( Fail to check for updates.\n"
"Please try it later."));
return;
}
m_proBar->setValue(100);
QString tag = json["tag_name"].toString();
if (tag.startsWith('v') && tag.size() > 3) {
tag = tag.right(tag.size() - 1);
}
QString releaseName = json["name"].toString();
QString releaseUrl = json["html_url"].toString();
QString body = json["body"].toString();
m_versionLabel->setText(tr("Current Version: v%1\nLatest Version: v%2")
.arg(vconfig.c_version).arg(tag));
if (isNewerVersion(vconfig.c_version, tag)) {
m_proLabel->setText(tr("<span style=\"font-weight: bold;\">Updates Available!</span><br/>"
"Please visit <a href=\"%1\">Github Releases</a> to download the latest version.")
.arg(releaseUrl));
} else {
m_proLabel->setText(tr("VNote is already the latest version."));
}
m_descriptionTb->setText(releaseName + "\n==========\n" + body);
m_descriptionTb->show();
m_proBar->hide();
}

41
src/dialog/vupdater.h Normal file
View File

@ -0,0 +1,41 @@
#ifndef VUPDATER_H
#define VUPDATER_H
#include <QDialog>
#include <QByteArray>
class QLabel;
class QDialogButtonBox;
class QTextBrowser;
class QProgressBar;
class QShowEvent;
class VUpdater : public QDialog
{
Q_OBJECT
public:
VUpdater(QWidget *p_parent = 0);
protected:
void showEvent(QShowEvent *p_event) Q_DECL_OVERRIDE;
private slots:
// Calling to Github api got responses.
void parseResult(const QByteArray &p_data);
private:
void setupUI();
// Fetch the latest release info from Github.
void checkUpdates();
QLabel *m_versionLabel;
QTextBrowser *m_descriptionTb;
QDialogButtonBox *m_btnBox;
// Progress label and bar.
QLabel *m_proLabel;
QProgressBar *m_proBar;
};
#endif // VUPDATER_H

View File

@ -69,7 +69,8 @@ SOURCES += main.cpp\
utils/veditutils.cpp \ utils/veditutils.cpp \
vvimindicator.cpp \ vvimindicator.cpp \
vbuttonwithwidget.cpp \ vbuttonwithwidget.cpp \
vtabindicator.cpp vtabindicator.cpp \
dialog/vupdater.cpp
HEADERS += vmainwindow.h \ HEADERS += vmainwindow.h \
vdirectorytree.h \ vdirectorytree.h \
@ -126,7 +127,8 @@ HEADERS += vmainwindow.h \
vvimindicator.h \ vvimindicator.h \
vbuttonwithwidget.h \ vbuttonwithwidget.h \
vedittabinfo.h \ vedittabinfo.h \
vtabindicator.h vtabindicator.h \
dialog/vupdater.h
RESOURCES += \ RESOURCES += \
vnote.qrc \ vnote.qrc \

View File

@ -469,9 +469,17 @@ DocType VUtils::docTypeFromName(const QString &p_name)
static QMap<int, QVector<QString>> suffixes; static QMap<int, QVector<QString>> suffixes;
if (suffixes.isEmpty()) { if (suffixes.isEmpty()) {
suffixes[(int)DocType::Markdown] = {"md", "markdown", "mkd"}; QVector<QString> md;
suffixes[(int)DocType::List] = {"ls", "list"}; md << "md" << "markdown" << "mkd";
suffixes[(int)DocType::Container] = {"co", "container", "con"}; suffixes[(int)DocType::Markdown] = md;
QVector<QString> list;
list << "ls" << "list";
suffixes[(int)DocType::List] = list;
QVector<QString> container;
container << "co" << "container" << "con";
suffixes[(int)DocType::Container] = container;
} }
QString suf = QFileInfo(p_name).suffix().toLower(); QString suf = QFileInfo(p_name).suffix().toLower();

View File

@ -22,6 +22,7 @@
#include "vmdtab.h" #include "vmdtab.h"
#include "vvimindicator.h" #include "vvimindicator.h"
#include "vtabindicator.h" #include "vtabindicator.h"
#include "dialog/vupdater.h"
extern VConfigManager vconfig; extern VConfigManager vconfig;
@ -320,6 +321,30 @@ void VMainWindow::initHelpMenu()
connect(shortcutAct, &QAction::triggered, connect(shortcutAct, &QAction::triggered,
this, &VMainWindow::shortcutHelp); this, &VMainWindow::shortcutHelp);
QAction *updateAct = new QAction(tr("Check For &Updates"), this);
updateAct->setToolTip(tr("Check for updates of VNote"));
connect(updateAct, &QAction::triggered,
this, [this]() {
VUpdater updater(this);
updater.exec();
});
QAction *starAct = new QAction(tr("Star VNote on &Github"), this);
starAct->setToolTip(tr("Give a star to VNote on Github project"));
connect(starAct, &QAction::triggered,
this, [this]() {
QString url("https://github.com/tamlok/vnote");
QDesktopServices::openUrl(url);
});
QAction *feedbackAct = new QAction(tr("&Feedback"), this);
feedbackAct->setToolTip(tr("Open an issue on Github"));
connect(feedbackAct, &QAction::triggered,
this, [this]() {
QString url("https://github.com/tamlok/vnote/issues");
QDesktopServices::openUrl(url);
});
QAction *aboutAct = new QAction(tr("&About VNote"), this); QAction *aboutAct = new QAction(tr("&About VNote"), this);
aboutAct->setToolTip(tr("View information about VNote")); aboutAct->setToolTip(tr("View information about VNote"));
connect(aboutAct, &QAction::triggered, connect(aboutAct, &QAction::triggered,
@ -335,6 +360,9 @@ void VMainWindow::initHelpMenu()
#endif #endif
helpMenu->addAction(shortcutAct); helpMenu->addAction(shortcutAct);
helpMenu->addAction(updateAct);
helpMenu->addAction(starAct);
helpMenu->addAction(feedbackAct);
helpMenu->addAction(aboutQtAct); helpMenu->addAction(aboutQtAct);
helpMenu->addAction(aboutAct); helpMenu->addAction(aboutAct);
} }
@ -797,11 +825,11 @@ void VMainWindow::changeMarkdownConverter(QAction *action)
void VMainWindow::aboutMessage() void VMainWindow::aboutMessage()
{ {
QString info = tr("v%1").arg(VConfigManager::c_version); QString info = tr("<span style=\"font-weight: bold;\">v%1</span>").arg(VConfigManager::c_version);
info += "\n\n"; info += "<br/><br/>";
info += tr("VNote is a Vim-inspired note-taking application for Markdown."); info += tr("VNote is a Vim-inspired note-taking application for Markdown.");
info += "\n"; info += "<br/>";
info += tr("Visit https://github.com/tamlok/vnote.git for more information."); info += tr("Please visit <a href=\"https://github.com/tamlok/vnote.git\">Github</a> for more information.");
QMessageBox::about(this, tr("About VNote"), info); QMessageBox::about(this, tr("About VNote"), info);
} }