diff --git a/src/qt_gui/compatibility_info.cpp b/src/qt_gui/compatibility_info.cpp index a9b3edcc5..e432ec9b2 100644 --- a/src/qt_gui/compatibility_info.cpp +++ b/src/qt_gui/compatibility_info.cpp @@ -1,12 +1,12 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include +#include +#include +#include + #include "common/path_util.h" #include "compatibility_info.h" -#include -#include -#include CompatibilityInfoClass::CompatibilityInfoClass() : m_network_manager(new QNetworkAccessManager(this)) { @@ -19,8 +19,9 @@ CompatibilityInfoClass::~CompatibilityInfoClass() = default; void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { QFileInfo check_file(m_compatibility_filename); - const auto modified_delta = check_file.lastModified() - QDateTime::currentDateTime(); - if (check_file.exists() && check_file.isFile() && std::chrono::duration_cast(modified_delta).count() < 60) { + const auto modified_delta = QDateTime::currentDateTime() - check_file.lastModified(); + if (check_file.exists() && check_file.isFile() && + std::chrono::duration_cast(modified_delta).count() < 60) { if (LoadCompatibilityFile()) return; QMessageBox::critical(parent, tr("Error"), @@ -46,9 +47,10 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { if (reply->error() != QNetworkReply::NoError) { reply->deleteLater(); - QMessageBox::critical(parent, tr("Error"), - tr("Unable to update compatibility data! Using old compatibility data...")); - //TODO: Try loading compatibility_file.json again + QMessageBox::critical( + parent, tr("Error"), + tr("Unable to update compatibility data! Using old compatibility data...")); + // Try loading compatibility_file.json again LoadCompatibilityFile(); return; } @@ -87,8 +89,7 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { dialog.reset(); }); - connect(&dialog, &QProgressDialog::canceled, &future_watcher, - &QFutureWatcher::cancel); + connect(&dialog, &QProgressDialog::canceled, &future_watcher, &QFutureWatcher::cancel); dialog.setRange(0, remaining_pages); connect(&future_watcher, &QFutureWatcher::progressValueChanged, &dialog, &QProgressDialog::setValue); @@ -117,7 +118,7 @@ void CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) { return; }; -CompatibilityStatus CompatibilityInfoClass::GetCompatibilityStatus(const std::string& serial) { +CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::string& serial) { QString title_id = QString::fromStdString(serial); if (m_compatibility_database.contains(title_id)) { { @@ -125,13 +126,18 @@ CompatibilityStatus CompatibilityInfoClass::GetCompatibilityStatus(const std::st QString os_string = OSTypeToString.at(static_cast(os_int)); QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject(); if (compatibility_obj.contains(os_string)) { - return LabelToCompatStatus.at( - compatibility_obj[os_string].toString()); + QJsonObject compatibility_entry_obj = compatibility_obj[os_string].toObject(); + CompatibilityEntry compatibility_entry{ + LabelToCompatStatus.at(compatibility_entry_obj["status"].toString()), + compatibility_entry_obj["version"].toString(), + QDateTime::fromString(compatibility_entry_obj["last_tested"].toString(), + Qt::ISODate)}; + return compatibility_entry; } } } } - return CompatibilityStatus::Unknown; + return CompatibilityEntry{CompatibilityStatus::Unknown}; } bool CompatibilityInfoClass::LoadCompatibilityFile() { @@ -152,7 +158,6 @@ bool CompatibilityInfoClass::LoadCompatibilityFile() { return true; } - void CompatibilityInfoClass::ExtractCompatibilityInfo(QByteArray response) { QJsonDocument json_doc(QJsonDocument::fromJson(response)); @@ -187,13 +192,20 @@ void CompatibilityInfoClass::ExtractCompatibilityInfo(QByteArray response) { } } - QJsonValueRef compatibility_object_ref = m_compatibility_database[title_id]; + // QJson does not support editing nested objects directly.. - if (compatibility_object_ref.isNull()) { - compatibility_object_ref = QJsonObject({{current_os, compatibility_status}}); - } else { - compatibility_object_ref.toObject()[current_os] = compatibility_status; - } + QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject(); + + QJsonObject compatibility_data{ + {{"status", compatibility_status}, + {"last_tested", issue_obj["updated_at"]}, + {"version", issue_obj["milestone"].isNull() + ? "unknown" + : issue_obj["milestone"].toObject()["title"].toString()}}}; + + compatibility_obj[current_os] = compatibility_data; + + m_compatibility_database[title_id] = compatibility_obj; } } diff --git a/src/qt_gui/compatibility_info.h b/src/qt_gui/compatibility_info.h index c7184bdc3..c1ba387e7 100644 --- a/src/qt_gui/compatibility_info.h +++ b/src/qt_gui/compatibility_info.h @@ -42,6 +42,12 @@ enum OSType { Last }; +struct CompatibilityEntry { + CompatibilityStatus status; + QString version; + QDateTime last_tested; +}; + class CompatibilityInfoClass : public QObject { Q_OBJECT public: @@ -75,7 +81,7 @@ public: ~CompatibilityInfoClass(); void UpdateCompatibilityDatabase(QWidget* parent = nullptr); bool LoadCompatibilityFile(); - CompatibilityStatus GetCompatibilityStatus(const std::string& serial); + CompatibilityEntry GetCompatibilityInfo(const std::string& serial); void ExtractCompatibilityInfo(QByteArray response); static void WaitForReply(QNetworkReply* reply); QNetworkReply* FetchPage(int page_num); diff --git a/src/qt_gui/game_list_frame.cpp b/src/qt_gui/game_list_frame.cpp index 7307caad9..78ebe4514 100644 --- a/src/qt_gui/game_list_frame.cpp +++ b/src/qt_gui/game_list_frame.cpp @@ -8,8 +8,8 @@ #include "game_list_utils.h" #include -GameListFrame::GameListFrame(std::shared_ptr game_info_get, - std::shared_ptr compat_info_get, +GameListFrame::GameListFrame(std::shared_ptr game_info_get, + std::shared_ptr compat_info_get, QWidget* parent) : QTableWidget(parent), m_game_info(game_info_get), m_compat_info(compat_info_get) { icon_size = Config::getIconSize(); @@ -22,7 +22,7 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, this->verticalScrollBar()->installEventFilter(this); this->verticalScrollBar()->setSingleStep(20); this->horizontalScrollBar()->setSingleStep(20); - this->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); + this->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); this->verticalHeader()->setVisible(false); this->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); this->horizontalHeader()->setHighlightSections(false); @@ -44,8 +44,8 @@ GameListFrame::GameListFrame(std::shared_ptr game_info_get, this->setHorizontalHeaderLabels(headers); this->horizontalHeader()->setSortIndicatorShown(true); this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); - this->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed); this->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); + this->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed); PopulateGameList(); connect(this, &QTableWidget::currentCellChanged, this, &GameListFrame::onCurrentCellChanged); @@ -108,9 +108,9 @@ void GameListFrame::PopulateGameList() { SetTableItem(i, 6, QString::fromStdString(m_game_info->m_games[i].size)); SetTableItem(i, 7, QString::fromStdString(m_game_info->m_games[i].version)); - m_game_info->m_games[i].compatibility_status = - m_compat_info->GetCompatibilityStatus(m_game_info->m_games[i].serial); - SetCompatibilityItem(i, 2, m_game_info->m_games[i].compatibility_status); + m_game_info->m_games[i].compatibility = + m_compat_info->GetCompatibilityInfo(m_game_info->m_games[i].serial); + SetCompatibilityItem(i, 2, m_game_info->m_games[i].compatibility); QString playTime = GetPlayTime(m_game_info->m_games[i].serial); if (playTime.isEmpty()) { @@ -213,7 +213,7 @@ void GameListFrame::ResizeIcons(int iconSize) { this->horizontalHeader()->setSectionResizeMode(8, QHeaderView::ResizeToContents); } -void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityStatus status) { +void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityEntry entry) { QTableWidgetItem* item = new QTableWidgetItem(); QWidget* widget = new QWidget(this); QGridLayout* layout = new QGridLayout(widget); @@ -221,7 +221,7 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityStatu QColor color; QString tooltip_string; - switch (status) { + switch (entry.status) { case Unknown: color = QStringLiteral("#000000"); tooltip_string = tr("Compatibility is untested"); @@ -259,9 +259,9 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityStatu QLabel* dotLabel = new QLabel("", widget); dotLabel->setPixmap(circle_pixmap); - QLabel* label = new QLabel(m_compat_info->CompatStatusToString.at(status), widget); + QLabel* label = new QLabel(m_compat_info->CompatStatusToString.at(entry.status), widget); - label->setStyleSheet("color: white; font-size: 16px; font-weight: bold;"); + label->setStyleSheet("color: white; font-size: 12px; font-weight: bold;"); // Create shadow effect QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(); @@ -271,8 +271,13 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityStatu label->setGraphicsEffect(shadowEffect); // Apply shadow effect to the QLabel - layout->addWidget(dotLabel, 0, 0, -1, 4); - layout->addWidget(label, 0, 4, -1, 4); + QLabel* version_label = + new QLabel(QString("%1, (%2)").arg(entry.last_tested.toString("yyyy-MM-dd"), entry.version), widget); + version_label->setStyleSheet("color: white; font-size: 10px;"); + + layout->addWidget(dotLabel, 0, 0, -1, 1); + layout->addWidget(label, 0, 1, 1, 1); + layout->addWidget(version_label, 1, 1, 1, 1); layout->setAlignment(Qt::AlignLeft); widget->setLayout(layout); widget->setToolTip(tooltip_string); diff --git a/src/qt_gui/game_list_frame.h b/src/qt_gui/game_list_frame.h index ddfa85ce7..8c6fcb1e2 100644 --- a/src/qt_gui/game_list_frame.h +++ b/src/qt_gui/game_list_frame.h @@ -18,7 +18,9 @@ class GameListFrame : public QTableWidget { Q_OBJECT public: - explicit GameListFrame(std::shared_ptr game_info_get, std::shared_ptr compat_info_get, QWidget* parent = nullptr); + explicit GameListFrame(std::shared_ptr game_info_get, + std::shared_ptr compat_info_get, + QWidget* parent = nullptr); Q_SIGNALS: void GameListFrameClosed(); @@ -34,7 +36,7 @@ public Q_SLOTS: private: void SetTableItem(int row, int column, QString itemStr); void SetRegionFlag(int row, int column, QString itemStr); - void SetCompatibilityItem(int row, int column, CompatibilityStatus status); + void SetCompatibilityItem(int row, int column, CompatibilityEntry entry); QString GetPlayTime(const std::string& serial); QList m_columnActs; GameInfoClass* game_inf_get = nullptr; @@ -66,7 +68,7 @@ public: case 1: return a.name < b.name; case 2: - return a.compatibility_status < b.compatibility_status; + return a.compatibility.status < b.compatibility.status; case 3: return a.serial.substr(4) < b.serial.substr(4); case 4: @@ -91,7 +93,7 @@ public: case 1: return a.name > b.name; case 2: - return a.compatibility_status > b.compatibility_status; + return a.compatibility.status > b.compatibility.status; case 3: return a.serial.substr(4) > b.serial.substr(4); case 4: diff --git a/src/qt_gui/game_list_utils.h b/src/qt_gui/game_list_utils.h index fa2d900f1..16c0307c8 100644 --- a/src/qt_gui/game_list_utils.h +++ b/src/qt_gui/game_list_utils.h @@ -27,7 +27,7 @@ struct GameInfo { std::string fw = "Unknown"; std::string play_time = "Unknown"; - CompatibilityStatus compatibility_status = CompatibilityStatus::Unknown; + CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown}; }; class GameListUtils {