From df7b50568d337993d6bdc4d48316cff4d974dbd4 Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Tue, 26 Mar 2024 22:52:03 -0500 Subject: [PATCH] Install update button --- scwx-qt/source/scwx/qt/ui/update_dialog.cpp | 125 +++++++++++++++++++- scwx-qt/source/scwx/qt/ui/update_dialog.hpp | 10 +- scwx-qt/source/scwx/qt/ui/update_dialog.ui | 7 ++ 3 files changed, 131 insertions(+), 11 deletions(-) diff --git a/scwx-qt/source/scwx/qt/ui/update_dialog.cpp b/scwx-qt/source/scwx/qt/ui/update_dialog.cpp index 4029fa9a..313fd35a 100644 --- a/scwx-qt/source/scwx/qt/ui/update_dialog.cpp +++ b/scwx-qt/source/scwx/qt/ui/update_dialog.cpp @@ -1,10 +1,15 @@ #include "update_dialog.hpp" #include "ui_update_dialog.h" #include +#include #include +#include +#include #include #include +#include +#include namespace scwx { @@ -13,19 +18,26 @@ namespace qt namespace ui { -class UpdateDialogImpl +static const std::string logPrefix_ = "scwx::qt::ui::update_dialog"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +class UpdateDialog::Impl { public: - explicit UpdateDialogImpl() = default; - ~UpdateDialogImpl() = default; + explicit Impl(UpdateDialog* self) : self_ {self} {}; + ~Impl() = default; + + void HandleAsset(const types::gh::ReleaseAsset& asset); + + UpdateDialog* self_; std::string downloadUrl_ {}; + std::string installUrl_ {}; + std::string installFilename_ {}; }; UpdateDialog::UpdateDialog(QWidget* parent) : - QDialog(parent), - p {std::make_unique()}, - ui(new Ui::UpdateDialog) + QDialog(parent), p {std::make_unique(this)}, ui(new Ui::UpdateDialog) { ui->setupUi(this); @@ -37,6 +49,8 @@ UpdateDialog::UpdateDialog(QWidget* parent) : ui->bannerLabel->setFont(titleFont); ui->releaseNotesText->setOpenExternalLinks(true); + + ui->installUpdateButton->setVisible(false); } UpdateDialog::~UpdateDialog() @@ -56,6 +70,25 @@ void UpdateDialog::UpdateReleaseInfo(const std::string& latestVersion, QString::fromStdString(latestRelease.body_)); p->downloadUrl_ = latestRelease.htmlUrl_; + + ui->installUpdateButton->setVisible(false); + + for (auto& asset : latestRelease.assets_) + { + p->HandleAsset(asset); + } +} + +void UpdateDialog::Impl::HandleAsset(const types::gh::ReleaseAsset& asset) +{ +#if defined(_WIN32) + if (asset.name_.ends_with(".msi")) + { + self_->ui->installUpdateButton->setVisible(true); + installUrl_ = asset.browserDownloadUrl_; + installFilename_ = asset.name_; + } +#endif } void UpdateDialog::on_downloadButton_clicked() @@ -66,6 +99,86 @@ void UpdateDialog::on_downloadButton_clicked() } } +void UpdateDialog::on_installUpdateButton_clicked() +{ + if (!p->installUrl_.empty()) + { + ui->installUpdateButton->setEnabled(false); + + std::string destinationPath { + QStandardPaths::writableLocation(QStandardPaths::TempLocation) + .toStdString()}; + + std::shared_ptr request = + std::make_shared( + p->installUrl_, + std::filesystem::path(destinationPath) / p->installFilename_); + + DownloadDialog* downloadDialog = new DownloadDialog(this); + downloadDialog->setAttribute(Qt::WA_DeleteOnClose); + + // Connect request signals + connect(request.get(), + &request::DownloadRequest::ProgressUpdated, + downloadDialog, + &DownloadDialog::UpdateProgress); + connect(request.get(), + &request::DownloadRequest::RequestComplete, + downloadDialog, + [=](request::DownloadRequest::CompleteReason reason) + { + switch (reason) + { + case request::DownloadRequest::CompleteReason::OK: + downloadDialog->FinishDownload(); + break; + + default: + downloadDialog->CancelDownload(); + break; + } + }); + + // Connect dialog signals + connect( + downloadDialog, + &QDialog::accepted, + this, + [=]() + { + std::filesystem::path installerPackage = + request->destination_path(); + installerPackage.make_preferred(); + + logger_->info("Launching application installer: {}", + installerPackage.string()); + + if (!QProcess::startDetached( + "msiexec.exe", + {"/i", QString::fromStdString(installerPackage.string())})) + { + logger_->error("Failed to launch installer"); + } + + ui->installUpdateButton->setEnabled(true); + }); + connect(downloadDialog, + &QDialog::rejected, + this, + [=]() + { + request->Cancel(); + + ui->installUpdateButton->setEnabled(true); + }); + + downloadDialog->set_filename(p->installFilename_); + downloadDialog->StartDownload(); + + manager::DownloadManager::Instance()->Download(request); + } +} + } // namespace ui } // namespace qt } // namespace scwx diff --git a/scwx-qt/source/scwx/qt/ui/update_dialog.hpp b/scwx-qt/source/scwx/qt/ui/update_dialog.hpp index 0df39648..fee03e2c 100644 --- a/scwx-qt/source/scwx/qt/ui/update_dialog.hpp +++ b/scwx-qt/source/scwx/qt/ui/update_dialog.hpp @@ -16,11 +16,10 @@ namespace qt namespace ui { -class UpdateDialogImpl; - class UpdateDialog : public QDialog { Q_OBJECT + Q_DISABLE_COPY_MOVE(UpdateDialog) public: explicit UpdateDialog(QWidget* parent = nullptr); @@ -31,11 +30,12 @@ public: private slots: void on_downloadButton_clicked(); + void on_installUpdateButton_clicked(); private: - friend UpdateDialogImpl; - std::unique_ptr p; - Ui::UpdateDialog* ui; + class Impl; + std::unique_ptr p; + Ui::UpdateDialog* ui; }; } // namespace ui diff --git a/scwx-qt/source/scwx/qt/ui/update_dialog.ui b/scwx-qt/source/scwx/qt/ui/update_dialog.ui index 0facca2a..5aa8e054 100644 --- a/scwx-qt/source/scwx/qt/ui/update_dialog.ui +++ b/scwx-qt/source/scwx/qt/ui/update_dialog.ui @@ -139,6 +139,13 @@ + + + + Install Update + + +