Skip to content

Commit 3db2f4e

Browse files
committed
major update
1 parent 37bc0c7 commit 3db2f4e

File tree

5 files changed

+144
-32
lines changed

5 files changed

+144
-32
lines changed

logo.ico

-39.6 KB
Binary file not shown.

logo2.ico

-66.1 KB
Binary file not shown.

src/mainwindow.cpp

Lines changed: 137 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ MainWindow::MainWindow(QWidget* parent)
9393
, m_restartWorker(nullptr)
9494
, m_fetchingNames(false)
9595
, m_nameFetchSearchId(0)
96+
, m_hasCachedData(false)
9697
{
9798
setWindowTitle("Steam Lua Patcher");
9899
setMinimumSize(900, 600);
@@ -440,16 +441,23 @@ void MainWindow::displayRandomGames() {
440441
for (int i = 0; i < count; ++i) {
441442
const GameInfo& game = shuffled[i];
442443

444+
// Apply name cache for games with unknown names
445+
QString displayName = game.name;
446+
if (displayName.isEmpty() || displayName.startsWith("Unknown Game") || displayName == game.id) {
447+
if (m_nameCache.contains(game.id)) {
448+
displayName = m_nameCache[game.id];
449+
} else {
450+
displayName = "Loading...";
451+
m_pendingNameFetchIds.append(game.id);
452+
}
453+
}
454+
443455
QMap<QString, QString> cd;
444-
cd["name"] = (game.name.isEmpty() || game.name == game.id || game.name == "Unknown Game")
445-
? "Loading..." : game.name;
456+
cd["name"] = displayName;
446457
cd["appid"] = game.id;
447458
cd["supported"] = "true";
448459
cd["hasFix"] = game.hasFix ? "true" : "false";
449460

450-
if (game.name.isEmpty() || game.name == game.id || game.name == "Unknown Game")
451-
m_pendingNameFetchIds.append(game.id);
452-
453461
GameCard* card = new GameCard(m_gridContainer);
454462
card->setGameData(cd);
455463
connect(card, &GameCard::clicked, this, &MainWindow::onCardClicked);
@@ -468,8 +476,6 @@ void MainWindow::displayRandomGames() {
468476
m_statusLabel->setText(QString("Showing %1 random games").arg(m_gameCards.count()));
469477
m_stack->setCurrentIndex(1);
470478
m_spinner->stop();
471-
m_stack->setCurrentIndex(1);
472-
m_spinner->stop();
473479
}
474480

475481
// ---- Display installed patches (Library) ----
@@ -544,37 +550,111 @@ void MainWindow::displayLibrary() {
544550

545551
// ---- Sync ----
546552
void MainWindow::startSync() {
547-
clearGameCards();
548-
549-
for (int i = 0; i < 12; ++i) {
550-
GameCard* card = new GameCard(m_gridContainer);
551-
card->setSkeleton(true);
552-
m_gridLayout->addWidget(card, i / 3, i % 3);
553-
m_gameCards.append(card);
553+
// Load persistent name cache from disk
554+
loadNameCache();
555+
556+
// Try to load cached index for instant display
557+
if (loadCachedIndex()) {
558+
m_hasCachedData = true;
559+
m_statusLabel->setText("Syncing in background...");
560+
} else {
561+
// No cache available - show skeleton placeholders
562+
m_hasCachedData = false;
563+
clearGameCards();
564+
for (int i = 0; i < 12; ++i) {
565+
GameCard* card = new GameCard(m_gridContainer);
566+
card->setSkeleton(true);
567+
m_gridLayout->addWidget(card, i / 3, i % 3);
568+
m_gameCards.append(card);
569+
}
570+
m_stack->setCurrentIndex(1);
571+
m_spinner->stop();
554572
}
555-
556-
m_stack->setCurrentIndex(1);
557-
m_spinner->stop();
573+
574+
// Always start background sync to get fresh data
558575
m_syncWorker = new IndexDownloadWorker(this);
559576
connect(m_syncWorker, &IndexDownloadWorker::finished, this, &MainWindow::onSyncDone);
560-
connect(m_syncWorker, &IndexDownloadWorker::progress, m_statusLabel, &QLabel::setText);
577+
connect(m_syncWorker, &IndexDownloadWorker::progress, [this](QString msg) {
578+
// Only show sync progress if we don't already have cached data displayed
579+
if (!m_hasCachedData) m_statusLabel->setText(msg);
580+
});
561581
connect(m_syncWorker, &IndexDownloadWorker::error, this, &MainWindow::onSyncError);
562582
m_syncWorker->start();
563583
}
564584

565-
void MainWindow::onSyncDone(QList<GameInfo> games) {
585+
bool MainWindow::loadCachedIndex() {
586+
QString indexPath = Paths::getLocalIndexPath();
587+
if (!QFile::exists(indexPath)) return false;
588+
589+
QFile file(indexPath);
590+
if (!file.open(QIODevice::ReadOnly)) return false;
591+
592+
QByteArray data = file.readAll();
593+
file.close();
594+
595+
QJsonDocument doc = QJsonDocument::fromJson(data);
596+
QJsonObject indexData = doc.object();
597+
QJsonArray arr = indexData["games"].toArray();
598+
if (arr.isEmpty()) return false;
599+
600+
// Parse games and apply name cache
601+
QList<GameInfo> games;
602+
games.reserve(arr.size());
603+
for (const QJsonValue& val : arr) {
604+
QJsonObject obj = val.toObject();
605+
GameInfo game;
606+
game.id = obj["id"].toString();
607+
game.name = obj["name"].toString();
608+
// Apply cached name if the index has an unknown name
609+
if (game.name.startsWith("Unknown Game") && m_nameCache.contains(game.id)) {
610+
game.name = m_nameCache[game.id];
611+
}
612+
game.hasFix = obj["has_fix"].toBool(false);
613+
games.append(game);
614+
}
615+
566616
m_supportedGames = games;
567-
m_spinner->stop();
568-
m_stack->setCurrentIndex(1);
569-
m_statusLabel->setText("Ready");
570617
m_searchInput->setFocus();
571-
if (!m_searchInput->text().isEmpty()) {
572-
doSearch();
573-
} else if (m_currentMode == AppMode::LuaPatcher) {
618+
619+
// Display immediately
620+
if (m_currentMode == AppMode::LuaPatcher) {
574621
displayRandomGames();
575622
} else if (m_currentMode == AppMode::Library) {
576623
displayLibrary();
577624
}
625+
return true;
626+
}
627+
628+
void MainWindow::onSyncDone(QList<GameInfo> games) {
629+
// Apply name cache to freshly downloaded data
630+
for (GameInfo& game : games) {
631+
if (game.name.startsWith("Unknown Game") && m_nameCache.contains(game.id)) {
632+
game.name = m_nameCache[game.id];
633+
}
634+
}
635+
m_supportedGames = games;
636+
m_spinner->stop();
637+
m_stack->setCurrentIndex(1);
638+
639+
if (m_hasCachedData) {
640+
// Background refresh done - only re-display if user isn't searching
641+
m_hasCachedData = false;
642+
m_statusLabel->setText(QString("Ready • %1 games").arg(m_supportedGames.size()));
643+
if (m_searchInput->text().trimmed().isEmpty()) {
644+
// Don't disrupt the user, just update data silently
645+
}
646+
} else {
647+
// First load (no cache was available)
648+
m_statusLabel->setText("Ready");
649+
m_searchInput->setFocus();
650+
if (!m_searchInput->text().isEmpty()) {
651+
doSearch();
652+
} else if (m_currentMode == AppMode::LuaPatcher) {
653+
displayRandomGames();
654+
} else if (m_currentMode == AppMode::Library) {
655+
displayLibrary();
656+
}
657+
}
578658
}
579659

580660
void MainWindow::onSyncError(QString error) {
@@ -1070,7 +1150,8 @@ void MainWindow::startBatchNameFetch() {
10701150
m_nameFetchSearchId = m_currentSearchId;
10711151
m_spinner->start();
10721152
m_statusLabel->setText(QString("Found %1 results %2 Fetching game names...").arg(m_gameCards.count()).arg(QChar(0x2022)));
1073-
for (int i = 0; i < 5 && !m_pendingNameFetchIds.isEmpty(); ++i) processNextNameFetch();
1153+
// Fetch all displayed cards concurrently for faster loading
1154+
for (int i = 0; i < 12 && !m_pendingNameFetchIds.isEmpty(); ++i) processNextNameFetch();
10741155
}
10751156

10761157
void MainWindow::processNextNameFetch() {
@@ -1131,6 +1212,10 @@ void MainWindow::onGameNameFetched(QNetworkReply* reply) {
11311212
}
11321213

11331214
if (!gameName.isEmpty()) {
1215+
// Persist to name cache so we never fetch this again
1216+
m_nameCache[appId] = gameName;
1217+
saveNameCache();
1218+
11341219
for (GameCard* card : m_gameCards) {
11351220
if (card->appId() == appId) {
11361221
QMap<QString, QString> d = card->gameData();
@@ -1180,3 +1265,29 @@ void MainWindow::onThumbnailDownloaded(QNetworkReply* reply) {
11801265
}
11811266
}
11821267
}
1268+
1269+
// ---- Persistent name cache ----
1270+
void MainWindow::loadNameCache() {
1271+
QString path = QDir(Paths::getLocalCacheDir()).filePath("name_cache.json");
1272+
QFile file(path);
1273+
if (!file.open(QIODevice::ReadOnly)) return;
1274+
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
1275+
file.close();
1276+
QJsonObject obj = doc.object();
1277+
for (auto it = obj.begin(); it != obj.end(); ++it) {
1278+
m_nameCache[it.key()] = it.value().toString();
1279+
}
1280+
}
1281+
1282+
void MainWindow::saveNameCache() {
1283+
QString path = QDir(Paths::getLocalCacheDir()).filePath("name_cache.json");
1284+
QJsonObject obj;
1285+
for (auto it = m_nameCache.begin(); it != m_nameCache.end(); ++it) {
1286+
obj[it.key()] = it.value();
1287+
}
1288+
QFile file(path);
1289+
if (file.open(QIODevice::WriteOnly)) {
1290+
file.write(QJsonDocument(obj).toJson(QJsonDocument::Compact));
1291+
file.close();
1292+
}
1293+
}

src/mainwindow.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,9 @@ private slots:
7676
void clearGameCards();
7777
void displayRandomGames();
7878
void displayLibrary();
79+
void loadNameCache();
80+
void saveNameCache();
81+
bool loadCachedIndex();
7982

8083
// UI Components
8184
QLabel* m_statusLabel;
@@ -124,6 +127,9 @@ private slots:
124127
QList<QNetworkReply*> m_activeNameFetches;
125128
bool m_fetchingNames;
126129
int m_nameFetchSearchId;
130+
// Persistent name cache (appId -> gameName)
131+
QMap<QString, QString> m_nameCache;
132+
bool m_hasCachedData; // true if we loaded from cache on startup
127133
// Thumbnail cache
128134
QMap<QString, QPixmap> m_thumbnailCache;
129135
QSet<QString> m_activeThumbnailDownloads;

src/workers/indexdownloadworker.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,7 @@ void IndexDownloadWorker::run() {
3030
QString indexPath = Paths::getLocalIndexPath();
3131
QJsonObject indexData;
3232

33-
// Explicitly remove old cache as requested
34-
if (QFile::exists(indexPath)) {
35-
QFile::remove(indexPath);
36-
}
37-
38-
// Try to download
33+
// Try to download (cache is preserved for instant startup)
3934
emit progress("Syncing library...");
4035

4136
QNetworkAccessManager manager;

0 commit comments

Comments
 (0)