Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 113 additions & 16 deletions rpcs3/rpcs3qt/update_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@
#include <QApplication>
#include <QCheckBox>
#include <QDateTime>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QMessageBox>
#include <QPushButton>
#include <QLabel>
#include <QJsonArray>
#include <QJsonObject>
#include <QJsonDocument>
#include <QTextBrowser>

#if defined(_WIN32) || defined(__APPLE__)
#include <7z.h>
Expand Down Expand Up @@ -286,6 +290,8 @@ bool update_manager::handle_json(bool automatic, bool check_only, bool auto_acce
update_log.notice("JSON changelog entry does not contain a title string.");
}

entry.pr = changelog_entry["pr"].toInt();

m_update_info.changelog.push_back(std::move(entry));
}
else
Expand Down Expand Up @@ -341,7 +347,7 @@ void update_manager::update(bool auto_accept, bool is_first_call)
if (m_update_info.diff_msec < 0)
{
// This usually means that the current version was marked as broken and won't be shipped anymore, so we need to downgrade to avoid certain bugs.
update_message = tr("A better version of RPCS3 is available!<br><br>Current version: %0 (%1)<br>Better version: %2 (%3)<br>%4<br>Do you want to update?")
update_message = tr("A better version of RPCS3 is available!<br><br>Current version: %0 (%1)<br>Better version: %2 (%3)<br>%4")
.arg(m_update_info.old_version)
.arg(m_update_info.cur_date)
.arg(m_update_info.new_version)
Expand All @@ -350,7 +356,7 @@ void update_manager::update(bool auto_accept, bool is_first_call)
}
else
{
update_message = tr("A new version of RPCS3 is available!<br><br>Current version: %0 (%1)<br>Latest version: %2 (%3)<br>Your version is %4 behind.<br>%5<br>Do you want to update?")
update_message = tr("A new version of RPCS3 is available!<br><br>Current version: %0 (%1)<br>Latest version: %2 (%3)<br>Your version is %4 behind.<br>%5")
.arg(m_update_info.old_version)
.arg(m_update_info.cur_date)
.arg(m_update_info.new_version)
Expand All @@ -361,42 +367,133 @@ void update_manager::update(bool auto_accept, bool is_first_call)
}
else
{
update_message = tr("You're currently using a custom or PR build.<br><br>Latest version: %0 (%1)<br>The latest version is %2 old.<br>%3<br>Do you want to update to the latest official RPCS3 version?")
update_message = tr("You're currently using a custom or PR build.<br><br>Latest version: %0 (%1)<br>The latest version is %2 old.<br>%3")
.arg(m_update_info.new_version)
.arg(m_update_info.lts_date)
.arg(localized.GetVerboseTimeByMs(std::abs(m_update_info.diff_msec), true))
.arg(support_message);
}

QString changelog_content;
// Build HTML changelog with clickable PR links when available
QString changelog_html;
QString changelog_html_6; // First 6 entries for height cap
int changelog_count = 0;

for (const changelog_data& entry : m_update_info.changelog)
{
if (!changelog_content.isEmpty())
changelog_content.append('\n');
changelog_content.append(tr("• %0: %1").arg(entry.version.isEmpty() ? tr("N/A") : entry.version, entry.title.isEmpty() ? tr("N/A") : entry.title));
const QString version_str = entry.version.isEmpty() ? tr("N/A") : entry.version;
const QString title_str = entry.title.isEmpty() ? tr("N/A") : entry.title;

QString entry_html;

if (entry.pr > 0)
{
entry_html = tr("&nbsp;&nbsp;&bull; %0: %1 (<a href=\"https://github.com/RPCS3/rpcs3/pull/%2\">#%2</a>)").arg(version_str, title_str, QString::number(entry.pr));
}
else
{
entry_html = tr("&nbsp;&nbsp;&bull; %0: %1").arg(version_str, title_str);
}

if (!changelog_html.isEmpty())
changelog_html += QStringLiteral("<br>");
changelog_html += entry_html;

if (changelog_count < 6)
{
if (!changelog_html_6.isEmpty())
changelog_html_6 += QStringLiteral("<br>");
changelog_html_6 += entry_html;
}

changelog_count++;
}

QMessageBox mb(QMessageBox::Icon::Question, tr("Update Available"), update_message, QMessageBox::Yes | QMessageBox::No, m_downloader->get_progress_dialog() ? m_downloader->get_progress_dialog() : m_parent);
mb.setTextFormat(Qt::RichText);
mb.setCheckBox(new QCheckBox(tr("Don't show again for this version")));

if (!changelog_content.isEmpty())
// Rearrange the layout: checkbox, then changelog, then prompt, then buttons
if (QGridLayout* grid = qobject_cast<QGridLayout*>(mb.layout()))
{
mb.setInformativeText(tr("To see the changelog, please click \"Show Details\"."));
mb.setDetailedText(tr("Changelog:\n\n%0").arg(changelog_content));
const int cols = grid->columnCount();

QDialogButtonBox* button_box = mb.findChild<QDialogButtonBox*>();

if (button_box)
grid->removeWidget(button_box);

// Smartass hack to make the unresizeable message box wide enough for the changelog
const int changelog_width = QLabel(changelog_content).sizeHint().width();
if (QLabel(update_message).sizeHint().width() < changelog_width)
int row = grid->rowCount();

if (!changelog_html.isEmpty())
{
update_message += " &nbsp;";
while (QLabel(update_message).sizeHint().width() < changelog_width)
QTextBrowser* changelog_browser = new QTextBrowser(&mb);
changelog_browser->setOpenExternalLinks(true);
changelog_browser->setReadOnly(true);
changelog_browser->setFrameShape(QFrame::NoFrame);
changelog_browser->setLineWrapMode(QTextBrowser::NoWrap);
changelog_browser->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
changelog_browser->setHtml(QStringLiteral("<h3>%0</h3>%1").arg(tr("Changelog:"), changelog_html));

// Natural height for ≤6 entries, capped at 6-entry height for more
int browser_height;

if (changelog_count > 6)
{
changelog_browser->setHtml(QStringLiteral("<h3>%0</h3>%1").arg(tr("Changelog:"), changelog_html_6));
browser_height = static_cast<int>(changelog_browser->document()->size().height());
changelog_browser->setHtml(QStringLiteral("<h3>%0</h3>%1").arg(tr("Changelog:"), changelog_html));
}
else
{
update_message += "&nbsp;";
browser_height = static_cast<int>(changelog_browser->document()->size().height());
}

changelog_browser->setFixedHeight(browser_height);
changelog_browser->setVisible(false);

const QString show_text = tr("Show Changelog");
const QString hide_text = tr("Hide Changelog");

QPushButton* toggle_btn = new QPushButton(show_text, &mb);
grid->addWidget(toggle_btn, row++, 0, 1, cols);
grid->addWidget(changelog_browser, row++, 0, 1, cols);

QObject::connect(toggle_btn, &QPushButton::clicked, [changelog_browser, toggle_btn, &mb, show_text, hide_text]()
{
const bool becoming_visible = !changelog_browser->isVisible();
changelog_browser->setVisible(becoming_visible);
toggle_btn->setText(becoming_visible ? hide_text : show_text);
mb.adjustSize();
});
}

// Horizontal separator before the prompt
QFrame* separator = new QFrame(&mb);
separator->setFrameShape(QFrame::HLine);
separator->setFrameShadow(QFrame::Sunken);
grid->addWidget(separator, row++, 0, 1, cols);

// "Do you want to update?" label
const QString prompt_text = m_update_info.hash_found
? tr("Do you want to update?")
: tr("Do you want to update to the latest official RPCS3 version?");
QLabel* prompt_label = new QLabel(prompt_text, &mb);
grid->addWidget(prompt_label, row++, 0, 1, cols);

// Re-add button box at the bottom
if (button_box)
grid->addWidget(button_box, row, 0, 1, cols);
}

// Pad message text to match changelog width
if (!changelog_html.isEmpty())
{
const int target_width = 500;
while (QLabel(update_message).sizeHint().width() < target_width)
{
update_message += QStringLiteral("&nbsp;");
}
mb.setText(update_message);
}

Expand Down
1 change: 1 addition & 0 deletions rpcs3/rpcs3qt/update_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class update_manager final : public QObject

struct changelog_data
{
int pr = 0;
QString version;
QString title;
};
Expand Down
Loading