mirror of
https://git.citron-emu.org/citron/emulator
synced 2025-12-19 10:43:33 +00:00
Merge branch 'fix/autoupdater' into 'main'
feat(updater): Overhaul to use commit hashes and improve UI See merge request citron/emulator!117
This commit is contained in:
@@ -95,7 +95,7 @@ set(DEFAULT_ENABLE_OPENSSL ON)
|
|||||||
if (ANDROID OR WIN32 OR APPLE)
|
if (ANDROID OR WIN32 OR APPLE)
|
||||||
set(DEFAULT_ENABLE_OPENSSL OFF)
|
set(DEFAULT_ENABLE_OPENSSL OFF)
|
||||||
endif()
|
endif()
|
||||||
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ${DEFAULT_ENABLE_OPENSSL})
|
option(ENABLE_OPENSSL "Enable OpenSSL backend for ISslConnection" ON)
|
||||||
|
|
||||||
if (ANDROID AND CITRON_DOWNLOAD_ANDROID_VVL)
|
if (ANDROID AND CITRON_DOWNLOAD_ANDROID_VVL)
|
||||||
set(vvl_version "vulkan-sdk-1.4.328.1")
|
set(vvl_version "vulkan-sdk-1.4.328.1")
|
||||||
|
|||||||
@@ -53,4 +53,11 @@ if (BUILD_REPOSITORY)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Add a fallback for local builds
|
||||||
|
# If BUILD_VERSION is still "0", it means the CI-specific logic was not executed.
|
||||||
|
# In that case, we should use the git description which contains the commit hash.
|
||||||
|
if (BUILD_VERSION STREQUAL "0")
|
||||||
|
set(BUILD_VERSION ${GIT_DESC})
|
||||||
|
endif()
|
||||||
|
|
||||||
configure_file(scm_rev.cpp.in scm_rev.cpp @ONLY)
|
configure_file(scm_rev.cpp.in scm_rev.cpp @ONLY)
|
||||||
|
|||||||
@@ -265,6 +265,8 @@ if (CITRON_USE_AUTO_UPDATER)
|
|||||||
$<$<BOOL:${WIN32}>:_WIN32>
|
$<$<BOOL:${WIN32}>:_WIN32>
|
||||||
CITRON_USE_AUTO_UPDATER
|
CITRON_USE_AUTO_UPDATER
|
||||||
)
|
)
|
||||||
|
|
||||||
|
target_link_libraries(citron PRIVATE Qt6::Network)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||||
@@ -429,7 +431,7 @@ else()
|
|||||||
target_link_libraries(citron PRIVATE common core input_common frontend_common network video_core)
|
target_link_libraries(citron PRIVATE common core input_common frontend_common network video_core)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
target_link_libraries(citron PRIVATE Boost::headers glad Qt6::Widgets)
|
target_link_libraries(citron PRIVATE Boost::headers glad Qt6::Widgets Qt6::Network)
|
||||||
target_link_libraries(citron PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
target_link_libraries(citron PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
|
||||||
|
|
||||||
# Add libarchive for updater functionality
|
# Add libarchive for updater functionality
|
||||||
|
|||||||
@@ -6092,20 +6092,12 @@ int main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
void GMainWindow::OnCheckForUpdates() {
|
void GMainWindow::OnCheckForUpdates() {
|
||||||
#ifdef CITRON_USE_AUTO_UPDATER
|
#ifdef CITRON_USE_AUTO_UPDATER
|
||||||
#ifdef _WIN32
|
std::string update_url = "https://api.github.com/repos/Zephyron-Dev/Citron-CI/releases";
|
||||||
// Use HTTP URL to bypass SSL issues (will be redirected to HTTPS but handled by updater)
|
|
||||||
// TODO: Fix SSL libraries and revert to https://releases.citron-emu.org/api/check
|
|
||||||
std::string update_url = "http://releases.citron-emu.org/api/check";
|
|
||||||
|
|
||||||
// Create and show the updater dialog
|
auto* updater_dialog = new Updater::UpdaterDialog(this);
|
||||||
auto* updater_dialog = new UpdaterDialog(this);
|
|
||||||
updater_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
updater_dialog->setAttribute(Qt::WA_DeleteOnClose);
|
||||||
updater_dialog->show();
|
updater_dialog->show();
|
||||||
updater_dialog->CheckForUpdates(update_url);
|
updater_dialog->CheckForUpdates(update_url);
|
||||||
#else
|
|
||||||
QMessageBox::information(this, tr("Updates"),
|
|
||||||
tr("The update dialog is only available on Windows in this build."));
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
QMessageBox::information(this, tr("Updates"),
|
QMessageBox::information(this, tr("Updates"),
|
||||||
tr("The automatic updater is not enabled in this build."));
|
tr("The automatic updater is not enabled in this build."));
|
||||||
@@ -6122,7 +6114,7 @@ void GMainWindow::CheckForUpdatesAutomatically() {
|
|||||||
LOG_INFO(Frontend, "Checking for updates automatically...");
|
LOG_INFO(Frontend, "Checking for updates automatically...");
|
||||||
|
|
||||||
// Use HTTP URL to bypass SSL issues
|
// Use HTTP URL to bypass SSL issues
|
||||||
std::string update_url = "http://releases.citron-emu.org/api/check";
|
std::string update_url = "https://api.github.com/repos/Zephyron-Dev/Citron-CI/releases";
|
||||||
|
|
||||||
// Create updater service for silent background check
|
// Create updater service for silent background check
|
||||||
auto* updater_service = new Updater::UpdaterService(this);
|
auto* updater_service = new Updater::UpdaterService(this);
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ class QtControllerSelectorDialog;
|
|||||||
class QtProfileSelectionDialog;
|
class QtProfileSelectionDialog;
|
||||||
class QtSoftwareKeyboardDialog;
|
class QtSoftwareKeyboardDialog;
|
||||||
class QtNXWebEngineView;
|
class QtNXWebEngineView;
|
||||||
class UpdaterDialog;
|
namespace Updater { class UpdaterDialog; }
|
||||||
|
|
||||||
enum class StartGameType { Normal, Global };
|
enum class StartGameType { Normal, Global };
|
||||||
|
|
||||||
|
|||||||
@@ -2,17 +2,33 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include "citron/updater/updater_dialog.h"
|
#include "citron/updater/updater_dialog.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "ui_updater_dialog.h"
|
#include "ui_updater_dialog.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
|
#include <QDateTime>
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
#include <QUrl>
|
#include <QMessageBox>
|
||||||
#include <QTimer>
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QTimer>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
namespace Updater {
|
||||||
|
|
||||||
|
// Helper function to format the date and time
|
||||||
|
QString FormatDateTimeString(const std::string& iso_string) {
|
||||||
|
if (iso_string.empty() || iso_string == "Unknown") {
|
||||||
|
return QStringLiteral("Unknown");
|
||||||
|
}
|
||||||
|
// Parse the ISO 8601 date string provided by the GitHub API.
|
||||||
|
QDateTime date_time = QDateTime::fromString(QString::fromStdString(iso_string), Qt::ISODate);
|
||||||
|
if (!date_time.isValid()) {
|
||||||
|
return QString::fromStdString(iso_string); // Fallback to original if parsing fails.
|
||||||
|
}
|
||||||
|
// Convert from UTC (which the 'Z' indicates) to the user's local time
|
||||||
|
// and format it in a friendly, readable way.
|
||||||
|
return date_time.toLocalTime().toString(QStringLiteral("MMMM d, yyyy 'at' hh:mm AP"));
|
||||||
|
}
|
||||||
|
|
||||||
UpdaterDialog::UpdaterDialog(QWidget* parent)
|
UpdaterDialog::UpdaterDialog(QWidget* parent)
|
||||||
: QDialog(parent), ui(std::make_unique<Ui::UpdaterDialog>()),
|
: QDialog(parent), ui(std::make_unique<Ui::UpdaterDialog>()),
|
||||||
@@ -23,16 +39,16 @@ UpdaterDialog::UpdaterDialog(QWidget* parent)
|
|||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
|
||||||
// Set up connections
|
// Set up connections
|
||||||
connect(updater_service.get(), &Updater::UpdaterService::UpdateCheckCompleted,
|
connect(updater_service.get(), &Updater::UpdaterService::UpdateCheckCompleted, this,
|
||||||
this, &UpdaterDialog::OnUpdateCheckCompleted);
|
&UpdaterDialog::OnUpdateCheckCompleted);
|
||||||
connect(updater_service.get(), &Updater::UpdaterService::UpdateDownloadProgress,
|
connect(updater_service.get(), &Updater::UpdaterService::UpdateDownloadProgress, this,
|
||||||
this, &UpdaterDialog::OnUpdateDownloadProgress);
|
&UpdaterDialog::OnUpdateDownloadProgress);
|
||||||
connect(updater_service.get(), &Updater::UpdaterService::UpdateInstallProgress,
|
connect(updater_service.get(), &Updater::UpdaterService::UpdateInstallProgress, this,
|
||||||
this, &UpdaterDialog::OnUpdateInstallProgress);
|
&UpdaterDialog::OnUpdateInstallProgress);
|
||||||
connect(updater_service.get(), &Updater::UpdaterService::UpdateCompleted,
|
connect(updater_service.get(), &Updater::UpdaterService::UpdateCompleted, this,
|
||||||
this, &UpdaterDialog::OnUpdateCompleted);
|
&UpdaterDialog::OnUpdateCompleted);
|
||||||
connect(updater_service.get(), &Updater::UpdaterService::UpdateError,
|
connect(updater_service.get(), &Updater::UpdaterService::UpdateError, this,
|
||||||
this, &UpdaterDialog::OnUpdateError);
|
&UpdaterDialog::OnUpdateError);
|
||||||
|
|
||||||
// Set up UI connections
|
// Set up UI connections
|
||||||
connect(ui->downloadButton, &QPushButton::clicked, this, &UpdaterDialog::OnDownloadButtonClicked);
|
connect(ui->downloadButton, &QPushButton::clicked, this, &UpdaterDialog::OnDownloadButtonClicked);
|
||||||
@@ -49,8 +65,7 @@ UpdaterDialog::UpdaterDialog(QWidget* parent)
|
|||||||
ui->downloadInfoLabel->setText(
|
ui->downloadInfoLabel->setText(
|
||||||
QStringLiteral("Downloaded: %1 / %2")
|
QStringLiteral("Downloaded: %1 / %2")
|
||||||
.arg(FormatBytes(downloaded_bytes))
|
.arg(FormatBytes(downloaded_bytes))
|
||||||
.arg(FormatBytes(total_download_size))
|
.arg(FormatBytes(total_download_size)));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -62,25 +77,17 @@ void UpdaterDialog::CheckForUpdates(const std::string& update_url) {
|
|||||||
updater_service->CheckForUpdates(update_url);
|
updater_service->CheckForUpdates(update_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowUpdateAvailable(const Updater::UpdateInfo& update_info) {
|
|
||||||
current_update_info = update_info;
|
|
||||||
ShowUpdateAvailableState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterDialog::ShowUpdateChecking() {
|
|
||||||
ShowCheckingState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterDialog::OnUpdateCheckCompleted(bool has_update, const Updater::UpdateInfo& update_info) {
|
void UpdaterDialog::OnUpdateCheckCompleted(bool has_update, const Updater::UpdateInfo& update_info) {
|
||||||
if (has_update) {
|
if (has_update) {
|
||||||
current_update_info = update_info;
|
current_update_info = update_info;
|
||||||
ShowUpdateAvailableState();
|
ShowUpdateAvailableState();
|
||||||
} else {
|
} else {
|
||||||
ShowNoUpdateState();
|
ShowNoUpdateState(update_info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::OnUpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total) {
|
void UpdaterDialog::OnUpdateDownloadProgress(int percentage, qint64 bytes_received,
|
||||||
|
qint64 bytes_total) {
|
||||||
downloaded_bytes = bytes_received;
|
downloaded_bytes = bytes_received;
|
||||||
total_download_size = bytes_total;
|
total_download_size = bytes_total;
|
||||||
|
|
||||||
@@ -100,7 +107,8 @@ void UpdaterDialog::OnUpdateInstallProgress(int percentage, const QString& curre
|
|||||||
ui->downloadInfoLabel->setText(current_file);
|
ui->downloadInfoLabel->setText(current_file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::OnUpdateCompleted(Updater::UpdaterService::UpdateResult result, const QString& message) {
|
void UpdaterDialog::OnUpdateCompleted(Updater::UpdaterService::UpdateResult result,
|
||||||
|
const QString& message) {
|
||||||
progress_timer->stop();
|
progress_timer->stop();
|
||||||
|
|
||||||
switch (result) {
|
switch (result) {
|
||||||
@@ -124,8 +132,27 @@ void UpdaterDialog::OnUpdateError(const QString& error_message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::OnDownloadButtonClicked() {
|
void UpdaterDialog::OnDownloadButtonClicked() {
|
||||||
|
std::string download_url;
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
if (ui->appImageSelector->isVisible() && !current_update_info.download_options.empty()) {
|
||||||
|
int current_index = ui->appImageSelector->currentIndex();
|
||||||
|
if (current_index >= 0 && static_cast<size_t>(current_index) < current_update_info.download_options.size()) {
|
||||||
|
download_url = current_update_info.download_options[current_index].url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (download_url.empty() && !current_update_info.download_options.empty()) {
|
||||||
|
download_url = current_update_info.download_options[0].url;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!download_url.empty()) {
|
||||||
ShowDownloadingState();
|
ShowDownloadingState();
|
||||||
updater_service->DownloadAndInstallUpdate(current_update_info);
|
updater_service->DownloadAndInstallUpdate(download_url);
|
||||||
|
} else {
|
||||||
|
OnUpdateError(QStringLiteral("No download URL could be found for the update."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::OnCancelButtonClicked() {
|
void UpdaterDialog::OnCancelButtonClicked() {
|
||||||
@@ -141,192 +168,187 @@ void UpdaterDialog::OnCloseButtonClicked() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::OnRestartButtonClicked() {
|
void UpdaterDialog::OnRestartButtonClicked() {
|
||||||
// Ask for confirmation
|
|
||||||
int ret = QMessageBox::question(this, QStringLiteral("Restart Citron"),
|
int ret = QMessageBox::question(this, QStringLiteral("Restart Citron"),
|
||||||
QStringLiteral("Are you sure you want to restart Citron now?"),
|
QStringLiteral("Are you sure you want to restart Citron now?"),
|
||||||
QMessageBox::Yes | QMessageBox::No,
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
|
||||||
QMessageBox::Yes);
|
|
||||||
|
|
||||||
if (ret == QMessageBox::Yes) {
|
if (ret == QMessageBox::Yes) {
|
||||||
// Get the current executable path
|
|
||||||
QString program = QApplication::applicationFilePath();
|
QString program = QApplication::applicationFilePath();
|
||||||
QStringList arguments = QApplication::arguments();
|
QStringList arguments = QApplication::arguments();
|
||||||
arguments.removeFirst(); // Remove the program name
|
arguments.removeFirst();
|
||||||
|
|
||||||
// Start the new instance
|
|
||||||
QProcess::startDetached(program, arguments);
|
QProcess::startDetached(program, arguments);
|
||||||
|
|
||||||
// Close the current instance
|
|
||||||
QApplication::quit();
|
QApplication::quit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::SetupUI() {
|
void UpdaterDialog::SetupUI() {
|
||||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
setFixedSize(size());
|
|
||||||
|
|
||||||
// Set current version
|
// MODIFIED: Use setMinimumSize to allow the window to be resized larger.
|
||||||
|
setMinimumSize(size());
|
||||||
|
|
||||||
ui->currentVersionValue->setText(QString::fromStdString(updater_service->GetCurrentVersion()));
|
ui->currentVersionValue->setText(QString::fromStdString(updater_service->GetCurrentVersion()));
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
ShowCheckingState();
|
ShowCheckingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowCheckingState() {
|
void UpdaterDialog::ShowCheckingState() {
|
||||||
current_state = State::Checking;
|
current_state = State::Checking;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("Checking for updates..."));
|
ui->titleLabel->setText(QStringLiteral("Checking for updates..."));
|
||||||
ui->statusLabel->setText(QStringLiteral("Please wait while we check for available updates..."));
|
ui->statusLabel->setText(QStringLiteral("Please wait while we check for available updates..."));
|
||||||
|
|
||||||
ui->updateInfoGroup->setVisible(false);
|
ui->updateInfoGroup->setVisible(false);
|
||||||
ui->changelogGroup->setVisible(false);
|
ui->changelogGroup->setVisible(false);
|
||||||
ui->progressGroup->setVisible(false);
|
ui->progressGroup->setVisible(false);
|
||||||
|
|
||||||
ui->downloadButton->setVisible(false);
|
ui->downloadButton->setVisible(false);
|
||||||
ui->cancelButton->setVisible(true);
|
ui->cancelButton->setVisible(true);
|
||||||
ui->closeButton->setVisible(false);
|
ui->closeButton->setVisible(false);
|
||||||
ui->restartButton->setVisible(false);
|
ui->restartButton->setVisible(false);
|
||||||
|
|
||||||
ui->cancelButton->setText(QStringLiteral("Cancel"));
|
ui->cancelButton->setText(QStringLiteral("Cancel"));
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowNoUpdateState() {
|
void UpdaterDialog::ShowNoUpdateState(const Updater::UpdateInfo& update_info) {
|
||||||
current_state = State::NoUpdate;
|
current_state = State::NoUpdate;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("No updates available"));
|
ui->titleLabel->setText(QStringLiteral("No updates available"));
|
||||||
ui->statusLabel->setText(QStringLiteral("You are running the latest version of Citron."));
|
ui->statusLabel->setText(QStringLiteral("You are running the latest version of Citron."));
|
||||||
|
|
||||||
ui->updateInfoGroup->setVisible(true);
|
ui->updateInfoGroup->setVisible(true);
|
||||||
|
|
||||||
|
ui->latestVersionValue->setText(QString::fromStdString(update_info.version));
|
||||||
|
|
||||||
|
// MODIFIED: Use the new helper function to format the release date.
|
||||||
|
ui->releaseDateValue->setText(FormatDateTimeString(update_info.release_date));
|
||||||
|
|
||||||
ui->changelogGroup->setVisible(false);
|
ui->changelogGroup->setVisible(false);
|
||||||
ui->progressGroup->setVisible(false);
|
ui->progressGroup->setVisible(false);
|
||||||
|
|
||||||
ui->downloadButton->setVisible(false);
|
ui->downloadButton->setVisible(false);
|
||||||
ui->cancelButton->setVisible(false);
|
ui->cancelButton->setVisible(false);
|
||||||
ui->closeButton->setVisible(true);
|
ui->closeButton->setVisible(true);
|
||||||
ui->restartButton->setVisible(false);
|
ui->restartButton->setVisible(false);
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowUpdateAvailableState() {
|
void UpdaterDialog::ShowUpdateAvailableState() {
|
||||||
current_state = State::UpdateAvailable;
|
current_state = State::UpdateAvailable;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("Update available"));
|
ui->titleLabel->setText(QStringLiteral("Update available"));
|
||||||
ui->statusLabel->setText(QStringLiteral("A new version of Citron is available for download."));
|
ui->statusLabel->setText(QStringLiteral("A new version of Citron is available for download."));
|
||||||
|
|
||||||
// Fill in update information
|
|
||||||
ui->latestVersionValue->setText(QString::fromStdString(current_update_info.version));
|
ui->latestVersionValue->setText(QString::fromStdString(current_update_info.version));
|
||||||
ui->releaseDateValue->setText(QString::fromStdString(current_update_info.release_date));
|
|
||||||
|
|
||||||
// Show changelog if available
|
// MODIFIED: Use the new helper function to format the release date.
|
||||||
|
ui->releaseDateValue->setText(FormatDateTimeString(current_update_info.release_date));
|
||||||
|
|
||||||
if (!current_update_info.changelog.empty()) {
|
if (!current_update_info.changelog.empty()) {
|
||||||
ui->changelogText->setPlainText(QString::fromStdString(current_update_info.changelog));
|
// MODIFIED: Use setMarkdown to render the changelog with formatting and links.
|
||||||
|
ui->changelogText->setMarkdown(QString::fromStdString(current_update_info.changelog));
|
||||||
ui->changelogGroup->setVisible(true);
|
ui->changelogGroup->setVisible(true);
|
||||||
} else {
|
} else {
|
||||||
ui->changelogGroup->setVisible(false);
|
ui->changelogGroup->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
if (current_update_info.download_options.size() > 1) {
|
||||||
|
ui->appImageSelector->clear();
|
||||||
|
for (const auto& option : current_update_info.download_options) {
|
||||||
|
ui->appImageSelector->addItem(QString::fromStdString(option.name));
|
||||||
|
}
|
||||||
|
ui->appImageSelectorLabel->setVisible(true);
|
||||||
|
ui->appImageSelector->setVisible(true);
|
||||||
|
} else {
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
ui->updateInfoGroup->setVisible(true);
|
ui->updateInfoGroup->setVisible(true);
|
||||||
ui->progressGroup->setVisible(false);
|
ui->progressGroup->setVisible(false);
|
||||||
|
|
||||||
ui->downloadButton->setVisible(true);
|
ui->downloadButton->setVisible(true);
|
||||||
ui->cancelButton->setVisible(true);
|
ui->cancelButton->setVisible(true);
|
||||||
ui->closeButton->setVisible(false);
|
ui->closeButton->setVisible(false);
|
||||||
ui->restartButton->setVisible(false);
|
ui->restartButton->setVisible(false);
|
||||||
|
|
||||||
ui->cancelButton->setText(QStringLiteral("Later"));
|
ui->cancelButton->setText(QStringLiteral("Later"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowDownloadingState() {
|
void UpdaterDialog::ShowDownloadingState() {
|
||||||
current_state = State::Downloading;
|
current_state = State::Downloading;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("Downloading update..."));
|
ui->titleLabel->setText(QStringLiteral("Downloading update..."));
|
||||||
ui->statusLabel->setText(QStringLiteral("Please wait while the update is being downloaded and installed."));
|
ui->statusLabel->setText(
|
||||||
|
QStringLiteral("Please wait while the update is being downloaded and installed."));
|
||||||
ui->updateInfoGroup->setVisible(false);
|
ui->updateInfoGroup->setVisible(false);
|
||||||
ui->changelogGroup->setVisible(false);
|
ui->changelogGroup->setVisible(false);
|
||||||
ui->progressGroup->setVisible(true);
|
ui->progressGroup->setVisible(true);
|
||||||
|
|
||||||
ui->progressLabel->setText(QStringLiteral("Preparing download..."));
|
ui->progressLabel->setText(QStringLiteral("Preparing download..."));
|
||||||
ui->progressBar->setValue(0);
|
ui->progressBar->setValue(0);
|
||||||
ui->downloadInfoLabel->setText(QStringLiteral(""));
|
ui->downloadInfoLabel->setText(QStringLiteral(""));
|
||||||
|
|
||||||
ui->downloadButton->setVisible(false);
|
ui->downloadButton->setVisible(false);
|
||||||
ui->cancelButton->setVisible(true);
|
ui->cancelButton->setVisible(true);
|
||||||
ui->closeButton->setVisible(false);
|
ui->closeButton->setVisible(false);
|
||||||
ui->restartButton->setVisible(false);
|
ui->restartButton->setVisible(false);
|
||||||
|
|
||||||
ui->cancelButton->setText(QStringLiteral("Cancel"));
|
ui->cancelButton->setText(QStringLiteral("Cancel"));
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
progress_timer->start();
|
progress_timer->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowInstallingState() {
|
void UpdaterDialog::ShowInstallingState() {
|
||||||
current_state = State::Installing;
|
current_state = State::Installing;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("Installing update..."));
|
ui->titleLabel->setText(QStringLiteral("Installing update..."));
|
||||||
ui->statusLabel->setText(QStringLiteral("Please wait while the update is being installed. Do not close the application."));
|
ui->statusLabel->setText(QStringLiteral(
|
||||||
|
"Please wait while the update is being installed. Do not close the application."));
|
||||||
ui->progressLabel->setText(QStringLiteral("Installing..."));
|
ui->progressLabel->setText(QStringLiteral("Installing..."));
|
||||||
ui->downloadInfoLabel->setText(QStringLiteral(""));
|
ui->downloadInfoLabel->setText(QStringLiteral(""));
|
||||||
|
|
||||||
ui->cancelButton->setVisible(false);
|
ui->cancelButton->setVisible(false);
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowCompletedState() {
|
void UpdaterDialog::ShowCompletedState() {
|
||||||
current_state = State::Completed;
|
current_state = State::Completed;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("Update ready!"));
|
ui->titleLabel->setText(QStringLiteral("Update ready!"));
|
||||||
ui->statusLabel->setText(QStringLiteral("The update has been downloaded and prepared successfully. The update will be applied when you restart Citron."));
|
ui->statusLabel->setText(QStringLiteral("The update has been downloaded and prepared "
|
||||||
|
"successfully. The update will be applied when you "
|
||||||
|
"restart Citron."));
|
||||||
ui->progressGroup->setVisible(false);
|
ui->progressGroup->setVisible(false);
|
||||||
|
|
||||||
ui->downloadButton->setVisible(false);
|
ui->downloadButton->setVisible(false);
|
||||||
ui->cancelButton->setVisible(false);
|
ui->cancelButton->setVisible(false);
|
||||||
ui->closeButton->setVisible(true);
|
ui->closeButton->setVisible(true);
|
||||||
ui->restartButton->setVisible(true);
|
ui->restartButton->setVisible(true);
|
||||||
|
|
||||||
ui->progressBar->setValue(100);
|
ui->progressBar->setValue(100);
|
||||||
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdaterDialog::ShowErrorState() {
|
void UpdaterDialog::ShowErrorState() {
|
||||||
current_state = State::Error;
|
current_state = State::Error;
|
||||||
|
|
||||||
ui->titleLabel->setText(QStringLiteral("Update failed"));
|
ui->titleLabel->setText(QStringLiteral("Update failed"));
|
||||||
// statusLabel text is set by the caller
|
|
||||||
|
|
||||||
ui->updateInfoGroup->setVisible(false);
|
ui->updateInfoGroup->setVisible(false);
|
||||||
ui->changelogGroup->setVisible(false);
|
ui->changelogGroup->setVisible(false);
|
||||||
ui->progressGroup->setVisible(false);
|
ui->progressGroup->setVisible(false);
|
||||||
|
|
||||||
ui->downloadButton->setVisible(false);
|
ui->downloadButton->setVisible(false);
|
||||||
ui->cancelButton->setVisible(false);
|
ui->cancelButton->setVisible(false);
|
||||||
ui->closeButton->setVisible(true);
|
ui->closeButton->setVisible(true);
|
||||||
ui->restartButton->setVisible(false);
|
ui->restartButton->setVisible(false);
|
||||||
}
|
ui->appImageSelectorLabel->setVisible(false);
|
||||||
|
ui->appImageSelector->setVisible(false);
|
||||||
void UpdaterDialog::UpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total) {
|
|
||||||
downloaded_bytes = bytes_received;
|
|
||||||
total_download_size = bytes_total;
|
|
||||||
|
|
||||||
ui->progressBar->setValue(percentage);
|
|
||||||
ui->progressLabel->setText(QStringLiteral("Downloading update... %1%").arg(percentage));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UpdaterDialog::UpdateInstallProgress(int percentage, const QString& current_file) {
|
|
||||||
ui->progressBar->setValue(percentage);
|
|
||||||
ui->progressLabel->setText(QStringLiteral("Installing update... %1%").arg(percentage));
|
|
||||||
ui->downloadInfoLabel->setText(current_file);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QString UpdaterDialog::FormatBytes(qint64 bytes) const {
|
QString UpdaterDialog::FormatBytes(qint64 bytes) const {
|
||||||
const QStringList units = {QStringLiteral("B"), QStringLiteral("KB"), QStringLiteral("MB"), QStringLiteral("GB")};
|
const QStringList units = {QStringLiteral("B"), QStringLiteral("KB"), QStringLiteral("MB"),
|
||||||
|
QStringLiteral("GB")};
|
||||||
double size = bytes;
|
double size = bytes;
|
||||||
int unit = 0;
|
int unit = 0;
|
||||||
|
|
||||||
while (size >= 1024.0 && unit < units.size() - 1) {
|
while (size >= 1024.0 && unit < units.size() - 1) {
|
||||||
size /= 1024.0;
|
size /= 1024.0;
|
||||||
unit++;
|
unit++;
|
||||||
}
|
}
|
||||||
|
return QStringLiteral("%1 %2")
|
||||||
return QStringLiteral("%1 %2").arg(QString::number(size, 'f', unit == 0 ? 0 : 1)).arg(units[unit]);
|
.arg(QString::number(size, 'f', unit == 0 ? 0 : 1))
|
||||||
|
.arg(units[unit]);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString UpdaterDialog::GetUpdateMessage(Updater::UpdaterService::UpdateResult result) const {
|
QString UpdaterDialog::GetUpdateMessage(Updater::UpdaterService::UpdateResult result) const {
|
||||||
@@ -352,55 +374,6 @@ QString UpdaterDialog::GetUpdateMessage(Updater::UpdaterService::UpdateResult re
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "updater_dialog.moc"
|
} // namespace Updater
|
||||||
|
|
||||||
#else // _WIN32
|
|
||||||
|
|
||||||
// Forward declarations for non-Windows platforms
|
|
||||||
namespace Updater {
|
|
||||||
struct UpdateInfo {};
|
|
||||||
class UpdaterService {
|
|
||||||
public:
|
|
||||||
enum class UpdateResult { Success };
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stub implementations for non-Windows platforms
|
|
||||||
UpdaterDialog::UpdaterDialog(QWidget* parent) : QDialog(parent) {}
|
|
||||||
UpdaterDialog::~UpdaterDialog() = default;
|
|
||||||
void UpdaterDialog::CheckForUpdates(const std::string&) {}
|
|
||||||
void UpdaterDialog::ShowUpdateAvailable(const Updater::UpdateInfo&) {}
|
|
||||||
void UpdaterDialog::ShowUpdateChecking() {}
|
|
||||||
void UpdaterDialog::OnUpdateCheckCompleted(bool, const Updater::UpdateInfo&) {}
|
|
||||||
void UpdaterDialog::OnUpdateDownloadProgress(int, qint64, qint64) {}
|
|
||||||
void UpdaterDialog::OnUpdateInstallProgress(int, const QString&) {}
|
|
||||||
#ifdef _WIN32
|
|
||||||
void UpdaterDialog::OnUpdateCompleted(Updater::UpdaterService::UpdateResult, const QString&) {}
|
|
||||||
#else
|
|
||||||
void UpdaterDialog::OnUpdateCompleted(int, const QString&) {}
|
|
||||||
#endif
|
|
||||||
void UpdaterDialog::OnUpdateError(const QString&) {}
|
|
||||||
void UpdaterDialog::OnDownloadButtonClicked() {}
|
|
||||||
void UpdaterDialog::OnCancelButtonClicked() {}
|
|
||||||
void UpdaterDialog::OnCloseButtonClicked() {}
|
|
||||||
void UpdaterDialog::OnRestartButtonClicked() {}
|
|
||||||
void UpdaterDialog::SetupUI() {}
|
|
||||||
void UpdaterDialog::ShowCheckingState() {}
|
|
||||||
void UpdaterDialog::ShowNoUpdateState() {}
|
|
||||||
void UpdaterDialog::ShowUpdateAvailableState() {}
|
|
||||||
void UpdaterDialog::ShowDownloadingState() {}
|
|
||||||
void UpdaterDialog::ShowInstallingState() {}
|
|
||||||
void UpdaterDialog::ShowCompletedState() {}
|
|
||||||
void UpdaterDialog::ShowErrorState() {}
|
|
||||||
void UpdaterDialog::UpdateDownloadProgress(int, qint64, qint64) {}
|
|
||||||
void UpdaterDialog::UpdateInstallProgress(int, const QString&) {}
|
|
||||||
QString UpdaterDialog::FormatBytes(qint64) const { return QString(); }
|
|
||||||
#ifdef _WIN32
|
|
||||||
QString UpdaterDialog::GetUpdateMessage(Updater::UpdaterService::UpdateResult) const { return QString(); }
|
|
||||||
#else
|
|
||||||
QString UpdaterDialog::GetUpdateMessage(int) const { return QString(); }
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "updater_dialog.moc"
|
#include "updater_dialog.moc"
|
||||||
|
|
||||||
#endif // _WIN32
|
|
||||||
|
|||||||
@@ -3,29 +3,22 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
#include <memory>
|
||||||
#include <QProgressBar>
|
|
||||||
#include <QLabel>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QTextBrowser>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include "citron/updater/updater_service.h"
|
#include "citron/updater/updater_service.h"
|
||||||
#else
|
|
||||||
// Forward declarations for non-Windows platforms
|
// Forward declare QString for the helper function.
|
||||||
namespace Updater {
|
class QString;
|
||||||
struct UpdateInfo;
|
|
||||||
class UpdaterService;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class UpdaterDialog;
|
class UpdaterDialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Updater {
|
||||||
|
|
||||||
|
// Add the declaration for the date formatting helper function.
|
||||||
|
QString FormatDateTimeString(const std::string& iso_string);
|
||||||
|
|
||||||
class UpdaterDialog : public QDialog {
|
class UpdaterDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
@@ -33,73 +26,40 @@ public:
|
|||||||
explicit UpdaterDialog(QWidget* parent = nullptr);
|
explicit UpdaterDialog(QWidget* parent = nullptr);
|
||||||
~UpdaterDialog() override;
|
~UpdaterDialog() override;
|
||||||
|
|
||||||
// Check for updates using the given URL
|
|
||||||
void CheckForUpdates(const std::string& update_url);
|
void CheckForUpdates(const std::string& update_url);
|
||||||
|
|
||||||
// Show update available dialog
|
|
||||||
void ShowUpdateAvailable(const Updater::UpdateInfo& update_info);
|
|
||||||
|
|
||||||
// Show update checking dialog
|
|
||||||
void ShowUpdateChecking();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void OnUpdateCheckCompleted(bool has_update, const Updater::UpdateInfo& update_info);
|
void OnUpdateCheckCompleted(bool has_update, const Updater::UpdateInfo& update_info);
|
||||||
void OnUpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total);
|
void OnUpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total);
|
||||||
void OnUpdateInstallProgress(int percentage, const QString& current_file);
|
void OnUpdateInstallProgress(int percentage, const QString& current_file);
|
||||||
#ifdef _WIN32
|
|
||||||
void OnUpdateCompleted(Updater::UpdaterService::UpdateResult result, const QString& message);
|
void OnUpdateCompleted(Updater::UpdaterService::UpdateResult result, const QString& message);
|
||||||
#else
|
|
||||||
void OnUpdateCompleted(int result, const QString& message);
|
|
||||||
#endif
|
|
||||||
void OnUpdateError(const QString& error_message);
|
void OnUpdateError(const QString& error_message);
|
||||||
|
|
||||||
void OnDownloadButtonClicked();
|
void OnDownloadButtonClicked();
|
||||||
void OnCancelButtonClicked();
|
void OnCancelButtonClicked();
|
||||||
void OnCloseButtonClicked();
|
void OnCloseButtonClicked();
|
||||||
void OnRestartButtonClicked();
|
void OnRestartButtonClicked();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
enum class State { Checking, NoUpdate, UpdateAvailable, Downloading, Installing, Completed, Error };
|
||||||
|
|
||||||
void SetupUI();
|
void SetupUI();
|
||||||
void ShowCheckingState();
|
void ShowCheckingState();
|
||||||
void ShowNoUpdateState();
|
void ShowNoUpdateState(const Updater::UpdateInfo& update_info);
|
||||||
void ShowUpdateAvailableState();
|
void ShowUpdateAvailableState();
|
||||||
void ShowDownloadingState();
|
void ShowDownloadingState();
|
||||||
void ShowInstallingState();
|
void ShowInstallingState();
|
||||||
void ShowCompletedState();
|
void ShowCompletedState();
|
||||||
void ShowErrorState();
|
void ShowErrorState();
|
||||||
|
|
||||||
void UpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total);
|
|
||||||
void UpdateInstallProgress(int percentage, const QString& current_file);
|
|
||||||
|
|
||||||
QString FormatBytes(qint64 bytes) const;
|
QString FormatBytes(qint64 bytes) const;
|
||||||
#ifdef _WIN32
|
|
||||||
QString GetUpdateMessage(Updater::UpdaterService::UpdateResult result) const;
|
QString GetUpdateMessage(Updater::UpdaterService::UpdateResult result) const;
|
||||||
#else
|
|
||||||
QString GetUpdateMessage(int result) const;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
#ifdef _WIN32
|
|
||||||
std::unique_ptr<Ui::UpdaterDialog> ui;
|
std::unique_ptr<Ui::UpdaterDialog> ui;
|
||||||
std::unique_ptr<Updater::UpdaterService> updater_service;
|
std::unique_ptr<Updater::UpdaterService> updater_service;
|
||||||
|
UpdateInfo current_update_info;
|
||||||
Updater::UpdateInfo current_update_info;
|
State current_state;
|
||||||
|
qint64 total_download_size;
|
||||||
// UI state
|
qint64 downloaded_bytes;
|
||||||
enum class State {
|
|
||||||
Checking,
|
|
||||||
NoUpdate,
|
|
||||||
UpdateAvailable,
|
|
||||||
Downloading,
|
|
||||||
Installing,
|
|
||||||
Completed,
|
|
||||||
Error
|
|
||||||
};
|
|
||||||
State current_state = State::Checking;
|
|
||||||
|
|
||||||
// Progress tracking
|
|
||||||
qint64 total_download_size = 0;
|
|
||||||
qint64 downloaded_bytes = 0;
|
|
||||||
QTimer* progress_timer;
|
QTimer* progress_timer;
|
||||||
#endif // _WIN32
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
} // namespace Updater
|
||||||
|
|||||||
@@ -192,6 +192,22 @@ p, li { white-space: pre-wrap; }
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
|
<!-- Start of added widgets -->
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="appImageSelectorLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="appImageSelectorLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Select AppImage:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="appImageSelector"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<!-- End of added widgets -->
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="buttonLayout">
|
<layout class="QHBoxLayout" name="buttonLayout">
|
||||||
<item>
|
<item>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -3,24 +3,31 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <QObject>
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <thread>
|
|
||||||
#include <atomic>
|
|
||||||
#include <QObject>
|
|
||||||
#include <QNetworkAccessManager>
|
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
#include <QNetworkRequest>
|
#include <memory>
|
||||||
#include <QProgressDialog>
|
#include <vector>
|
||||||
#include <QMessageBox>
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <QNetworkAccessManager>
|
||||||
|
|
||||||
namespace Updater {
|
namespace Updater {
|
||||||
|
|
||||||
|
// Declaration for the helper function.
|
||||||
|
QString FormatDateTimeString(const std::string& iso_string);
|
||||||
|
std::string ExtractCommitHash(const std::string& version_string);
|
||||||
|
|
||||||
|
struct DownloadOption {
|
||||||
|
std::string name;
|
||||||
|
std::string url;
|
||||||
|
};
|
||||||
|
|
||||||
struct UpdateInfo {
|
struct UpdateInfo {
|
||||||
std::string version;
|
std::string version;
|
||||||
std::string download_url;
|
std::vector<DownloadOption> download_options;
|
||||||
std::string changelog;
|
std::string changelog;
|
||||||
std::string release_date;
|
std::string release_date;
|
||||||
bool is_newer_version = false;
|
bool is_newer_version = false;
|
||||||
@@ -30,36 +37,17 @@ class UpdaterService : public QObject {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class UpdateResult {
|
enum class UpdateResult { Success, Failed, Cancelled, NetworkError, ExtractionError, PermissionError, InvalidArchive, NoUpdateAvailable };
|
||||||
Success,
|
|
||||||
Failed,
|
|
||||||
Cancelled,
|
|
||||||
NetworkError,
|
|
||||||
ExtractionError,
|
|
||||||
PermissionError,
|
|
||||||
InvalidArchive,
|
|
||||||
NoUpdateAvailable
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit UpdaterService(QObject* parent = nullptr);
|
explicit UpdaterService(QObject* parent = nullptr);
|
||||||
~UpdaterService() override;
|
~UpdaterService() override;
|
||||||
|
|
||||||
// Check for updates from the configured URL
|
|
||||||
void CheckForUpdates(const std::string& update_url);
|
void CheckForUpdates(const std::string& update_url);
|
||||||
|
void DownloadAndInstallUpdate(const std::string& download_url);
|
||||||
// Download and install update
|
|
||||||
void DownloadAndInstallUpdate(const UpdateInfo& update_info);
|
|
||||||
|
|
||||||
// Cancel current operation
|
|
||||||
void CancelUpdate();
|
void CancelUpdate();
|
||||||
|
|
||||||
// Get current application version
|
|
||||||
std::string GetCurrentVersion() const;
|
std::string GetCurrentVersion() const;
|
||||||
|
|
||||||
// Check if update is in progress
|
|
||||||
bool IsUpdateInProgress() const;
|
bool IsUpdateInProgress() const;
|
||||||
|
|
||||||
// Static methods for startup update handling
|
|
||||||
static bool HasStagedUpdate(const std::filesystem::path& app_directory);
|
static bool HasStagedUpdate(const std::filesystem::path& app_directory);
|
||||||
static bool ApplyStagedUpdate(const std::filesystem::path& app_directory);
|
static bool ApplyStagedUpdate(const std::filesystem::path& app_directory);
|
||||||
|
|
||||||
@@ -76,50 +64,37 @@ private slots:
|
|||||||
void OnDownloadError(QNetworkReply::NetworkError error);
|
void OnDownloadError(QNetworkReply::NetworkError error);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Network operations
|
void InitializeSSL();
|
||||||
|
void ConfigureSSLForRequest(QNetworkRequest& request);
|
||||||
void ParseUpdateResponse(const QByteArray& response);
|
void ParseUpdateResponse(const QByteArray& response);
|
||||||
bool CompareVersions(const std::string& current, const std::string& latest) const;
|
bool CompareVersions(const std::string& current, const std::string& latest) const;
|
||||||
|
|
||||||
// SSL configuration
|
#ifdef _WIN32
|
||||||
void InitializeSSL();
|
|
||||||
void ConfigureSSLForRequest(QNetworkRequest& request);
|
|
||||||
|
|
||||||
// File operations
|
|
||||||
bool ExtractArchive(const std::filesystem::path& archive_path, const std::filesystem::path& extract_path);
|
bool ExtractArchive(const std::filesystem::path& archive_path, const std::filesystem::path& extract_path);
|
||||||
#if defined(_WIN32) && !defined(CITRON_ENABLE_LIBARCHIVE)
|
#ifndef CITRON_ENABLE_LIBARCHIVE
|
||||||
bool ExtractArchiveWindows(const std::filesystem::path& archive_path, const std::filesystem::path& extract_path);
|
bool ExtractArchiveWindows(const std::filesystem::path& archive_path, const std::filesystem::path& extract_path);
|
||||||
#endif
|
#endif
|
||||||
bool InstallUpdate(const std::filesystem::path& update_path);
|
bool InstallUpdate(const std::filesystem::path& update_path);
|
||||||
bool CreateBackup();
|
bool CreateBackup();
|
||||||
bool RestoreBackup();
|
bool RestoreBackup();
|
||||||
|
#endif
|
||||||
bool CleanupFiles();
|
bool CleanupFiles();
|
||||||
|
|
||||||
// Helper functions
|
|
||||||
std::filesystem::path GetTempDirectory() const;
|
std::filesystem::path GetTempDirectory() const;
|
||||||
std::filesystem::path GetApplicationDirectory() const;
|
std::filesystem::path GetApplicationDirectory() const;
|
||||||
std::filesystem::path GetBackupDirectory() const;
|
std::filesystem::path GetBackupDirectory() const;
|
||||||
bool EnsureDirectoryExists(const std::filesystem::path& path) const;
|
bool EnsureDirectoryExists(const std::filesystem::path& path) const;
|
||||||
|
|
||||||
// Network components
|
|
||||||
std::unique_ptr<QNetworkAccessManager> network_manager;
|
std::unique_ptr<QNetworkAccessManager> network_manager;
|
||||||
QNetworkReply* current_reply = nullptr;
|
QNetworkReply* current_reply = nullptr;
|
||||||
|
|
||||||
// Update state
|
|
||||||
std::atomic<bool> update_in_progress{false};
|
std::atomic<bool> update_in_progress{false};
|
||||||
std::atomic<bool> cancel_requested{false};
|
std::atomic<bool> cancel_requested{false};
|
||||||
UpdateInfo current_update_info;
|
UpdateInfo current_update_info;
|
||||||
|
std::filesystem::path app_directory;
|
||||||
// File paths
|
|
||||||
std::filesystem::path temp_download_path;
|
std::filesystem::path temp_download_path;
|
||||||
std::filesystem::path backup_path;
|
std::filesystem::path backup_path;
|
||||||
std::filesystem::path app_directory;
|
|
||||||
|
|
||||||
// Constants
|
|
||||||
static constexpr const char* CITRON_VERSION_FILE = "version.txt";
|
static constexpr const char* CITRON_VERSION_FILE = "version.txt";
|
||||||
static constexpr const char* UPDATE_MANIFEST_FILE = "update_manifest.json";
|
|
||||||
static constexpr const char* BACKUP_DIRECTORY = "backup";
|
static constexpr const char* BACKUP_DIRECTORY = "backup";
|
||||||
static constexpr const char* TEMP_DIRECTORY = "temp";
|
|
||||||
static constexpr size_t MAX_DOWNLOAD_SIZE = 500 * 1024 * 1024; // 500MB limit
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Updater
|
} // namespace Updater
|
||||||
Reference in New Issue
Block a user