mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-10-31 23:10: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/resource_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 | ||||
|                 source/scwx/qt/manager/radar_product_manager_notifier.cpp | ||||
|                 source/scwx/qt/manager/resource_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 | ||||
|             source/scwx/qt/map/color_table_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_base.cpp) | ||||
| 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/radar_product_record.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) | ||||
| set(HDR_UI source/scwx/qt/ui/about_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/level3_products_widget.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 | ||||
|            source/scwx/qt/ui/alert_dialog.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/level3_products_widget.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 | ||||
|            source/scwx/qt/ui/alert_dialog.ui | ||||
|            source/scwx/qt/ui/alert_dock_widget.ui | ||||
|            source/scwx/qt/ui/imgui_debug_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 | ||||
|              source/scwx/qt/util/file.hpp | ||||
|              source/scwx/qt/util/font.hpp | ||||
|  |  | |||
|  | @ -4,9 +4,11 @@ | |||
| #include "./ui_main_window.h" | ||||
| 
 | ||||
| #include <scwx/qt/main/application.hpp> | ||||
| #include <scwx/qt/main/versions.hpp> | ||||
| #include <scwx/qt/manager/radar_product_manager.hpp> | ||||
| #include <scwx/qt/manager/settings_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/model/radar_product_model.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/radar_site_dialog.hpp> | ||||
| #include <scwx/qt/ui/settings_dialog.hpp> | ||||
| #include <scwx/qt/ui/update_dialog.hpp> | ||||
| #include <scwx/common/characters.hpp> | ||||
| #include <scwx/common/products.hpp> | ||||
| #include <scwx/common/vcp.hpp> | ||||
| #include <scwx/util/logger.hpp> | ||||
| #include <scwx/util/threads.hpp> | ||||
| 
 | ||||
| #include <QDesktopServices> | ||||
| #include <QFileDialog> | ||||
|  | @ -61,8 +65,10 @@ public: | |||
|        imGuiDebugDialog_ {nullptr}, | ||||
|        radarSiteDialog_ {nullptr}, | ||||
|        settingsDialog_ {nullptr}, | ||||
|        updateDialog_ {nullptr}, | ||||
|        radarProductModel_ {nullptr}, | ||||
|        textEventManager_ {manager::TextEventManager::Instance()}, | ||||
|        updateManager_ {manager::UpdateManager::Instance()}, | ||||
|        maps_ {}, | ||||
|        elevationCuts_ {}, | ||||
|        elevationButtonsChanged_ {false}, | ||||
|  | @ -94,6 +100,7 @@ public: | |||
|    } | ||||
|    ~MainWindowImpl() = default; | ||||
| 
 | ||||
|    void AsyncSetup(); | ||||
|    void ConfigureMapLayout(); | ||||
|    void ConnectMapSignals(); | ||||
|    void ConnectOtherSignals(); | ||||
|  | @ -126,9 +133,11 @@ public: | |||
|    ui::ImGuiDebugDialog* imGuiDebugDialog_; | ||||
|    ui::RadarSiteDialog*  radarSiteDialog_; | ||||
|    ui::SettingsDialog*   settingsDialog_; | ||||
|    ui::UpdateDialog*     updateDialog_; | ||||
| 
 | ||||
|    std::unique_ptr<model::RadarProductModel>  radarProductModel_; | ||||
|    std::shared_ptr<manager::TextEventManager> textEventManager_; | ||||
|    std::shared_ptr<manager::UpdateManager>    updateManager_; | ||||
| 
 | ||||
|    std::vector<map::MapWidget*> maps_; | ||||
|    std::vector<float>           elevationCuts_; | ||||
|  | @ -223,6 +232,9 @@ MainWindow::MainWindow(QWidget* parent) : | |||
|    // About Dialog
 | ||||
|    p->aboutDialog_ = new ui::AboutDialog(this); | ||||
| 
 | ||||
|    // Update Dialog
 | ||||
|    p->updateDialog_ = new ui::UpdateDialog(this); | ||||
| 
 | ||||
|    auto& mapSettings = manager::SettingsManager::map_settings(); | ||||
|    for (size_t i = 0; i < p->maps_.size(); i++) | ||||
|    { | ||||
|  | @ -236,6 +248,7 @@ MainWindow::MainWindow(QWidget* parent) : | |||
|    p->ConnectMapSignals(); | ||||
|    p->ConnectOtherSignals(); | ||||
|    p->HandleFocusChange(p->activeMap_); | ||||
|    p->AsyncSetup(); | ||||
| 
 | ||||
|    Application::FinishInitialization(); | ||||
| } | ||||
|  | @ -381,6 +394,29 @@ void MainWindow::on_actionGitHubRepository_triggered() | |||
|    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() | ||||
| { | ||||
|    p->aboutDialog_->show(); | ||||
|  | @ -468,6 +504,18 @@ void MainWindow::on_resourceTreeView_doubleClicked(const QModelIndex& index) | |||
|    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() | ||||
| { | ||||
|    auto& generalSettings = manager::SettingsManager::general_settings(); | ||||
|  | @ -629,6 +677,15 @@ void MainWindowImpl::ConnectOtherSignals() | |||
|                  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) | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ private slots: | |||
|    void on_actionUserManual_triggered(); | ||||
|    void on_actionDiscord_triggered(); | ||||
|    void on_actionGitHubRepository_triggered(); | ||||
|    void on_actionCheckForUpdates_triggered(); | ||||
|    void on_actionAboutSupercellWx_triggered(); | ||||
|    void on_radarSiteSelectButton_clicked(); | ||||
|    void on_resourceTreeCollapseAllButton_clicked(); | ||||
|  |  | |||
|  | @ -68,6 +68,7 @@ | |||
|     <addaction name="actionDiscord"/> | ||||
|     <addaction name="actionGitHubRepository"/> | ||||
|     <addaction name="separator"/> | ||||
|     <addaction name="actionCheckForUpdates"/> | ||||
|     <addaction name="actionAboutSupercellWx"/> | ||||
|    </widget> | ||||
|    <widget class="QMenu" name="menuView"> | ||||
|  | @ -404,6 +405,11 @@ | |||
|     <string>Dump Radar &Product Records</string> | ||||
|    </property> | ||||
|   </action> | ||||
|   <action name="actionCheckForUpdates"> | ||||
|    <property name="text"> | ||||
|     <string>&Check for Updates</string> | ||||
|    </property> | ||||
|   </action> | ||||
|  </widget> | ||||
|  <resources> | ||||
|   <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); | ||||
|       gridHeight_.SetDefault(1); | ||||
|       mapboxApiKey_.SetDefault("?"); | ||||
|       updateNotificationsEnabled_.SetDefault(true); | ||||
| 
 | ||||
|       fontSizes_.SetElementMinimum(1); | ||||
|       fontSizes_.SetElementMaximum(72); | ||||
|  | @ -42,6 +43,7 @@ public: | |||
|    SettingsVariable<std::int64_t>               gridWidth_ {"grid_width"}; | ||||
|    SettingsVariable<std::int64_t>               gridHeight_ {"grid_height"}; | ||||
|    SettingsVariable<std::string> mapboxApiKey_ {"mapbox_api_key"}; | ||||
|    SettingsVariable<bool> updateNotificationsEnabled_ {"update_notifications"}; | ||||
| }; | ||||
| 
 | ||||
| GeneralSettings::GeneralSettings() : | ||||
|  | @ -52,7 +54,8 @@ GeneralSettings::GeneralSettings() : | |||
|                       &p->fontSizes_, | ||||
|                       &p->gridWidth_, | ||||
|                       &p->gridHeight_, | ||||
|                       &p->mapboxApiKey_}); | ||||
|                       &p->mapboxApiKey_, | ||||
|                       &p->updateNotificationsEnabled_}); | ||||
|    SetDefaults(); | ||||
| } | ||||
| GeneralSettings::~GeneralSettings() = default; | ||||
|  | @ -92,6 +95,11 @@ SettingsVariable<std::string>& GeneralSettings::mapbox_api_key() const | |||
|    return p->mapboxApiKey_; | ||||
| } | ||||
| 
 | ||||
| SettingsVariable<bool>& GeneralSettings::update_notifications_enabled() const | ||||
| { | ||||
|    return p->updateNotificationsEnabled_; | ||||
| } | ||||
| 
 | ||||
| bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs) | ||||
| { | ||||
|    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->gridWidth_ == rhs.p->gridWidth_ && | ||||
|            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
 | ||||
|  |  | |||
|  | @ -33,6 +33,7 @@ public: | |||
|    SettingsVariable<std::int64_t>&               grid_height() const; | ||||
|    SettingsVariable<std::int64_t>&               grid_width() const; | ||||
|    SettingsVariable<std::string>&                mapbox_api_key() const; | ||||
|    SettingsVariable<bool>& update_notifications_enabled() const; | ||||
| 
 | ||||
|    friend bool operator==(const GeneralSettings& lhs, | ||||
|                           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_, | ||||
|           &gridHeight_, | ||||
|           &mapboxApiKey_, | ||||
|           &updateNotificationsEnabled_, | ||||
|           &debugEnabled_}} | ||||
|    { | ||||
|       // Configure default alert phenomena colors
 | ||||
|  | @ -137,7 +138,8 @@ public: | |||
|    settings::SettingsInterface<std::int64_t>              gridWidth_ {}; | ||||
|    settings::SettingsInterface<std::int64_t>              gridHeight_ {}; | ||||
|    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>> | ||||
|       colorTables_ {}; | ||||
|  | @ -315,6 +317,11 @@ void SettingsDialogImpl::SetupGeneralTab() | |||
|    mapboxApiKey_.SetEditWidget(self_->ui->mapboxApiKeyLineEdit); | ||||
|    mapboxApiKey_.SetResetButton(self_->ui->resetMapboxApiKeyButton); | ||||
| 
 | ||||
|    updateNotificationsEnabled_.SetSettingsVariable( | ||||
|       generalSettings.update_notifications_enabled()); | ||||
|    updateNotificationsEnabled_.SetEditWidget( | ||||
|       self_->ui->enableUpdateNotificationsCheckBox); | ||||
| 
 | ||||
|    debugEnabled_.SetSettingsVariable(generalSettings.debug_enabled()); | ||||
|    debugEnabled_.SetEditWidget(self_->ui->debugEnabledCheckBox); | ||||
| } | ||||
|  |  | |||
|  | @ -224,6 +224,13 @@ | |||
|             </layout> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item> | ||||
|            <widget class="QCheckBox" name="enableUpdateNotificationsCheckBox"> | ||||
|             <property name="text"> | ||||
|              <string>Update Notifications Enabled</string> | ||||
|             </property> | ||||
|            </widget> | ||||
|           </item> | ||||
|           <item> | ||||
|            <widget class="QCheckBox" name="debugEnabledCheckBox"> | ||||
|             <property name="text"> | ||||
|  | @ -268,8 +275,8 @@ | |||
|                   <rect> | ||||
|                    <x>0</x> | ||||
|                    <y>0</y> | ||||
|                    <width>489</width> | ||||
|                    <height>382</height> | ||||
|                    <width>66</width> | ||||
|                    <height>18</height> | ||||
|                   </rect> | ||||
|                  </property> | ||||
|                  <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) | ||||
| set(SRC_QT_CONFIG_TESTS source/scwx/qt/config/county_database.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_SETTINGS_TESTS source/scwx/qt/settings/settings_container.test.cpp | ||||
|                           source/scwx/qt/settings/settings_variable.test.cpp) | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Dan Paulat
						Dan Paulat