mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-11-02 01:30:06 +00:00
Merge pull request #39 from dpaulat/feature/release-notification
Feature/release notification
This commit is contained in:
commit
26067255f0
18 changed files with 849 additions and 13 deletions
|
|
@ -64,12 +64,14 @@ set(HDR_MANAGER source/scwx/qt/manager/radar_product_manager.hpp
|
||||||
source/scwx/qt/manager/radar_product_manager_notifier.hpp
|
source/scwx/qt/manager/radar_product_manager_notifier.hpp
|
||||||
source/scwx/qt/manager/resource_manager.hpp
|
source/scwx/qt/manager/resource_manager.hpp
|
||||||
source/scwx/qt/manager/settings_manager.hpp
|
source/scwx/qt/manager/settings_manager.hpp
|
||||||
source/scwx/qt/manager/text_event_manager.hpp)
|
source/scwx/qt/manager/text_event_manager.hpp
|
||||||
|
source/scwx/qt/manager/update_manager.hpp)
|
||||||
set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp
|
set(SRC_MANAGER source/scwx/qt/manager/radar_product_manager.cpp
|
||||||
source/scwx/qt/manager/radar_product_manager_notifier.cpp
|
source/scwx/qt/manager/radar_product_manager_notifier.cpp
|
||||||
source/scwx/qt/manager/resource_manager.cpp
|
source/scwx/qt/manager/resource_manager.cpp
|
||||||
source/scwx/qt/manager/settings_manager.cpp
|
source/scwx/qt/manager/settings_manager.cpp
|
||||||
source/scwx/qt/manager/text_event_manager.cpp)
|
source/scwx/qt/manager/text_event_manager.cpp
|
||||||
|
source/scwx/qt/manager/update_manager.cpp)
|
||||||
set(HDR_MAP source/scwx/qt/map/alert_layer.hpp
|
set(HDR_MAP source/scwx/qt/map/alert_layer.hpp
|
||||||
source/scwx/qt/map/color_table_layer.hpp
|
source/scwx/qt/map/color_table_layer.hpp
|
||||||
source/scwx/qt/map/draw_layer.hpp
|
source/scwx/qt/map/draw_layer.hpp
|
||||||
|
|
@ -126,10 +128,12 @@ set(SRC_SETTINGS source/scwx/qt/settings/general_settings.cpp
|
||||||
source/scwx/qt/settings/settings_variable.cpp
|
source/scwx/qt/settings/settings_variable.cpp
|
||||||
source/scwx/qt/settings/settings_variable_base.cpp)
|
source/scwx/qt/settings/settings_variable_base.cpp)
|
||||||
set(HDR_TYPES source/scwx/qt/types/font_types.hpp
|
set(HDR_TYPES source/scwx/qt/types/font_types.hpp
|
||||||
|
source/scwx/qt/types/github_types.hpp
|
||||||
source/scwx/qt/types/qt_types.hpp
|
source/scwx/qt/types/qt_types.hpp
|
||||||
source/scwx/qt/types/radar_product_record.hpp
|
source/scwx/qt/types/radar_product_record.hpp
|
||||||
source/scwx/qt/types/text_event_key.hpp)
|
source/scwx/qt/types/text_event_key.hpp)
|
||||||
set(SRC_TYPES source/scwx/qt/types/radar_product_record.cpp
|
set(SRC_TYPES source/scwx/qt/types/github_types.cpp
|
||||||
|
source/scwx/qt/types/radar_product_record.cpp
|
||||||
source/scwx/qt/types/text_event_key.cpp)
|
source/scwx/qt/types/text_event_key.cpp)
|
||||||
set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
|
set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
|
||||||
source/scwx/qt/ui/alert_dialog.hpp
|
source/scwx/qt/ui/alert_dialog.hpp
|
||||||
|
|
@ -141,7 +145,8 @@ set(HDR_UI source/scwx/qt/ui/about_dialog.hpp
|
||||||
source/scwx/qt/ui/level2_settings_widget.hpp
|
source/scwx/qt/ui/level2_settings_widget.hpp
|
||||||
source/scwx/qt/ui/level3_products_widget.hpp
|
source/scwx/qt/ui/level3_products_widget.hpp
|
||||||
source/scwx/qt/ui/radar_site_dialog.hpp
|
source/scwx/qt/ui/radar_site_dialog.hpp
|
||||||
source/scwx/qt/ui/settings_dialog.hpp)
|
source/scwx/qt/ui/settings_dialog.hpp
|
||||||
|
source/scwx/qt/ui/update_dialog.hpp)
|
||||||
set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
|
set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
|
||||||
source/scwx/qt/ui/alert_dialog.cpp
|
source/scwx/qt/ui/alert_dialog.cpp
|
||||||
source/scwx/qt/ui/alert_dock_widget.cpp
|
source/scwx/qt/ui/alert_dock_widget.cpp
|
||||||
|
|
@ -152,13 +157,15 @@ set(SRC_UI source/scwx/qt/ui/about_dialog.cpp
|
||||||
source/scwx/qt/ui/level2_settings_widget.cpp
|
source/scwx/qt/ui/level2_settings_widget.cpp
|
||||||
source/scwx/qt/ui/level3_products_widget.cpp
|
source/scwx/qt/ui/level3_products_widget.cpp
|
||||||
source/scwx/qt/ui/radar_site_dialog.cpp
|
source/scwx/qt/ui/radar_site_dialog.cpp
|
||||||
source/scwx/qt/ui/settings_dialog.cpp)
|
source/scwx/qt/ui/settings_dialog.cpp
|
||||||
|
source/scwx/qt/ui/update_dialog.cpp)
|
||||||
set(UI_UI source/scwx/qt/ui/about_dialog.ui
|
set(UI_UI source/scwx/qt/ui/about_dialog.ui
|
||||||
source/scwx/qt/ui/alert_dialog.ui
|
source/scwx/qt/ui/alert_dialog.ui
|
||||||
source/scwx/qt/ui/alert_dock_widget.ui
|
source/scwx/qt/ui/alert_dock_widget.ui
|
||||||
source/scwx/qt/ui/imgui_debug_dialog.ui
|
source/scwx/qt/ui/imgui_debug_dialog.ui
|
||||||
source/scwx/qt/ui/radar_site_dialog.ui
|
source/scwx/qt/ui/radar_site_dialog.ui
|
||||||
source/scwx/qt/ui/settings_dialog.ui)
|
source/scwx/qt/ui/settings_dialog.ui
|
||||||
|
source/scwx/qt/ui/update_dialog.ui)
|
||||||
set(HDR_UTIL source/scwx/qt/util/color.hpp
|
set(HDR_UTIL source/scwx/qt/util/color.hpp
|
||||||
source/scwx/qt/util/file.hpp
|
source/scwx/qt/util/file.hpp
|
||||||
source/scwx/qt/util/font.hpp
|
source/scwx/qt/util/font.hpp
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,11 @@
|
||||||
#include "./ui_main_window.h"
|
#include "./ui_main_window.h"
|
||||||
|
|
||||||
#include <scwx/qt/main/application.hpp>
|
#include <scwx/qt/main/application.hpp>
|
||||||
|
#include <scwx/qt/main/versions.hpp>
|
||||||
#include <scwx/qt/manager/radar_product_manager.hpp>
|
#include <scwx/qt/manager/radar_product_manager.hpp>
|
||||||
#include <scwx/qt/manager/settings_manager.hpp>
|
#include <scwx/qt/manager/settings_manager.hpp>
|
||||||
#include <scwx/qt/manager/text_event_manager.hpp>
|
#include <scwx/qt/manager/text_event_manager.hpp>
|
||||||
|
#include <scwx/qt/manager/update_manager.hpp>
|
||||||
#include <scwx/qt/map/map_widget.hpp>
|
#include <scwx/qt/map/map_widget.hpp>
|
||||||
#include <scwx/qt/model/radar_product_model.hpp>
|
#include <scwx/qt/model/radar_product_model.hpp>
|
||||||
#include <scwx/qt/ui/alert_dock_widget.hpp>
|
#include <scwx/qt/ui/alert_dock_widget.hpp>
|
||||||
|
|
@ -18,10 +20,12 @@
|
||||||
#include <scwx/qt/ui/level3_products_widget.hpp>
|
#include <scwx/qt/ui/level3_products_widget.hpp>
|
||||||
#include <scwx/qt/ui/radar_site_dialog.hpp>
|
#include <scwx/qt/ui/radar_site_dialog.hpp>
|
||||||
#include <scwx/qt/ui/settings_dialog.hpp>
|
#include <scwx/qt/ui/settings_dialog.hpp>
|
||||||
|
#include <scwx/qt/ui/update_dialog.hpp>
|
||||||
#include <scwx/common/characters.hpp>
|
#include <scwx/common/characters.hpp>
|
||||||
#include <scwx/common/products.hpp>
|
#include <scwx/common/products.hpp>
|
||||||
#include <scwx/common/vcp.hpp>
|
#include <scwx/common/vcp.hpp>
|
||||||
#include <scwx/util/logger.hpp>
|
#include <scwx/util/logger.hpp>
|
||||||
|
#include <scwx/util/threads.hpp>
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
@ -61,8 +65,10 @@ public:
|
||||||
imGuiDebugDialog_ {nullptr},
|
imGuiDebugDialog_ {nullptr},
|
||||||
radarSiteDialog_ {nullptr},
|
radarSiteDialog_ {nullptr},
|
||||||
settingsDialog_ {nullptr},
|
settingsDialog_ {nullptr},
|
||||||
|
updateDialog_ {nullptr},
|
||||||
radarProductModel_ {nullptr},
|
radarProductModel_ {nullptr},
|
||||||
textEventManager_ {manager::TextEventManager::Instance()},
|
textEventManager_ {manager::TextEventManager::Instance()},
|
||||||
|
updateManager_ {manager::UpdateManager::Instance()},
|
||||||
maps_ {},
|
maps_ {},
|
||||||
elevationCuts_ {},
|
elevationCuts_ {},
|
||||||
elevationButtonsChanged_ {false},
|
elevationButtonsChanged_ {false},
|
||||||
|
|
@ -94,6 +100,7 @@ public:
|
||||||
}
|
}
|
||||||
~MainWindowImpl() = default;
|
~MainWindowImpl() = default;
|
||||||
|
|
||||||
|
void AsyncSetup();
|
||||||
void ConfigureMapLayout();
|
void ConfigureMapLayout();
|
||||||
void ConnectMapSignals();
|
void ConnectMapSignals();
|
||||||
void ConnectOtherSignals();
|
void ConnectOtherSignals();
|
||||||
|
|
@ -126,9 +133,11 @@ public:
|
||||||
ui::ImGuiDebugDialog* imGuiDebugDialog_;
|
ui::ImGuiDebugDialog* imGuiDebugDialog_;
|
||||||
ui::RadarSiteDialog* radarSiteDialog_;
|
ui::RadarSiteDialog* radarSiteDialog_;
|
||||||
ui::SettingsDialog* settingsDialog_;
|
ui::SettingsDialog* settingsDialog_;
|
||||||
|
ui::UpdateDialog* updateDialog_;
|
||||||
|
|
||||||
std::unique_ptr<model::RadarProductModel> radarProductModel_;
|
std::unique_ptr<model::RadarProductModel> radarProductModel_;
|
||||||
std::shared_ptr<manager::TextEventManager> textEventManager_;
|
std::shared_ptr<manager::TextEventManager> textEventManager_;
|
||||||
|
std::shared_ptr<manager::UpdateManager> updateManager_;
|
||||||
|
|
||||||
std::vector<map::MapWidget*> maps_;
|
std::vector<map::MapWidget*> maps_;
|
||||||
std::vector<float> elevationCuts_;
|
std::vector<float> elevationCuts_;
|
||||||
|
|
@ -223,6 +232,9 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||||
// About Dialog
|
// About Dialog
|
||||||
p->aboutDialog_ = new ui::AboutDialog(this);
|
p->aboutDialog_ = new ui::AboutDialog(this);
|
||||||
|
|
||||||
|
// Update Dialog
|
||||||
|
p->updateDialog_ = new ui::UpdateDialog(this);
|
||||||
|
|
||||||
auto& mapSettings = manager::SettingsManager::map_settings();
|
auto& mapSettings = manager::SettingsManager::map_settings();
|
||||||
for (size_t i = 0; i < p->maps_.size(); i++)
|
for (size_t i = 0; i < p->maps_.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -236,6 +248,7 @@ MainWindow::MainWindow(QWidget* parent) :
|
||||||
p->ConnectMapSignals();
|
p->ConnectMapSignals();
|
||||||
p->ConnectOtherSignals();
|
p->ConnectOtherSignals();
|
||||||
p->HandleFocusChange(p->activeMap_);
|
p->HandleFocusChange(p->activeMap_);
|
||||||
|
p->AsyncSetup();
|
||||||
|
|
||||||
Application::FinishInitialization();
|
Application::FinishInitialization();
|
||||||
}
|
}
|
||||||
|
|
@ -381,6 +394,29 @@ void MainWindow::on_actionGitHubRepository_triggered()
|
||||||
QDesktopServices::openUrl(QUrl {"https://github.com/dpaulat/supercell-wx"});
|
QDesktopServices::openUrl(QUrl {"https://github.com/dpaulat/supercell-wx"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::on_actionCheckForUpdates_triggered()
|
||||||
|
{
|
||||||
|
scwx::util::async(
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
if (!p->updateManager_->CheckForUpdates(main::kVersionString_))
|
||||||
|
{
|
||||||
|
QMetaObject::invokeMethod(
|
||||||
|
this,
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
QMessageBox* messageBox = new QMessageBox(this);
|
||||||
|
messageBox->setIcon(QMessageBox::Icon::Information);
|
||||||
|
messageBox->setWindowTitle(tr("Check for Updates"));
|
||||||
|
messageBox->setText(tr("Supercell Wx is up to date."));
|
||||||
|
messageBox->setStandardButtons(
|
||||||
|
QMessageBox::StandardButton::Ok);
|
||||||
|
messageBox->show();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_actionAboutSupercellWx_triggered()
|
void MainWindow::on_actionAboutSupercellWx_triggered()
|
||||||
{
|
{
|
||||||
p->aboutDialog_->show();
|
p->aboutDialog_->show();
|
||||||
|
|
@ -468,6 +504,18 @@ void MainWindow::on_resourceTreeView_doubleClicked(const QModelIndex& index)
|
||||||
p->activeMap_->SelectRadarProduct(group, product, 0, time);
|
p->activeMap_->SelectRadarProduct(group, product, 0, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindowImpl::AsyncSetup()
|
||||||
|
{
|
||||||
|
auto& generalSettings = manager::SettingsManager::general_settings();
|
||||||
|
|
||||||
|
// Check for updates
|
||||||
|
if (generalSettings.update_notifications_enabled().GetValue())
|
||||||
|
{
|
||||||
|
scwx::util::async(
|
||||||
|
[this]() { updateManager_->CheckForUpdates(main::kVersionString_); });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindowImpl::ConfigureMapLayout()
|
void MainWindowImpl::ConfigureMapLayout()
|
||||||
{
|
{
|
||||||
auto& generalSettings = manager::SettingsManager::general_settings();
|
auto& generalSettings = manager::SettingsManager::general_settings();
|
||||||
|
|
@ -629,6 +677,15 @@ void MainWindowImpl::ConnectOtherSignals()
|
||||||
map->SelectRadarSite(selectedRadarSite);
|
map->SelectRadarSite(selectedRadarSite);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
connect(updateManager_.get(),
|
||||||
|
&manager::UpdateManager::UpdateAvailable,
|
||||||
|
this,
|
||||||
|
[this](const std::string& latestVersion,
|
||||||
|
const types::gh::Release& latestRelease)
|
||||||
|
{
|
||||||
|
updateDialog_->UpdateReleaseInfo(latestVersion, latestRelease);
|
||||||
|
updateDialog_->show();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindowImpl::HandleFocusChange(QWidget* focused)
|
void MainWindowImpl::HandleFocusChange(QWidget* focused)
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@ private slots:
|
||||||
void on_actionUserManual_triggered();
|
void on_actionUserManual_triggered();
|
||||||
void on_actionDiscord_triggered();
|
void on_actionDiscord_triggered();
|
||||||
void on_actionGitHubRepository_triggered();
|
void on_actionGitHubRepository_triggered();
|
||||||
|
void on_actionCheckForUpdates_triggered();
|
||||||
void on_actionAboutSupercellWx_triggered();
|
void on_actionAboutSupercellWx_triggered();
|
||||||
void on_radarSiteSelectButton_clicked();
|
void on_radarSiteSelectButton_clicked();
|
||||||
void on_resourceTreeCollapseAllButton_clicked();
|
void on_resourceTreeCollapseAllButton_clicked();
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@
|
||||||
<addaction name="actionDiscord"/>
|
<addaction name="actionDiscord"/>
|
||||||
<addaction name="actionGitHubRepository"/>
|
<addaction name="actionGitHubRepository"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionCheckForUpdates"/>
|
||||||
<addaction name="actionAboutSupercellWx"/>
|
<addaction name="actionAboutSupercellWx"/>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QMenu" name="menuView">
|
<widget class="QMenu" name="menuView">
|
||||||
|
|
@ -404,6 +405,11 @@
|
||||||
<string>Dump Radar &Product Records</string>
|
<string>Dump Radar &Product Records</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionCheckForUpdates">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Check for Updates</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="../../../../scwx-qt.qrc"/>
|
<include location="../../../../scwx-qt.qrc"/>
|
||||||
|
|
|
||||||
260
scwx-qt/source/scwx/qt/manager/update_manager.cpp
Normal file
260
scwx-qt/source/scwx/qt/manager/update_manager.cpp
Normal file
|
|
@ -0,0 +1,260 @@
|
||||||
|
#include <scwx/qt/manager/update_manager.hpp>
|
||||||
|
#include <scwx/util/logger.hpp>
|
||||||
|
|
||||||
|
#include <mutex>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include <boost/json.hpp>
|
||||||
|
#include <cpr/cpr.h>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace manager
|
||||||
|
{
|
||||||
|
|
||||||
|
static const std::string logPrefix_ = "scwx::qt::manager::update_manager";
|
||||||
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
||||||
|
|
||||||
|
static const std::string kGithubApiBase {"https://api.github.com"};
|
||||||
|
static const std::string kScwxReleaseEndpoint {
|
||||||
|
kGithubApiBase + "/repos/dpaulat/supercell-wx/releases"};
|
||||||
|
|
||||||
|
class UpdateManager::Impl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit Impl(UpdateManager* self) : self_ {self} {}
|
||||||
|
|
||||||
|
~Impl() {}
|
||||||
|
|
||||||
|
static std::string GetVersionString(const std::string& releaseName);
|
||||||
|
static boost::json::value ParseResponseText(const std::string& s);
|
||||||
|
|
||||||
|
size_t PopulateReleases();
|
||||||
|
size_t AddReleases(const boost::json::value& json);
|
||||||
|
std::pair<std::vector<types::gh::Release>::iterator, std::string>
|
||||||
|
FindLatestRelease();
|
||||||
|
|
||||||
|
UpdateManager* self_;
|
||||||
|
|
||||||
|
std::mutex updateMutex_ {};
|
||||||
|
|
||||||
|
std::vector<types::gh::Release> releases_ {};
|
||||||
|
types::gh::Release latestRelease_ {};
|
||||||
|
std::string latestVersion_ {};
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdateManager::UpdateManager() : p(std::make_unique<Impl>(this)) {}
|
||||||
|
UpdateManager::~UpdateManager() = default;
|
||||||
|
|
||||||
|
types::gh::Release UpdateManager::latest_release() const
|
||||||
|
{
|
||||||
|
return p->latestRelease_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string UpdateManager::latest_version() const
|
||||||
|
{
|
||||||
|
return p->latestVersion_;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
UpdateManager::Impl::GetVersionString(const std::string& releaseName)
|
||||||
|
{
|
||||||
|
static const std::regex re {"\\d+\\.\\d+\\.\\d+"};
|
||||||
|
std::string versionString {};
|
||||||
|
std::smatch m;
|
||||||
|
|
||||||
|
std::regex_search(releaseName, m, re);
|
||||||
|
|
||||||
|
if (!m.empty())
|
||||||
|
{
|
||||||
|
versionString = m[0].str();
|
||||||
|
}
|
||||||
|
|
||||||
|
return versionString;
|
||||||
|
}
|
||||||
|
|
||||||
|
boost::json::value UpdateManager::Impl::ParseResponseText(const std::string& s)
|
||||||
|
{
|
||||||
|
boost::json::stream_parser p;
|
||||||
|
boost::json::error_code ec;
|
||||||
|
|
||||||
|
p.write(s, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
logger_->warn("{}", ec.message());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.finish(ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
logger_->warn("{}", ec.message());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UpdateManager::CheckForUpdates(const std::string& currentVersion)
|
||||||
|
{
|
||||||
|
std::unique_lock lock(p->updateMutex_);
|
||||||
|
|
||||||
|
logger_->info("Checking for updates");
|
||||||
|
|
||||||
|
// Query GitHub for releases
|
||||||
|
size_t numReleases = p->PopulateReleases();
|
||||||
|
bool newRelease = false;
|
||||||
|
|
||||||
|
// If GitHub returned valid releases
|
||||||
|
if (numReleases > 0)
|
||||||
|
{
|
||||||
|
// Get the latest release
|
||||||
|
auto [latestRelease, latestVersion] = p->FindLatestRelease();
|
||||||
|
|
||||||
|
// Validate the latest release, and compare to the current version
|
||||||
|
if (latestRelease != p->releases_.end() && latestVersion > currentVersion)
|
||||||
|
{
|
||||||
|
logger_->info("An update is available: {}", latestVersion);
|
||||||
|
|
||||||
|
p->latestRelease_ = *latestRelease;
|
||||||
|
p->latestVersion_ = latestVersion;
|
||||||
|
newRelease = true;
|
||||||
|
emit UpdateAvailable(latestVersion, *latestRelease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newRelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UpdateManager::Impl::PopulateReleases()
|
||||||
|
{
|
||||||
|
static constexpr size_t perPage =
|
||||||
|
100u; // The number of results per page (max 100)
|
||||||
|
size_t page = 1u; // Page number of the results to fetch
|
||||||
|
size_t numResults = 0u;
|
||||||
|
|
||||||
|
static const std::string perPageString {fmt::format("{}", perPage)};
|
||||||
|
|
||||||
|
// Clear any existing releases
|
||||||
|
releases_.clear();
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
const std::string pageString {fmt::format("{}", page)};
|
||||||
|
|
||||||
|
cpr::Response r = cpr::Get(
|
||||||
|
cpr::Url {kScwxReleaseEndpoint},
|
||||||
|
cpr::Parameters {{"per_page", perPageString}, {"page", pageString}},
|
||||||
|
cpr::Header {{"accept", "application/vnd.github+json"},
|
||||||
|
{"X-GitHub-Api-Version", "2022-11-28"}});
|
||||||
|
|
||||||
|
// Successful REST API query
|
||||||
|
if (r.status_code == 200)
|
||||||
|
{
|
||||||
|
boost::json::value json = Impl::ParseResponseText(r.text);
|
||||||
|
if (json == nullptr)
|
||||||
|
{
|
||||||
|
logger_->warn("Response not JSON: {}", r.header["content-type"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add results from response
|
||||||
|
size_t newResults = AddReleases(json);
|
||||||
|
numResults += newResults;
|
||||||
|
|
||||||
|
if (newResults < perPage)
|
||||||
|
{
|
||||||
|
// We have reached the last page of results
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logger_->warn(
|
||||||
|
"Invalid API response: [{}] {}", r.status_code, r.error.message);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check page is less than 100, this is to prevent an infinite loop
|
||||||
|
} while (++page < 100);
|
||||||
|
|
||||||
|
return numResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t UpdateManager::Impl::AddReleases(const boost::json::value& json)
|
||||||
|
{
|
||||||
|
// Parse releases
|
||||||
|
std::vector<types::gh::Release> newReleases {};
|
||||||
|
try
|
||||||
|
{
|
||||||
|
newReleases =
|
||||||
|
boost::json::value_to<std::vector<types::gh::Release>>(json);
|
||||||
|
}
|
||||||
|
catch (const std::exception& ex)
|
||||||
|
{
|
||||||
|
logger_->warn("Error parsing JSON: {}", ex.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t newReleaseCount = newReleases.size();
|
||||||
|
|
||||||
|
// Add releases to the current list
|
||||||
|
releases_.insert(releases_.end(), newReleases.begin(), newReleases.end());
|
||||||
|
|
||||||
|
return newReleaseCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<std::vector<types::gh::Release>::iterator, std::string>
|
||||||
|
UpdateManager::Impl::FindLatestRelease()
|
||||||
|
{
|
||||||
|
// Initialize the latest release to the end iterator
|
||||||
|
std::vector<types::gh::Release>::iterator latestRelease = releases_.end();
|
||||||
|
std::string latestReleaseVersion {};
|
||||||
|
|
||||||
|
for (auto it = releases_.begin(); it != releases_.end(); ++it)
|
||||||
|
{
|
||||||
|
if (it->draft_ || it->prerelease_)
|
||||||
|
{
|
||||||
|
// Skip drafts and prereleases
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the version string of the current release
|
||||||
|
std::string currentVersion {GetVersionString(it->name_)};
|
||||||
|
|
||||||
|
// If not set, or current version is lexographically newer
|
||||||
|
if (latestRelease == releases_.end() ||
|
||||||
|
currentVersion > latestReleaseVersion)
|
||||||
|
{
|
||||||
|
// Update the latest release
|
||||||
|
latestRelease = it;
|
||||||
|
latestReleaseVersion = currentVersion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {latestRelease, latestReleaseVersion};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<UpdateManager> UpdateManager::Instance()
|
||||||
|
{
|
||||||
|
static std::weak_ptr<UpdateManager> updateManagerReference_ {};
|
||||||
|
static std::mutex instanceMutex_ {};
|
||||||
|
|
||||||
|
std::unique_lock lock(instanceMutex_);
|
||||||
|
|
||||||
|
std::shared_ptr<UpdateManager> updateManager =
|
||||||
|
updateManagerReference_.lock();
|
||||||
|
|
||||||
|
if (updateManager == nullptr)
|
||||||
|
{
|
||||||
|
updateManager = std::make_shared<UpdateManager>();
|
||||||
|
updateManagerReference_ = updateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace manager
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
43
scwx-qt/source/scwx/qt/manager/update_manager.hpp
Normal file
43
scwx-qt/source/scwx/qt/manager/update_manager.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <scwx/qt/types/github_types.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace manager
|
||||||
|
{
|
||||||
|
|
||||||
|
class UpdateManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit UpdateManager();
|
||||||
|
~UpdateManager();
|
||||||
|
|
||||||
|
types::gh::Release latest_release() const;
|
||||||
|
std::string latest_version() const;
|
||||||
|
|
||||||
|
bool CheckForUpdates(const std::string& currentVersion = {});
|
||||||
|
|
||||||
|
static std::shared_ptr<UpdateManager> Instance();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void UpdateAvailable(const std::string& latestVersion,
|
||||||
|
const types::gh::Release& latestRelease);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class Impl;
|
||||||
|
std::unique_ptr<Impl> p;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace manager
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -21,6 +21,7 @@ public:
|
||||||
gridWidth_.SetDefault(1);
|
gridWidth_.SetDefault(1);
|
||||||
gridHeight_.SetDefault(1);
|
gridHeight_.SetDefault(1);
|
||||||
mapboxApiKey_.SetDefault("?");
|
mapboxApiKey_.SetDefault("?");
|
||||||
|
updateNotificationsEnabled_.SetDefault(true);
|
||||||
|
|
||||||
fontSizes_.SetElementMinimum(1);
|
fontSizes_.SetElementMinimum(1);
|
||||||
fontSizes_.SetElementMaximum(72);
|
fontSizes_.SetElementMaximum(72);
|
||||||
|
|
@ -42,6 +43,7 @@ public:
|
||||||
SettingsVariable<std::int64_t> gridWidth_ {"grid_width"};
|
SettingsVariable<std::int64_t> gridWidth_ {"grid_width"};
|
||||||
SettingsVariable<std::int64_t> gridHeight_ {"grid_height"};
|
SettingsVariable<std::int64_t> gridHeight_ {"grid_height"};
|
||||||
SettingsVariable<std::string> mapboxApiKey_ {"mapbox_api_key"};
|
SettingsVariable<std::string> mapboxApiKey_ {"mapbox_api_key"};
|
||||||
|
SettingsVariable<bool> updateNotificationsEnabled_ {"update_notifications"};
|
||||||
};
|
};
|
||||||
|
|
||||||
GeneralSettings::GeneralSettings() :
|
GeneralSettings::GeneralSettings() :
|
||||||
|
|
@ -52,7 +54,8 @@ GeneralSettings::GeneralSettings() :
|
||||||
&p->fontSizes_,
|
&p->fontSizes_,
|
||||||
&p->gridWidth_,
|
&p->gridWidth_,
|
||||||
&p->gridHeight_,
|
&p->gridHeight_,
|
||||||
&p->mapboxApiKey_});
|
&p->mapboxApiKey_,
|
||||||
|
&p->updateNotificationsEnabled_});
|
||||||
SetDefaults();
|
SetDefaults();
|
||||||
}
|
}
|
||||||
GeneralSettings::~GeneralSettings() = default;
|
GeneralSettings::~GeneralSettings() = default;
|
||||||
|
|
@ -92,6 +95,11 @@ SettingsVariable<std::string>& GeneralSettings::mapbox_api_key() const
|
||||||
return p->mapboxApiKey_;
|
return p->mapboxApiKey_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SettingsVariable<bool>& GeneralSettings::update_notifications_enabled() const
|
||||||
|
{
|
||||||
|
return p->updateNotificationsEnabled_;
|
||||||
|
}
|
||||||
|
|
||||||
bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs)
|
bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs)
|
||||||
{
|
{
|
||||||
return (lhs.p->debugEnabled_ == rhs.p->debugEnabled_ &&
|
return (lhs.p->debugEnabled_ == rhs.p->debugEnabled_ &&
|
||||||
|
|
@ -99,7 +107,9 @@ bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs)
|
||||||
lhs.p->fontSizes_ == rhs.p->fontSizes_ &&
|
lhs.p->fontSizes_ == rhs.p->fontSizes_ &&
|
||||||
lhs.p->gridWidth_ == rhs.p->gridWidth_ &&
|
lhs.p->gridWidth_ == rhs.p->gridWidth_ &&
|
||||||
lhs.p->gridHeight_ == rhs.p->gridHeight_ &&
|
lhs.p->gridHeight_ == rhs.p->gridHeight_ &&
|
||||||
lhs.p->mapboxApiKey_ == rhs.p->mapboxApiKey_);
|
lhs.p->mapboxApiKey_ == rhs.p->mapboxApiKey_ &&
|
||||||
|
lhs.p->updateNotificationsEnabled_ ==
|
||||||
|
rhs.p->updateNotificationsEnabled_);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace settings
|
} // namespace settings
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ public:
|
||||||
SettingsVariable<std::int64_t>& grid_height() const;
|
SettingsVariable<std::int64_t>& grid_height() const;
|
||||||
SettingsVariable<std::int64_t>& grid_width() const;
|
SettingsVariable<std::int64_t>& grid_width() const;
|
||||||
SettingsVariable<std::string>& mapbox_api_key() const;
|
SettingsVariable<std::string>& mapbox_api_key() const;
|
||||||
|
SettingsVariable<bool>& update_notifications_enabled() const;
|
||||||
|
|
||||||
friend bool operator==(const GeneralSettings& lhs,
|
friend bool operator==(const GeneralSettings& lhs,
|
||||||
const GeneralSettings& rhs);
|
const GeneralSettings& rhs);
|
||||||
|
|
|
||||||
39
scwx-qt/source/scwx/qt/types/github_types.cpp
Normal file
39
scwx-qt/source/scwx/qt/types/github_types.cpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include <scwx/qt/types/github_types.hpp>
|
||||||
|
|
||||||
|
#include <boost/json/value_to.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace types
|
||||||
|
{
|
||||||
|
namespace gh
|
||||||
|
{
|
||||||
|
|
||||||
|
Release tag_invoke(boost::json::value_to_tag<Release>,
|
||||||
|
const boost::json::value& jv)
|
||||||
|
{
|
||||||
|
auto jo = jv.as_object();
|
||||||
|
|
||||||
|
Release release {};
|
||||||
|
|
||||||
|
// Required parameters
|
||||||
|
release.name_ = jo.at("name").as_string();
|
||||||
|
release.htmlUrl_ = jo.at("html_url").as_string();
|
||||||
|
release.draft_ = jo.at("draft").as_bool();
|
||||||
|
release.prerelease_ = jo.at("prerelease").as_bool();
|
||||||
|
|
||||||
|
// Optional parameters
|
||||||
|
if (jo.contains("body"))
|
||||||
|
{
|
||||||
|
release.body_ = jo.at("body").as_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
return release;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace gh
|
||||||
|
} // namespace types
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
36
scwx-qt/source/scwx/qt/types/github_types.hpp
Normal file
36
scwx-qt/source/scwx/qt/types/github_types.hpp
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <boost/json/value.hpp>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace types
|
||||||
|
{
|
||||||
|
namespace gh
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief GitHub Release object
|
||||||
|
*
|
||||||
|
* <https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28>
|
||||||
|
*/
|
||||||
|
struct Release
|
||||||
|
{
|
||||||
|
std::string name_ {};
|
||||||
|
std::string htmlUrl_ {};
|
||||||
|
std::string body_ {};
|
||||||
|
bool draft_ {};
|
||||||
|
bool prerelease_ {};
|
||||||
|
};
|
||||||
|
|
||||||
|
Release tag_invoke(boost::json::value_to_tag<Release>,
|
||||||
|
const boost::json::value& jv);
|
||||||
|
|
||||||
|
} // namespace gh
|
||||||
|
} // namespace types
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -84,6 +84,7 @@ public:
|
||||||
&gridWidth_,
|
&gridWidth_,
|
||||||
&gridHeight_,
|
&gridHeight_,
|
||||||
&mapboxApiKey_,
|
&mapboxApiKey_,
|
||||||
|
&updateNotificationsEnabled_,
|
||||||
&debugEnabled_}}
|
&debugEnabled_}}
|
||||||
{
|
{
|
||||||
// Configure default alert phenomena colors
|
// Configure default alert phenomena colors
|
||||||
|
|
@ -137,7 +138,8 @@ public:
|
||||||
settings::SettingsInterface<std::int64_t> gridWidth_ {};
|
settings::SettingsInterface<std::int64_t> gridWidth_ {};
|
||||||
settings::SettingsInterface<std::int64_t> gridHeight_ {};
|
settings::SettingsInterface<std::int64_t> gridHeight_ {};
|
||||||
settings::SettingsInterface<std::string> mapboxApiKey_ {};
|
settings::SettingsInterface<std::string> mapboxApiKey_ {};
|
||||||
settings::SettingsInterface<bool> debugEnabled_ {};
|
settings::SettingsInterface<bool> updateNotificationsEnabled_ {};
|
||||||
|
settings::SettingsInterface<bool> debugEnabled_ {};
|
||||||
|
|
||||||
std::unordered_map<std::string, settings::SettingsInterface<std::string>>
|
std::unordered_map<std::string, settings::SettingsInterface<std::string>>
|
||||||
colorTables_ {};
|
colorTables_ {};
|
||||||
|
|
@ -315,6 +317,11 @@ void SettingsDialogImpl::SetupGeneralTab()
|
||||||
mapboxApiKey_.SetEditWidget(self_->ui->mapboxApiKeyLineEdit);
|
mapboxApiKey_.SetEditWidget(self_->ui->mapboxApiKeyLineEdit);
|
||||||
mapboxApiKey_.SetResetButton(self_->ui->resetMapboxApiKeyButton);
|
mapboxApiKey_.SetResetButton(self_->ui->resetMapboxApiKeyButton);
|
||||||
|
|
||||||
|
updateNotificationsEnabled_.SetSettingsVariable(
|
||||||
|
generalSettings.update_notifications_enabled());
|
||||||
|
updateNotificationsEnabled_.SetEditWidget(
|
||||||
|
self_->ui->enableUpdateNotificationsCheckBox);
|
||||||
|
|
||||||
debugEnabled_.SetSettingsVariable(generalSettings.debug_enabled());
|
debugEnabled_.SetSettingsVariable(generalSettings.debug_enabled());
|
||||||
debugEnabled_.SetEditWidget(self_->ui->debugEnabledCheckBox);
|
debugEnabled_.SetEditWidget(self_->ui->debugEnabledCheckBox);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,13 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="enableUpdateNotificationsCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Update Notifications Enabled</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="debugEnabledCheckBox">
|
<widget class="QCheckBox" name="debugEnabledCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
|
@ -268,8 +275,8 @@
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>489</width>
|
<width>66</width>
|
||||||
<height>382</height>
|
<height>18</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
|
|
||||||
71
scwx-qt/source/scwx/qt/ui/update_dialog.cpp
Normal file
71
scwx-qt/source/scwx/qt/ui/update_dialog.cpp
Normal file
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "update_dialog.hpp"
|
||||||
|
#include "ui_update_dialog.h"
|
||||||
|
#include <scwx/qt/main/versions.hpp>
|
||||||
|
#include <scwx/qt/manager/resource_manager.hpp>
|
||||||
|
|
||||||
|
#include <QDesktopServices>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
|
||||||
|
class UpdateDialogImpl
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit UpdateDialogImpl() = default;
|
||||||
|
~UpdateDialogImpl() = default;
|
||||||
|
|
||||||
|
std::string downloadUrl_ {};
|
||||||
|
};
|
||||||
|
|
||||||
|
UpdateDialog::UpdateDialog(QWidget* parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
p {std::make_unique<UpdateDialogImpl>()},
|
||||||
|
ui(new Ui::UpdateDialog)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
int titleFontId =
|
||||||
|
manager::ResourceManager::FontId(types::Font::din1451alt_g);
|
||||||
|
QString titleFontFamily =
|
||||||
|
QFontDatabase::applicationFontFamilies(titleFontId).at(0);
|
||||||
|
QFont titleFont(titleFontFamily, 12);
|
||||||
|
ui->bannerLabel->setFont(titleFont);
|
||||||
|
|
||||||
|
ui->releaseNotesText->setOpenExternalLinks(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateDialog::~UpdateDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialog::UpdateReleaseInfo(const std::string& latestVersion,
|
||||||
|
const types::gh::Release& latestRelease)
|
||||||
|
{
|
||||||
|
ui->versionLabel->setText(tr("Supercell Wx v%1 is now available. You are "
|
||||||
|
"currently running version %2.")
|
||||||
|
.arg(latestVersion.c_str())
|
||||||
|
.arg(main::kVersionString_.c_str()));
|
||||||
|
|
||||||
|
ui->releaseNotesText->setMarkdown(
|
||||||
|
QString::fromStdString(latestRelease.body_));
|
||||||
|
|
||||||
|
p->downloadUrl_ = latestRelease.htmlUrl_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateDialog::on_downloadButton_clicked()
|
||||||
|
{
|
||||||
|
if (!p->downloadUrl_.empty())
|
||||||
|
{
|
||||||
|
QDesktopServices::openUrl(QUrl {QString::fromStdString(p->downloadUrl_)});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
43
scwx-qt/source/scwx/qt/ui/update_dialog.hpp
Normal file
43
scwx-qt/source/scwx/qt/ui/update_dialog.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <scwx/qt/types/github_types.hpp>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
namespace Ui
|
||||||
|
{
|
||||||
|
class UpdateDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace ui
|
||||||
|
{
|
||||||
|
|
||||||
|
class UpdateDialogImpl;
|
||||||
|
|
||||||
|
class UpdateDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit UpdateDialog(QWidget* parent = nullptr);
|
||||||
|
~UpdateDialog();
|
||||||
|
|
||||||
|
void UpdateReleaseInfo(const std::string& latestVersion,
|
||||||
|
const types::gh::Release& latestRelease);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_downloadButton_clicked();
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend UpdateDialogImpl;
|
||||||
|
std::unique_ptr<UpdateDialogImpl> p;
|
||||||
|
Ui::UpdateDialog* ui;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ui
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
207
scwx-qt/source/scwx/qt/ui/update_dialog.ui
Normal file
207
scwx-qt/source/scwx/qt/ui/update_dialog.ui
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>UpdateDialog</class>
|
||||||
|
<widget class="QDialog" name="UpdateDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>300</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Update Available</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="topFrame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="iconLabel">
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>64</width>
|
||||||
|
<height>64</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="pixmap">
|
||||||
|
<pixmap resource="../../../../scwx-qt.qrc">:/res/icons/scwx-256.png</pixmap>
|
||||||
|
</property>
|
||||||
|
<property name="scaledContents">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="textFrame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="bannerLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>A new version of Supercell Wx is available!</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="versionLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Supercell Wx X.Y.Z is now available. You are running version X.Y.Z.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="releaseNotesLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Release Notes:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextBrowser" name="releaseNotesText"/>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QFrame" name="bottomFrame">
|
||||||
|
<property name="frameShape">
|
||||||
|
<enum>QFrame::StyledPanel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="frameShadow">
|
||||||
|
<enum>QFrame::Raised</enum>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="downloadButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Download</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources>
|
||||||
|
<include location="../../../../scwx-qt.qrc"/>
|
||||||
|
</resources>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>UpdateDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>UpdateDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 16017d0b6446228ecfd8ef4cd733e8b1595ab2fb
|
Subproject commit 5b5073780fe44e55eb4c33799036683b28ffd2bd
|
||||||
40
test/source/scwx/qt/manager/update_manager.test.cpp
Normal file
40
test/source/scwx/qt/manager/update_manager.test.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#include <scwx/qt/manager/update_manager.hpp>
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace scwx
|
||||||
|
{
|
||||||
|
namespace qt
|
||||||
|
{
|
||||||
|
namespace manager
|
||||||
|
{
|
||||||
|
|
||||||
|
TEST(UpdateManagerTest, CheckForUpdates)
|
||||||
|
{
|
||||||
|
auto updateManager = UpdateManager::Instance();
|
||||||
|
bool updateFound;
|
||||||
|
types::gh::Release latestRelease;
|
||||||
|
std::string latestVersion;
|
||||||
|
|
||||||
|
// Check for updates, and expect an update to be found
|
||||||
|
updateFound = updateManager->CheckForUpdates("0.0.0");
|
||||||
|
latestRelease = updateManager->latest_release();
|
||||||
|
latestVersion = updateManager->latest_version();
|
||||||
|
|
||||||
|
EXPECT_EQ(updateFound, true);
|
||||||
|
EXPECT_GT(latestRelease.name_.size(), 0);
|
||||||
|
EXPECT_GT(latestRelease.htmlUrl_.size(), 0);
|
||||||
|
EXPECT_GT(latestRelease.body_.size(), 0);
|
||||||
|
EXPECT_EQ(latestRelease.draft_, false);
|
||||||
|
EXPECT_EQ(latestRelease.prerelease_, false);
|
||||||
|
EXPECT_GT(latestVersion, "0.0.0");
|
||||||
|
|
||||||
|
// Check for updates, and expect no updates to be found
|
||||||
|
updateFound = updateManager->CheckForUpdates("9999.99.99");
|
||||||
|
|
||||||
|
EXPECT_EQ(updateFound, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace manager
|
||||||
|
} // namespace qt
|
||||||
|
} // namespace scwx
|
||||||
|
|
@ -21,7 +21,8 @@ set(SRC_PROVIDER_TESTS source/scwx/provider/aws_level2_data_provider.test.cpp
|
||||||
source/scwx/provider/warnings_provider.test.cpp)
|
source/scwx/provider/warnings_provider.test.cpp)
|
||||||
set(SRC_QT_CONFIG_TESTS source/scwx/qt/config/county_database.test.cpp
|
set(SRC_QT_CONFIG_TESTS source/scwx/qt/config/county_database.test.cpp
|
||||||
source/scwx/qt/config/radar_site.test.cpp)
|
source/scwx/qt/config/radar_site.test.cpp)
|
||||||
set(SRC_QT_MANAGER_TESTS source/scwx/qt/manager/settings_manager.test.cpp)
|
set(SRC_QT_MANAGER_TESTS source/scwx/qt/manager/settings_manager.test.cpp
|
||||||
|
source/scwx/qt/manager/update_manager.test.cpp)
|
||||||
set(SRC_QT_MODEL_TESTS source/scwx/qt/model/imgui_context_model.test.cpp)
|
set(SRC_QT_MODEL_TESTS source/scwx/qt/model/imgui_context_model.test.cpp)
|
||||||
set(SRC_QT_SETTINGS_TESTS source/scwx/qt/settings/settings_container.test.cpp
|
set(SRC_QT_SETTINGS_TESTS source/scwx/qt/settings/settings_container.test.cpp
|
||||||
source/scwx/qt/settings/settings_variable.test.cpp)
|
source/scwx/qt/settings/settings_variable.test.cpp)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue