Include version & last_tested info

This commit is contained in:
faith 2024-12-06 13:25:20 +08:00
commit 3862ed6a59
5 changed files with 66 additions and 41 deletions

View File

@ -1,12 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <iostream> #include <QFileInfo>
#include <QMessageBox>
#include <QProgressDialog>
#include "common/path_util.h" #include "common/path_util.h"
#include "compatibility_info.h" #include "compatibility_info.h"
#include <QProgressDialog>
#include <QMessageBox>
#include <QFileInfo>
CompatibilityInfoClass::CompatibilityInfoClass() CompatibilityInfoClass::CompatibilityInfoClass()
: m_network_manager(new QNetworkAccessManager(this)) { : m_network_manager(new QNetworkAccessManager(this)) {
@ -19,8 +19,9 @@ CompatibilityInfoClass::~CompatibilityInfoClass() = default;
void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) { void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
QFileInfo check_file(m_compatibility_filename); QFileInfo check_file(m_compatibility_filename);
const auto modified_delta = check_file.lastModified() - QDateTime::currentDateTime(); const auto modified_delta = QDateTime::currentDateTime() - check_file.lastModified();
if (check_file.exists() && check_file.isFile() && std::chrono::duration_cast<std::chrono::minutes>(modified_delta).count() < 60) { if (check_file.exists() && check_file.isFile() &&
std::chrono::duration_cast<std::chrono::minutes>(modified_delta).count() < 60) {
if (LoadCompatibilityFile()) if (LoadCompatibilityFile())
return; return;
QMessageBox::critical(parent, tr("Error"), QMessageBox::critical(parent, tr("Error"),
@ -46,9 +47,10 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
if (reply->error() != QNetworkReply::NoError) { if (reply->error() != QNetworkReply::NoError) {
reply->deleteLater(); reply->deleteLater();
QMessageBox::critical(parent, tr("Error"), QMessageBox::critical(
tr("Unable to update compatibility data! Using old compatibility data...")); parent, tr("Error"),
//TODO: Try loading compatibility_file.json again tr("Unable to update compatibility data! Using old compatibility data..."));
// Try loading compatibility_file.json again
LoadCompatibilityFile(); LoadCompatibilityFile();
return; return;
} }
@ -87,8 +89,7 @@ void CompatibilityInfoClass::UpdateCompatibilityDatabase(QWidget* parent) {
dialog.reset(); dialog.reset();
}); });
connect(&dialog, &QProgressDialog::canceled, &future_watcher, connect(&dialog, &QProgressDialog::canceled, &future_watcher, &QFutureWatcher<void>::cancel);
&QFutureWatcher<void>::cancel);
dialog.setRange(0, remaining_pages); dialog.setRange(0, remaining_pages);
connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &dialog, connect(&future_watcher, &QFutureWatcher<void>::progressValueChanged, &dialog,
&QProgressDialog::setValue); &QProgressDialog::setValue);
@ -117,7 +118,7 @@ void CompatibilityInfoClass::WaitForReply(QNetworkReply* reply) {
return; return;
}; };
CompatibilityStatus CompatibilityInfoClass::GetCompatibilityStatus(const std::string& serial) { CompatibilityEntry CompatibilityInfoClass::GetCompatibilityInfo(const std::string& serial) {
QString title_id = QString::fromStdString(serial); QString title_id = QString::fromStdString(serial);
if (m_compatibility_database.contains(title_id)) { if (m_compatibility_database.contains(title_id)) {
{ {
@ -125,13 +126,18 @@ CompatibilityStatus CompatibilityInfoClass::GetCompatibilityStatus(const std::st
QString os_string = OSTypeToString.at(static_cast<OSType>(os_int)); QString os_string = OSTypeToString.at(static_cast<OSType>(os_int));
QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject(); QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject();
if (compatibility_obj.contains(os_string)) { if (compatibility_obj.contains(os_string)) {
return LabelToCompatStatus.at( QJsonObject compatibility_entry_obj = compatibility_obj[os_string].toObject();
compatibility_obj[os_string].toString()); 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() { bool CompatibilityInfoClass::LoadCompatibilityFile() {
@ -152,7 +158,6 @@ bool CompatibilityInfoClass::LoadCompatibilityFile() {
return true; return true;
} }
void CompatibilityInfoClass::ExtractCompatibilityInfo(QByteArray response) { void CompatibilityInfoClass::ExtractCompatibilityInfo(QByteArray response) {
QJsonDocument json_doc(QJsonDocument::fromJson(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()) { QJsonObject compatibility_obj = m_compatibility_database[title_id].toObject();
compatibility_object_ref = QJsonObject({{current_os, compatibility_status}});
} else { QJsonObject compatibility_data{
compatibility_object_ref.toObject()[current_os] = compatibility_status; {{"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;
} }
} }

View File

@ -42,6 +42,12 @@ enum OSType {
Last Last
}; };
struct CompatibilityEntry {
CompatibilityStatus status;
QString version;
QDateTime last_tested;
};
class CompatibilityInfoClass : public QObject { class CompatibilityInfoClass : public QObject {
Q_OBJECT Q_OBJECT
public: public:
@ -75,7 +81,7 @@ public:
~CompatibilityInfoClass(); ~CompatibilityInfoClass();
void UpdateCompatibilityDatabase(QWidget* parent = nullptr); void UpdateCompatibilityDatabase(QWidget* parent = nullptr);
bool LoadCompatibilityFile(); bool LoadCompatibilityFile();
CompatibilityStatus GetCompatibilityStatus(const std::string& serial); CompatibilityEntry GetCompatibilityInfo(const std::string& serial);
void ExtractCompatibilityInfo(QByteArray response); void ExtractCompatibilityInfo(QByteArray response);
static void WaitForReply(QNetworkReply* reply); static void WaitForReply(QNetworkReply* reply);
QNetworkReply* FetchPage(int page_num); QNetworkReply* FetchPage(int page_num);

View File

@ -8,8 +8,8 @@
#include "game_list_utils.h" #include "game_list_utils.h"
#include <QToolTip> #include <QToolTip>
GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get, GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
std::shared_ptr<CompatibilityInfoClass> compat_info_get, std::shared_ptr<CompatibilityInfoClass> compat_info_get,
QWidget* parent) QWidget* parent)
: QTableWidget(parent), m_game_info(game_info_get), m_compat_info(compat_info_get) { : QTableWidget(parent), m_game_info(game_info_get), m_compat_info(compat_info_get) {
icon_size = Config::getIconSize(); icon_size = Config::getIconSize();
@ -22,7 +22,7 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
this->verticalScrollBar()->installEventFilter(this); this->verticalScrollBar()->installEventFilter(this);
this->verticalScrollBar()->setSingleStep(20); this->verticalScrollBar()->setSingleStep(20);
this->horizontalScrollBar()->setSingleStep(20); this->horizontalScrollBar()->setSingleStep(20);
this->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); this->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
this->verticalHeader()->setVisible(false); this->verticalHeader()->setVisible(false);
this->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu); this->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
this->horizontalHeader()->setHighlightSections(false); this->horizontalHeader()->setHighlightSections(false);
@ -44,8 +44,8 @@ GameListFrame::GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
this->setHorizontalHeaderLabels(headers); this->setHorizontalHeaderLabels(headers);
this->horizontalHeader()->setSortIndicatorShown(true); this->horizontalHeader()->setSortIndicatorShown(true);
this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents); this->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
this->horizontalHeader()->setSectionResizeMode(2, QHeaderView::Fixed);
this->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed); this->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Fixed);
this->horizontalHeader()->setSectionResizeMode(4, QHeaderView::Fixed);
PopulateGameList(); PopulateGameList();
connect(this, &QTableWidget::currentCellChanged, this, &GameListFrame::onCurrentCellChanged); 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, 6, QString::fromStdString(m_game_info->m_games[i].size));
SetTableItem(i, 7, QString::fromStdString(m_game_info->m_games[i].version)); SetTableItem(i, 7, QString::fromStdString(m_game_info->m_games[i].version));
m_game_info->m_games[i].compatibility_status = m_game_info->m_games[i].compatibility =
m_compat_info->GetCompatibilityStatus(m_game_info->m_games[i].serial); m_compat_info->GetCompatibilityInfo(m_game_info->m_games[i].serial);
SetCompatibilityItem(i, 2, m_game_info->m_games[i].compatibility_status); SetCompatibilityItem(i, 2, m_game_info->m_games[i].compatibility);
QString playTime = GetPlayTime(m_game_info->m_games[i].serial); QString playTime = GetPlayTime(m_game_info->m_games[i].serial);
if (playTime.isEmpty()) { if (playTime.isEmpty()) {
@ -213,7 +213,7 @@ void GameListFrame::ResizeIcons(int iconSize) {
this->horizontalHeader()->setSectionResizeMode(8, QHeaderView::ResizeToContents); 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(); QTableWidgetItem* item = new QTableWidgetItem();
QWidget* widget = new QWidget(this); QWidget* widget = new QWidget(this);
QGridLayout* layout = new QGridLayout(widget); QGridLayout* layout = new QGridLayout(widget);
@ -221,7 +221,7 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityStatu
QColor color; QColor color;
QString tooltip_string; QString tooltip_string;
switch (status) { switch (entry.status) {
case Unknown: case Unknown:
color = QStringLiteral("#000000"); color = QStringLiteral("#000000");
tooltip_string = tr("Compatibility is untested"); tooltip_string = tr("Compatibility is untested");
@ -259,9 +259,9 @@ void GameListFrame::SetCompatibilityItem(int row, int column, CompatibilityStatu
QLabel* dotLabel = new QLabel("", widget); QLabel* dotLabel = new QLabel("", widget);
dotLabel->setPixmap(circle_pixmap); 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 // Create shadow effect
QGraphicsDropShadowEffect* shadowEffect = new QGraphicsDropShadowEffect(); 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 label->setGraphicsEffect(shadowEffect); // Apply shadow effect to the QLabel
layout->addWidget(dotLabel, 0, 0, -1, 4); QLabel* version_label =
layout->addWidget(label, 0, 4, -1, 4); 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); layout->setAlignment(Qt::AlignLeft);
widget->setLayout(layout); widget->setLayout(layout);
widget->setToolTip(tooltip_string); widget->setToolTip(tooltip_string);

View File

@ -18,7 +18,9 @@
class GameListFrame : public QTableWidget { class GameListFrame : public QTableWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit GameListFrame(std::shared_ptr<GameInfoClass> game_info_get, std::shared_ptr<CompatibilityInfoClass> compat_info_get, QWidget* parent = nullptr); explicit GameListFrame(std::shared_ptr<GameInfoClass> game_info_get,
std::shared_ptr<CompatibilityInfoClass> compat_info_get,
QWidget* parent = nullptr);
Q_SIGNALS: Q_SIGNALS:
void GameListFrameClosed(); void GameListFrameClosed();
@ -34,7 +36,7 @@ public Q_SLOTS:
private: private:
void SetTableItem(int row, int column, QString itemStr); void SetTableItem(int row, int column, QString itemStr);
void SetRegionFlag(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); QString GetPlayTime(const std::string& serial);
QList<QAction*> m_columnActs; QList<QAction*> m_columnActs;
GameInfoClass* game_inf_get = nullptr; GameInfoClass* game_inf_get = nullptr;
@ -66,7 +68,7 @@ public:
case 1: case 1:
return a.name < b.name; return a.name < b.name;
case 2: case 2:
return a.compatibility_status < b.compatibility_status; return a.compatibility.status < b.compatibility.status;
case 3: case 3:
return a.serial.substr(4) < b.serial.substr(4); return a.serial.substr(4) < b.serial.substr(4);
case 4: case 4:
@ -91,7 +93,7 @@ public:
case 1: case 1:
return a.name > b.name; return a.name > b.name;
case 2: case 2:
return a.compatibility_status > b.compatibility_status; return a.compatibility.status > b.compatibility.status;
case 3: case 3:
return a.serial.substr(4) > b.serial.substr(4); return a.serial.substr(4) > b.serial.substr(4);
case 4: case 4:

View File

@ -27,7 +27,7 @@ struct GameInfo {
std::string fw = "Unknown"; std::string fw = "Unknown";
std::string play_time = "Unknown"; std::string play_time = "Unknown";
CompatibilityStatus compatibility_status = CompatibilityStatus::Unknown; CompatibilityEntry compatibility = CompatibilityEntry{CompatibilityStatus::Unknown};
}; };
class GameListUtils { class GameListUtils {