diff --git a/src/citron/updater/updater_dialog.cpp b/src/citron/updater/updater_dialog.cpp index 58716ee8f..af01fd831 100644 --- a/src/citron/updater/updater_dialog.cpp +++ b/src/citron/updater/updater_dialog.cpp @@ -6,30 +6,40 @@ #include #include -#include +#include #include #include #include +#include #include #include 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()), updater_service(std::make_unique(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) { diff --git a/src/citron/updater/updater_dialog.h b/src/citron/updater/updater_dialog.h index fa517e345..8a44fffec 100644 --- a/src/citron/updater/updater_dialog.h +++ b/src/citron/updater/updater_dialog.h @@ -7,59 +7,60 @@ #include #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; - std::unique_ptr 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; + std::unique_ptr updater_service; + UpdateInfo current_update_info; + State current_state; + qint64 total_download_size; + qint64 downloaded_bytes; + QTimer* progress_timer; + }; } // namespace Updater