Merge branch 'fix/auto-update-link' into 'main'

fix(updater): Link to Commits

See merge request citron/emulator!119
This commit is contained in:
Zephyron
2025-10-26 15:36:21 +10:00
2 changed files with 69 additions and 53 deletions

View File

@@ -10,26 +10,36 @@
#include <QDesktopServices>
#include <QMessageBox>
#include <QProcess>
#include <QRegularExpression>
#include <QTimer>
#include <QUrl>
namespace Updater {
// Helper function to format the date and time
// Helper function to format the date and time nicely.
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.
return QString::fromStdString(iso_string);
}
// 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"));
}
// Helper function to reformat the changelog with the correct commit link.
QString FormatChangelog(const std::string& raw_changelog) {
QString changelog = QString::fromStdString(raw_changelog);
const QString new_url = QStringLiteral("https://git.citron-emu.org/citron/emulator/-/commits/main");
QRegularExpression regex(QStringLiteral("\\[\\`([0-9a-fA-F]{7,40})\\`\\]\\(.*?\\)"));
QString replacement = QStringLiteral("[`\\1`](%1)").arg(new_url);
changelog.replace(regex, replacement);
return changelog;
}
UpdaterDialog::UpdaterDialog(QWidget* parent)
: QDialog(parent), ui(std::make_unique<Ui::UpdaterDialog>()),
updater_service(std::make_unique<Updater::UpdaterService>(this)),
@@ -38,6 +48,15 @@ UpdaterDialog::UpdaterDialog(QWidget* parent)
ui->setupUi(this);
// NEW: Disable the default link handling behavior of the QTextBrowser.
// This prevents it from trying to load the URL internally.
ui->changelogText->setOpenLinks(false);
// Manually handle link clicks to ensure they always open in an external browser.
connect(ui->changelogText, &QTextBrowser::anchorClicked, this, [](const QUrl& link) {
QDesktopServices::openUrl(link);
});
// Set up connections
connect(updater_service.get(), &Updater::UpdaterService::UpdateCheckCompleted, this,
&UpdaterDialog::OnUpdateCheckCompleted);
@@ -185,7 +204,6 @@ void UpdaterDialog::OnRestartButtonClicked() {
void UpdaterDialog::SetupUI() {
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
// MODIFIED: Use setMinimumSize to allow the window to be resized larger.
setMinimumSize(size());
ui->currentVersionValue->setText(QString::fromStdString(updater_service->GetCurrentVersion()));
@@ -218,7 +236,6 @@ void UpdaterDialog::ShowNoUpdateState(const Updater::UpdateInfo& update_info) {
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);
@@ -237,16 +254,14 @@ void UpdaterDialog::ShowUpdateAvailableState() {
ui->statusLabel->setText(QStringLiteral("A new version of Citron is available for download."));
ui->latestVersionValue->setText(QString::fromStdString(current_update_info.version));
// 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()) {
// 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->changelogText->setMarkdown(FormatChangelog(current_update_info.changelog));
} else {
ui->changelogGroup->setVisible(false);
ui->changelogText->setText(tr("No changelog information was provided for this update."));
}
ui->changelogGroup->setVisible(true);
#ifdef __linux__
if (current_update_info.download_options.size() > 1) {

View File

@@ -7,59 +7,60 @@
#include <memory>
#include "citron/updater/updater_service.h"
// Forward declare QString for the helper function.
class QString;
namespace Ui {
class UpdaterDialog;
class UpdaterDialog;
}
namespace Updater {
// Add the declaration for the date formatting helper function.
QString FormatDateTimeString(const std::string& iso_string);
// Declarations for helper functions
QString FormatDateTimeString(const std::string& iso_string);
class UpdaterDialog : public QDialog {
Q_OBJECT
QString FormatChangelog(const std::string& raw_changelog);
public:
explicit UpdaterDialog(QWidget* parent = nullptr);
~UpdaterDialog() override;
class UpdaterDialog : public QDialog {
Q_OBJECT
void CheckForUpdates(const std::string& update_url);
public:
explicit UpdaterDialog(QWidget* parent = nullptr);
~UpdaterDialog() override;
private slots:
void OnUpdateCheckCompleted(bool has_update, const Updater::UpdateInfo& update_info);
void OnUpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total);
void OnUpdateInstallProgress(int percentage, const QString& current_file);
void OnUpdateCompleted(Updater::UpdaterService::UpdateResult result, const QString& message);
void OnUpdateError(const QString& error_message);
void OnDownloadButtonClicked();
void OnCancelButtonClicked();
void OnCloseButtonClicked();
void OnRestartButtonClicked();
void CheckForUpdates(const std::string& update_url);
private:
enum class State { Checking, NoUpdate, UpdateAvailable, Downloading, Installing, Completed, Error };
private slots:
void OnUpdateCheckCompleted(bool has_update, const Updater::UpdateInfo& update_info);
void OnUpdateDownloadProgress(int percentage, qint64 bytes_received, qint64 bytes_total);
void OnUpdateInstallProgress(int percentage, const QString& current_file);
void OnUpdateCompleted(Updater::UpdaterService::UpdateResult result, const QString& message);
void OnUpdateError(const QString& error_message);
void OnDownloadButtonClicked();
void OnCancelButtonClicked();
void OnCloseButtonClicked();
void OnRestartButtonClicked();
void SetupUI();
void ShowCheckingState();
void ShowNoUpdateState(const Updater::UpdateInfo& update_info);
void ShowUpdateAvailableState();
void ShowDownloadingState();
void ShowInstallingState();
void ShowCompletedState();
void ShowErrorState();
QString FormatBytes(qint64 bytes) const;
QString GetUpdateMessage(Updater::UpdaterService::UpdateResult result) const;
private:
enum class State { Checking, NoUpdate, UpdateAvailable, Downloading, Installing, Completed, Error };
std::unique_ptr<Ui::UpdaterDialog> ui;
std::unique_ptr<Updater::UpdaterService> updater_service;
UpdateInfo current_update_info;
State current_state;
qint64 total_download_size;
qint64 downloaded_bytes;
QTimer* progress_timer;
};
void SetupUI();
void ShowCheckingState();
void ShowNoUpdateState(const Updater::UpdateInfo& update_info);
void ShowUpdateAvailableState();
void ShowDownloadingState();
void ShowInstallingState();
void ShowCompletedState();
void ShowErrorState();
QString FormatBytes(qint64 bytes) const;
QString GetUpdateMessage(Updater::UpdaterService::UpdateResult result) const;
std::unique_ptr<Ui::UpdaterDialog> ui;
std::unique_ptr<Updater::UpdaterService> updater_service;
UpdateInfo current_update_info;
State current_state;
qint64 total_download_size;
qint64 downloaded_bytes;
QTimer* progress_timer;
};
} // namespace Updater