WinUpdater: More useful options on update failure #7217

Signed-off-by: Kevin Ottens <kevin.ottens@nextcloud.com>
This commit is contained in:
Christian Kamm 2019-06-04 14:42:34 +02:00 committed by Camila (Rebase PR Action)
parent 9596eb7f20
commit 0b3512f49c
2 changed files with 97 additions and 53 deletions

View file

@ -32,7 +32,6 @@ namespace OCC {
static const char updateAvailableC[] = "Updater/updateAvailable"; static const char updateAvailableC[] = "Updater/updateAvailable";
static const char updateTargetVersionC[] = "Updater/updateTargetVersion"; static const char updateTargetVersionC[] = "Updater/updateTargetVersion";
static const char seenVersionC[] = "Updater/seenVersion"; static const char seenVersionC[] = "Updater/seenVersion";
static const char autoUpdateFailedVersionC[] = "Updater/autoUpdateFailedVersion";
static const char autoUpdateAttemptedC[] = "Updater/autoUpdateAttempted"; static const char autoUpdateAttemptedC[] = "Updater/autoUpdateAttempted";
@ -275,7 +274,6 @@ void OCUpdater::slotTimedOut()
NSISUpdater::NSISUpdater(const QUrl &url) NSISUpdater::NSISUpdater(const QUrl &url)
: OCUpdater(url) : OCUpdater(url)
, _showFallbackMessage(false)
{ {
} }
@ -287,6 +285,18 @@ void NSISUpdater::slotWriteFile()
} }
} }
void NSISUpdater::wipeUpdateData()
{
ConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat);
QString updateFileName = settings.value(updateAvailableC).toString();
if (!updateFileName.isEmpty())
QFile::remove(updateFileName);
settings.remove(updateAvailableC);
settings.remove(updateTargetVersionC);
settings.remove(autoUpdateAttemptedC);
}
void NSISUpdater::slotDownloadFinished() void NSISUpdater::slotDownloadFinished()
{ {
auto *reply = qobject_cast<QNetworkReply *>(sender()); auto *reply = qobject_cast<QNetworkReply *>(sender());
@ -329,12 +339,9 @@ void NSISUpdater::versionInfoArrived(const UpdateInfo &info)
setDownloadState(UpToDate); setDownloadState(UpToDate);
} else { } else {
QString url = info.downloadUrl(); QString url = info.downloadUrl();
qint64 autoUpdateFailedVersion = if (url.isEmpty()) {
Helper::stringVersionToInt(settings.value(autoUpdateFailedVersionC).toString()); showNoUrlDialog(info);
if (url.isEmpty() || _showFallbackMessage || infoVersion == autoUpdateFailedVersion) { } else {
showDialog(info);
}
if (!url.isEmpty()) {
_targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/')+1); _targetFile = cfg.configPath() + url.mid(url.lastIndexOf('/')+1);
if (QFile(_targetFile).exists()) { if (QFile(_targetFile).exists()) {
setDownloadState(DownloadComplete); setDownloadState(DownloadComplete);
@ -353,14 +360,15 @@ void NSISUpdater::versionInfoArrived(const UpdateInfo &info)
} }
} }
void NSISUpdater::showDialog(const UpdateInfo &info) void NSISUpdater::showNoUrlDialog(const UpdateInfo &info)
{ {
// if the version tag is set, there is a newer version. // if the version tag is set, there is a newer version.
auto *msgBox = new QDialog; auto *msgBox = new QDialog;
msgBox->setAttribute(Qt::WA_DeleteOnClose); msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setWindowFlags(msgBox->windowFlags() & ~Qt::WindowContextHelpButtonHint);
QIcon infoIcon = msgBox->style()->standardIcon(QStyle::SP_MessageBoxInformation, nullptr, nullptr); QIcon infoIcon = msgBox->style()->standardIcon(QStyle::SP_MessageBoxInformation);
int iconSize = msgBox->style()->pixelMetric(QStyle::PM_MessageBoxIconSize, nullptr, nullptr); int iconSize = msgBox->style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
msgBox->setWindowIcon(infoIcon); msgBox->setWindowIcon(infoIcon);
@ -387,7 +395,6 @@ void NSISUpdater::showDialog(const UpdateInfo &info)
hlayout->addWidget(lbl); hlayout->addWidget(lbl);
auto *bb = new QDialogButtonBox; auto *bb = new QDialogButtonBox;
bb->setWindowFlags(bb->windowFlags() & ~Qt::WindowContextHelpButtonHint);
QPushButton *skip = bb->addButton(tr("Skip this version"), QDialogButtonBox::ResetRole); QPushButton *skip = bb->addButton(tr("Skip this version"), QDialogButtonBox::ResetRole);
QPushButton *reject = bb->addButton(tr("Skip this time"), QDialogButtonBox::AcceptRole); QPushButton *reject = bb->addButton(tr("Skip this time"), QDialogButtonBox::AcceptRole);
QPushButton *getupdate = bb->addButton(tr("Get update"), QDialogButtonBox::AcceptRole); QPushButton *getupdate = bb->addButton(tr("Get update"), QDialogButtonBox::AcceptRole);
@ -397,14 +404,78 @@ void NSISUpdater::showDialog(const UpdateInfo &info)
connect(getupdate, &QAbstractButton::clicked, msgBox, &QDialog::accept); connect(getupdate, &QAbstractButton::clicked, msgBox, &QDialog::accept);
connect(skip, &QAbstractButton::clicked, this, &NSISUpdater::slotSetSeenVersion); connect(skip, &QAbstractButton::clicked, this, &NSISUpdater::slotSetSeenVersion);
connect(getupdate, SIGNAL(clicked()), SLOT(slotOpenUpdateUrl())); connect(getupdate, &QAbstractButton::clicked, this, &NSISUpdater::slotOpenUpdateUrl);
layout->addWidget(bb); layout->addWidget(bb);
msgBox->open(); msgBox->open();
} }
NSISUpdater::UpdateState NSISUpdater::updateStateOnStart() void NSISUpdater::showUpdateErrorDialog()
{
QDialog *msgBox = new QDialog;
msgBox->setAttribute(Qt::WA_DeleteOnClose);
msgBox->setWindowFlags(msgBox->windowFlags() & ~Qt::WindowContextHelpButtonHint);
QIcon infoIcon = msgBox->style()->standardIcon(QStyle::SP_MessageBoxInformation);
int iconSize = msgBox->style()->pixelMetric(QStyle::PM_MessageBoxIconSize);
msgBox->setWindowIcon(infoIcon);
QVBoxLayout *layout = new QVBoxLayout(msgBox);
QHBoxLayout *hlayout = new QHBoxLayout;
layout->addLayout(hlayout);
msgBox->setWindowTitle(tr("Update Failed"));
QLabel *ico = new QLabel;
ico->setFixedSize(iconSize, iconSize);
ico->setPixmap(infoIcon.pixmap(iconSize));
QLabel *lbl = new QLabel;
QString txt = tr("<p>A new version of the %1 Client is available but the updating process failed.</p>"
"<p><b>%2</b> has been downloaded. The installed version is %3.</p>")
.arg(Utility::escape(Theme::instance()->appNameGUI()),
Utility::escape(updateInfo().versionString()), Utility::escape(clientVersion()));
lbl->setText(txt);
lbl->setTextFormat(Qt::RichText);
lbl->setWordWrap(true);
hlayout->addWidget(ico);
hlayout->addWidget(lbl);
QDialogButtonBox *bb = new QDialogButtonBox;
QPushButton *skip = bb->addButton(tr("Skip this version"), QDialogButtonBox::ResetRole);
QPushButton *askagain = bb->addButton(tr("Ask again later"), QDialogButtonBox::ResetRole);
QPushButton *retry = bb->addButton(tr("Restart and update"), QDialogButtonBox::AcceptRole);
QPushButton *getupdate = bb->addButton(tr("Update manually"), QDialogButtonBox::AcceptRole);
connect(skip, &QAbstractButton::clicked, msgBox, &QDialog::reject);
connect(askagain, &QAbstractButton::clicked, msgBox, &QDialog::reject);
connect(retry, &QAbstractButton::clicked, msgBox, &QDialog::accept);
connect(getupdate, &QAbstractButton::clicked, msgBox, &QDialog::accept);
connect(skip, &QAbstractButton::clicked, this, [this]() {
wipeUpdateData();
slotSetSeenVersion();
});
// askagain: do nothing
connect(retry, &QAbstractButton::clicked, this, [this]() {
slotStartInstaller();
qApp->quit();
});
connect(getupdate, &QAbstractButton::clicked, this, [this]() {
wipeUpdateData();
slotSetSeenVersion();
slotOpenUpdateUrl();
});
layout->addWidget(bb);
msgBox->open();
}
bool NSISUpdater::handleStartup()
{ {
ConfigFile cfg; ConfigFile cfg;
QSettings settings(cfg.configFile(), QSettings::IniFormat); QSettings settings(cfg.configFile(), QSettings::IniFormat);
@ -413,44 +484,20 @@ NSISUpdater::UpdateState NSISUpdater::updateStateOnStart()
if (!updateFileName.isEmpty() && QFile(updateFileName).exists()) { if (!updateFileName.isEmpty() && QFile(updateFileName).exists()) {
// did it try to execute the update? // did it try to execute the update?
if (settings.value(autoUpdateAttemptedC, false).toBool()) { if (settings.value(autoUpdateAttemptedC, false).toBool()) {
// clean up
settings.remove(autoUpdateAttemptedC);
settings.remove(updateAvailableC);
QFile::remove(updateFileName);
if (updateSucceeded()) { if (updateSucceeded()) {
// success: clean up even more // success: clean up
settings.remove(updateTargetVersionC); wipeUpdateData();
settings.remove(autoUpdateFailedVersionC); return false;
return NoUpdate;
} else { } else {
// auto update failed. Set autoUpdateFailedVersion as a hint // auto update failed. Ask user what to do
// for visual fallback notification showUpdateErrorDialog();
QString targetVersion = settings.value(updateTargetVersionC).toString(); return false;
settings.setValue(autoUpdateFailedVersionC, targetVersion);
settings.remove(updateTargetVersionC);
return UpdateFailed;
} }
} else { } else {
if (!settings.contains(autoUpdateFailedVersionC)) { return performUpdate();
return UpdateAvailable;
}
} }
} }
return NoUpdate; return false;
}
bool NSISUpdater::handleStartup()
{
switch (updateStateOnStart()) {
case NSISUpdater::UpdateAvailable:
return performUpdate();
case NSISUpdater::UpdateFailed:
_showFallbackMessage = true;
return false;
case NSISUpdater::NoUpdate:
default:
return false;
}
} }
void NSISUpdater::slotSetSeenVersion() void NSISUpdater::slotSetSeenVersion()

View file

@ -120,9 +120,9 @@ public slots:
protected slots: protected slots:
void backgroundCheckForUpdate() override; void backgroundCheckForUpdate() override;
void slotOpenUpdateUrl();
private slots: private slots:
void slotOpenUpdateUrl();
void slotVersionInfoArrived(); void slotVersionInfoArrived();
void slotTimedOut(); void slotTimedOut();
@ -148,9 +148,6 @@ class NSISUpdater : public OCUpdater
{ {
Q_OBJECT Q_OBJECT
public: public:
enum UpdateState { NoUpdate = 0,
UpdateAvailable,
UpdateFailed };
explicit NSISUpdater(const QUrl &url); explicit NSISUpdater(const QUrl &url);
bool handleStartup() override; bool handleStartup() override;
private slots: private slots:
@ -159,12 +156,12 @@ private slots:
void slotWriteFile(); void slotWriteFile();
private: private:
NSISUpdater::UpdateState updateStateOnStart(); void wipeUpdateData();
void showDialog(const UpdateInfo &info); void showNoUrlDialog(const UpdateInfo &info);
void showUpdateErrorDialog();
void versionInfoArrived(const UpdateInfo &info) override; void versionInfoArrived(const UpdateInfo &info) override;
QScopedPointer<QTemporaryFile> _file; QScopedPointer<QTemporaryFile> _file;
QString _targetFile; QString _targetFile;
bool _showFallbackMessage;
}; };
/** /**