From 881b2f2b385f19d9b64a149fca3c3741a803a172 Mon Sep 17 00:00:00 2001 From: flow Date: Wed, 2 Mar 2022 18:35:59 -0300 Subject: [PATCH 01/18] refactor: Use a single indexed pack for mods Since there's little difference between them, let's remove duplication and merge them. --- launcher/modplatform/ModIndex.h | 42 +++++++++++ launcher/modplatform/flame/FlameModIndex.cpp | 62 ++++++++--------- launcher/modplatform/flame/FlameModIndex.h | 48 +++---------- .../modrinth/ModrinthPackIndex.cpp | 69 +++++++++---------- .../modplatform/modrinth/ModrinthPackIndex.h | 48 +++---------- .../pages/modplatform/flame/FlameModModel.cpp | 6 +- .../pages/modplatform/flame/FlameModModel.h | 2 +- .../pages/modplatform/flame/FlameModPage.cpp | 6 +- .../ui/pages/modplatform/flame/FlameModPage.h | 2 +- .../modplatform/modrinth/ModrinthModel.cpp | 6 +- .../modplatform/modrinth/ModrinthModel.h | 2 +- .../modplatform/modrinth/ModrinthPage.cpp | 8 +-- .../pages/modplatform/modrinth/ModrinthPage.h | 2 +- 13 files changed, 137 insertions(+), 166 deletions(-) create mode 100644 launcher/modplatform/ModIndex.h diff --git a/launcher/modplatform/ModIndex.h b/launcher/modplatform/ModIndex.h new file mode 100644 index 000000000..7e1cf254e --- /dev/null +++ b/launcher/modplatform/ModIndex.h @@ -0,0 +1,42 @@ +#pragma once + +#include +#include +#include +#include +#include + +namespace ModPlatform { + +struct ModpackAuthor { + QString name; + QString url; +}; + +struct IndexedVersion { + QVariant addonId; + QVariant fileId; + QString version; + QVector mcVersion; + QString downloadUrl; + QString date; + QString fileName; + QVector loaders = {}; +}; + +struct IndexedPack { + QVariant addonId; + QString name; + QString description; + QList authors; + QString logoName; + QString logoUrl; + QString websiteUrl; + + bool versionsLoaded = false; + QVector versions; +}; + +} // namespace ModPlatform + +Q_DECLARE_METATYPE(ModPlatform::IndexedPack) diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 4adaf5f16..61cb534ce 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -1,13 +1,11 @@ -#include #include "FlameModIndex.h" + #include "Json.h" -#include "net/NetJob.h" -#include "BaseInstance.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" +#include "net/NetJob.h" - -void FlameMod::loadIndexedPack(FlameMod::IndexedPack & pack, QJsonObject & obj) +void FlameMod::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) { pack.addonId = Json::requireInteger(obj, "id"); pack.name = Json::requireString(obj, "name"); @@ -16,10 +14,10 @@ void FlameMod::loadIndexedPack(FlameMod::IndexedPack & pack, QJsonObject & obj) bool thumbnailFound = false; auto attachments = Json::requireArray(obj, "attachments"); - for(auto attachmentRaw: attachments) { + for (auto attachmentRaw : attachments) { auto attachmentObj = Json::requireObject(attachmentRaw); bool isDefault = attachmentObj.value("isDefault").toBool(false); - if(isDefault) { + if (isDefault) { thumbnailFound = true; pack.logoName = Json::requireString(attachmentObj, "title"); pack.logoUrl = Json::requireString(attachmentObj, "thumbnailUrl"); @@ -27,37 +25,35 @@ void FlameMod::loadIndexedPack(FlameMod::IndexedPack & pack, QJsonObject & obj) } } - if(!thumbnailFound) { - throw JSONValidationError(QString("Pack without an icon, skipping: %1").arg(pack.name)); - } - + if (!thumbnailFound) { throw JSONValidationError(QString("Pack without an icon, skipping: %1").arg(pack.name)); } auto authors = Json::requireArray(obj, "authors"); - for(auto authorIter: authors) { + for (auto authorIter : authors) { auto author = Json::requireObject(authorIter); - FlameMod::ModpackAuthor packAuthor; + ModPlatform::ModpackAuthor packAuthor; packAuthor.name = Json::requireString(author, "name"); packAuthor.url = Json::requireString(author, "url"); pack.authors.append(packAuthor); } } -void FlameMod::loadIndexedPackVersions(FlameMod::IndexedPack & pack, QJsonArray & arr, const shared_qobject_ptr& network, BaseInstance * inst) +void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, + QJsonArray& arr, + const shared_qobject_ptr& network, + BaseInstance* inst) { - QVector unsortedVersions; - bool hasFabric = !((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); - QString mcVersion = ((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.minecraft"); + QVector unsortedVersions; + bool hasFabric = !((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); + QString mcVersion = ((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.minecraft"); - for(auto versionIter: arr) { + for (auto versionIter : arr) { auto obj = versionIter.toObject(); auto versionArray = Json::requireArray(obj, "gameVersion"); - if (versionArray.isEmpty()) { - continue; - } + if (versionArray.isEmpty()) { continue; } - FlameMod::IndexedVersion file; - for(auto mcVer : versionArray){ + ModPlatform::IndexedVersion file; + for (auto mcVer : versionArray) { file.mcVersion.append(mcVer.toString()); } @@ -70,29 +66,27 @@ void FlameMod::loadIndexedPackVersions(FlameMod::IndexedPack & pack, QJsonArray auto modules = Json::requireArray(obj, "modules"); bool is_valid_fabric_version = false; - for(auto m : modules){ - auto fname = Json::requireString(m.toObject(),"foldername"); + for (auto m : modules) { + auto fname = Json::requireString(m.toObject(), "foldername"); // FIXME: This does not work properly when a mod supports more than one mod loader, since // they bundle the meta files for all of them in the same arquive, even when that version // doesn't support the given mod loader. - if(hasFabric){ - if(fname == "fabric.mod.json"){ + if (hasFabric) { + if (fname == "fabric.mod.json") { is_valid_fabric_version = true; break; } - } - else break; + } else + break; // NOTE: Since we're not validating forge versions, we can just skip this loop. } - if(hasFabric && !is_valid_fabric_version) - continue; + if (hasFabric && !is_valid_fabric_version) continue; unsortedVersions.append(file); } - auto orderSortPredicate = [](const IndexedVersion & a, const IndexedVersion & b) -> bool - { - //dates are in RFC 3339 format + auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool { + // dates are in RFC 3339 format return a.date > b.date; }; std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate); diff --git a/launcher/modplatform/flame/FlameModIndex.h b/launcher/modplatform/flame/FlameModIndex.h index 0293bb230..34f71498e 100644 --- a/launcher/modplatform/flame/FlameModIndex.h +++ b/launcher/modplatform/flame/FlameModIndex.h @@ -3,48 +3,18 @@ // #pragma once -#include -#include -#include -#include + +#include "modplatform/ModIndex.h" + #include -#include -#include "net/NetJob.h" #include "BaseInstance.h" namespace FlameMod { - struct ModpackAuthor { - QString name; - QString url; - }; - struct IndexedVersion { - int addonId; - int fileId; - QString version; - QVector mcVersion; - QString downloadUrl; - QString date; - QString fileName; - }; +void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj); +void loadIndexedPackVersions(ModPlatform::IndexedPack& pack, + QJsonArray& arr, + const shared_qobject_ptr& network, + BaseInstance* inst); - struct IndexedPack - { - int addonId; - QString name; - QString description; - QList authors; - QString logoName; - QString logoUrl; - QString websiteUrl; - - bool versionsLoaded = false; - QVector versions; - }; - - void loadIndexedPack(IndexedPack & m, QJsonObject & obj); - void loadIndexedPackVersions(IndexedPack &pack, QJsonArray &arr, const shared_qobject_ptr &network, BaseInstance *inst); - -} - -Q_DECLARE_METATYPE(FlameMod::IndexedPack) +} // namespace FlameMod diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 9017eb67d..a59186f76 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -1,14 +1,11 @@ -#include #include "ModrinthPackIndex.h" #include "Json.h" -#include "net/NetJob.h" -#include "BaseInstance.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" +#include "net/NetJob.h" - -void Modrinth::loadIndexedPack(Modrinth::IndexedPack & pack, QJsonObject & obj) +void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) { pack.addonId = Json::requireString(obj, "project_id"); pack.name = Json::requireString(obj, "title"); @@ -16,59 +13,60 @@ void Modrinth::loadIndexedPack(Modrinth::IndexedPack & pack, QJsonObject & obj) pack.description = Json::ensureString(obj, "description", ""); pack.logoUrl = Json::requireString(obj, "icon_url"); - pack.logoName = pack.addonId; + pack.logoName = pack.addonId.toString(); - Modrinth::ModpackAuthor modAuthor; + ModPlatform::ModpackAuthor modAuthor; modAuthor.name = Json::requireString(obj, "author"); - modAuthor.url = "https://modrinth.com/user/"+modAuthor.name; - pack.author = modAuthor; + modAuthor.url = "https://modrinth.com/user/" + modAuthor.name; + pack.authors.append(modAuthor); } -void Modrinth::loadIndexedPackVersions(Modrinth::IndexedPack & pack, QJsonArray & arr, const shared_qobject_ptr& network, BaseInstance * inst) +void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, + QJsonArray& arr, + const shared_qobject_ptr& network, + BaseInstance* inst) { - QVector unsortedVersions; - bool hasFabric = !((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); - QString mcVersion = ((MinecraftInstance *)inst)->getPackProfile()->getComponentVersion("net.minecraft"); + QVector unsortedVersions; + bool hasFabric = !((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); + QString mcVersion = ((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.minecraft"); - for(auto versionIter: arr) { + for (auto versionIter : arr) { auto obj = versionIter.toObject(); - Modrinth::IndexedVersion file; - file.addonId = Json::requireString(obj,"project_id") ; + ModPlatform::IndexedVersion file; + file.addonId = Json::requireString(obj, "project_id"); file.fileId = Json::requireString(obj, "id"); file.date = Json::requireString(obj, "date_published"); auto versionArray = Json::requireArray(obj, "game_versions"); - if (versionArray.empty()) { - continue; - } - for(auto mcVer : versionArray){ + if (versionArray.empty()) { continue; } + for (auto mcVer : versionArray) { file.mcVersion.append(mcVer.toString()); } - auto loaders = Json::requireArray(obj,"loaders"); - for(auto loader : loaders){ + auto loaders = Json::requireArray(obj, "loaders"); + for (auto loader : loaders) { file.loaders.append(loader.toString()); } file.version = Json::requireString(obj, "name"); auto files = Json::requireArray(obj, "files"); int i = 0; - while (files.count() > 1 && i < files.count()){ - //try to resolve the correct file + while (files.count() > 1 && i < files.count()) { + // try to resolve the correct file auto parent = files[i].toObject(); auto fileName = Json::requireString(parent, "filename"); - //avoid grabbing "dev" files - if(fileName.contains("javadocs",Qt::CaseInsensitive) || fileName.contains("sources",Qt::CaseInsensitive)){ + // avoid grabbing "dev" files + if (fileName.contains("javadocs", Qt::CaseInsensitive) || fileName.contains("sources", Qt::CaseInsensitive)) { i++; continue; } - //grab the correct mod loader - if(fileName.contains("forge",Qt::CaseInsensitive) || fileName.contains("fabric",Qt::CaseInsensitive) ){ - if(hasFabric){ - if(fileName.contains("forge",Qt::CaseInsensitive)){ + // grab the correct mod loader + if (fileName.contains("forge", Qt::CaseInsensitive) || fileName.contains("fabric", Qt::CaseInsensitive)) { + if (hasFabric) { + if (fileName.contains("forge", Qt::CaseInsensitive)) { i++; continue; } - }else{ - if(fileName.contains("fabric",Qt::CaseInsensitive)){ + } else { + if (fileName.contains("fabric", Qt::CaseInsensitive)) { i++; continue; } @@ -77,16 +75,15 @@ void Modrinth::loadIndexedPackVersions(Modrinth::IndexedPack & pack, QJsonArray break; } auto parent = files[i].toObject(); - if(parent.contains("url")) { + if (parent.contains("url")) { file.downloadUrl = Json::requireString(parent, "url"); file.fileName = Json::requireString(parent, "filename"); unsortedVersions.append(file); } } - auto orderSortPredicate = [](const IndexedVersion & a, const IndexedVersion & b) -> bool - { - //dates are in RFC 3339 format + auto orderSortPredicate = [](const ModPlatform::IndexedVersion& a, const ModPlatform::IndexedVersion& b) -> bool { + // dates are in RFC 3339 format return a.date > b.date; }; std::sort(unsortedVersions.begin(), unsortedVersions.end(), orderSortPredicate); diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.h b/launcher/modplatform/modrinth/ModrinthPackIndex.h index 3a4cd2707..abfdabb69 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.h +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.h @@ -1,48 +1,16 @@ #pragma once -#include -#include -#include -#include +#include "modplatform/ModIndex.h" + #include -#include -#include "net/NetJob.h" #include "BaseInstance.h" namespace Modrinth { -struct ModpackAuthor { - QString name; - QString url; -}; +void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj); +void loadIndexedPackVersions(ModPlatform::IndexedPack& pack, + QJsonArray& arr, + const shared_qobject_ptr& network, + BaseInstance* inst); -struct IndexedVersion { - QString addonId; - QString fileId; - QString version; - QVector mcVersion; - QString downloadUrl; - QString date; - QString fileName; - QVector loaders; -}; - -struct IndexedPack -{ - QString addonId; - QString name; - QString description; - ModpackAuthor author; - QString logoName; - QString logoUrl; - QString websiteUrl; - - bool versionsLoaded = false; - QVector versions; -}; - -void loadIndexedPack(IndexedPack & m, QJsonObject & obj); -void loadIndexedPackVersions(IndexedPack &pack, QJsonArray &arr, const shared_qobject_ptr &network, BaseInstance *inst); -} - -Q_DECLARE_METATYPE(Modrinth::IndexedPack) +} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index e8afba5a1..052f30d17 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -39,7 +39,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const return QString("INVALID INDEX %1").arg(pos); } - IndexedPack pack = modpacks.at(pos); + ModPlatform::IndexedPack pack = modpacks.at(pos); if(role == Qt::DisplayRole) { return pack.name; @@ -225,12 +225,12 @@ void ListModel::searchRequestFinished() return; } - QList newList; + QList newList; auto packs = doc.array(); for(auto packRaw : packs) { auto packObj = packRaw.toObject(); - FlameMod::IndexedPack pack; + ModPlatform::IndexedPack pack; try { FlameMod::loadIndexedPack(pack, packObj); diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index 0c1cb95e4..ec19ab2f4 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -57,7 +57,7 @@ private: void requestLogo(QString file, QString url); private: - QList modpacks; + QList modpacks; QStringList m_failedLogos; QStringList m_loadingLogos; LogoMap m_logoMap; diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 114ac9070..48d38b821 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -77,7 +77,7 @@ void FlameModPage::onSelectionChanged(QModelIndex first, QModelIndex second) { return; } - current = listModel->data(first, Qt::UserRole).value(); + current = listModel->data(first, Qt::UserRole).value(); QString text = ""; QString name = current.name; @@ -86,7 +86,7 @@ void FlameModPage::onSelectionChanged(QModelIndex first, QModelIndex second) { else text = "" + name + ""; if (!current.authors.empty()) { - auto authorToStr = [](FlameMod::ModpackAuthor &author) { + auto authorToStr = [](ModPlatform::ModpackAuthor &author) { if (author.url.isEmpty()) { return author.name; } @@ -112,7 +112,7 @@ void FlameModPage::onSelectionChanged(QModelIndex first, QModelIndex second) { new NetJob(QString("Flame::ModVersions(%1)").arg(current.name), APPLICATION->network()); auto response = new QByteArray(); - int addonId = current.addonId; + int addonId = current.addonId.toInt(); netJob->addNetAction(Net::Download::makeByteArray( QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files") .arg(addonId), diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index b5b19a4f3..24dfcbc72 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -62,7 +62,7 @@ private: Ui::FlameModPage *ui = nullptr; ModDownloadDialog* dialog = nullptr; FlameMod::ListModel* listModel = nullptr; - FlameMod::IndexedPack current; + ModPlatform::IndexedPack current; int selectedVersion = -1; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 5a18830a6..088ca411f 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -41,7 +41,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const return QString("INVALID INDEX %1").arg(pos); } - IndexedPack pack = modpacks.at(pos); + ModPlatform::IndexedPack pack = modpacks.at(pos); if(role == Qt::DisplayRole) { return pack.name; @@ -222,12 +222,12 @@ void Modrinth::ListModel::searchRequestFinished() return; } - QList newList; + QList newList; auto packs = doc.object().value("hits").toArray(); for(auto packRaw : packs) { auto packObj = packRaw.toObject(); - Modrinth::IndexedPack pack; + ModPlatform::IndexedPack pack; try { Modrinth::loadIndexedPack(pack, packObj); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 53f1f134e..20661412b 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -57,7 +57,7 @@ private: void requestLogo(QString file, QString url); private: - QList modpacks; + QList modpacks; QStringList m_failedLogos; QStringList m_loadingLogos; LogoMap m_logoMap; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 35cd743ab..4dfc8504c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -76,7 +76,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) { return; } - current = listModel->data(first, Qt::UserRole).value(); + current = listModel->data(first, Qt::UserRole).value(); QString text = ""; QString name = current.name; @@ -84,8 +84,8 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) { text = name; else text = "" + name + ""; - text += "
" + tr(" by ") + "" + - current.author.name + "

"; + text += "
" + tr(" by ") + "" + + current.authors[0].name + "

"; ui->packDescription->setHtml(text + current.description); if (!current.versionsLoaded) { @@ -98,7 +98,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) { new NetJob(QString("Modrinth::ModVersions(%1)").arg(current.name), APPLICATION->network()); auto response = new QByteArray(); - QString addonId = current.addonId; + QString addonId = current.addonId.toString(); netJob->addNetAction(Net::Download::makeByteArray( QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId), response)); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 52b538e35..1d725d471 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -62,7 +62,7 @@ private: Ui::ModrinthPage *ui = nullptr; ModDownloadDialog* dialog = nullptr; Modrinth::ListModel* listModel = nullptr; - Modrinth::IndexedPack current; + ModPlatform::IndexedPack current; int selectedVersion = -1; }; From 0dd1c26cf3cd68cd83f5d9da6cf34d4aa3f30db2 Mon Sep 17 00:00:00 2001 From: flow Date: Wed, 2 Mar 2022 21:17:10 -0300 Subject: [PATCH 02/18] refactor: extract common code in mod pages and model This creates a hierarchy in which ModPage and ModModel are the parents of every mod provider, providing the basic functionality common to all of them. It also imposes a unique .ui file (they were already equal before, just duplicated basically) on all mod providers. --- launcher/CMakeLists.txt | 8 +- launcher/ui/pages/modplatform/ModModel.cpp | 166 ++++++++++++ launcher/ui/pages/modplatform/ModModel.h | 60 +++++ launcher/ui/pages/modplatform/ModPage.cpp | 152 +++++++++++ launcher/ui/pages/modplatform/ModPage.h | 57 ++++ .../{modrinth/ModrinthPage.ui => ModPage.ui} | 4 +- .../pages/modplatform/flame/FlameModModel.cpp | 223 ++-------------- .../pages/modplatform/flame/FlameModModel.h | 68 +---- .../pages/modplatform/flame/FlameModPage.cpp | 229 +++------------- .../ui/pages/modplatform/flame/FlameModPage.h | 72 +---- .../pages/modplatform/flame/FlameModPage.ui | 97 ------- .../modplatform/modrinth/ModrinthModel.cpp | 245 ++---------------- .../modplatform/modrinth/ModrinthModel.h | 68 +---- .../modplatform/modrinth/ModrinthPage.cpp | 215 +++------------ .../pages/modplatform/modrinth/ModrinthPage.h | 72 +---- 15 files changed, 623 insertions(+), 1113 deletions(-) create mode 100644 launcher/ui/pages/modplatform/ModModel.cpp create mode 100644 launcher/ui/pages/modplatform/ModModel.h create mode 100644 launcher/ui/pages/modplatform/ModPage.cpp create mode 100644 launcher/ui/pages/modplatform/ModPage.h rename launcher/ui/pages/modplatform/{modrinth/ModrinthPage.ui => ModPage.ui} (97%) delete mode 100644 launcher/ui/pages/modplatform/flame/FlameModPage.ui diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 86c05651e..0dcda9257 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -721,6 +721,11 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/VanillaPage.cpp ui/pages/modplatform/VanillaPage.h + ui/pages/modplatform/ModPage.cpp + ui/pages/modplatform/ModPage.h + ui/pages/modplatform/ModModel.cpp + ui/pages/modplatform/ModModel.h + ui/pages/modplatform/atlauncher/AtlFilterModel.cpp ui/pages/modplatform/atlauncher/AtlFilterModel.h ui/pages/modplatform/atlauncher/AtlListModel.cpp @@ -879,13 +884,12 @@ qt5_wrap_ui(LAUNCHER_UI ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui ui/pages/modplatform/atlauncher/AtlPage.ui ui/pages/modplatform/VanillaPage.ui + ui/pages/modplatform/ModPage.ui ui/pages/modplatform/flame/FlamePage.ui - ui/pages/modplatform/flame/FlameModPage.ui ui/pages/modplatform/legacy_ftb/Page.ui ui/pages/modplatform/ImportPage.ui ui/pages/modplatform/ftb/FtbPage.ui ui/pages/modplatform/technic/TechnicPage.ui - ui/pages/modplatform/modrinth/ModrinthPage.ui ui/widgets/InstanceCardWidget.ui ui/widgets/CustomCommands.ui ui/widgets/MCModInfoFrame.ui diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp new file mode 100644 index 000000000..5bd7e33e1 --- /dev/null +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -0,0 +1,166 @@ +#include "ModModel.h" +#include "ModPage.h" + +#include "ui/dialogs/ModDownloadDialog.h" + +#include + +namespace ModPlatform { + +ListModel::ListModel(ModPage* parent) : QAbstractListModel(parent), m_parent(parent) {} + +ListModel::~ListModel() {} + +int ListModel::rowCount(const QModelIndex& parent) const +{ + return modpacks.size(); +} + +int ListModel::columnCount(const QModelIndex& parent) const +{ + return 1; +} + +QVariant ListModel::data(const QModelIndex& index, int role) const +{ + int pos = index.row(); + if (pos >= modpacks.size() || pos < 0 || !index.isValid()) { return QString("INVALID INDEX %1").arg(pos); } + + ModPlatform::IndexedPack pack = modpacks.at(pos); + if (role == Qt::DisplayRole) { + return pack.name; + } else if (role == Qt::ToolTipRole) { + if (pack.description.length() > 100) { + // some magic to prevent to long tooltips and replace html linebreaks + QString edit = pack.description.left(97); + edit = edit.left(edit.lastIndexOf("
")).left(edit.lastIndexOf(" ")).append("..."); + return edit; + } + return pack.description; + } else if (role == Qt::DecorationRole) { + if (m_logoMap.contains(pack.logoName)) { return (m_logoMap.value(pack.logoName)); } + QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); + ((ListModel*)this)->requestLogo(pack.logoName, pack.logoUrl); + return icon; + } else if (role == Qt::UserRole) { + QVariant v; + v.setValue(pack); + return v; + } + + return QVariant(); +} + +void ListModel::logoLoaded(QString logo, QIcon out) +{ + m_loadingLogos.removeAll(logo); + m_logoMap.insert(logo, out); + for (int i = 0; i < modpacks.size(); i++) { + if (modpacks[i].logoName == logo) { emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole }); } + } +} + +void ListModel::logoFailed(QString logo) +{ + m_failedLogos.append(logo); + m_loadingLogos.removeAll(logo); +} + +Qt::ItemFlags ListModel::flags(const QModelIndex& index) const +{ + return QAbstractListModel::flags(index); +} + +bool ListModel::canFetchMore(const QModelIndex& parent) const +{ + return searchState == CanPossiblyFetchMore; +} + +void ListModel::fetchMore(const QModelIndex& parent) +{ + if (parent.isValid()) return; + if (nextSearchOffset == 0) { + qWarning() << "fetchMore with 0 offset is wrong..."; + return; + } + performPaginatedSearch(); +} + +void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) +{ + if (m_logoMap.contains(logo)) { + callback(APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); + } else { + requestLogo(logo, logoUrl); + } +} + +void ListModel::searchWithTerm(const QString& term, const int sort) +{ + if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { return; } + currentSearchTerm = term; + currentSort = sort; + if (jobPtr) { + jobPtr->abort(); + searchState = ResetRequested; + return; + } else { + beginResetModel(); + modpacks.clear(); + endResetModel(); + searchState = None; + } + nextSearchOffset = 0; + performPaginatedSearch(); +} + +void ListModel::searchRequestFailed(QString reason) +{ + if (jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { + // 409 Gone, notify user to update + QMessageBox::critical(nullptr, tr("Error"), + QString("%1 %2") + .arg(m_parent->displayName()) + .arg(tr("API version too old!\nPlease update PolyMC!"))); + // self-destruct + ((ModDownloadDialog*)((ModPage*)parent())->parentWidget())->reject(); + } + jobPtr.reset(); + + if (searchState == ResetRequested) { + beginResetModel(); + modpacks.clear(); + endResetModel(); + + nextSearchOffset = 0; + performPaginatedSearch(); + } else { + searchState = Finished; + } +} + +void ListModel::requestLogo(QString logo, QString url) +{ + if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) { return; } + + MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); + job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + + auto fullPath = entry->getFullPath(); + QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { + job->deleteLater(); + emit logoLoaded(logo, QIcon(fullPath)); + if (waitingCallbacks.contains(logo)) { waitingCallbacks.value(logo)(fullPath); } + }); + + QObject::connect(job, &NetJob::failed, this, [this, logo, job] { + job->deleteLater(); + emit logoFailed(logo); + }); + + job->start(); + m_loadingLogos.append(logo); +} + +} // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h new file mode 100644 index 000000000..ae8ceb7c3 --- /dev/null +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -0,0 +1,60 @@ +#pragma once + +#include + +#include "modplatform/ModIndex.h" +#include "net/NetJob.h" + +class ModPage; + +namespace ModPlatform { + +typedef QMap LogoMap; +typedef std::function LogoCallback; + +class ListModel : public QAbstractListModel { + Q_OBJECT + + public: + ListModel(ModPage* parent); + virtual ~ListModel(); + + int rowCount(const QModelIndex& parent) const override; + int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; + Qt::ItemFlags flags(const QModelIndex& index) const override; + bool canFetchMore(const QModelIndex& parent) const override; + void fetchMore(const QModelIndex& parent) override; + + void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); + void searchWithTerm(const QString& term, const int sort); + + protected slots: + virtual void performPaginatedSearch() = 0; + virtual void searchRequestFinished() = 0; + + void logoFailed(QString logo); + void logoLoaded(QString logo, QIcon out); + + void searchRequestFailed(QString reason); + + protected: + void requestLogo(QString file, QString url); + + protected: + ModPage* m_parent; + + QList modpacks; + QStringList m_failedLogos; + QStringList m_loadingLogos; + LogoMap m_logoMap; + QMap waitingCallbacks; + + QString currentSearchTerm; + int currentSort = 0; + int nextSearchOffset = 0; + enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; + NetJob::Ptr jobPtr; + QByteArray response; +}; +} // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp new file mode 100644 index 000000000..8af534a6f --- /dev/null +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -0,0 +1,152 @@ +#include "ModPage.h" +#include "ui_ModPage.h" + +#include + +#include "ui/dialogs/ModDownloadDialog.h" + +ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance) + : QWidget(dialog), m_instance(instance), ui(new Ui::ModPage), dialog(dialog) +{ + ui->setupUi(this); + connect(ui->searchButton, &QPushButton::clicked, this, &ModPage::triggerSearch); + ui->searchEdit->installEventFilter(this); + + ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); + +} + +ModPage::~ModPage() +{ + delete ui; +} + +void ModPage::openedImpl() +{ + updateSelectionButton(); + triggerSearch(); +} + +bool ModPage::eventFilter(QObject* watched, QEvent* event) +{ + if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Return) { + triggerSearch(); + keyEvent->accept(); + return true; + } + } + return QWidget::eventFilter(watched, event); +} + +void ModPage::updateSelectionButton() +{ + if (!isOpened || selectedVersion < 0) { + ui->modSelectionButton->setEnabled(false); + return; + } + + ui->modSelectionButton->setEnabled(true); + auto& version = current.versions[selectedVersion]; + if (!dialog->isModSelected(current.name, version.fileName)) { + ui->modSelectionButton->setText(tr("Select mod for download")); + } else { + ui->modSelectionButton->setText(tr("Deselect mod for download")); + } +} + +void ModPage::triggerSearch() +{ + listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex()); +} + +void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) +{ + ui->versionSelectionBox->clear(); + + if (!first.isValid()) { return; } + + current = listModel->data(first, Qt::UserRole).value(); + QString text = ""; + QString name = current.name; + + if (current.websiteUrl.isEmpty()) + text = name; + else + text = "" + name + ""; + + if (!current.authors.empty()) { + auto authorToStr = [](ModPlatform::ModpackAuthor& author) { + if (author.url.isEmpty()) { return author.name; } + return QString("%2").arg(author.url, author.name); + }; + QStringList authorStrs; + for (auto& author : current.authors) { + authorStrs.push_back(authorToStr(author)); + } + text += "
" + tr(" by ") + authorStrs.join(", "); + } + text += "

"; + + ui->packDescription->setHtml(text + current.description); + + if (!current.versionsLoaded) { + qDebug() << QString("Loading %1 mod versions").arg(debugName()); + + ui->modSelectionButton->setText(tr("Loading versions...")); + ui->modSelectionButton->setEnabled(false); + + auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName()).arg(current.name), APPLICATION->network()); + auto response = new QByteArray(); + QString addonId = current.addonId.toString(); + //FIXME + if(debugName() == "Modrinth") + netJob->addNetAction( + Net::Download::makeByteArray(QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId), response)); + else + netJob->addNetAction( + Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ + onModVersionSucceed(this, response, addonId); + }); + + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + + netJob->start(); + } else { + for (int i = 0; i < current.versions.size(); i++) { + ui->versionSelectionBox->addItem(current.versions[i].version, QVariant(i)); + } + if (ui->versionSelectionBox->count() == 0) { ui->versionSelectionBox->addItem(tr("No Valid Version found !"), QVariant(-1)); } + + updateSelectionButton(); + } +} + +void ModPage::onVersionSelectionChanged(QString data) +{ + if (data.isNull() || data.isEmpty()) { + selectedVersion = -1; + return; + } + selectedVersion = ui->versionSelectionBox->currentData().toInt(); + updateSelectionButton(); +} + +void ModPage::onModSelected() +{ + auto& version = current.versions[selectedVersion]; + if (dialog->isModSelected(current.name, version.fileName)) { + dialog->removeSelectedMod(current.name); + } else { + dialog->addSelectedMod(current.name, new ModDownloadTask(version.downloadUrl, version.fileName, dialog->mods)); + } + + updateSelectionButton(); +} diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h new file mode 100644 index 000000000..c0102549d --- /dev/null +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -0,0 +1,57 @@ +#pragma once + +#include +#include + +#include "modplatform/ModIndex.h" +#include "tasks/Task.h" +#include "ui/pages/BasePage.h" +#include "ui/pages/modplatform/ModModel.h" + +class ModDownloadDialog; + +namespace Ui { +class ModPage; +} + +class ModPage : public QWidget, public BasePage { + Q_OBJECT + + public: + explicit ModPage(ModDownloadDialog* dialog, BaseInstance* instance); + virtual ~ModPage(); + + inline virtual QString displayName() const override = 0; + inline virtual QIcon icon() const override = 0; + inline virtual QString id() const override = 0; + inline virtual QString helpPage() const override = 0; + + inline virtual QString debugName() const = 0; + inline virtual QString metaEntryBase() const = 0; + + virtual bool shouldDisplay() const override = 0; + + void openedImpl() override; + bool eventFilter(QObject* watched, QEvent* event) override; + + BaseInstance* m_instance; + + protected: + virtual void onModVersionSucceed(ModPage*, QByteArray*, QString) = 0; + + void updateSelectionButton(); + + protected slots: + void triggerSearch(); + void onSelectionChanged(QModelIndex first, QModelIndex second); + void onVersionSelectionChanged(QString data); + void onModSelected(); + + protected: + Ui::ModPage* ui = nullptr; + ModDownloadDialog* dialog = nullptr; + ModPlatform::ListModel* listModel = nullptr; + ModPlatform::IndexedPack current; + + int selectedVersion = -1; +}; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/ModPage.ui similarity index 97% rename from launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui rename to launcher/ui/pages/modplatform/ModPage.ui index d0a8b8f78..2b52df22c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/ModPage.ui @@ -1,7 +1,7 @@ - ModrinthPage - + ModPage + 0 diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 052f30d17..5ab6672fa 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -1,169 +1,25 @@ #include "FlameModModel.h" -#include "Application.h" +#include "FlameModPage.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" -#include "FlameModPage.h" + #include -#include -#include - -#include - - namespace FlameMod { -ListModel::ListModel(FlameModPage *parent) : QAbstractListModel(parent) -{ -} +ListModel::ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} -ListModel::~ListModel() -{ -} +ListModel::~ListModel() {} -int ListModel::rowCount(const QModelIndex &parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int pos = index.row(); - if(pos >= modpacks.size() || pos < 0 || !index.isValid()) - { - return QString("INVALID INDEX %1").arg(pos); - } - - ModPlatform::IndexedPack pack = modpacks.at(pos); - if(role == Qt::DisplayRole) - { - return pack.name; - } - else if (role == Qt::ToolTipRole) - { - if(pack.description.length() > 100) - { - //some magic to prevent to long tooltips and replace html linebreaks - QString edit = pack.description.left(97); - edit = edit.left(edit.lastIndexOf("
")).left(edit.lastIndexOf(" ")).append("..."); - return edit; - - } - return pack.description; - } - else if(role == Qt::DecorationRole) - { - if(m_logoMap.contains(pack.logoName)) - { - return (m_logoMap.value(pack.logoName)); - } - QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); - ((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl); - return icon; - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - - return QVariant(); -} - -void ListModel::logoLoaded(QString logo, QIcon out) -{ - m_loadingLogos.removeAll(logo); - m_logoMap.insert(logo, out); - for(int i = 0; i < modpacks.size(); i++) { - if(modpacks[i].logoName == logo) { - emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole}); - } - } -} - -void ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -void ListModel::requestLogo(QString logo, QString url) -{ - if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) - { - return; - } - - MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FlameMods", QString("logos/%1").arg(logo.section(".", 0, 0))); - auto job = new NetJob(QString("Flame Icon Download %1").arg(logo), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] - { - job->deleteLater(); - emit logoLoaded(logo, QIcon(fullPath)); - if(waitingCallbacks.contains(logo)) - { - waitingCallbacks.value(logo)(fullPath); - } - }); - - QObject::connect(job, &NetJob::failed, this, [this, logo, job] - { - job->deleteLater(); - emit logoFailed(logo); - }); - - job->start(); - m_loadingLogos.append(logo); -} - -void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(APPLICATION->metacache()->resolveEntry("FlameMods", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); - } - else - { - requestLogo(logo, logoUrl); - } -} - -Qt::ItemFlags ListModel::flags(const QModelIndex &index) const -{ - return QAbstractListModel::flags(index); -} - -bool ListModel::canFetchMore(const QModelIndex& parent) const -{ - return searchState == CanPossiblyFetchMore; -} - -void ListModel::fetchMore(const QModelIndex& parent) -{ - if (parent.isValid()) - return; - if(nextSearchOffset == 0) { - qWarning() << "fetchMore with 0 offset is wrong..."; - return; - } - performPaginatedSearch(); -} -const char* sorts[6]{"Featured","Popularity","LastUpdated","Name","Author","TotalDownloads"}; +const char* sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; void ListModel::performPaginatedSearch() { - - QString mcVersion = ((MinecraftInstance *)((FlameModPage *)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance *)((FlameModPage *)parent())->m_instance)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); + QString mcVersion = ((MinecraftInstance*)((FlameModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !((MinecraftInstance*)((FlameModPage*)parent())->m_instance) + ->getPackProfile() + ->getComponentVersion("net.fabricmc.fabric-loader") + .isEmpty(); auto netJob = new NetJob("Flame::Search", APPLICATION->network()); auto searchUrl = QString( "https://addons-ecs.forgesvc.net/api/v2/addon/search?" @@ -176,44 +32,22 @@ void ListModel::performPaginatedSearch() "searchFilter=%2&" "sort=%3&" "modLoaderType=%4&" - "gameVersion=%5" - ) - .arg(nextSearchOffset) - .arg(currentSearchTerm) - .arg(sorts[currentSort]) - .arg(hasFabric ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType - .arg(mcVersion); + "gameVersion=%5") + .arg(nextSearchOffset) + .arg(currentSearchTerm) + .arg(sorts[currentSort]) + .arg(hasFabric ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType + .arg(mcVersion); netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); jobPtr = netJob; jobPtr->start(); - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); + + QObject::connect(netJob, &NetJob::succeeded, this, &FlameMod::ListModel::searchRequestFinished); QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); } -void ListModel::searchWithTerm(const QString &term, const int sort) -{ - if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { - return; - } - currentSearchTerm = term; - currentSort = sort; - if(jobPtr) { - jobPtr->abort(); - searchState = ResetRequested; - return; - } - else { - beginResetModel(); - modpacks.clear(); - endResetModel(); - searchState = None; - } - nextSearchOffset = 0; - performPaginatedSearch(); -} - -void ListModel::searchRequestFinished() +void FlameMod::ListModel::searchRequestFinished() { jobPtr.reset(); @@ -253,21 +87,4 @@ void ListModel::searchRequestFinished() endInsertRows(); } -void ListModel::searchRequestFailed(QString reason) -{ - jobPtr.reset(); - - if(searchState == ResetRequested) { - beginResetModel(); - modpacks.clear(); - endResetModel(); - - nextSearchOffset = 0; - performPaginatedSearch(); - } else { - searchState = Finished; - } -} - -} - +} // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index ec19ab2f4..a585331d8 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -2,78 +2,36 @@ #include -#include -#include -#include #include -#include #include +#include +#include #include #include -#include +#include +#include -#include #include +#include -#include -#include "modplatform/flame/FlameModIndex.h" #include "BaseInstance.h" #include "FlameModPage.h" +#include "modplatform/flame/FlameModIndex.h" namespace FlameMod { - -typedef QMap LogoMap; typedef std::function LogoCallback; -class ListModel : public QAbstractListModel -{ +class ListModel : public ModPlatform::ListModel { Q_OBJECT -public: - ListModel(FlameModPage *parent); + public: + ListModel(FlameModPage* parent); virtual ~ListModel(); - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - bool canFetchMore(const QModelIndex & parent) const override; - void fetchMore(const QModelIndex & parent) override; - - void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback); - void searchWithTerm(const QString &term, const int sort); - -private slots: - void performPaginatedSearch(); - - void logoFailed(QString logo); - void logoLoaded(QString logo, QIcon out); - - void searchRequestFinished(); - void searchRequestFailed(QString reason); - -private: - void requestLogo(QString file, QString url); - -private: - QList modpacks; - QStringList m_failedLogos; - QStringList m_loadingLogos; - LogoMap m_logoMap; - QMap waitingCallbacks; - - QString currentSearchTerm; - int currentSort = 0; - int nextSearchOffset = 0; - enum SearchState { - None, - CanPossiblyFetchMore, - ResetRequested, - Finished - } searchState = None; - NetJob::Ptr jobPtr; - QByteArray response; + private slots: + void performPaginatedSearch() override; + void searchRequestFinished() override; }; -} +} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 48d38b821..ef33f9725 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -1,5 +1,5 @@ #include "FlameModPage.h" -#include "ui_FlameModPage.h" +#include "ui_ModPage.h" #include @@ -12,206 +12,59 @@ #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" -FlameModPage::FlameModPage(ModDownloadDialog *dialog, BaseInstance *instance) - : QWidget(dialog), m_instance(instance), ui(new Ui::FlameModPage), - dialog(dialog) { - ui->setupUi(this); - connect(ui->searchButton, &QPushButton::clicked, this, - &FlameModPage::triggerSearch); - ui->searchEdit->installEventFilter(this); - listModel = new FlameMod::ListModel(this); - ui->packView->setModel(listModel); +FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) + : ModPage(dialog, instance) +{ + listModel = new FlameMod::ListModel(this); + ui->packView->setModel(listModel); - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy( - Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); + // index is used to set the sorting with the flame api + ui->sortByBox->addItem(tr("Sort by Featured")); + ui->sortByBox->addItem(tr("Sort by Popularity")); + ui->sortByBox->addItem(tr("Sort by last updated")); + ui->sortByBox->addItem(tr("Sort by Name")); + ui->sortByBox->addItem(tr("Sort by Author")); + ui->sortByBox->addItem(tr("Sort by Downloads")); - // index is used to set the sorting with the flame api - ui->sortByBox->addItem(tr("Sort by Featured")); - ui->sortByBox->addItem(tr("Sort by Popularity")); - ui->sortByBox->addItem(tr("Sort by last updated")); - ui->sortByBox->addItem(tr("Sort by Name")); - ui->sortByBox->addItem(tr("Sort by Author")); - ui->sortByBox->addItem(tr("Sort by Downloads")); - - connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, - SLOT(triggerSearch())); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, - this, &FlameModPage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, - &FlameModPage::onVersionSelectionChanged); - connect(ui->modSelectionButton, &QPushButton::clicked, this, - &FlameModPage::onModSelected); -} - -FlameModPage::~FlameModPage() { delete ui; } - -bool FlameModPage::eventFilter(QObject *watched, QEvent *event) { - if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Return) { - triggerSearch(); - keyEvent->accept(); - return true; - } - } - return QWidget::eventFilter(watched, event); + // sometimes Qt just ignores virtual slots and doesn't work as intended it seems, + // so it's best not to connect them in the parent's contructor... + connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameModPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FlameModPage::onVersionSelectionChanged); + connect(ui->modSelectionButton, &QPushButton::clicked, this, &FlameModPage::onModSelected); } bool FlameModPage::shouldDisplay() const { return true; } -void FlameModPage::openedImpl() { - updateSelectionButton(); - triggerSearch(); -} - -void FlameModPage::triggerSearch() { - listModel->searchWithTerm(ui->searchEdit->text(), - ui->sortByBox->currentIndex()); -} - -void FlameModPage::onSelectionChanged(QModelIndex first, QModelIndex second) { - ui->versionSelectionBox->clear(); - - if (!first.isValid()) { - return; - } - - current = listModel->data(first, Qt::UserRole).value(); - QString text = ""; - QString name = current.name; - - if (current.websiteUrl.isEmpty()) - text = name; - else - text = "" + name + ""; - if (!current.authors.empty()) { - auto authorToStr = [](ModPlatform::ModpackAuthor &author) { - if (author.url.isEmpty()) { - return author.name; - } - return QString("%2").arg(author.url, author.name); - }; - QStringList authorStrs; - for (auto &author : current.authors) { - authorStrs.push_back(authorToStr(author)); +void FlameModPage::onModVersionSucceed(ModPage* instance, QByteArray* response, QString addonId) +{ + if (addonId != current.addonId) { + return; // wrong request } - text += "
" + tr(" by ") + authorStrs.join(", "); - } - text += "

"; - - ui->packDescription->setHtml(text + current.description); - - if (!current.versionsLoaded) { - qDebug() << "Loading flame mod versions"; - - ui->modSelectionButton->setText(tr("Loading versions...")); - ui->modSelectionButton->setEnabled(false); - - auto netJob = - new NetJob(QString("Flame::ModVersions(%1)").arg(current.name), - APPLICATION->network()); - auto response = new QByteArray(); - int addonId = current.addonId.toInt(); - netJob->addNetAction(Net::Download::makeByteArray( - QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files") - .arg(addonId), - response)); - - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] { - if(addonId != current.addonId){ - return; //wrong request - } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Flame at " - << parse_error.offset - << " reason: " << parse_error.errorString(); + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Flame at " << parse_error.offset << " reason: " << parse_error.errorString(); qWarning() << *response; return; - } - QJsonArray arr = doc.array(); - try { - FlameMod::loadIndexedPackVersions(current, arr, APPLICATION->network(), - m_instance); - } catch (const JSONValidationError &e) { + } + QJsonArray arr = doc.array(); + try { + FlameMod::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance); + } catch (const JSONValidationError& e) { qDebug() << *response; qWarning() << "Error while reading Flame mod version: " << e.cause(); - } - auto packProfile = ((MinecraftInstance *)m_instance)->getPackProfile(); - QString mcVersion = packProfile->getComponentVersion("net.minecraft"); - QString loaderString = - (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) - ? "fabric" - : "forge"; - for (int i = 0; i < current.versions.size(); i++) { - auto version = current.versions[i]; - if (!version.mcVersion.contains(mcVersion)) { - continue; - } - ui->versionSelectionBox->addItem(version.version, QVariant(i)); - } - if (ui->versionSelectionBox->count() == 0) { - ui->versionSelectionBox->addItem(tr("No Valid Version found!"), - QVariant(-1)); - } - - ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); - updateSelectionButton(); - }); - QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { - netJob->deleteLater(); - delete response; - }); - netJob->start(); - } else { + } + auto packProfile = ((MinecraftInstance*)m_instance)->getPackProfile(); + QString mcVersion = packProfile->getComponentVersion("net.minecraft"); + QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge"; for (int i = 0; i < current.versions.size(); i++) { - ui->versionSelectionBox->addItem(current.versions[i].version, - QVariant(i)); - } - if (ui->versionSelectionBox->count() == 0) { - ui->versionSelectionBox->addItem(tr("No Valid Version found!"), - QVariant(-1)); + auto version = current.versions[i]; + if (!version.mcVersion.contains(mcVersion)) { continue; } + ui->versionSelectionBox->addItem(version.version, QVariant(i)); } + if (ui->versionSelectionBox->count() == 0) { ui->versionSelectionBox->addItem(tr("No Valid Version found!"), QVariant(-1)); } + ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); updateSelectionButton(); - } -} - -void FlameModPage::updateSelectionButton() { - if (!isOpened || selectedVersion < 0) { - ui->modSelectionButton->setEnabled(false); - return; - } - - ui->modSelectionButton->setEnabled(true); - auto &version = current.versions[selectedVersion]; - if (!dialog->isModSelected(current.name, version.fileName)) { - ui->modSelectionButton->setText(tr("Select mod for download")); - } else { - ui->modSelectionButton->setText(tr("Deselect mod for download")); - } -} - -void FlameModPage::onVersionSelectionChanged(QString data) { - if (data.isNull() || data.isEmpty()) { - selectedVersion = -1; - return; - } - selectedVersion = ui->versionSelectionBox->currentData().toInt(); - updateSelectionButton(); -} - -void FlameModPage::onModSelected() { - auto &version = current.versions[selectedVersion]; - if (dialog->isModSelected(current.name, version.fileName)) { - dialog->removeSelectedMod(current.name); - } else { - dialog->addSelectedMod(current.name, - new ModDownloadTask(version.downloadUrl, - version.fileName, dialog->mods)); - } - - updateSelectionButton(); } diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 24dfcbc72..2daa155f2 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -1,68 +1,24 @@ #pragma once -#include +#include "ui/pages/modplatform/ModPage.h" -#include "ui/pages/BasePage.h" -#include -#include "tasks/Task.h" -#include "modplatform/flame/FlameModIndex.h" - -namespace Ui -{ -class FlameModPage; -} - -class ModDownloadDialog; - -namespace FlameMod { - class ListModel; -} - -class FlameModPage : public QWidget, public BasePage -{ +class FlameModPage : public ModPage { Q_OBJECT -public: - explicit FlameModPage(ModDownloadDialog *dialog, BaseInstance *instance); - virtual ~FlameModPage(); - virtual QString displayName() const override - { - return tr("CurseForge"); - } - virtual QIcon icon() const override - { - return APPLICATION->getThemedIcon("flame"); - } - virtual QString id() const override - { - return "curseforge"; - } - virtual QString helpPage() const override - { - return "Flame-platform"; - } - virtual bool shouldDisplay() const override; + public: + explicit FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance); + virtual ~FlameModPage() = default; - void openedImpl() override; + inline QString displayName() const override { return tr("CurseForge"); } + inline QIcon icon() const override { return APPLICATION->getThemedIcon("flame"); } + inline QString id() const override { return "curseforge"; } + inline QString helpPage() const override { return "Flame-platform"; } - bool eventFilter(QObject * watched, QEvent * event) override; + inline QString debugName() const override { return tr("Flame"); } + inline QString metaEntryBase() const override { return "FlameMods"; }; - BaseInstance *m_instance; + bool shouldDisplay() const override; -private: - void updateSelectionButton(); - -private slots: - void triggerSearch(); - void onSelectionChanged(QModelIndex first, QModelIndex second); - void onVersionSelectionChanged(QString data); - void onModSelected(); - -private: - Ui::FlameModPage *ui = nullptr; - ModDownloadDialog* dialog = nullptr; - FlameMod::ListModel* listModel = nullptr; - ModPlatform::IndexedPack current; - - int selectedVersion = -1; + private: + void onModVersionSucceed(ModPage*, QByteArray*, QString) override; }; diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.ui b/launcher/ui/pages/modplatform/flame/FlameModPage.ui deleted file mode 100644 index 36df7e8a4..000000000 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.ui +++ /dev/null @@ -1,97 +0,0 @@ - - - FlameModPage - - - - 0 - 0 - 837 - 685 - - - - - - - - - - - - - - - Version selected: - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Select mod for download - - - - - - - - - Search and filter ... - - - - - - - - - Qt::ScrollBarAlwaysOff - - - true - - - - 48 - 48 - - - - - - - - true - - - true - - - - - - - - - Search - - - - - - - searchEdit - searchButton - packView - packDescription - sortByBox - versionSelectionBox - - - - diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 088ca411f..d2e86ef80 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,171 +1,25 @@ #include "ModrinthModel.h" -#include "Application.h" +#include "ModrinthPage.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" -#include "ModrinthPage.h" -#include "ui/dialogs/ModDownloadDialog.h" + #include -#include -#include - -#include -#include - - namespace Modrinth { -ListModel::ListModel(ModrinthPage *parent) : QAbstractListModel(parent) -{ -} +ListModel::ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent) {} -ListModel::~ListModel() -{ -} +ListModel::~ListModel() {} -int ListModel::rowCount(const QModelIndex &parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int pos = index.row(); - if(pos >= modpacks.size() || pos < 0 || !index.isValid()) - { - return QString("INVALID INDEX %1").arg(pos); - } - - ModPlatform::IndexedPack pack = modpacks.at(pos); - if(role == Qt::DisplayRole) - { - return pack.name; - } - else if (role == Qt::ToolTipRole) - { - if(pack.description.length() > 100) - { - //some magic to prevent to long tooltips and replace html linebreaks - QString edit = pack.description.left(97); - edit = edit.left(edit.lastIndexOf("
")).left(edit.lastIndexOf(" ")).append("..."); - return edit; - - } - return pack.description; - } - else if(role == Qt::DecorationRole) - { - if(m_logoMap.contains(pack.logoName)) - { - return (m_logoMap.value(pack.logoName)); - } - QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder"); - ((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl); - return icon; - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - - return QVariant(); -} - -void ListModel::logoLoaded(QString logo, QIcon out) -{ - m_loadingLogos.removeAll(logo); - m_logoMap.insert(logo, out); - for(int i = 0; i < modpacks.size(); i++) { - if(modpacks[i].logoName == logo) { - emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole}); - } - } -} - -void ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -void ListModel::requestLogo(QString logo, QString url) -{ - if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) - { - return; - } - - MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ModrinthPacks", QString("logos/%1").arg(logo.section(".", 0, 0))); - auto job = new NetJob(QString("Modrinth Icon Download %1").arg(logo), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] - { - job->deleteLater(); - emit logoLoaded(logo, QIcon(fullPath)); - if(waitingCallbacks.contains(logo)) - { - waitingCallbacks.value(logo)(fullPath); - } - }); - - QObject::connect(job, &NetJob::failed, this, [this, logo, job] - { - job->deleteLater(); - emit logoFailed(logo); - }); - - job->start(); - m_loadingLogos.append(logo); -} - -void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(APPLICATION->metacache()->resolveEntry("ModrinthPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); - } - else - { - requestLogo(logo, logoUrl); - } -} - -Qt::ItemFlags ListModel::flags(const QModelIndex &index) const -{ - return QAbstractListModel::flags(index); -} - -bool ListModel::canFetchMore(const QModelIndex& parent) const -{ - return searchState == CanPossiblyFetchMore; -} - -void ListModel::fetchMore(const QModelIndex& parent) -{ - if (parent.isValid()) - return; - if(nextSearchOffset == 0) { - qWarning() << "fetchMore with 0 offset is wrong..."; - return; - } - performPaginatedSearch(); -} -const char* sorts[5]{"relevance","downloads","follows","updated","newest"}; +const char* sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; void ListModel::performPaginatedSearch() { - - QString mcVersion = ((MinecraftInstance *)((ModrinthPage *)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance *)((ModrinthPage *)parent())->m_instance)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); + QString mcVersion = ((MinecraftInstance*)((ModrinthPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !((MinecraftInstance*)((ModrinthPage*)parent())->m_instance) + ->getPackProfile() + ->getComponentVersion("net.fabricmc.fabric-loader") + .isEmpty(); auto netJob = new NetJob("Modrinth::Search", APPLICATION->network()); auto searchUrl = QString( "https://api.modrinth.com/v2/search?" @@ -173,41 +27,19 @@ void ListModel::performPaginatedSearch() "limit=25&" "query=%2&" "index=%3&" - "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]" - ) - .arg(nextSearchOffset) - .arg(currentSearchTerm) - .arg(sorts[currentSort]) - .arg(hasFabric ? "fabric" : "forge") - .arg(mcVersion); + "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") + .arg(nextSearchOffset) + .arg(currentSearchTerm) + .arg(sorts[currentSort]) + .arg(hasFabric ? "fabric" : "forge") + .arg(mcVersion); netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); jobPtr = netJob; jobPtr->start(); - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} -void ListModel::searchWithTerm(const QString &term, const int sort) -{ - if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { - return; - } - currentSearchTerm = term; - currentSort = sort; - if(jobPtr) { - jobPtr->abort(); - searchState = ResetRequested; - return; - } - else { - beginResetModel(); - modpacks.clear(); - endResetModel(); - searchState = None; - } - nextSearchOffset = 0; - performPaginatedSearch(); + QObject::connect(netJob, &NetJob::succeeded, this, &Modrinth::ListModel::searchRequestFinished); + QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); } void Modrinth::ListModel::searchRequestFinished() @@ -216,30 +48,28 @@ void Modrinth::ListModel::searchRequestFinished() QJsonParseError parse_error; QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error); - if(parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset << " reason: " << parse_error.errorString(); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); qWarning() << response; return; } QList newList; auto packs = doc.object().value("hits").toArray(); - for(auto packRaw : packs) { + for (auto packRaw : packs) { auto packObj = packRaw.toObject(); ModPlatform::IndexedPack pack; - try - { + try { Modrinth::loadIndexedPack(pack, packObj); newList.append(pack); - } - catch(const JSONValidationError &e) - { + } catch (const JSONValidationError& e) { qWarning() << "Error while loading mod from Modrinth: " << e.cause(); continue; } } - if(packs.size() < 25) { + if (packs.size() < 25) { searchState = Finished; } else { nextSearchOffset += 25; @@ -250,27 +80,4 @@ void Modrinth::ListModel::searchRequestFinished() endInsertRows(); } -void Modrinth::ListModel::searchRequestFailed(QString reason) -{ - if(jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409){ - //409 Gone, notify user to update - QMessageBox::critical(nullptr, tr("Error"), tr("Modrinth API version too old!\nPlease update PolyMC!")); - //self-destruct - ((ModDownloadDialog *)((ModrinthPage *)parent())->parentWidget())->reject(); - } - jobPtr.reset(); - - if(searchState == ResetRequested) { - beginResetModel(); - modpacks.clear(); - endResetModel(); - - nextSearchOffset = 0; - performPaginatedSearch(); - } else { - searchState = Finished; - } -} - -} - +} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 20661412b..734923564 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -2,78 +2,36 @@ #include -#include -#include -#include #include -#include #include +#include +#include #include #include -#include +#include +#include -#include #include +#include -#include -#include "modplatform/modrinth/ModrinthPackIndex.h" #include "BaseInstance.h" #include "ModrinthPage.h" +#include "modplatform/modrinth/ModrinthPackIndex.h" namespace Modrinth { - -typedef QMap LogoMap; typedef std::function LogoCallback; -class ListModel : public QAbstractListModel -{ +class ListModel : public ModPlatform::ListModel { Q_OBJECT -public: - ListModel(ModrinthPage *parent); + public: + ListModel(ModrinthPage* parent); virtual ~ListModel(); - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - bool canFetchMore(const QModelIndex & parent) const override; - void fetchMore(const QModelIndex & parent) override; - - void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback); - void searchWithTerm(const QString &term, const int sort); - -private slots: - void performPaginatedSearch(); - - void logoFailed(QString logo); - void logoLoaded(QString logo, QIcon out); - - void searchRequestFinished(); - void searchRequestFailed(QString reason); - -private: - void requestLogo(QString file, QString url); - -private: - QList modpacks; - QStringList m_failedLogos; - QStringList m_loadingLogos; - LogoMap m_logoMap; - QMap waitingCallbacks; - - QString currentSearchTerm; - int currentSort = 0; - int nextSearchOffset = 0; - enum SearchState { - None, - CanPossiblyFetchMore, - ResetRequested, - Finished - } searchState = None; - NetJob::Ptr jobPtr; - QByteArray response; + private slots: + void performPaginatedSearch() override; + void searchRequestFinished() override; }; -} +} // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 4dfc8504c..aa3efe556 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -1,5 +1,5 @@ #include "ModrinthPage.h" -#include "ui_ModrinthPage.h" +#include "ui_ModPage.h" #include @@ -12,194 +12,57 @@ #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" -ModrinthPage::ModrinthPage(ModDownloadDialog *dialog, BaseInstance *instance) - : QWidget(dialog), m_instance(instance), ui(new Ui::ModrinthPage), - dialog(dialog) { - ui->setupUi(this); - connect(ui->searchButton, &QPushButton::clicked, this, - &ModrinthPage::triggerSearch); - ui->searchEdit->installEventFilter(this); - listModel = new Modrinth::ListModel(this); - ui->packView->setModel(listModel); +ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) + : ModPage(dialog, instance) +{ + listModel = new Modrinth::ListModel(this); + ui->packView->setModel(listModel); - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy( - Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); + // index is used to set the sorting with the modrinth api + ui->sortByBox->addItem(tr("Sort by Relevence")); + ui->sortByBox->addItem(tr("Sort by Downloads")); + ui->sortByBox->addItem(tr("Sort by Follows")); + ui->sortByBox->addItem(tr("Sort by last updated")); + ui->sortByBox->addItem(tr("Sort by newest")); - // index is used to set the sorting with the modrinth api - ui->sortByBox->addItem(tr("Sort by Relevence")); - ui->sortByBox->addItem(tr("Sort by Downloads")); - ui->sortByBox->addItem(tr("Sort by Follows")); - ui->sortByBox->addItem(tr("Sort by last updated")); - ui->sortByBox->addItem(tr("Sort by newest")); - - connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, - SLOT(triggerSearch())); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, - this, &ModrinthPage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, - &ModrinthPage::onVersionSelectionChanged); - connect(ui->modSelectionButton, &QPushButton::clicked, this, - &ModrinthPage::onModSelected); -} - -ModrinthPage::~ModrinthPage() { delete ui; } - -bool ModrinthPage::eventFilter(QObject *watched, QEvent *event) { - if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - QKeyEvent *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Return) { - triggerSearch(); - keyEvent->accept(); - return true; - } - } - return QWidget::eventFilter(watched, event); + // sometimes Qt just ignores virtual slots and doesn't work as intended it seems, + // so it's best not to connect them in the parent's contructor... + connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); + connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthPage::onSelectionChanged); + connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &ModrinthPage::onVersionSelectionChanged); + connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthPage::onModSelected); } bool ModrinthPage::shouldDisplay() const { return true; } -void ModrinthPage::openedImpl() { - updateSelectionButton(); - triggerSearch(); -} - -void ModrinthPage::triggerSearch() { - listModel->searchWithTerm(ui->searchEdit->text(), - ui->sortByBox->currentIndex()); -} - -void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second) { - ui->versionSelectionBox->clear(); - - if (!first.isValid()) { - return; - } - - current = listModel->data(first, Qt::UserRole).value(); - QString text = ""; - QString name = current.name; - - if (current.websiteUrl.isEmpty()) - text = name; - else - text = "" + name + ""; - text += "
" + tr(" by ") + "" + - current.authors[0].name + "

"; - ui->packDescription->setHtml(text + current.description); - - if (!current.versionsLoaded) { - qDebug() << "Loading Modrinth mod versions"; - - ui->modSelectionButton->setText(tr("Loading versions...")); - ui->modSelectionButton->setEnabled(false); - - auto netJob = - new NetJob(QString("Modrinth::ModVersions(%1)").arg(current.name), - APPLICATION->network()); - auto response = new QByteArray(); - QString addonId = current.addonId.toString(); - netJob->addNetAction(Net::Download::makeByteArray( - QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId), - response)); - - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] { - if(addonId != current.addonId){ - return; - } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Modrinth at " - << parse_error.offset +void ModrinthPage::onModVersionSucceed(ModPage* instance, QByteArray* response, QString addonId) +{ + if (addonId != current.addonId) { return; } + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset << " reason: " << parse_error.errorString(); qWarning() << *response; return; - } - QJsonArray arr = doc.array(); - try { - Modrinth::loadIndexedPackVersions(current, arr, APPLICATION->network(), - m_instance); - } catch (const JSONValidationError &e) { + } + QJsonArray arr = doc.array(); + try { + Modrinth::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance); + } catch (const JSONValidationError& e) { qDebug() << *response; qWarning() << "Error while reading Modrinth mod version: " << e.cause(); - } - auto packProfile = ((MinecraftInstance *)m_instance)->getPackProfile(); - QString mcVersion = packProfile->getComponentVersion("net.minecraft"); - QString loaderString = - (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) - ? "fabric" - : "forge"; - for (int i = 0; i < current.versions.size(); i++) { - auto version = current.versions[i]; - if (!version.mcVersion.contains(mcVersion) || - !version.loaders.contains(loaderString)) { - continue; - } - ui->versionSelectionBox->addItem(version.version, QVariant(i)); - } - if (ui->versionSelectionBox->count() == 0) { - ui->versionSelectionBox->addItem(tr("No Valid Version found !"), - QVariant(-1)); - } - - ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); - updateSelectionButton(); - }); - - QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { - netJob->deleteLater(); - delete response; - }); - - netJob->start(); - } else { + } + auto packProfile = ((MinecraftInstance*)m_instance)->getPackProfile(); + QString mcVersion = packProfile->getComponentVersion("net.minecraft"); + QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge"; for (int i = 0; i < current.versions.size(); i++) { - ui->versionSelectionBox->addItem(current.versions[i].version, - QVariant(i)); - } - if (ui->versionSelectionBox->count() == 0) { - ui->versionSelectionBox->addItem(tr("No Valid Version found !"), - QVariant(-1)); + auto version = current.versions[i]; + if (!version.mcVersion.contains(mcVersion) || !version.loaders.contains(loaderString)) { continue; } + ui->versionSelectionBox->addItem(version.version, QVariant(i)); } + if (ui->versionSelectionBox->count() == 0) { ui->versionSelectionBox->addItem(tr("No Valid Version found !"), QVariant(-1)); } + ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); updateSelectionButton(); - } -} - -void ModrinthPage::updateSelectionButton() { - if (!isOpened || selectedVersion < 0) { - ui->modSelectionButton->setEnabled(false); - return; - } - - ui->modSelectionButton->setEnabled(true); - auto &version = current.versions[selectedVersion]; - if (!dialog->isModSelected(current.name, version.fileName)) { - ui->modSelectionButton->setText(tr("Select mod for download")); - } else { - ui->modSelectionButton->setText(tr("Deselect mod for download")); - } -} - -void ModrinthPage::onVersionSelectionChanged(QString data) { - if (data.isNull() || data.isEmpty()) { - selectedVersion = -1; - return; - } - selectedVersion = ui->versionSelectionBox->currentData().toInt(); - updateSelectionButton(); -} - -void ModrinthPage::onModSelected() { - auto &version = current.versions[selectedVersion]; - if (dialog->isModSelected(current.name, version.fileName)) { - dialog->removeSelectedMod(current.name); - } else { - dialog->addSelectedMod(current.name, - new ModDownloadTask(version.downloadUrl, - version.fileName, dialog->mods)); - } - - updateSelectionButton(); } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 1d725d471..41c6c31d1 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -1,68 +1,24 @@ #pragma once -#include +#include "ui/pages/modplatform/ModPage.h" -#include "ui/pages/BasePage.h" -#include -#include "tasks/Task.h" -#include "modplatform/modrinth/ModrinthPackIndex.h" - -namespace Ui -{ -class ModrinthPage; -} - -class ModDownloadDialog; - -namespace Modrinth { - class ListModel; -} - -class ModrinthPage : public QWidget, public BasePage -{ +class ModrinthPage : public ModPage { Q_OBJECT -public: - explicit ModrinthPage(ModDownloadDialog *dialog, BaseInstance *instance); - virtual ~ModrinthPage(); - virtual QString displayName() const override - { - return tr("Modrinth"); - } - virtual QIcon icon() const override - { - return APPLICATION->getThemedIcon("modrinth"); - } - virtual QString id() const override - { - return "modrinth"; - } - virtual QString helpPage() const override - { - return "Modrinth-platform"; - } - virtual bool shouldDisplay() const override; + public: + explicit ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance); + virtual ~ModrinthPage() = default; - void openedImpl() override; + inline QString displayName() const override { return tr("Modrinth"); } + inline QIcon icon() const override { return APPLICATION->getThemedIcon("modrinth"); } + inline QString id() const override { return "modrinth"; } + inline QString helpPage() const override { return "Modrinth-platform"; } - bool eventFilter(QObject * watched, QEvent * event) override; + inline QString debugName() const override { return tr("Modrinth"); } + inline QString metaEntryBase() const override { return "ModrinthPacks"; }; - BaseInstance *m_instance; + bool shouldDisplay() const override; -private: - void updateSelectionButton(); - -private slots: - void triggerSearch(); - void onSelectionChanged(QModelIndex first, QModelIndex second); - void onVersionSelectionChanged(QString data); - void onModSelected(); - -private: - Ui::ModrinthPage *ui = nullptr; - ModDownloadDialog* dialog = nullptr; - Modrinth::ListModel* listModel = nullptr; - ModPlatform::IndexedPack current; - - int selectedVersion = -1; + private: + void onModVersionSucceed(ModPage*, QByteArray*, QString) override; }; From 2d68308d4920be4c28a73d7646814765eee7b7a2 Mon Sep 17 00:00:00 2001 From: flow Date: Wed, 2 Mar 2022 23:01:23 -0300 Subject: [PATCH 03/18] refactor: move url creation for mods to modplatform/ Moves all things related to creating the URLs of the mod platforms that go to network tasks to a single place, so that: 1. Maintaining and fixing eventual issues is more straightforward. 2. Makes it possible to factor out more common code between the different modplatform pages --- launcher/modplatform/ModAPI.h | 12 ++++++ launcher/modplatform/flame/FlameAPI.h | 27 ++++++++++++ launcher/modplatform/modrinth/ModrinthAPI.h | 25 +++++++++++ .../modrinth/ModrinthPackIndex.cpp | 5 ++- launcher/ui/pages/modplatform/ModModel.cpp | 20 +++++++++ launcher/ui/pages/modplatform/ModModel.h | 7 ++- launcher/ui/pages/modplatform/ModPage.cpp | 9 +--- launcher/ui/pages/modplatform/ModPage.h | 2 + .../pages/modplatform/flame/FlameModModel.cpp | 43 +++---------------- .../pages/modplatform/flame/FlameModModel.h | 4 +- .../ui/pages/modplatform/flame/FlameModPage.h | 6 +++ .../modplatform/modrinth/ModrinthModel.cpp | 39 +++-------------- .../modplatform/modrinth/ModrinthModel.h | 4 +- .../pages/modplatform/modrinth/ModrinthPage.h | 6 +++ 14 files changed, 130 insertions(+), 79 deletions(-) create mode 100644 launcher/modplatform/ModAPI.h create mode 100644 launcher/modplatform/flame/FlameAPI.h create mode 100644 launcher/modplatform/modrinth/ModrinthAPI.h diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h new file mode 100644 index 000000000..e60fa8e0a --- /dev/null +++ b/launcher/modplatform/ModAPI.h @@ -0,0 +1,12 @@ +#pragma once + +#include + +class ModAPI { + public: + virtual ~ModAPI() = default; + + inline virtual QString getModSearchURL(int, QString, QString, bool, QString) const { return ""; }; + inline virtual QString getVersionsURL(const QString& addonId) const { return ""; }; + inline virtual QString getAuthorURL(const QString& name) const { return ""; }; +}; diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h new file mode 100644 index 000000000..6e2b9e253 --- /dev/null +++ b/launcher/modplatform/flame/FlameAPI.h @@ -0,0 +1,27 @@ +#pragma once + +#include "modplatform/ModAPI.h" + +class FlameAPI : public ModAPI { + public: + inline QString getModSearchURL(int index, QString searchFilter, QString sort, bool fabricCompatible, QString version) const override + { + return QString("https://addons-ecs.forgesvc.net/api/v2/addon/search?" + "gameId=432&" "categoryId=0&" "sectionId=6&" + + "index=%1&" "pageSize=25&" "searchFilter=%2&" + "sort=%3&" "modLoaderType=%4&" "gameVersion=%5") + .arg(index) + .arg(searchFilter) + .arg(sort) + .arg(fabricCompatible ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType + .arg(version); + }; + + inline QString getVersionsURL(const QString& addonId) const override + { + return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId); + }; + + inline QString getAuthorURL(const QString& name) const override { return ""; }; +}; diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h new file mode 100644 index 000000000..4ae8b8f9d --- /dev/null +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -0,0 +1,25 @@ +#pragma once + +#include "modplatform/ModAPI.h" + +class ModrinthAPI : public ModAPI { + public: + inline QString getModSearchURL(int offset, QString query, QString sort, bool fabricCompatible, QString version) const override + { + return QString("https://api.modrinth.com/v2/search?" + "offset=%1&" "limit=25&" "query=%2&" "index=%3&" + "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") + .arg(offset) + .arg(query) + .arg(sort) + .arg(fabricCompatible ? "fabric" : "forge") + .arg(version); + }; + + inline QString getVersionsURL(const QString& addonId) const override + { + return QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId); + }; + + inline QString getAuthorURL(const QString& name) const override { return "https://modrinth.com/user/" + name; }; +}; diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index a59186f76..02aac34d5 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -1,10 +1,13 @@ #include "ModrinthPackIndex.h" +#include "ModrinthAPI.h" #include "Json.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "net/NetJob.h" +static ModrinthAPI api; + void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) { pack.addonId = Json::requireString(obj, "project_id"); @@ -17,7 +20,7 @@ void Modrinth::loadIndexedPack(ModPlatform::IndexedPack& pack, QJsonObject& obj) ModPlatform::ModpackAuthor modAuthor; modAuthor.name = Json::requireString(obj, "author"); - modAuthor.url = "https://modrinth.com/user/" + modAuthor.name; + modAuthor.url = api.getAuthorURL(modAuthor.name); pack.authors.append(modAuthor); } diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 5bd7e33e1..481f1c560 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -1,6 +1,8 @@ #include "ModModel.h" #include "ModPage.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" #include @@ -95,6 +97,24 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac } } +void ListModel::performPaginatedSearch() +{ + QString mcVersion = ((MinecraftInstance*)((ModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !((MinecraftInstance*)((ModPage*)parent())->m_instance) + ->getPackProfile() + ->getComponentVersion("net.fabricmc.fabric-loader") + .isEmpty(); + auto netJob = new NetJob(QString("%1::Search").arg(m_parent->debugName()), APPLICATION->network()); + auto searchUrl = m_parent->apiProvider()->getModSearchURL(nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric, mcVersion); + + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); + jobPtr = netJob; + jobPtr->start(); + + QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); + QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); +} + void ListModel::searchWithTerm(const QString& term, const int sort) { if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { return; } diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index ae8ceb7c3..23e544f1f 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -3,6 +3,7 @@ #include #include "modplatform/ModIndex.h" +#include "modplatform/ModAPI.h" #include "net/NetJob.h" class ModPage; @@ -30,15 +31,18 @@ class ListModel : public QAbstractListModel { void searchWithTerm(const QString& term, const int sort); protected slots: - virtual void performPaginatedSearch() = 0; virtual void searchRequestFinished() = 0; + void performPaginatedSearch(); + void logoFailed(QString logo); void logoLoaded(QString logo, QIcon out); void searchRequestFailed(QString reason); protected: + virtual const char** getSorts() const = 0; + void requestLogo(QString file, QString url); protected: @@ -56,5 +60,6 @@ class ListModel : public QAbstractListModel { enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; NetJob::Ptr jobPtr; QByteArray response; + }; } // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 8af534a6f..2d47e31c2 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -101,13 +101,8 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName()).arg(current.name), APPLICATION->network()); auto response = new QByteArray(); QString addonId = current.addonId.toString(); - //FIXME - if(debugName() == "Modrinth") - netJob->addNetAction( - Net::Download::makeByteArray(QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId), response)); - else - netJob->addNetAction( - Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response)); + + netJob->addNetAction(Net::Download::makeByteArray(apiProvider()->getVersionsURL(addonId), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ onModVersionSucceed(this, response, addonId); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index c0102549d..4657bc5e6 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -3,6 +3,7 @@ #include #include +#include "modplatform/ModAPI.h" #include "modplatform/ModIndex.h" #include "tasks/Task.h" #include "ui/pages/BasePage.h" @@ -30,6 +31,7 @@ class ModPage : public QWidget, public BasePage { inline virtual QString metaEntryBase() const = 0; virtual bool shouldDisplay() const override = 0; + virtual const ModAPI* apiProvider() const = 0; void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 5ab6672fa..283f9ce75 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -1,6 +1,5 @@ #include "FlameModModel.h" #include "FlameModPage.h" -#include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include @@ -11,41 +10,6 @@ ListModel::ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} ListModel::~ListModel() {} -const char* sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; - -void ListModel::performPaginatedSearch() -{ - QString mcVersion = ((MinecraftInstance*)((FlameModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance*)((FlameModPage*)parent())->m_instance) - ->getPackProfile() - ->getComponentVersion("net.fabricmc.fabric-loader") - .isEmpty(); - auto netJob = new NetJob("Flame::Search", APPLICATION->network()); - auto searchUrl = QString( - "https://addons-ecs.forgesvc.net/api/v2/addon/search?" - "gameId=432&" - "categoryId=0&" - "sectionId=6&" - - "index=%1&" - "pageSize=25&" - "searchFilter=%2&" - "sort=%3&" - "modLoaderType=%4&" - "gameVersion=%5") - .arg(nextSearchOffset) - .arg(currentSearchTerm) - .arg(sorts[currentSort]) - .arg(hasFabric ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType - .arg(mcVersion); - - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &FlameMod::ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} void FlameMod::ListModel::searchRequestFinished() { @@ -87,4 +51,11 @@ void FlameMod::ListModel::searchRequestFinished() endInsertRows(); } +const char* sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; + +const char** FlameMod::ListModel::getSorts() const +{ + return sorts; +} + } // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index a585331d8..ae919e639 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -30,8 +30,10 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel(); private slots: - void performPaginatedSearch() override; void searchRequestFinished() override; + + private: + const char** getSorts() const override; }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 2daa155f2..e7d98cb08 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -2,6 +2,8 @@ #include "ui/pages/modplatform/ModPage.h" +#include "modplatform/flame/FlameAPI.h" + class FlameModPage : public ModPage { Q_OBJECT @@ -18,7 +20,11 @@ class FlameModPage : public ModPage { inline QString metaEntryBase() const override { return "FlameMods"; }; bool shouldDisplay() const override; + const ModAPI* apiProvider() const override { return &api; }; private: void onModVersionSucceed(ModPage*, QByteArray*, QString) override; + + private: + FlameAPI api; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index d2e86ef80..dc3d14697 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,7 +1,6 @@ #include "ModrinthModel.h" #include "ModrinthPage.h" #include "minecraft/MinecraftInstance.h" -#include "minecraft/PackProfile.h" #include @@ -11,37 +10,6 @@ ListModel::ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent) {} ListModel::~ListModel() {} -const char* sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; - -void ListModel::performPaginatedSearch() -{ - QString mcVersion = ((MinecraftInstance*)((ModrinthPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance*)((ModrinthPage*)parent())->m_instance) - ->getPackProfile() - ->getComponentVersion("net.fabricmc.fabric-loader") - .isEmpty(); - auto netJob = new NetJob("Modrinth::Search", APPLICATION->network()); - auto searchUrl = QString( - "https://api.modrinth.com/v2/search?" - "offset=%1&" - "limit=25&" - "query=%2&" - "index=%3&" - "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") - .arg(nextSearchOffset) - .arg(currentSearchTerm) - .arg(sorts[currentSort]) - .arg(hasFabric ? "fabric" : "forge") - .arg(mcVersion); - - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &Modrinth::ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} - void Modrinth::ListModel::searchRequestFinished() { jobPtr.reset(); @@ -80,4 +48,11 @@ void Modrinth::ListModel::searchRequestFinished() endInsertRows(); } +const char* sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; + +const char** Modrinth::ListModel::getSorts() const +{ + return sorts; +} + } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 734923564..b8937b506 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -30,8 +30,10 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel(); private slots: - void performPaginatedSearch() override; void searchRequestFinished() override; + + private: + const char** getSorts() const override; }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 41c6c31d1..504f42ada 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -2,6 +2,8 @@ #include "ui/pages/modplatform/ModPage.h" +#include "modplatform/modrinth/ModrinthAPI.h" + class ModrinthPage : public ModPage { Q_OBJECT @@ -18,7 +20,11 @@ class ModrinthPage : public ModPage { inline QString metaEntryBase() const override { return "ModrinthPacks"; }; bool shouldDisplay() const override; + const ModAPI* apiProvider() const override { return &api; }; private: void onModVersionSucceed(ModPage*, QByteArray*, QString) override; + + private: + ModrinthAPI api; }; From 9a8599e4ba7e1df616d0e4b4a4a899792ecaa3e1 Mon Sep 17 00:00:00 2001 From: flow Date: Thu, 3 Mar 2022 00:06:37 -0300 Subject: [PATCH 04/18] fix windows compilation --- launcher/ui/pages/modplatform/ModPage.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index 4657bc5e6..f79d494fd 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -22,13 +22,13 @@ class ModPage : public QWidget, public BasePage { explicit ModPage(ModDownloadDialog* dialog, BaseInstance* instance); virtual ~ModPage(); - inline virtual QString displayName() const override = 0; - inline virtual QIcon icon() const override = 0; - inline virtual QString id() const override = 0; - inline virtual QString helpPage() const override = 0; + virtual QString displayName() const override = 0; + virtual QIcon icon() const override = 0; + virtual QString id() const override = 0; + virtual QString helpPage() const override = 0; - inline virtual QString debugName() const = 0; - inline virtual QString metaEntryBase() const = 0; + virtual QString debugName() const = 0; + virtual QString metaEntryBase() const = 0; virtual bool shouldDisplay() const override = 0; virtual const ModAPI* apiProvider() const = 0; From 5e9d49a91082c53907db84df809d21c3bdc8bcac Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 6 Mar 2022 13:54:05 -0300 Subject: [PATCH 05/18] refactor: use only a single unique_ptr for the api --- launcher/ui/pages/modplatform/ModPage.cpp | 4 ++-- launcher/ui/pages/modplatform/ModPage.h | 12 +++++++++--- launcher/ui/pages/modplatform/flame/FlameModPage.cpp | 2 +- launcher/ui/pages/modplatform/flame/FlameModPage.h | 4 ---- .../ui/pages/modplatform/modrinth/ModrinthPage.cpp | 2 +- .../ui/pages/modplatform/modrinth/ModrinthPage.h | 4 ---- 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 2d47e31c2..f427d32ab 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -5,8 +5,8 @@ #include "ui/dialogs/ModDownloadDialog.h" -ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance) - : QWidget(dialog), m_instance(instance), ui(new Ui::ModPage), dialog(dialog) +ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) + : QWidget(dialog), m_instance(instance), ui(new Ui::ModPage), dialog(dialog), api(api) { ui->setupUi(this); connect(ui->searchButton, &QPushButton::clicked, this, &ModPage::triggerSearch); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index f79d494fd..cd034a3a8 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -15,23 +15,27 @@ namespace Ui { class ModPage; } +/* This page handles most logic related to browsing and selecting mods to download. + * By default, the methods provided work with net requests, to fetch data from remote APIs. */ class ModPage : public QWidget, public BasePage { Q_OBJECT public: - explicit ModPage(ModDownloadDialog* dialog, BaseInstance* instance); + explicit ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api); virtual ~ModPage(); + /* The name visible to the user */ virtual QString displayName() const override = 0; virtual QIcon icon() const override = 0; virtual QString id() const override = 0; virtual QString helpPage() const override = 0; - virtual QString debugName() const = 0; virtual QString metaEntryBase() const = 0; + /* This only appears in the debug console */ + virtual QString debugName() const = 0; virtual bool shouldDisplay() const override = 0; - virtual const ModAPI* apiProvider() const = 0; + const ModAPI* apiProvider() const { return api.get(); }; void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; @@ -55,5 +59,7 @@ class ModPage : public QWidget, public BasePage { ModPlatform::ListModel* listModel = nullptr; ModPlatform::IndexedPack current; + std::unique_ptr api; + int selectedVersion = -1; }; diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index ef33f9725..47a79bd6d 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -13,7 +13,7 @@ #include "ui/dialogs/ModDownloadDialog.h" FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) - : ModPage(dialog, instance) + : ModPage(dialog, instance, new FlameAPI()) { listModel = new FlameMod::ListModel(this); ui->packView->setModel(listModel); diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index e7d98cb08..89311e7f1 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -20,11 +20,7 @@ class FlameModPage : public ModPage { inline QString metaEntryBase() const override { return "FlameMods"; }; bool shouldDisplay() const override; - const ModAPI* apiProvider() const override { return &api; }; private: void onModVersionSucceed(ModPage*, QByteArray*, QString) override; - - private: - FlameAPI api; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index aa3efe556..4e4a9db43 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -13,7 +13,7 @@ #include "ui/dialogs/ModDownloadDialog.h" ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) - : ModPage(dialog, instance) + : ModPage(dialog, instance, new ModrinthAPI()) { listModel = new Modrinth::ListModel(this); ui->packView->setModel(listModel); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 504f42ada..d92274dd1 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -20,11 +20,7 @@ class ModrinthPage : public ModPage { inline QString metaEntryBase() const override { return "ModrinthPacks"; }; bool shouldDisplay() const override; - const ModAPI* apiProvider() const override { return &api; }; private: void onModVersionSucceed(ModPage*, QByteArray*, QString) override; - - private: - ModrinthAPI api; }; From 5a638fa97711231638615f920462ed5f5f4507e0 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 6 Mar 2022 15:23:00 -0300 Subject: [PATCH 06/18] refactor: move "get versions" task from page to model This seems more reasonable --- launcher/ui/pages/modplatform/ModModel.cpp | 20 +++++++++++++++++++ launcher/ui/pages/modplatform/ModModel.h | 2 ++ launcher/ui/pages/modplatform/ModPage.cpp | 17 +--------------- launcher/ui/pages/modplatform/ModPage.h | 6 +++--- .../pages/modplatform/flame/FlameModPage.cpp | 2 +- .../ui/pages/modplatform/flame/FlameModPage.h | 2 +- .../modplatform/modrinth/ModrinthPage.cpp | 2 +- .../pages/modplatform/modrinth/ModrinthPage.h | 2 +- 8 files changed, 30 insertions(+), 23 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 481f1c560..c71acd350 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -97,6 +97,26 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac } } +void ListModel::populateVersions(ModPlatform::IndexedPack const& current) +{ + auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(m_parent->debugName()).arg(current.name), APPLICATION->network()); + auto response = new QByteArray(); + QString addonId = current.addonId.toString(); + + netJob->addNetAction(Net::Download::makeByteArray(m_parent->apiProvider()->getVersionsURL(addonId), response)); + + QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ + m_parent->onGetVersionsSucceeded(m_parent, response, addonId); + }); + + QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + + netJob->start(); +} + void ListModel::performPaginatedSearch() { QString mcVersion = ((MinecraftInstance*)((ModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 23e544f1f..2b8ff65e6 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -30,6 +30,8 @@ class ListModel : public QAbstractListModel { void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); void searchWithTerm(const QString& term, const int sort); + virtual void populateVersions(const ModPlatform::IndexedPack& current); + protected slots: virtual void searchRequestFinished() = 0; diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index f427d32ab..68c62fb84 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -98,22 +98,7 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) ui->modSelectionButton->setText(tr("Loading versions...")); ui->modSelectionButton->setEnabled(false); - auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName()).arg(current.name), APPLICATION->network()); - auto response = new QByteArray(); - QString addonId = current.addonId.toString(); - - netJob->addNetAction(Net::Download::makeByteArray(apiProvider()->getVersionsURL(addonId), response)); - - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ - onModVersionSucceed(this, response, addonId); - }); - - QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { - netJob->deleteLater(); - delete response; - }); - - netJob->start(); + listModel->populateVersions(current); } else { for (int i = 0; i < current.versions.size(); i++) { ui->versionSelectionBox->addItem(current.versions[i].version, QVariant(i)); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index cd034a3a8..b1681b8cb 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -1,11 +1,10 @@ #pragma once -#include #include +#include "Application.h" #include "modplatform/ModAPI.h" #include "modplatform/ModIndex.h" -#include "tasks/Task.h" #include "ui/pages/BasePage.h" #include "ui/pages/modplatform/ModModel.h" @@ -37,13 +36,14 @@ class ModPage : public QWidget, public BasePage { virtual bool shouldDisplay() const override = 0; const ModAPI* apiProvider() const { return api.get(); }; + virtual void onGetVersionsSucceeded(ModPage*, QByteArray*, QString) = 0; + void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; BaseInstance* m_instance; protected: - virtual void onModVersionSucceed(ModPage*, QByteArray*, QString) = 0; void updateSelectionButton(); diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 47a79bd6d..147668510 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -36,7 +36,7 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) bool FlameModPage::shouldDisplay() const { return true; } -void FlameModPage::onModVersionSucceed(ModPage* instance, QByteArray* response, QString addonId) +void FlameModPage::onGetVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) { if (addonId != current.addonId) { return; // wrong request diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 89311e7f1..7e8d6707f 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -22,5 +22,5 @@ class FlameModPage : public ModPage { bool shouldDisplay() const override; private: - void onModVersionSucceed(ModPage*, QByteArray*, QString) override; + void onGetVersionsSucceeded(ModPage*, QByteArray*, QString) override; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 4e4a9db43..7ac9b4067 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -35,7 +35,7 @@ ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) bool ModrinthPage::shouldDisplay() const { return true; } -void ModrinthPage::onModVersionSucceed(ModPage* instance, QByteArray* response, QString addonId) +void ModrinthPage::onGetVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) { if (addonId != current.addonId) { return; } QJsonParseError parse_error; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index d92274dd1..0112c5ea2 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -22,5 +22,5 @@ class ModrinthPage : public ModPage { bool shouldDisplay() const override; private: - void onModVersionSucceed(ModPage*, QByteArray*, QString) override; + void onGetVersionsSucceeded(ModPage*, QByteArray*, QString) override; }; From d755174bee1b1c5ba507d1d407236190501c7940 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 6 Mar 2022 16:04:24 -0300 Subject: [PATCH 07/18] clarify some method names and comments --- launcher/ui/pages/modplatform/ModModel.cpp | 4 ++-- launcher/ui/pages/modplatform/ModModel.h | 16 +++++++++------- launcher/ui/pages/modplatform/ModPage.cpp | 2 +- launcher/ui/pages/modplatform/ModPage.h | 7 ++++--- .../ui/pages/modplatform/flame/FlameModPage.cpp | 2 +- .../ui/pages/modplatform/flame/FlameModPage.h | 2 +- .../pages/modplatform/modrinth/ModrinthPage.cpp | 2 +- .../ui/pages/modplatform/modrinth/ModrinthPage.h | 2 +- 8 files changed, 20 insertions(+), 17 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index c71acd350..4462c20b2 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -97,7 +97,7 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac } } -void ListModel::populateVersions(ModPlatform::IndexedPack const& current) +void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) { auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(m_parent->debugName()).arg(current.name), APPLICATION->network()); auto response = new QByteArray(); @@ -106,7 +106,7 @@ void ListModel::populateVersions(ModPlatform::IndexedPack const& current) netJob->addNetAction(Net::Download::makeByteArray(m_parent->apiProvider()->getVersionsURL(addonId), response)); QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ - m_parent->onGetVersionsSucceeded(m_parent, response, addonId); + m_parent->onRequestVersionsSucceeded(m_parent, response, addonId); }); QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 2b8ff65e6..64c17b4a6 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -22,25 +22,26 @@ class ListModel : public QAbstractListModel { int rowCount(const QModelIndex& parent) const override; int columnCount(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; + bool canFetchMore(const QModelIndex& parent) const override; void fetchMore(const QModelIndex& parent) override; void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); void searchWithTerm(const QString& term, const int sort); - virtual void populateVersions(const ModPlatform::IndexedPack& current); + virtual void requestModVersions(const ModPlatform::IndexedPack& current); protected slots: virtual void searchRequestFinished() = 0; - - void performPaginatedSearch(); + void searchRequestFailed(QString reason); void logoFailed(QString logo); void logoLoaded(QString logo, QIcon out); - void searchRequestFailed(QString reason); + void performPaginatedSearch(); protected: virtual const char** getSorts() const = 0; @@ -51,17 +52,18 @@ class ListModel : public QAbstractListModel { ModPage* m_parent; QList modpacks; - QStringList m_failedLogos; - QStringList m_loadingLogos; + LogoMap m_logoMap; QMap waitingCallbacks; + QStringList m_failedLogos; + QStringList m_loadingLogos; QString currentSearchTerm; int currentSort = 0; int nextSearchOffset = 0; enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; + NetJob::Ptr jobPtr; QByteArray response; - }; } // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 68c62fb84..a57f2903d 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -98,7 +98,7 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) ui->modSelectionButton->setText(tr("Loading versions...")); ui->modSelectionButton->setEnabled(false); - listModel->populateVersions(current); + listModel->requestModVersions(current); } else { for (int i = 0; i < current.versions.size(); i++) { ui->versionSelectionBox->addItem(current.versions[i].version, QVariant(i)); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index b1681b8cb..e0d7c95ca 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -23,20 +23,21 @@ class ModPage : public QWidget, public BasePage { explicit ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api); virtual ~ModPage(); - /* The name visible to the user */ + /* Affects what the user sees */ virtual QString displayName() const override = 0; virtual QIcon icon() const override = 0; virtual QString id() const override = 0; virtual QString helpPage() const override = 0; + /* Used internally */ virtual QString metaEntryBase() const = 0; - /* This only appears in the debug console */ virtual QString debugName() const = 0; + virtual bool shouldDisplay() const override = 0; const ModAPI* apiProvider() const { return api.get(); }; - virtual void onGetVersionsSucceeded(ModPage*, QByteArray*, QString) = 0; + virtual void onRequestVersionsSucceeded(ModPage*, QByteArray*, QString) = 0; void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 147668510..6564265c4 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -36,7 +36,7 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) bool FlameModPage::shouldDisplay() const { return true; } -void FlameModPage::onGetVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) +void FlameModPage::onRequestVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) { if (addonId != current.addonId) { return; // wrong request diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 7e8d6707f..9c6f0e6c7 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -22,5 +22,5 @@ class FlameModPage : public ModPage { bool shouldDisplay() const override; private: - void onGetVersionsSucceeded(ModPage*, QByteArray*, QString) override; + void onRequestVersionsSucceeded(ModPage*, QByteArray*, QString) override; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 7ac9b4067..944f8afbf 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -35,7 +35,7 @@ ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) bool ModrinthPage::shouldDisplay() const { return true; } -void ModrinthPage::onGetVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) +void ModrinthPage::onRequestVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) { if (addonId != current.addonId) { return; } QJsonParseError parse_error; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 0112c5ea2..7b1d0a00c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -22,5 +22,5 @@ class ModrinthPage : public ModPage { bool shouldDisplay() const override; private: - void onGetVersionsSucceeded(ModPage*, QByteArray*, QString) override; + void onRequestVersionsSucceeded(ModPage*, QByteArray*, QString) override; }; From 39bd04f06ff42623f7349096d707c4a877fc7cd7 Mon Sep 17 00:00:00 2001 From: flow Date: Sun, 6 Mar 2022 16:45:39 -0300 Subject: [PATCH 08/18] refactor: use Enum instead of raw int for ModLoaderType --- launcher/modplatform/ModAPI.h | 11 +++++++- launcher/modplatform/flame/FlameAPI.h | 5 ++-- launcher/modplatform/modrinth/ModrinthAPI.h | 29 +++++++++++++++++++-- launcher/ui/pages/modplatform/ModModel.cpp | 3 ++- 4 files changed, 42 insertions(+), 6 deletions(-) diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h index e60fa8e0a..4d22a63dd 100644 --- a/launcher/modplatform/ModAPI.h +++ b/launcher/modplatform/ModAPI.h @@ -6,7 +6,16 @@ class ModAPI { public: virtual ~ModAPI() = default; - inline virtual QString getModSearchURL(int, QString, QString, bool, QString) const { return ""; }; + // https://docs.curseforge.com/?http#tocS_ModLoaderType + enum ModLoaderType { + Any = 0, + Forge = 1, + Cauldron = 2, + LiteLoader = 3, + Fabric = 4 + }; + + inline virtual QString getModSearchURL(int, QString, QString, ModLoaderType, QString) const { return ""; }; inline virtual QString getVersionsURL(const QString& addonId) const { return ""; }; inline virtual QString getAuthorURL(const QString& name) const { return ""; }; }; diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h index 6e2b9e253..b49aeb242 100644 --- a/launcher/modplatform/flame/FlameAPI.h +++ b/launcher/modplatform/flame/FlameAPI.h @@ -4,7 +4,8 @@ class FlameAPI : public ModAPI { public: - inline QString getModSearchURL(int index, QString searchFilter, QString sort, bool fabricCompatible, QString version) const override + + inline QString getModSearchURL(int index, QString searchFilter, QString sort, ModLoaderType modLoader, QString version) const override { return QString("https://addons-ecs.forgesvc.net/api/v2/addon/search?" "gameId=432&" "categoryId=0&" "sectionId=6&" @@ -14,7 +15,7 @@ class FlameAPI : public ModAPI { .arg(index) .arg(searchFilter) .arg(sort) - .arg(fabricCompatible ? 4 : 1) // Enum: https://docs.curseforge.com/?http#tocS_ModLoaderType + .arg(modLoader) .arg(version); }; diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 4ae8b8f9d..44a362c85 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -2,17 +2,24 @@ #include "modplatform/ModAPI.h" +#include + class ModrinthAPI : public ModAPI { public: - inline QString getModSearchURL(int offset, QString query, QString sort, bool fabricCompatible, QString version) const override + inline QString getModSearchURL(int offset, QString query, QString sort, ModLoaderType modLoader, QString version) const override { + if(!validateModLoader(modLoader)){ + qWarning() << "Modrinth only have Forge and Fabric-compatible mods!"; + return ""; + } + return QString("https://api.modrinth.com/v2/search?" "offset=%1&" "limit=25&" "query=%2&" "index=%3&" "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") .arg(offset) .arg(query) .arg(sort) - .arg(fabricCompatible ? "fabric" : "forge") + .arg(getModLoaderString(modLoader)) .arg(version); }; @@ -22,4 +29,22 @@ class ModrinthAPI : public ModAPI { }; inline QString getAuthorURL(const QString& name) const override { return "https://modrinth.com/user/" + name; }; + + private: + inline bool validateModLoader(ModLoaderType modLoader) const{ + return modLoader == Any || modLoader == Forge || modLoader == Fabric; + } + + inline QString getModLoaderString(ModLoaderType modLoader) const{ + switch(modLoader){ + case Any: + return "fabric, forge"; + case Forge: + return "forge"; + case Fabric: + return "fabric"; + default: + return ""; + } + } }; diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 4462c20b2..5be578c1e 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -125,7 +125,8 @@ void ListModel::performPaginatedSearch() ->getComponentVersion("net.fabricmc.fabric-loader") .isEmpty(); auto netJob = new NetJob(QString("%1::Search").arg(m_parent->debugName()), APPLICATION->network()); - auto searchUrl = m_parent->apiProvider()->getModSearchURL(nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric, mcVersion); + auto searchUrl = m_parent->apiProvider()->getModSearchURL( + nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric ? ModAPI::Fabric : ModAPI::Forge, mcVersion); netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); jobPtr = netJob; From f714adf6d2cc94f20ba37f2776d0d61e22267f0e Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 7 Mar 2022 16:22:57 -0300 Subject: [PATCH 09/18] refactor: move NetJob away from ModModel to ModAPI This is done so that 1. ModAPI behaves more like an actual API instead of just a helper, and 2. Allows for more easily creating other mod providers that may or may not use network tasks (foreshadowing lol) --- launcher/modplatform/ModAPI.h | 35 ++++-- launcher/modplatform/flame/FlameAPI.h | 91 ++++++++++++-- launcher/modplatform/modrinth/ModrinthAPI.h | 117 +++++++++++++----- launcher/ui/pages/modplatform/ModModel.cpp | 47 +++---- launcher/ui/pages/modplatform/ModModel.h | 13 +- launcher/ui/pages/modplatform/ModPage.h | 2 +- .../pages/modplatform/flame/FlameModModel.cpp | 10 +- .../pages/modplatform/flame/FlameModModel.h | 2 +- .../pages/modplatform/flame/FlameModPage.cpp | 12 +- .../ui/pages/modplatform/flame/FlameModPage.h | 2 +- .../modplatform/modrinth/ModrinthModel.cpp | 13 +- .../modplatform/modrinth/ModrinthModel.h | 4 +- .../modplatform/modrinth/ModrinthPage.cpp | 15 +-- .../pages/modplatform/modrinth/ModrinthPage.h | 2 +- 14 files changed, 230 insertions(+), 135 deletions(-) diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h index 4d22a63dd..8503d7fc0 100644 --- a/launcher/modplatform/ModAPI.h +++ b/launcher/modplatform/ModAPI.h @@ -1,21 +1,30 @@ #pragma once +#include #include +namespace ModPlatform { +class ListModel; +} + class ModAPI { - public: - virtual ~ModAPI() = default; + protected: + using CallerType = ModPlatform::ListModel; - // https://docs.curseforge.com/?http#tocS_ModLoaderType - enum ModLoaderType { - Any = 0, - Forge = 1, - Cauldron = 2, - LiteLoader = 3, - Fabric = 4 - }; + public: + virtual ~ModAPI() = default; - inline virtual QString getModSearchURL(int, QString, QString, ModLoaderType, QString) const { return ""; }; - inline virtual QString getVersionsURL(const QString& addonId) const { return ""; }; - inline virtual QString getAuthorURL(const QString& name) const { return ""; }; + // https://docs.curseforge.com/?http#tocS_ModLoaderType + enum ModLoaderType { Any = 0, Forge = 1, Cauldron = 2, LiteLoader = 3, Fabric = 4 }; + + struct SearchArgs { + int offset; + QString search; + QString sorting; + ModLoaderType mod_loader; + QString version; + }; + + inline virtual void searchMods(CallerType* caller, SearchArgs&& args) const {}; + inline virtual void getVersions(CallerType* caller, const QString& addonId, const QString& debugName = "") const {}; }; diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h index b49aeb242..be88df656 100644 --- a/launcher/modplatform/flame/FlameAPI.h +++ b/launcher/modplatform/flame/FlameAPI.h @@ -1,28 +1,93 @@ #pragma once #include "modplatform/ModAPI.h" +#include "ui/pages/modplatform/ModModel.h" + +#include "Application.h" +#include "net/NetJob.h" class FlameAPI : public ModAPI { public: - - inline QString getModSearchURL(int index, QString searchFilter, QString sort, ModLoaderType modLoader, QString version) const override + inline void searchMods(CallerType* caller, SearchArgs&& args) const override { - return QString("https://addons-ecs.forgesvc.net/api/v2/addon/search?" - "gameId=432&" "categoryId=0&" "sectionId=6&" + auto netJob = new NetJob(QString("Flame::Search"), APPLICATION->network()); + auto searchUrl = getModSearchURL(args); - "index=%1&" "pageSize=25&" "searchFilter=%2&" - "sort=%3&" "modLoaderType=%4&" "gameVersion=%5") - .arg(index) - .arg(searchFilter) - .arg(sort) - .arg(modLoader) - .arg(version); + auto response = new QByteArray(); + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + + QObject::connect(netJob, &NetJob::started, caller, [caller, netJob]{ caller->setActiveJob(netJob); }); + QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed); + QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] { + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + caller->searchRequestFinished(doc); + }); + + netJob->start(); }; - inline QString getVersionsURL(const QString& addonId) const override + inline void getVersions(CallerType* caller, const QString& addonId, const QString& debugName = "Flame") const override + { + auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName).arg(addonId), APPLICATION->network()); + auto response = new QByteArray(); + + netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response)); + + QObject::connect(netJob, &NetJob::succeeded, caller, [response, debugName, caller, addonId] { + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from " << debugName << " at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + caller->versionRequestSucceeded(doc, addonId); + }); + + QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + + netJob->start(); + }; + + private: + inline QString getModSearchURL(SearchArgs& args) const + { + return QString( + "https://addons-ecs.forgesvc.net/api/v2/addon/search?" + "gameId=432&" + "categoryId=0&" + "sectionId=6&" + + "index=%1&" + "pageSize=25&" + "searchFilter=%2&" + "sort=%3&" + "modLoaderType=%4&" + "gameVersion=%5") + .arg(args.offset) + .arg(args.search) + .arg(args.sorting) + .arg(args.mod_loader) + .arg(args.version); + }; + + inline QString getVersionsURL(const QString& addonId) const { return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId); }; - inline QString getAuthorURL(const QString& name) const override { return ""; }; + inline QString getAuthorURL(const QString& name) const { return ""; }; }; diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 44a362c85..84cc561b1 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -1,50 +1,111 @@ #pragma once #include "modplatform/ModAPI.h" +#include "ui/pages/modplatform/ModModel.h" + +#include "Application.h" +#include "net/NetJob.h" #include class ModrinthAPI : public ModAPI { public: - inline QString getModSearchURL(int offset, QString query, QString sort, ModLoaderType modLoader, QString version) const override - { - if(!validateModLoader(modLoader)){ + inline void searchMods(CallerType* caller, SearchArgs&& args) const override + { + auto netJob = new NetJob(QString("Modrinth::Search"), APPLICATION->network()); + auto searchUrl = getModSearchURL(args); + + auto response = new QByteArray(); + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + + QObject::connect(netJob, &NetJob::started, caller, [caller, netJob]{ caller->setActiveJob(netJob); }); + QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed); + QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] { + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + caller->searchRequestFinished(doc); + }); + + netJob->start(); + }; + + inline void getVersions(CallerType* caller, const QString& addonId, const QString& debugName = "Modrinth") const override + { + auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName).arg(addonId), APPLICATION->network()); + auto response = new QByteArray(); + + netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response)); + + QObject::connect(netJob, &NetJob::succeeded, caller, [response, debugName, caller, addonId] { + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from " << debugName << " at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + caller->versionRequestSucceeded(doc, addonId); + }); + + QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + + netJob->start(); + }; + + inline QString getAuthorURL(const QString& name) const { return "https://modrinth.com/user/" + name; }; + + private: + inline QString getModSearchURL(SearchArgs& args) const + { + if (!validateModLoader(args.mod_loader)) { qWarning() << "Modrinth only have Forge and Fabric-compatible mods!"; return ""; } - return QString("https://api.modrinth.com/v2/search?" - "offset=%1&" "limit=25&" "query=%2&" "index=%3&" - "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") - .arg(offset) - .arg(query) - .arg(sort) - .arg(getModLoaderString(modLoader)) - .arg(version); + return QString( + "https://api.modrinth.com/v2/search?" + "offset=%1&" + "limit=25&" + "query=%2&" + "index=%3&" + "facets=[[\"categories:%4\"],[\"versions:%5\"],[\"project_type:mod\"]]") + .arg(args.offset) + .arg(args.search) + .arg(args.sorting) + .arg(getModLoaderString(args.mod_loader)) + .arg(args.version); }; - inline QString getVersionsURL(const QString& addonId) const override + inline QString getVersionsURL(const QString& addonId) const { return QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId); }; - inline QString getAuthorURL(const QString& name) const override { return "https://modrinth.com/user/" + name; }; + inline bool validateModLoader(ModLoaderType modLoader) const { return modLoader == Any || modLoader == Forge || modLoader == Fabric; } - private: - inline bool validateModLoader(ModLoaderType modLoader) const{ - return modLoader == Any || modLoader == Forge || modLoader == Fabric; - } - - inline QString getModLoaderString(ModLoaderType modLoader) const{ - switch(modLoader){ - case Any: - return "fabric, forge"; - case Forge: - return "forge"; - case Fabric: - return "fabric"; - default: - return ""; + inline QString getModLoaderString(ModLoaderType modLoader) const + { + switch (modLoader) { + case Any: + return "fabric, forge"; + case Forge: + return "forge"; + case Fabric: + return "fabric"; + default: + return ""; } } }; diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 5be578c1e..705f384e8 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -91,30 +91,16 @@ void ListModel::fetchMore(const QModelIndex& parent) void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) { if (m_logoMap.contains(logo)) { - callback(APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); + callback(APPLICATION->metacache() + ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) + ->getFullPath()); } else { requestLogo(logo, logoUrl); } } -void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) -{ - auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(m_parent->debugName()).arg(current.name), APPLICATION->network()); - auto response = new QByteArray(); - QString addonId = current.addonId.toString(); - - netJob->addNetAction(Net::Download::makeByteArray(m_parent->apiProvider()->getVersionsURL(addonId), response)); - - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId]{ - m_parent->onRequestVersionsSucceeded(m_parent, response, addonId); - }); - - QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { - netJob->deleteLater(); - delete response; - }); - - netJob->start(); +void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) { + m_parent->apiProvider()->getVersions(this, current.addonId.toString(), m_parent->debugName()); } void ListModel::performPaginatedSearch() @@ -124,16 +110,9 @@ void ListModel::performPaginatedSearch() ->getPackProfile() ->getComponentVersion("net.fabricmc.fabric-loader") .isEmpty(); - auto netJob = new NetJob(QString("%1::Search").arg(m_parent->debugName()), APPLICATION->network()); - auto searchUrl = m_parent->apiProvider()->getModSearchURL( - nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric ? ModAPI::Fabric : ModAPI::Forge, mcVersion); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); + m_parent->apiProvider()->searchMods( + this, { nextSearchOffset, currentSearchTerm, getSorts()[currentSort], hasFabric ? ModAPI::Fabric : ModAPI::Forge, mcVersion }); } void ListModel::searchWithTerm(const QString& term, const int sort) @@ -160,9 +139,7 @@ void ListModel::searchRequestFailed(QString reason) if (jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { // 409 Gone, notify user to update QMessageBox::critical(nullptr, tr("Error"), - QString("%1 %2") - .arg(m_parent->displayName()) - .arg(tr("API version too old!\nPlease update PolyMC!"))); + QString("%1 %2").arg(m_parent->displayName()).arg(tr("API version too old!\nPlease update PolyMC!"))); // self-destruct ((ModDownloadDialog*)((ModPage*)parent())->parentWidget())->reject(); } @@ -180,11 +157,17 @@ void ListModel::searchRequestFailed(QString reason) } } +void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId) +{ + m_parent->onRequestVersionsSucceeded(doc, addonId); +} + void ListModel::requestLogo(QString logo, QString url) { if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) { return; } - MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + MetaEntryPtr entry = + APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 64c17b4a6..28bf05bb5 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -1,9 +1,10 @@ #pragma once +#include #include -#include "modplatform/ModIndex.h" #include "modplatform/ModAPI.h" +#include "modplatform/ModIndex.h" #include "net/NetJob.h" class ModPage; @@ -26,6 +27,8 @@ class ListModel : public QAbstractListModel { QVariant data(const QModelIndex& index, int role) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; + void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } + bool canFetchMore(const QModelIndex& parent) const override; void fetchMore(const QModelIndex& parent) override; @@ -34,10 +37,14 @@ class ListModel : public QAbstractListModel { virtual void requestModVersions(const ModPlatform::IndexedPack& current); - protected slots: - virtual void searchRequestFinished() = 0; + public slots: + virtual void searchRequestFinished(QJsonDocument& doc) = 0; void searchRequestFailed(QString reason); + void versionRequestSucceeded(QJsonDocument doc, QString addonId); + + protected slots: + void logoFailed(QString logo); void logoLoaded(QString logo, QIcon out); diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index e0d7c95ca..aa0e8894e 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -37,7 +37,7 @@ class ModPage : public QWidget, public BasePage { virtual bool shouldDisplay() const override = 0; const ModAPI* apiProvider() const { return api.get(); }; - virtual void onRequestVersionsSucceeded(ModPage*, QByteArray*, QString) = 0; + virtual void onRequestVersionsSucceeded(QJsonDocument&, QString) = 0; void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 283f9ce75..cff29a79f 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -11,18 +11,10 @@ ListModel::ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} ListModel::~ListModel() {} -void FlameMod::ListModel::searchRequestFinished() +void FlameMod::ListModel::searchRequestFinished(QJsonDocument& doc) { jobPtr.reset(); - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error); - if(parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Flame at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << response; - return; - } - QList newList; auto packs = doc.array(); for(auto packRaw : packs) { diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index ae919e639..022ec32e5 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -30,7 +30,7 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel(); private slots: - void searchRequestFinished() override; + void searchRequestFinished(QJsonDocument& doc) override; private: const char** getSorts() const override; diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 6564265c4..19f582808 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -36,23 +36,17 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) bool FlameModPage::shouldDisplay() const { return true; } -void FlameModPage::onRequestVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) +void FlameModPage::onRequestVersionsSucceeded(QJsonDocument& doc, QString addonId) { if (addonId != current.addonId) { return; // wrong request } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Flame at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } + QJsonArray arr = doc.array(); try { FlameMod::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance); } catch (const JSONValidationError& e) { - qDebug() << *response; + qDebug() << doc; qWarning() << "Error while reading Flame mod version: " << e.cause(); } auto packProfile = ((MinecraftInstance*)m_instance)->getPackProfile(); diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 9c6f0e6c7..f15b51ec8 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -22,5 +22,5 @@ class FlameModPage : public ModPage { bool shouldDisplay() const override; private: - void onRequestVersionsSucceeded(ModPage*, QByteArray*, QString) override; + void onRequestVersionsSucceeded(QJsonDocument&, QString) override; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index dc3d14697..784b11284 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -10,19 +10,10 @@ ListModel::ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent) {} ListModel::~ListModel() {} -void Modrinth::ListModel::searchRequestFinished() +void Modrinth::ListModel::searchRequestFinished(QJsonDocument& doc) { jobPtr.reset(); - - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << response; - return; - } - + QList newList; auto packs = doc.object().value("hits").toArray(); for (auto packRaw : packs) { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index b8937b506..d095b18ca 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -29,8 +29,8 @@ class ListModel : public ModPlatform::ListModel { ListModel(ModrinthPage* parent); virtual ~ListModel(); - private slots: - void searchRequestFinished() override; + public slots: + void searchRequestFinished(QJsonDocument& doc) override; private: const char** getSorts() const override; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 944f8afbf..fa703e38f 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -35,22 +35,15 @@ ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) bool ModrinthPage::shouldDisplay() const { return true; } -void ModrinthPage::onRequestVersionsSucceeded(ModPage* instance, QByteArray* response, QString addonId) +void ModrinthPage::onRequestVersionsSucceeded(QJsonDocument& response, QString addonId) { if (addonId != current.addonId) { return; } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } - QJsonArray arr = doc.array(); + + QJsonArray arr = response.array(); try { Modrinth::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance); } catch (const JSONValidationError& e) { - qDebug() << *response; + qDebug() << response; qWarning() << "Error while reading Modrinth mod version: " << e.cause(); } auto packProfile = ((MinecraftInstance*)m_instance)->getPackProfile(); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 7b1d0a00c..f6d1eef0c 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -22,5 +22,5 @@ class ModrinthPage : public ModPage { bool shouldDisplay() const override; private: - void onRequestVersionsSucceeded(ModPage*, QByteArray*, QString) override; + void onRequestVersionsSucceeded(QJsonDocument&, QString) override; }; From 16bfafa29e2cb54e1553c813cab0fff5203f8c60 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 7 Mar 2022 16:46:08 -0300 Subject: [PATCH 10/18] refactor: de-duplicate common code in network mod APIs --- launcher/CMakeLists.txt | 11 +++ launcher/modplatform/ModAPI.h | 5 +- launcher/modplatform/flame/FlameAPI.h | 65 +--------------- .../modplatform/helpers/NetworkModAPI.cpp | 60 +++++++++++++++ launcher/modplatform/helpers/NetworkModAPI.h | 13 ++++ launcher/modplatform/modrinth/ModrinthAPI.h | 74 +++---------------- launcher/ui/pages/modplatform/ModModel.cpp | 10 ++- launcher/ui/pages/modplatform/ModModel.h | 4 +- 8 files changed, 109 insertions(+), 133 deletions(-) create mode 100644 launcher/modplatform/helpers/NetworkModAPI.cpp create mode 100644 launcher/modplatform/helpers/NetworkModAPI.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 0dcda9257..48370c967 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -492,6 +492,16 @@ set(META_SOURCES meta/Index.h ) +set(API_SOURCES + modplatform/ModAPI.h + + modplatform/flame/FlameAPI.h + modplatform/modrinth/ModrinthAPI.h + + modplatform/helpers/NetworkModAPI.h + modplatform/helpers/NetworkModAPI.cpp +) + set(FTB_SOURCES modplatform/legacy_ftb/PackFetchTask.h modplatform/legacy_ftb/PackFetchTask.cpp @@ -572,6 +582,7 @@ set(LOGIC_SOURCES ${TOOLS_SOURCES} ${META_SOURCES} ${ICONS_SOURCES} + ${API_SOURCES} ${FTB_SOURCES} ${FLAME_SOURCES} ${MODRINTH_SOURCES} diff --git a/launcher/modplatform/ModAPI.h b/launcher/modplatform/ModAPI.h index 8503d7fc0..5c7c63490 100644 --- a/launcher/modplatform/ModAPI.h +++ b/launcher/modplatform/ModAPI.h @@ -1,6 +1,5 @@ #pragma once -#include #include namespace ModPlatform { @@ -25,6 +24,6 @@ class ModAPI { QString version; }; - inline virtual void searchMods(CallerType* caller, SearchArgs&& args) const {}; - inline virtual void getVersions(CallerType* caller, const QString& addonId, const QString& debugName = "") const {}; + virtual void searchMods(CallerType* caller, SearchArgs&& args) const = 0; + virtual void getVersions(CallerType* caller, const QString& addonId) const = 0; }; diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h index be88df656..f7f993d72 100644 --- a/launcher/modplatform/flame/FlameAPI.h +++ b/launcher/modplatform/flame/FlameAPI.h @@ -1,67 +1,8 @@ #pragma once -#include "modplatform/ModAPI.h" -#include "ui/pages/modplatform/ModModel.h" - -#include "Application.h" -#include "net/NetJob.h" - -class FlameAPI : public ModAPI { - public: - inline void searchMods(CallerType* caller, SearchArgs&& args) const override - { - auto netJob = new NetJob(QString("Flame::Search"), APPLICATION->network()); - auto searchUrl = getModSearchURL(args); - - auto response = new QByteArray(); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); - - QObject::connect(netJob, &NetJob::started, caller, [caller, netJob]{ caller->setActiveJob(netJob); }); - QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed); - QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] { - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } - - caller->searchRequestFinished(doc); - }); - - netJob->start(); - }; - - inline void getVersions(CallerType* caller, const QString& addonId, const QString& debugName = "Flame") const override - { - auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName).arg(addonId), APPLICATION->network()); - auto response = new QByteArray(); - - netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response)); - - QObject::connect(netJob, &NetJob::succeeded, caller, [response, debugName, caller, addonId] { - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from " << debugName << " at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } - - caller->versionRequestSucceeded(doc, addonId); - }); - - QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] { - netJob->deleteLater(); - delete response; - }); - - netJob->start(); - }; +#include "modplatform/helpers/NetworkModAPI.h" +class FlameAPI : public NetworkModAPI { private: inline QString getModSearchURL(SearchArgs& args) const { @@ -88,6 +29,4 @@ class FlameAPI : public ModAPI { { return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId); }; - - inline QString getAuthorURL(const QString& name) const { return ""; }; }; diff --git a/launcher/modplatform/helpers/NetworkModAPI.cpp b/launcher/modplatform/helpers/NetworkModAPI.cpp new file mode 100644 index 000000000..4b0661028 --- /dev/null +++ b/launcher/modplatform/helpers/NetworkModAPI.cpp @@ -0,0 +1,60 @@ +#include "NetworkModAPI.h" + +#include "ui/pages/modplatform/ModModel.h" + +#include "Application.h" +#include "net/NetJob.h" + +void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const +{ + auto netJob = new NetJob(QString("Modrinth::Search"), APPLICATION->network()); + auto searchUrl = getModSearchURL(args); + + auto response = new QByteArray(); + netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); + + QObject::connect(netJob, &NetJob::started, caller, [caller, netJob] { caller->setActiveJob(netJob); }); + QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed); + QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] { + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + caller->searchRequestFinished(doc); + }); + + netJob->start(); +}; + +void NetworkModAPI::getVersions(CallerType* caller, const QString& addonId) const +{ + auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(caller->debugName()).arg(addonId), APPLICATION->network()); + auto response = new QByteArray(); + + netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response)); + + QObject::connect(netJob, &NetJob::succeeded, caller, [response, caller, addonId] { + QJsonParseError parse_error; + QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); + if (parse_error.error != QJsonParseError::NoError) { + qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset + << " reason: " << parse_error.errorString(); + qWarning() << *response; + return; + } + + caller->versionRequestSucceeded(doc, addonId); + }); + + QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] { + netJob->deleteLater(); + delete response; + }); + + netJob->start(); +}; diff --git a/launcher/modplatform/helpers/NetworkModAPI.h b/launcher/modplatform/helpers/NetworkModAPI.h new file mode 100644 index 000000000..651920464 --- /dev/null +++ b/launcher/modplatform/helpers/NetworkModAPI.h @@ -0,0 +1,13 @@ +#pragma once + +#include "modplatform/ModAPI.h" + +class NetworkModAPI : public ModAPI { + public: + void searchMods(CallerType* caller, SearchArgs&& args) const override; + void getVersions(CallerType* caller, const QString& addonId) const override; + + protected: + virtual QString getModSearchURL(SearchArgs& args) const = 0; + virtual QString getVersionsURL(const QString& addonId) const = 0; +}; diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 84cc561b1..1cc51ff26 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -1,73 +1,15 @@ #pragma once -#include "modplatform/ModAPI.h" -#include "ui/pages/modplatform/ModModel.h" - -#include "Application.h" -#include "net/NetJob.h" +#include "modplatform/helpers/NetworkModAPI.h" #include -class ModrinthAPI : public ModAPI { +class ModrinthAPI : public NetworkModAPI { public: - inline void searchMods(CallerType* caller, SearchArgs&& args) const override - { - auto netJob = new NetJob(QString("Modrinth::Search"), APPLICATION->network()); - auto searchUrl = getModSearchURL(args); - - auto response = new QByteArray(); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response)); - - QObject::connect(netJob, &NetJob::started, caller, [caller, netJob]{ caller->setActiveJob(netJob); }); - QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed); - QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] { - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } - - caller->searchRequestFinished(doc); - }); - - netJob->start(); - }; - - inline void getVersions(CallerType* caller, const QString& addonId, const QString& debugName = "Modrinth") const override - { - auto netJob = new NetJob(QString("%1::ModVersions(%2)").arg(debugName).arg(addonId), APPLICATION->network()); - auto response = new QByteArray(); - - netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response)); - - QObject::connect(netJob, &NetJob::succeeded, caller, [response, debugName, caller, addonId] { - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - if (parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from " << debugName << " at " << parse_error.offset - << " reason: " << parse_error.errorString(); - qWarning() << *response; - return; - } - - caller->versionRequestSucceeded(doc, addonId); - }); - - QObject::connect(netJob, &NetJob::finished, caller, [response, netJob] { - netJob->deleteLater(); - delete response; - }); - - netJob->start(); - }; - inline QString getAuthorURL(const QString& name) const { return "https://modrinth.com/user/" + name; }; private: - inline QString getModSearchURL(SearchArgs& args) const + inline QString getModSearchURL(SearchArgs& args) const override { if (!validateModLoader(args.mod_loader)) { qWarning() << "Modrinth only have Forge and Fabric-compatible mods!"; @@ -88,13 +30,11 @@ class ModrinthAPI : public ModAPI { .arg(args.version); }; - inline QString getVersionsURL(const QString& addonId) const + inline QString getVersionsURL(const QString& addonId) const override { return QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId); }; - inline bool validateModLoader(ModLoaderType modLoader) const { return modLoader == Any || modLoader == Forge || modLoader == Fabric; } - inline QString getModLoaderString(ModLoaderType modLoader) const { switch (modLoader) { @@ -108,4 +48,10 @@ class ModrinthAPI : public ModAPI { return ""; } } + + inline bool validateModLoader(ModLoaderType modLoader) const + { + return modLoader == Any || modLoader == Forge || modLoader == Fabric; + } + }; diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 705f384e8..015fcf7d5 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -53,6 +53,11 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return QVariant(); } +QString ListModel::debugName() const +{ + return m_parent->debugName(); +} + void ListModel::logoLoaded(QString logo, QIcon out) { m_loadingLogos.removeAll(logo); @@ -99,8 +104,9 @@ void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallbac } } -void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) { - m_parent->apiProvider()->getVersions(this, current.addonId.toString(), m_parent->debugName()); +void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) +{ + m_parent->apiProvider()->getVersions(this, current.addonId.toString()); } void ListModel::performPaginatedSearch() diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 28bf05bb5..e971149c9 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -1,6 +1,5 @@ #pragma once -#include #include #include "modplatform/ModAPI.h" @@ -24,6 +23,9 @@ class ListModel : public QAbstractListModel { int rowCount(const QModelIndex& parent) const override; int columnCount(const QModelIndex& parent) const override; + QString debugName() const; + + /* Retrieve information from the model at a given index with the given role */ QVariant data(const QModelIndex& index, int role) const override; Qt::ItemFlags flags(const QModelIndex& index) const override; From b131d3b2ecbe6a9be35088d8411927bcd30de896 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 7 Mar 2022 17:46:18 -0300 Subject: [PATCH 11/18] refactor: move more common code to base class Also removes unused imports and organize the ModModel header --- launcher/ui/pages/modplatform/ModModel.cpp | 56 +++++++++++-------- launcher/ui/pages/modplatform/ModModel.h | 22 ++++---- .../pages/modplatform/flame/FlameModModel.cpp | 48 +--------------- .../pages/modplatform/flame/FlameModModel.h | 34 ++++------- .../modplatform/modrinth/ModrinthModel.cpp | 44 +-------------- .../modplatform/modrinth/ModrinthModel.h | 31 +++------- 6 files changed, 65 insertions(+), 170 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 015fcf7d5..b8b90f84c 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -1,6 +1,6 @@ #include "ModModel.h" -#include "ModPage.h" +#include "Json.h" #include "minecraft/MinecraftInstance.h" #include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" @@ -11,18 +11,6 @@ namespace ModPlatform { ListModel::ListModel(ModPage* parent) : QAbstractListModel(parent), m_parent(parent) {} -ListModel::~ListModel() {} - -int ListModel::rowCount(const QModelIndex& parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex& parent) const -{ - return 1; -} - QVariant ListModel::data(const QModelIndex& index, int role) const { int pos = index.row(); @@ -73,16 +61,6 @@ void ListModel::logoFailed(QString logo) m_loadingLogos.removeAll(logo); } -Qt::ItemFlags ListModel::flags(const QModelIndex& index) const -{ - return QAbstractListModel::flags(index); -} - -bool ListModel::canFetchMore(const QModelIndex& parent) const -{ - return searchState == CanPossiblyFetchMore; -} - void ListModel::fetchMore(const QModelIndex& parent) { if (parent.isValid()) return; @@ -140,6 +118,38 @@ void ListModel::searchWithTerm(const QString& term, const int sort) performPaginatedSearch(); } +void ListModel::searchRequestFinished(QJsonDocument& doc) +{ + jobPtr.reset(); + + QList newList; + auto packs = documentToArray(doc); + + for (auto packRaw : packs) { + auto packObj = packRaw.toObject(); + + ModPlatform::IndexedPack pack; + try { + loadIndexedPack(pack, packObj); + newList.append(pack); + } catch (const JSONValidationError& e) { + qWarning() << "Error while loading mod from " << m_parent->debugName() << ": " << e.cause(); + continue; + } + } + + if (packs.size() < 25) { + searchState = Finished; + } else { + nextSearchOffset += 25; + searchState = CanPossiblyFetchMore; + } + + beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); + modpacks.append(newList); + endInsertRows(); +} + void ListModel::searchRequestFailed(QString reason) { if (jobPtr->first()->m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 409) { diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index e971149c9..e0cc098df 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -18,29 +18,30 @@ class ListModel : public QAbstractListModel { public: ListModel(ModPage* parent); - virtual ~ListModel(); + virtual ~ListModel() = default; - int rowCount(const QModelIndex& parent) const override; - int columnCount(const QModelIndex& parent) const override; + inline int rowCount(const QModelIndex& parent) const override { return modpacks.size(); }; + inline int columnCount(const QModelIndex& parent) const override { return 1; }; + inline Qt::ItemFlags flags(const QModelIndex& index) const override { return QAbstractListModel::flags(index); }; QString debugName() const; /* Retrieve information from the model at a given index with the given role */ QVariant data(const QModelIndex& index, int role) const override; - Qt::ItemFlags flags(const QModelIndex& index) const override; - void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } + inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } - bool canFetchMore(const QModelIndex& parent) const override; + /* Ask the API for more information */ void fetchMore(const QModelIndex& parent) override; + void searchWithTerm(const QString& term, const int sort); + void requestModVersions(const ModPlatform::IndexedPack& current); void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); - void searchWithTerm(const QString& term, const int sort); - virtual void requestModVersions(const ModPlatform::IndexedPack& current); + inline bool canFetchMore(const QModelIndex& parent) const override { return searchState == CanPossiblyFetchMore; }; public slots: - virtual void searchRequestFinished(QJsonDocument& doc) = 0; + void searchRequestFinished(QJsonDocument& doc); void searchRequestFailed(QString reason); void versionRequestSucceeded(QJsonDocument doc, QString addonId); @@ -53,6 +54,8 @@ class ListModel : public QAbstractListModel { void performPaginatedSearch(); protected: + virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0; + virtual QJsonArray documentToArray(QJsonDocument& obj) const = 0; virtual const char** getSorts() const = 0; void requestLogo(QString file, QString url); @@ -73,6 +76,5 @@ class ListModel : public QAbstractListModel { enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None; NetJob::Ptr jobPtr; - QByteArray response; }; } // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index cff29a79f..7588a714c 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -1,53 +1,7 @@ #include "FlameModModel.h" -#include "FlameModPage.h" -#include "minecraft/PackProfile.h" - -#include namespace FlameMod { -ListModel::ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} - -ListModel::~ListModel() {} - - -void FlameMod::ListModel::searchRequestFinished(QJsonDocument& doc) -{ - jobPtr.reset(); - - QList newList; - auto packs = doc.array(); - for(auto packRaw : packs) { - auto packObj = packRaw.toObject(); - - ModPlatform::IndexedPack pack; - try - { - FlameMod::loadIndexedPack(pack, packObj); - newList.append(pack); - } - catch(const JSONValidationError &e) - { - qWarning() << "Error while loading mod from Flame: " << e.cause(); - continue; - } - } - if(packs.size() < 25) { - searchState = Finished; - } else { - nextSearchOffset += 25; - searchState = CanPossiblyFetchMore; - } - beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); - modpacks.append(newList); - endInsertRows(); -} - -const char* sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; - -const char** FlameMod::ListModel::getSorts() const -{ - return sorts; -} +const char* ListModel::sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; } // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index 022ec32e5..204834c9d 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -1,39 +1,25 @@ #pragma once -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "BaseInstance.h" #include "FlameModPage.h" #include "modplatform/flame/FlameModIndex.h" namespace FlameMod { -typedef std::function LogoCallback; - class ListModel : public ModPlatform::ListModel { Q_OBJECT public: - ListModel(FlameModPage* parent); - virtual ~ListModel(); - - private slots: - void searchRequestFinished(QJsonDocument& doc) override; + ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} +; + virtual ~ListModel() = default; private: - const char** getSorts() const override; + void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override { FlameMod::loadIndexedPack(m, obj); }; + + QJsonArray documentToArray(QJsonDocument& obj) const override { return obj.array(); }; + + static const char* sorts[6]; + const char** getSorts() const override { return sorts; }; }; -} // namespace Modrinth +} // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 784b11284..9361546e8 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,49 +1,7 @@ #include "ModrinthModel.h" -#include "ModrinthPage.h" -#include "minecraft/MinecraftInstance.h" - -#include namespace Modrinth { -ListModel::ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent) {} - -ListModel::~ListModel() {} - -void Modrinth::ListModel::searchRequestFinished(QJsonDocument& doc) -{ - jobPtr.reset(); - - QList newList; - auto packs = doc.object().value("hits").toArray(); - for (auto packRaw : packs) { - auto packObj = packRaw.toObject(); - - ModPlatform::IndexedPack pack; - try { - Modrinth::loadIndexedPack(pack, packObj); - newList.append(pack); - } catch (const JSONValidationError& e) { - qWarning() << "Error while loading mod from Modrinth: " << e.cause(); - continue; - } - } - if (packs.size() < 25) { - searchState = Finished; - } else { - nextSearchOffset += 25; - searchState = CanPossiblyFetchMore; - } - beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); - modpacks.append(newList); - endInsertRows(); -} - -const char* sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; - -const char** Modrinth::ListModel::getSorts() const -{ - return sorts; -} +const char* ListModel::sorts[5] { "relevance", "downloads", "follows", "updated", "newest" }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index d095b18ca..9137190d9 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -1,39 +1,24 @@ #pragma once -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "BaseInstance.h" #include "ModrinthPage.h" #include "modplatform/modrinth/ModrinthPackIndex.h" namespace Modrinth { -typedef std::function LogoCallback; - class ListModel : public ModPlatform::ListModel { Q_OBJECT public: - ListModel(ModrinthPage* parent); - virtual ~ListModel(); - - public slots: - void searchRequestFinished(QJsonDocument& doc) override; + ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent){}; + virtual ~ListModel() = default; private: - const char** getSorts() const override; + void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override { Modrinth::loadIndexedPack(m, obj); }; + + QJsonArray documentToArray(QJsonDocument& obj) const override { return obj.object().value("hits").toArray(); }; + + static const char* sorts[5]; + const char** getSorts() const override { return sorts; }; }; } // namespace Modrinth From 9c57b54a81a9026aa86a983a203df17c023eaa8d Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 7 Mar 2022 19:29:59 -0300 Subject: [PATCH 12/18] refactor: move things around so that related things are close together This also adds some comments around ModModel.cpp and ModPage.cpp to add some ease of reading the code. Also move some things from headers to cpp files. --- launcher/ui/pages/modplatform/ModModel.cpp | 149 ++++++++++-------- launcher/ui/pages/modplatform/ModModel.h | 4 +- launcher/ui/pages/modplatform/ModPage.cpp | 61 +++++-- launcher/ui/pages/modplatform/ModPage.h | 6 +- .../pages/modplatform/flame/FlameModModel.cpp | 17 ++ .../pages/modplatform/flame/FlameModModel.h | 8 +- .../pages/modplatform/flame/FlameModPage.cpp | 42 +---- .../ui/pages/modplatform/flame/FlameModPage.h | 5 +- .../modplatform/modrinth/ModrinthModel.cpp | 19 ++- .../modplatform/modrinth/ModrinthModel.h | 10 +- .../modplatform/modrinth/ModrinthPage.cpp | 39 +---- .../pages/modplatform/modrinth/ModrinthPage.h | 5 +- 12 files changed, 200 insertions(+), 165 deletions(-) diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index b8b90f84c..6f3c6ce04 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -11,6 +11,24 @@ namespace ModPlatform { ListModel::ListModel(ModPage* parent) : QAbstractListModel(parent), m_parent(parent) {} +QString ListModel::debugName() const +{ + return m_parent->debugName(); +} + + +/******** Make data requests ********/ + +void ListModel::fetchMore(const QModelIndex& parent) +{ + if (parent.isValid()) return; + if (nextSearchOffset == 0) { + qWarning() << "fetchMore with 0 offset is wrong..."; + return; + } + performPaginatedSearch(); +} + QVariant ListModel::data(const QModelIndex& index, int role) const { int pos = index.row(); @@ -41,47 +59,6 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return QVariant(); } -QString ListModel::debugName() const -{ - return m_parent->debugName(); -} - -void ListModel::logoLoaded(QString logo, QIcon out) -{ - m_loadingLogos.removeAll(logo); - m_logoMap.insert(logo, out); - for (int i = 0; i < modpacks.size(); i++) { - if (modpacks[i].logoName == logo) { emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole }); } - } -} - -void ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -void ListModel::fetchMore(const QModelIndex& parent) -{ - if (parent.isValid()) return; - if (nextSearchOffset == 0) { - qWarning() << "fetchMore with 0 offset is wrong..."; - return; - } - performPaginatedSearch(); -} - -void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) -{ - if (m_logoMap.contains(logo)) { - callback(APPLICATION->metacache() - ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) - ->getFullPath()); - } else { - requestLogo(logo, logoUrl); - } -} - void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) { m_parent->apiProvider()->getVersions(this, current.addonId.toString()); @@ -118,6 +95,60 @@ void ListModel::searchWithTerm(const QString& term, const int sort) performPaginatedSearch(); } +void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback) +{ + if (m_logoMap.contains(logo)) { + callback(APPLICATION->metacache() + ->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))) + ->getFullPath()); + } else { + requestLogo(logo, logoUrl); + } +} + +void ListModel::requestLogo(QString logo, QString url) +{ + if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) { return; } + + MetaEntryPtr entry = + APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); + auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); + job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); + + auto fullPath = entry->getFullPath(); + QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { + job->deleteLater(); + emit logoLoaded(logo, QIcon(fullPath)); + if (waitingCallbacks.contains(logo)) { waitingCallbacks.value(logo)(fullPath); } + }); + + QObject::connect(job, &NetJob::failed, this, [this, logo, job] { + job->deleteLater(); + emit logoFailed(logo); + }); + + job->start(); + m_loadingLogos.append(logo); +} + + +/******** Request callbacks ********/ + +void ListModel::logoLoaded(QString logo, QIcon out) +{ + m_loadingLogos.removeAll(logo); + m_logoMap.insert(logo, out); + for (int i = 0; i < modpacks.size(); i++) { + if (modpacks[i].logoName == logo) { emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole }); } + } +} + +void ListModel::logoFailed(QString logo) +{ + m_failedLogos.append(logo); + m_loadingLogos.removeAll(logo); +} + void ListModel::searchRequestFinished(QJsonDocument& doc) { jobPtr.reset(); @@ -175,32 +206,18 @@ void ListModel::searchRequestFailed(QString reason) void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId) { - m_parent->onRequestVersionsSucceeded(doc, addonId); -} + auto& current = m_parent->getCurrent(); + if (addonId != current.addonId) { return; } + + QJsonArray arr = doc.array(); + try { + loadIndexedPackVersions(current, arr); + } catch (const JSONValidationError& e) { + qDebug() << doc; + qWarning() << "Error while reading " << debugName() << " mod version: " << e.cause(); + } -void ListModel::requestLogo(QString logo, QString url) -{ - if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) { return; } - - MetaEntryPtr entry = - APPLICATION->metacache()->resolveEntry(m_parent->metaEntryBase(), QString("logos/%1").arg(logo.section(".", 0, 0))); - auto job = new NetJob(QString("%1 Icon Download %2").arg(m_parent->debugName()).arg(logo), APPLICATION->network()); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] { - job->deleteLater(); - emit logoLoaded(logo, QIcon(fullPath)); - if (waitingCallbacks.contains(logo)) { waitingCallbacks.value(logo)(fullPath); } - }); - - QObject::connect(job, &NetJob::failed, this, [this, logo, job] { - job->deleteLater(); - emit logoFailed(logo); - }); - - job->start(); - m_loadingLogos.append(logo); + m_parent->updateModVersions(); } } // namespace ModPlatform diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index e0cc098df..6c3ecc3d0 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -36,6 +36,9 @@ class ListModel : public QAbstractListModel { void searchWithTerm(const QString& term, const int sort); void requestModVersions(const ModPlatform::IndexedPack& current); + virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0; + virtual void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) = 0; + void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); inline bool canFetchMore(const QModelIndex& parent) const override { return searchState == CanPossiblyFetchMore; }; @@ -54,7 +57,6 @@ class ListModel : public QAbstractListModel { void performPaginatedSearch(); protected: - virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0; virtual QJsonArray documentToArray(QJsonDocument& obj) const = 0; virtual const char** getSorts() const = 0; diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index a57f2903d..94cf4bcfe 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -3,6 +3,8 @@ #include +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api) @@ -22,6 +24,9 @@ ModPage::~ModPage() delete ui; } + +/******** Qt things ********/ + void ModPage::openedImpl() { updateSelectionButton(); @@ -41,21 +46,8 @@ bool ModPage::eventFilter(QObject* watched, QEvent* event) return QWidget::eventFilter(watched, event); } -void ModPage::updateSelectionButton() -{ - if (!isOpened || selectedVersion < 0) { - ui->modSelectionButton->setEnabled(false); - return; - } - ui->modSelectionButton->setEnabled(true); - auto& version = current.versions[selectedVersion]; - if (!dialog->isModSelected(current.name, version.fileName)) { - ui->modSelectionButton->setText(tr("Select mod for download")); - } else { - ui->modSelectionButton->setText(tr("Deselect mod for download")); - } -} +/******** Callbacks to events in the UI (set up in the derived classes) ********/ void ModPage::triggerSearch() { @@ -130,3 +122,44 @@ void ModPage::onModSelected() updateSelectionButton(); } + + +/******** Make changes to the UI ********/ + +void ModPage::updateModVersions() +{ + auto packProfile = (static_cast(m_instance))->getPackProfile(); + + QString mcVersion = packProfile->getComponentVersion("net.minecraft"); + QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge"; + + for (int i = 0; i < current.versions.size(); i++) { + auto version = current.versions[i]; + //NOTE: Flame doesn't care about loaderString, so passing it changes nothing. + if (!validateVersion(version, mcVersion, loaderString)) { + continue; + } + ui->versionSelectionBox->addItem(version.version, QVariant(i)); + } + if (ui->versionSelectionBox->count() == 0) { ui->versionSelectionBox->addItem(tr("No valid version found!"), QVariant(-1)); } + + ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); + updateSelectionButton(); +} + + +void ModPage::updateSelectionButton() +{ + if (!isOpened || selectedVersion < 0) { + ui->modSelectionButton->setEnabled(false); + return; + } + + ui->modSelectionButton->setEnabled(true); + auto& version = current.versions[selectedVersion]; + if (!dialog->isModSelected(current.name, version.fileName)) { + ui->modSelectionButton->setText(tr("Select mod for download")); + } else { + ui->modSelectionButton->setText(tr("Deselect mod for download")); + } +} diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index aa0e8894e..de66b3b08 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -35,9 +35,12 @@ class ModPage : public QWidget, public BasePage { virtual bool shouldDisplay() const override = 0; + virtual bool validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const = 0; + const ModAPI* apiProvider() const { return api.get(); }; - virtual void onRequestVersionsSucceeded(QJsonDocument&, QString) = 0; + ModPlatform::IndexedPack& getCurrent() { return current; } + void updateModVersions(); void openedImpl() override; bool eventFilter(QObject* watched, QEvent* event) override; @@ -45,7 +48,6 @@ class ModPage : public QWidget, public BasePage { BaseInstance* m_instance; protected: - void updateSelectionButton(); protected slots: diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 7588a714c..ce2f74f1c 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -1,7 +1,24 @@ #include "FlameModModel.h" +#include "modplatform/flame/FlameModIndex.h" + namespace FlameMod { const char* ListModel::sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; +void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) +{ + FlameMod::loadIndexedPack(m, obj); +}; + +void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) +{ + FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); +}; + +QJsonArray ListModel::documentToArray(QJsonDocument& obj) const +{ + return obj.array(); +} + } // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index 204834c9d..cf3042ed8 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -1,7 +1,6 @@ #pragma once #include "FlameModPage.h" -#include "modplatform/flame/FlameModIndex.h" namespace FlameMod { @@ -14,12 +13,13 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel() = default; private: - void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override { FlameMod::loadIndexedPack(m, obj); }; + void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; + void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; - QJsonArray documentToArray(QJsonDocument& obj) const override { return obj.array(); }; + QJsonArray documentToArray(QJsonDocument& obj) const override; static const char* sorts[6]; - const char** getSorts() const override { return sorts; }; + inline const char** getSorts() const override { return sorts; }; }; } // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 19f582808..091e49c74 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -1,15 +1,7 @@ #include "FlameModPage.h" #include "ui_ModPage.h" -#include - -#include "Application.h" #include "FlameModModel.h" -#include "InstanceImportTask.h" -#include "Json.h" -#include "ModDownloadTask.h" -#include "minecraft/MinecraftInstance.h" -#include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) @@ -34,31 +26,13 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) connect(ui->modSelectionButton, &QPushButton::clicked, this, &FlameModPage::onModSelected); } -bool FlameModPage::shouldDisplay() const { return true; } - -void FlameModPage::onRequestVersionsSucceeded(QJsonDocument& doc, QString addonId) +bool FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer) const { - if (addonId != current.addonId) { - return; // wrong request - } - - QJsonArray arr = doc.array(); - try { - FlameMod::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance); - } catch (const JSONValidationError& e) { - qDebug() << doc; - qWarning() << "Error while reading Flame mod version: " << e.cause(); - } - auto packProfile = ((MinecraftInstance*)m_instance)->getPackProfile(); - QString mcVersion = packProfile->getComponentVersion("net.minecraft"); - QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge"; - for (int i = 0; i < current.versions.size(); i++) { - auto version = current.versions[i]; - if (!version.mcVersion.contains(mcVersion)) { continue; } - ui->versionSelectionBox->addItem(version.version, QVariant(i)); - } - if (ui->versionSelectionBox->count() == 0) { ui->versionSelectionBox->addItem(tr("No Valid Version found!"), QVariant(-1)); } - - ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); - updateSelectionButton(); + (void) loaderVer; + return ver.mcVersion.contains(mineVer); } + +// I don't know why, but doing this on the parent class makes it so that +// other mod providers start loading before being selected, at least with +// my Qt, so we need to implement this in every derived class... +bool FlameModPage::shouldDisplay() const { return true; } diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index f15b51ec8..90513ca5e 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -19,8 +19,7 @@ class FlameModPage : public ModPage { inline QString debugName() const override { return tr("Flame"); } inline QString metaEntryBase() const override { return "FlameMods"; }; - bool shouldDisplay() const override; + bool validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const override; - private: - void onRequestVersionsSucceeded(QJsonDocument&, QString) override; + bool shouldDisplay() const override; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 9361546e8..0db6aeffb 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -1,7 +1,24 @@ #include "ModrinthModel.h" +#include "modplatform/modrinth/ModrinthPackIndex.h" + namespace Modrinth { -const char* ListModel::sorts[5] { "relevance", "downloads", "follows", "updated", "newest" }; +const char* ListModel::sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; + +void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) +{ + Modrinth::loadIndexedPack(m, obj); +} + +void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) +{ + Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); +}; + +QJsonArray ListModel::documentToArray(QJsonDocument& obj) const +{ + return obj.object().value("hits").toArray(); +} } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index 9137190d9..de73704cd 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -1,7 +1,6 @@ #pragma once #include "ModrinthPage.h" -#include "modplatform/modrinth/ModrinthPackIndex.h" namespace Modrinth { @@ -13,12 +12,13 @@ class ListModel : public ModPlatform::ListModel { virtual ~ListModel() = default; private: - void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override { Modrinth::loadIndexedPack(m, obj); }; - - QJsonArray documentToArray(QJsonDocument& obj) const override { return obj.object().value("hits").toArray(); }; + void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; + void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; + + QJsonArray documentToArray(QJsonDocument& obj) const override; static const char* sorts[5]; - const char** getSorts() const override { return sorts; }; + inline const char** getSorts() const override { return sorts; }; }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index fa703e38f..cf01506ed 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -1,15 +1,7 @@ #include "ModrinthPage.h" #include "ui_ModPage.h" -#include - -#include "Application.h" -#include "InstanceImportTask.h" -#include "Json.h" -#include "ModDownloadTask.h" #include "ModrinthModel.h" -#include "minecraft/MinecraftInstance.h" -#include "minecraft/PackProfile.h" #include "ui/dialogs/ModDownloadDialog.h" ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) @@ -33,29 +25,12 @@ ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthPage::onModSelected); } -bool ModrinthPage::shouldDisplay() const { return true; } - -void ModrinthPage::onRequestVersionsSucceeded(QJsonDocument& response, QString addonId) +bool ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer) const { - if (addonId != current.addonId) { return; } - - QJsonArray arr = response.array(); - try { - Modrinth::loadIndexedPackVersions(current, arr, APPLICATION->network(), m_instance); - } catch (const JSONValidationError& e) { - qDebug() << response; - qWarning() << "Error while reading Modrinth mod version: " << e.cause(); - } - auto packProfile = ((MinecraftInstance*)m_instance)->getPackProfile(); - QString mcVersion = packProfile->getComponentVersion("net.minecraft"); - QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge"; - for (int i = 0; i < current.versions.size(); i++) { - auto version = current.versions[i]; - if (!version.mcVersion.contains(mcVersion) || !version.loaders.contains(loaderString)) { continue; } - ui->versionSelectionBox->addItem(version.version, QVariant(i)); - } - if (ui->versionSelectionBox->count() == 0) { ui->versionSelectionBox->addItem(tr("No Valid Version found !"), QVariant(-1)); } - - ui->modSelectionButton->setText(tr("Cannot select invalid version :(")); - updateSelectionButton(); + return ver.mcVersion.contains(mineVer) && ver.loaders.contains(loaderVer); } + +// I don't know why, but doing this on the parent class makes it so that +// other mod providers start loading before being selected, at least with +// my Qt, so we need to implement this in every derived class... +bool ModrinthPage::shouldDisplay() const { return true; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index f6d1eef0c..6f3877082 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -19,8 +19,7 @@ class ModrinthPage : public ModPage { inline QString debugName() const override { return tr("Modrinth"); } inline QString metaEntryBase() const override { return "ModrinthPacks"; }; - bool shouldDisplay() const override; + bool validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const override; - private: - void onRequestVersionsSucceeded(QJsonDocument&, QString) override; + bool shouldDisplay() const override; }; From b3c2a56ece925bc6fe327b8824c50f194610b5b9 Mon Sep 17 00:00:00 2001 From: flow Date: Mon, 7 Mar 2022 19:55:20 -0300 Subject: [PATCH 13/18] fix: delete semicolons at the end of .cpp file's functions my lsp is weird sometimes --- launcher/modplatform/helpers/NetworkModAPI.cpp | 4 ++-- launcher/ui/pages/modplatform/flame/FlameModModel.cpp | 4 ++-- launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/launcher/modplatform/helpers/NetworkModAPI.cpp b/launcher/modplatform/helpers/NetworkModAPI.cpp index 4b0661028..ef084535b 100644 --- a/launcher/modplatform/helpers/NetworkModAPI.cpp +++ b/launcher/modplatform/helpers/NetworkModAPI.cpp @@ -29,7 +29,7 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const }); netJob->start(); -}; +} void NetworkModAPI::getVersions(CallerType* caller, const QString& addonId) const { @@ -57,4 +57,4 @@ void NetworkModAPI::getVersions(CallerType* caller, const QString& addonId) cons }); netJob->start(); -}; +} diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index ce2f74f1c..8437f6231 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -9,12 +9,12 @@ const char* ListModel::sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name" void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) { FlameMod::loadIndexedPack(m, obj); -}; +} void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) { FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); -}; +} QJsonArray ListModel::documentToArray(QJsonDocument& obj) const { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index 0db6aeffb..ac3c14f21 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -14,7 +14,7 @@ void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) { Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); -}; +} QJsonArray ListModel::documentToArray(QJsonDocument& obj) const { From 8409aa2571d57f015a634a220107d199e88ba2fd Mon Sep 17 00:00:00 2001 From: flow Date: Tue, 8 Mar 2022 11:12:35 -0300 Subject: [PATCH 14/18] tidy: Fix clang-tidy issues on files changed in this PR The checks used are roughly the same as the ones proposed in the clang-tidy PR (except perhaps that I used modernize-* instead of listing them individually,though I don't think this caused any readability detriments). In ModrinthModel.cpp and FlameModModel.cpp I ignored the modernize-avoid-c-arrays one, mostly because making the sorts array an std::array would most likely increase the code complexity because of the virtual function. Aside from that, the static_cast warning from Application.h was not dealt with, since it's not in this PR's scope. --- launcher/modplatform/flame/FlameAPI.h | 4 +-- launcher/modplatform/flame/FlameModIndex.cpp | 4 +-- launcher/modplatform/flame/FlameModIndex.h | 2 +- .../modplatform/helpers/NetworkModAPI.cpp | 6 ++--- launcher/modplatform/helpers/NetworkModAPI.h | 4 +-- launcher/modplatform/modrinth/ModrinthAPI.h | 10 +++---- .../modrinth/ModrinthPackIndex.cpp | 4 +-- .../modplatform/modrinth/ModrinthPackIndex.h | 2 +- launcher/ui/pages/modplatform/ModModel.cpp | 12 ++++----- launcher/ui/pages/modplatform/ModModel.h | 22 +++++++-------- launcher/ui/pages/modplatform/ModPage.cpp | 8 +++--- launcher/ui/pages/modplatform/ModPage.h | 27 +++++++++---------- .../pages/modplatform/flame/FlameModModel.cpp | 3 ++- .../pages/modplatform/flame/FlameModModel.h | 8 +++--- .../pages/modplatform/flame/FlameModPage.cpp | 4 +-- .../ui/pages/modplatform/flame/FlameModPage.h | 18 ++++++------- .../modplatform/modrinth/ModrinthModel.cpp | 3 ++- .../modplatform/modrinth/ModrinthModel.h | 7 ++--- .../modplatform/modrinth/ModrinthPage.cpp | 4 +-- .../pages/modplatform/modrinth/ModrinthPage.h | 18 ++++++------- 20 files changed, 86 insertions(+), 84 deletions(-) diff --git a/launcher/modplatform/flame/FlameAPI.h b/launcher/modplatform/flame/FlameAPI.h index f7f993d72..62accfa4d 100644 --- a/launcher/modplatform/flame/FlameAPI.h +++ b/launcher/modplatform/flame/FlameAPI.h @@ -4,7 +4,7 @@ class FlameAPI : public NetworkModAPI { private: - inline QString getModSearchURL(SearchArgs& args) const + inline auto getModSearchURL(SearchArgs& args) const -> QString override { return QString( "https://addons-ecs.forgesvc.net/api/v2/addon/search?" @@ -25,7 +25,7 @@ class FlameAPI : public NetworkModAPI { .arg(args.version); }; - inline QString getVersionsURL(const QString& addonId) const + inline auto getVersionsURL(const QString& addonId) const -> QString override { return QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId); }; diff --git a/launcher/modplatform/flame/FlameModIndex.cpp b/launcher/modplatform/flame/FlameModIndex.cpp index 61cb534ce..2c3adee43 100644 --- a/launcher/modplatform/flame/FlameModIndex.cpp +++ b/launcher/modplatform/flame/FlameModIndex.cpp @@ -43,8 +43,8 @@ void FlameMod::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, BaseInstance* inst) { QVector unsortedVersions; - bool hasFabric = !((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); - QString mcVersion = ((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !(dynamic_cast(inst))->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); + QString mcVersion = (dynamic_cast(inst))->getPackProfile()->getComponentVersion("net.minecraft"); for (auto versionIter : arr) { auto obj = versionIter.toObject(); diff --git a/launcher/modplatform/flame/FlameModIndex.h b/launcher/modplatform/flame/FlameModIndex.h index 34f71498e..d3171d943 100644 --- a/launcher/modplatform/flame/FlameModIndex.h +++ b/launcher/modplatform/flame/FlameModIndex.h @@ -6,8 +6,8 @@ #include "modplatform/ModIndex.h" -#include #include "BaseInstance.h" +#include namespace FlameMod { diff --git a/launcher/modplatform/helpers/NetworkModAPI.cpp b/launcher/modplatform/helpers/NetworkModAPI.cpp index ef084535b..25c7b9fd2 100644 --- a/launcher/modplatform/helpers/NetworkModAPI.cpp +++ b/launcher/modplatform/helpers/NetworkModAPI.cpp @@ -7,7 +7,7 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const { - auto netJob = new NetJob(QString("Modrinth::Search"), APPLICATION->network()); + auto netJob = new NetJob(QString("%1::Search").arg(caller->debugName()), APPLICATION->network()); auto searchUrl = getModSearchURL(args); auto response = new QByteArray(); @@ -16,7 +16,7 @@ void NetworkModAPI::searchMods(CallerType* caller, SearchArgs&& args) const QObject::connect(netJob, &NetJob::started, caller, [caller, netJob] { caller->setActiveJob(netJob); }); QObject::connect(netJob, &NetJob::failed, caller, &CallerType::searchRequestFailed); QObject::connect(netJob, &NetJob::succeeded, caller, [caller, response] { - QJsonParseError parse_error; + QJsonParseError parse_error{}; QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); if (parse_error.error != QJsonParseError::NoError) { qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset @@ -39,7 +39,7 @@ void NetworkModAPI::getVersions(CallerType* caller, const QString& addonId) cons netJob->addNetAction(Net::Download::makeByteArray(getVersionsURL(addonId), response)); QObject::connect(netJob, &NetJob::succeeded, caller, [response, caller, addonId] { - QJsonParseError parse_error; + QJsonParseError parse_error{}; QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); if (parse_error.error != QJsonParseError::NoError) { qWarning() << "Error while parsing JSON response from " << caller->debugName() << " at " << parse_error.offset diff --git a/launcher/modplatform/helpers/NetworkModAPI.h b/launcher/modplatform/helpers/NetworkModAPI.h index 651920464..4d3f70057 100644 --- a/launcher/modplatform/helpers/NetworkModAPI.h +++ b/launcher/modplatform/helpers/NetworkModAPI.h @@ -8,6 +8,6 @@ class NetworkModAPI : public ModAPI { void getVersions(CallerType* caller, const QString& addonId) const override; protected: - virtual QString getModSearchURL(SearchArgs& args) const = 0; - virtual QString getVersionsURL(const QString& addonId) const = 0; + virtual auto getModSearchURL(SearchArgs& args) const -> QString = 0; + virtual auto getVersionsURL(const QString& addonId) const -> QString = 0; }; diff --git a/launcher/modplatform/modrinth/ModrinthAPI.h b/launcher/modplatform/modrinth/ModrinthAPI.h index 1cc51ff26..cf4dec1a8 100644 --- a/launcher/modplatform/modrinth/ModrinthAPI.h +++ b/launcher/modplatform/modrinth/ModrinthAPI.h @@ -6,10 +6,10 @@ class ModrinthAPI : public NetworkModAPI { public: - inline QString getAuthorURL(const QString& name) const { return "https://modrinth.com/user/" + name; }; + inline auto getAuthorURL(const QString& name) const -> QString { return "https://modrinth.com/user/" + name; }; private: - inline QString getModSearchURL(SearchArgs& args) const override + inline auto getModSearchURL(SearchArgs& args) const -> QString override { if (!validateModLoader(args.mod_loader)) { qWarning() << "Modrinth only have Forge and Fabric-compatible mods!"; @@ -30,12 +30,12 @@ class ModrinthAPI : public NetworkModAPI { .arg(args.version); }; - inline QString getVersionsURL(const QString& addonId) const override + inline auto getVersionsURL(const QString& addonId) const -> QString override { return QString("https://api.modrinth.com/v2/project/%1/version").arg(addonId); }; - inline QString getModLoaderString(ModLoaderType modLoader) const + inline auto getModLoaderString(ModLoaderType modLoader) const -> QString { switch (modLoader) { case Any: @@ -49,7 +49,7 @@ class ModrinthAPI : public NetworkModAPI { } } - inline bool validateModLoader(ModLoaderType modLoader) const + inline auto validateModLoader(ModLoaderType modLoader) const -> bool { return modLoader == Any || modLoader == Forge || modLoader == Fabric; } diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp index 02aac34d5..ab6b451b5 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.cpp +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.cpp @@ -30,8 +30,8 @@ void Modrinth::loadIndexedPackVersions(ModPlatform::IndexedPack& pack, BaseInstance* inst) { QVector unsortedVersions; - bool hasFabric = !((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); - QString mcVersion = ((MinecraftInstance*)inst)->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !(static_cast(inst))->getPackProfile()->getComponentVersion("net.fabricmc.fabric-loader").isEmpty(); + QString mcVersion = (static_cast(inst))->getPackProfile()->getComponentVersion("net.minecraft"); for (auto versionIter : arr) { auto obj = versionIter.toObject(); diff --git a/launcher/modplatform/modrinth/ModrinthPackIndex.h b/launcher/modplatform/modrinth/ModrinthPackIndex.h index abfdabb69..fd17847af 100644 --- a/launcher/modplatform/modrinth/ModrinthPackIndex.h +++ b/launcher/modplatform/modrinth/ModrinthPackIndex.h @@ -2,8 +2,8 @@ #include "modplatform/ModIndex.h" -#include #include "BaseInstance.h" +#include namespace Modrinth { diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp index 6f3c6ce04..cc3c5326b 100644 --- a/launcher/ui/pages/modplatform/ModModel.cpp +++ b/launcher/ui/pages/modplatform/ModModel.cpp @@ -11,7 +11,7 @@ namespace ModPlatform { ListModel::ListModel(ModPage* parent) : QAbstractListModel(parent), m_parent(parent) {} -QString ListModel::debugName() const +auto ListModel::debugName() const -> QString { return m_parent->debugName(); } @@ -29,7 +29,7 @@ void ListModel::fetchMore(const QModelIndex& parent) performPaginatedSearch(); } -QVariant ListModel::data(const QModelIndex& index, int role) const +auto ListModel::data(const QModelIndex& index, int role) const -> QVariant { int pos = index.row(); if (pos >= modpacks.size() || pos < 0 || !index.isValid()) { return QString("INVALID INDEX %1").arg(pos); } @@ -56,7 +56,7 @@ QVariant ListModel::data(const QModelIndex& index, int role) const return v; } - return QVariant(); + return {}; } void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) @@ -66,8 +66,8 @@ void ListModel::requestModVersions(ModPlatform::IndexedPack const& current) void ListModel::performPaginatedSearch() { - QString mcVersion = ((MinecraftInstance*)((ModPage*)parent())->m_instance)->getPackProfile()->getComponentVersion("net.minecraft"); - bool hasFabric = !((MinecraftInstance*)((ModPage*)parent())->m_instance) + QString mcVersion = (dynamic_cast((dynamic_cast(parent()))->m_instance))->getPackProfile()->getComponentVersion("net.minecraft"); + bool hasFabric = !(dynamic_cast((dynamic_cast(parent()))->m_instance)) ->getPackProfile() ->getComponentVersion("net.fabricmc.fabric-loader") .isEmpty(); @@ -188,7 +188,7 @@ void ListModel::searchRequestFailed(QString reason) QMessageBox::critical(nullptr, tr("Error"), QString("%1 %2").arg(m_parent->displayName()).arg(tr("API version too old!\nPlease update PolyMC!"))); // self-destruct - ((ModDownloadDialog*)((ModPage*)parent())->parentWidget())->reject(); + (dynamic_cast((dynamic_cast(parent()))->parentWidget()))->reject(); } jobPtr.reset(); diff --git a/launcher/ui/pages/modplatform/ModModel.h b/launcher/ui/pages/modplatform/ModModel.h index 6c3ecc3d0..02be60491 100644 --- a/launcher/ui/pages/modplatform/ModModel.h +++ b/launcher/ui/pages/modplatform/ModModel.h @@ -10,24 +10,24 @@ class ModPage; namespace ModPlatform { -typedef QMap LogoMap; -typedef std::function LogoCallback; +using LogoMap = QMap; +using LogoCallback = std::function; class ListModel : public QAbstractListModel { Q_OBJECT public: ListModel(ModPage* parent); - virtual ~ListModel() = default; + ~ListModel() override = default; - inline int rowCount(const QModelIndex& parent) const override { return modpacks.size(); }; - inline int columnCount(const QModelIndex& parent) const override { return 1; }; - inline Qt::ItemFlags flags(const QModelIndex& index) const override { return QAbstractListModel::flags(index); }; + inline auto rowCount(const QModelIndex& parent) const -> int override { return modpacks.size(); }; + inline auto columnCount(const QModelIndex& parent) const -> int override { return 1; }; + inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); }; - QString debugName() const; + auto debugName() const -> QString; /* Retrieve information from the model at a given index with the given role */ - QVariant data(const QModelIndex& index, int role) const override; + auto data(const QModelIndex& index, int role) const -> QVariant override; inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; } @@ -41,7 +41,7 @@ class ListModel : public QAbstractListModel { void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback); - inline bool canFetchMore(const QModelIndex& parent) const override { return searchState == CanPossiblyFetchMore; }; + inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return searchState == CanPossiblyFetchMore; }; public slots: void searchRequestFinished(QJsonDocument& doc); @@ -57,8 +57,8 @@ class ListModel : public QAbstractListModel { void performPaginatedSearch(); protected: - virtual QJsonArray documentToArray(QJsonDocument& obj) const = 0; - virtual const char** getSorts() const = 0; + virtual auto documentToArray(QJsonDocument& obj) const -> QJsonArray = 0; + virtual auto getSorts() const -> const char** = 0; void requestLogo(QString file, QString url); diff --git a/launcher/ui/pages/modplatform/ModPage.cpp b/launcher/ui/pages/modplatform/ModPage.cpp index 94cf4bcfe..1386ba240 100644 --- a/launcher/ui/pages/modplatform/ModPage.cpp +++ b/launcher/ui/pages/modplatform/ModPage.cpp @@ -33,10 +33,10 @@ void ModPage::openedImpl() triggerSearch(); } -bool ModPage::eventFilter(QObject* watched, QEvent* event) +auto ModPage::eventFilter(QObject* watched, QEvent* event) -> bool { if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - QKeyEvent* keyEvent = static_cast(event); + auto* keyEvent = dynamic_cast(event); if (keyEvent->key() == Qt::Key_Return) { triggerSearch(); keyEvent->accept(); @@ -70,7 +70,7 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second) text = "" + name + ""; if (!current.authors.empty()) { - auto authorToStr = [](ModPlatform::ModpackAuthor& author) { + auto authorToStr = [](ModPlatform::ModpackAuthor& author) -> QString { if (author.url.isEmpty()) { return author.name; } return QString("%2").arg(author.url, author.name); }; @@ -128,7 +128,7 @@ void ModPage::onModSelected() void ModPage::updateModVersions() { - auto packProfile = (static_cast(m_instance))->getPackProfile(); + auto packProfile = (dynamic_cast(m_instance))->getPackProfile(); QString mcVersion = packProfile->getComponentVersion("net.minecraft"); QString loaderString = (packProfile->getComponentVersion("net.minecraftforge").isEmpty()) ? "fabric" : "forge"; diff --git a/launcher/ui/pages/modplatform/ModPage.h b/launcher/ui/pages/modplatform/ModPage.h index de66b3b08..58024260f 100644 --- a/launcher/ui/pages/modplatform/ModPage.h +++ b/launcher/ui/pages/modplatform/ModPage.h @@ -14,36 +14,35 @@ namespace Ui { class ModPage; } -/* This page handles most logic related to browsing and selecting mods to download. - * By default, the methods provided work with net requests, to fetch data from remote APIs. */ +/* This page handles most logic related to browsing and selecting mods to download. */ class ModPage : public QWidget, public BasePage { Q_OBJECT public: explicit ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api); - virtual ~ModPage(); + ~ModPage() override; /* Affects what the user sees */ - virtual QString displayName() const override = 0; - virtual QIcon icon() const override = 0; - virtual QString id() const override = 0; - virtual QString helpPage() const override = 0; + auto displayName() const -> QString override = 0; + auto icon() const -> QIcon override = 0; + auto id() const -> QString override = 0; + auto helpPage() const -> QString override = 0; /* Used internally */ - virtual QString metaEntryBase() const = 0; - virtual QString debugName() const = 0; + virtual auto metaEntryBase() const -> QString = 0; + virtual auto debugName() const -> QString = 0; - virtual bool shouldDisplay() const override = 0; - virtual bool validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const = 0; + auto shouldDisplay() const -> bool override = 0; + virtual auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const -> bool = 0; - const ModAPI* apiProvider() const { return api.get(); }; + auto apiProvider() const -> const ModAPI* { return api.get(); }; - ModPlatform::IndexedPack& getCurrent() { return current; } + auto getCurrent() -> ModPlatform::IndexedPack& { return current; } void updateModVersions(); void openedImpl() override; - bool eventFilter(QObject* watched, QEvent* event) override; + auto eventFilter(QObject* watched, QEvent* event) -> bool override; BaseInstance* m_instance; diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp index 8437f6231..905fb2dd1 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.cpp @@ -4,6 +4,7 @@ namespace FlameMod { +// NOLINTNEXTLINE(modernize-avoid-c-arrays) const char* ListModel::sorts[6]{ "Featured", "Popularity", "LastUpdated", "Name", "Author", "TotalDownloads" }; void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) @@ -16,7 +17,7 @@ void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); } -QJsonArray ListModel::documentToArray(QJsonDocument& obj) const +auto ListModel::documentToArray(QJsonDocument& obj) const -> QJsonArray { return obj.array(); } diff --git a/launcher/ui/pages/modplatform/flame/FlameModModel.h b/launcher/ui/pages/modplatform/flame/FlameModModel.h index cf3042ed8..707c1bb15 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModModel.h +++ b/launcher/ui/pages/modplatform/flame/FlameModModel.h @@ -9,17 +9,17 @@ class ListModel : public ModPlatform::ListModel { public: ListModel(FlameModPage* parent) : ModPlatform::ListModel(parent) {} -; - virtual ~ListModel() = default; + ~ListModel() override = default; private: void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; - QJsonArray documentToArray(QJsonDocument& obj) const override; + auto documentToArray(QJsonDocument& obj) const -> QJsonArray override; + // NOLINTNEXTLINE(modernize-avoid-c-arrays) static const char* sorts[6]; - inline const char** getSorts() const override { return sorts; }; + inline auto getSorts() const -> const char** override { return sorts; }; }; } // namespace FlameMod diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp index 091e49c74..c409a5cbd 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp @@ -26,7 +26,7 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance) connect(ui->modSelectionButton, &QPushButton::clicked, this, &FlameModPage::onModSelected); } -bool FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer) const +auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer) const -> bool { (void) loaderVer; return ver.mcVersion.contains(mineVer); @@ -35,4 +35,4 @@ bool FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString min // I don't know why, but doing this on the parent class makes it so that // other mod providers start loading before being selected, at least with // my Qt, so we need to implement this in every derived class... -bool FlameModPage::shouldDisplay() const { return true; } +auto FlameModPage::shouldDisplay() const -> bool { return true; } diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h index 90513ca5e..b48216bb7 100644 --- a/launcher/ui/pages/modplatform/flame/FlameModPage.h +++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h @@ -9,17 +9,17 @@ class FlameModPage : public ModPage { public: explicit FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance); - virtual ~FlameModPage() = default; + ~FlameModPage() override = default; - inline QString displayName() const override { return tr("CurseForge"); } - inline QIcon icon() const override { return APPLICATION->getThemedIcon("flame"); } - inline QString id() const override { return "curseforge"; } - inline QString helpPage() const override { return "Flame-platform"; } + inline auto displayName() const -> QString override { return tr("CurseForge"); } + inline auto icon() const -> QIcon override { return APPLICATION->getThemedIcon("flame"); } + inline auto id() const -> QString override { return "curseforge"; } + inline auto helpPage() const -> QString override { return "Flame-platform"; } - inline QString debugName() const override { return tr("Flame"); } - inline QString metaEntryBase() const override { return "FlameMods"; }; + inline auto debugName() const -> QString override { return tr("Flame"); } + inline auto metaEntryBase() const -> QString override { return "FlameMods"; }; - bool validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const override; + auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const -> bool override; - bool shouldDisplay() const override; + auto shouldDisplay() const -> bool override; }; diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp index ac3c14f21..daa43e26e 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp @@ -4,6 +4,7 @@ namespace Modrinth { +// NOLINTNEXTLINE(modernize-avoid-c-arrays) const char* ListModel::sorts[5]{ "relevance", "downloads", "follows", "updated", "newest" }; void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) @@ -16,7 +17,7 @@ void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance); } -QJsonArray ListModel::documentToArray(QJsonDocument& obj) const +auto ListModel::documentToArray(QJsonDocument& obj) const -> QJsonArray { return obj.object().value("hits").toArray(); } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h index de73704cd..45a6090a7 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h @@ -9,16 +9,17 @@ class ListModel : public ModPlatform::ListModel { public: ListModel(ModrinthPage* parent) : ModPlatform::ListModel(parent){}; - virtual ~ListModel() = default; + ~ListModel() override = default; private: void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override; void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override; - QJsonArray documentToArray(QJsonDocument& obj) const override; + auto documentToArray(QJsonDocument& obj) const -> QJsonArray override; + // NOLINTNEXTLINE(modernize-avoid-c-arrays) static const char* sorts[5]; - inline const char** getSorts() const override { return sorts; }; + inline auto getSorts() const -> const char** override { return sorts; }; }; } // namespace Modrinth diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index cf01506ed..aebfee743 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -25,7 +25,7 @@ ModrinthPage::ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance) connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthPage::onModSelected); } -bool ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer) const +auto ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer) const -> bool { return ver.mcVersion.contains(mineVer) && ver.loaders.contains(loaderVer); } @@ -33,4 +33,4 @@ bool ModrinthPage::validateVersion(ModPlatform::IndexedVersion& ver, QString min // I don't know why, but doing this on the parent class makes it so that // other mod providers start loading before being selected, at least with // my Qt, so we need to implement this in every derived class... -bool ModrinthPage::shouldDisplay() const { return true; } +auto ModrinthPage::shouldDisplay() const -> bool { return true; } diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 6f3877082..6e911b83e 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -9,17 +9,17 @@ class ModrinthPage : public ModPage { public: explicit ModrinthPage(ModDownloadDialog* dialog, BaseInstance* instance); - virtual ~ModrinthPage() = default; + ~ModrinthPage() override = default; - inline QString displayName() const override { return tr("Modrinth"); } - inline QIcon icon() const override { return APPLICATION->getThemedIcon("modrinth"); } - inline QString id() const override { return "modrinth"; } - inline QString helpPage() const override { return "Modrinth-platform"; } + inline auto displayName() const -> QString override { return tr("Modrinth"); } + inline auto icon() const -> QIcon override { return APPLICATION->getThemedIcon("modrinth"); } + inline auto id() const -> QString override { return "modrinth"; } + inline auto helpPage() const -> QString override { return "Modrinth-platform"; } - inline QString debugName() const override { return tr("Modrinth"); } - inline QString metaEntryBase() const override { return "ModrinthPacks"; }; + inline auto debugName() const -> QString override { return tr("Modrinth"); } + inline auto metaEntryBase() const -> QString override { return "ModrinthPacks"; }; - bool validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const override; + auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, QString loaderVer = "") const -> bool override; - bool shouldDisplay() const override; + auto shouldDisplay() const -> bool override; }; From 0d46ea5c71a7c1cb06fc36a530a4036ed997feb2 Mon Sep 17 00:00:00 2001 From: txtsd Date: Fri, 25 Mar 2022 23:17:14 +0530 Subject: [PATCH 15/18] chore: Ignore more paths --- .github/workflows/trigger_builds.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/trigger_builds.yml b/.github/workflows/trigger_builds.yml index 1561b9d68..7cf10b1a8 100644 --- a/.github/workflows/trigger_builds.yml +++ b/.github/workflows/trigger_builds.yml @@ -9,12 +9,16 @@ on: - '**/LICENSE' - 'flake.lock' - '**.nix' + - 'packages/**' + - '.github/ISSUE_TEMPLATE/**' pull_request: paths-ignore: - '**.md' - '**/LICENSE' - 'flake.lock' - '**.nix' + - 'packages/**' + - '.github/ISSUE_TEMPLATE/**' workflow_dispatch: jobs: From 94e7961df018bbc00fbb06786ca3488b9490572a Mon Sep 17 00:00:00 2001 From: txtsd Date: Fri, 25 Mar 2022 23:18:55 +0530 Subject: [PATCH 16/18] chore: Don't build release type during development --- .github/workflows/trigger_builds.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/trigger_builds.yml b/.github/workflows/trigger_builds.yml index 7cf10b1a8..3ec6bb958 100644 --- a/.github/workflows/trigger_builds.yml +++ b/.github/workflows/trigger_builds.yml @@ -28,9 +28,3 @@ jobs: uses: ./.github/workflows/build.yml with: build_type: Debug - - build_release: - name: Build Release - uses: ./.github/workflows/build.yml - with: - build_type: Release From b1af689546704d5e05ef4bc44f43ce9e8bb4854c Mon Sep 17 00:00:00 2001 From: dada513 Date: Wed, 23 Mar 2022 19:06:17 +0100 Subject: [PATCH 17/18] Add quit launcher after game stops option (Steam Deck) lecense --- launcher/Application.cpp | 1 + launcher/CMakeLists.txt | 2 ++ launcher/launch/steps/QuitAfterGameStop.cpp | 26 ++++++++++++++ launcher/launch/steps/QuitAfterGameStop.h | 35 +++++++++++++++++++ launcher/minecraft/MinecraftInstance.cpp | 6 ++++ .../minecraft/launch/LauncherPartLaunch.cpp | 1 + launcher/ui/pages/global/MinecraftPage.cpp | 2 ++ launcher/ui/pages/global/MinecraftPage.ui | 10 ++++++ 8 files changed, 83 insertions(+) create mode 100644 launcher/launch/steps/QuitAfterGameStop.cpp create mode 100644 launcher/launch/steps/QuitAfterGameStop.h diff --git a/launcher/Application.cpp b/launcher/Application.cpp index 33b1774c8..e701accaa 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -727,6 +727,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) m_settings->registerSetting("PastebinURL", "https://0x0.st"); m_settings->registerSetting("CloseAfterLaunch", false); + m_settings->registerSetting("QuitAfterGameStop", false); // Custom MSA credentials m_settings->registerSetting("MSAClientIDOverride", ""); diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 98cb0a3b2..c65c17ce2 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -144,6 +144,8 @@ set(LAUNCH_SOURCES launch/steps/TextPrint.h launch/steps/Update.cpp launch/steps/Update.h + launch/steps/QuitAfterGameStop.cpp + launch/steps/QuitAfterGameStop.h launch/LaunchStep.cpp launch/LaunchStep.h launch/LaunchTask.cpp diff --git a/launcher/launch/steps/QuitAfterGameStop.cpp b/launcher/launch/steps/QuitAfterGameStop.cpp new file mode 100644 index 000000000..257f473d4 --- /dev/null +++ b/launcher/launch/steps/QuitAfterGameStop.cpp @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 dada513 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "QuitAfterGameStop.h" +#include +#include "Application.h" + +void QuitAfterGameStop::executeTask() +{ + APPLICATION->quit(); +} \ No newline at end of file diff --git a/launcher/launch/steps/QuitAfterGameStop.h b/launcher/launch/steps/QuitAfterGameStop.h new file mode 100644 index 000000000..1ce14da95 --- /dev/null +++ b/launcher/launch/steps/QuitAfterGameStop.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * PolyMC - Minecraft Launcher + * Copyright (C) 2022 dada513 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +class QuitAfterGameStop: public LaunchStep +{ + Q_OBJECT +public: + explicit QuitAfterGameStop(LaunchTask *parent) :LaunchStep(parent){}; + virtual ~QuitAfterGameStop() {}; + + virtual void executeTask(); + virtual bool canAbort() const + { + return false; + } +}; diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 6db12c42b..90bb92a17 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -20,6 +20,7 @@ #include "launch/steps/PreLaunchCommand.h" #include "launch/steps/TextPrint.h" #include "launch/steps/CheckJava.h" +#include "launch/steps/QuitAfterGameStop.h" #include "minecraft/launch/LauncherPartLaunch.h" #include "minecraft/launch/DirectJavaLaunch.h" @@ -935,6 +936,11 @@ shared_qobject_ptr MinecraftInstance::createLaunchTask(AuthSessionPt { process->setCensorFilter(createCensorFilterFromSession(session)); } + if(APPLICATION->settings()->get("QuitAfterGameStop").toBool()) + { + auto step = new QuitAfterGameStop(pptr); + process->appendStep(step); + } m_launchProcess = process; emit launchTaskChanged(m_launchProcess); return m_launchProcess; diff --git a/launcher/minecraft/launch/LauncherPartLaunch.cpp b/launcher/minecraft/launch/LauncherPartLaunch.cpp index d15d7e9db..173f29b50 100644 --- a/launcher/minecraft/launch/LauncherPartLaunch.cpp +++ b/launcher/minecraft/launch/LauncherPartLaunch.cpp @@ -170,6 +170,7 @@ void LauncherPartLaunch::on_state(LoggedProcess::State state) { if (APPLICATION->settings()->get("CloseAfterLaunch").toBool()) APPLICATION->showMainWindow(); + m_parent->setPid(-1); // if the exit code wasn't 0, report this as a crash auto exitCode = m_process.exitCode(); diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp index 9abae425a..f49f5a920 100644 --- a/launcher/ui/pages/global/MinecraftPage.cpp +++ b/launcher/ui/pages/global/MinecraftPage.cpp @@ -94,6 +94,7 @@ void MinecraftPage::applySettings() // Miscellaneous s->set("CloseAfterLaunch", ui->closeAfterLaunchCheck->isChecked()); + s->set("QuitAfterGameStop", ui->quitAfterGameStopCheck->isChecked()); } void MinecraftPage::loadSettings() @@ -113,6 +114,7 @@ void MinecraftPage::loadSettings() ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool()); ui->closeAfterLaunchCheck->setChecked(s->get("CloseAfterLaunch").toBool()); + ui->quitAfterGameStopCheck->setChecked(s->get("QuitAfterGameStop").toBool()); } void MinecraftPage::retranslate() diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui index a28b1f596..decc9b8b1 100644 --- a/launcher/ui/pages/global/MinecraftPage.ui +++ b/launcher/ui/pages/global/MinecraftPage.ui @@ -180,6 +180,16 @@
+ + + + <html><head/><body><p>PolyMC will automatically exit if the game crashes or exists.</p></body></html> + + + Quit PolyMC after game window stops + + +
From ec6409914d07dce67f86522ff7f5015e5060fb7e Mon Sep 17 00:00:00 2001 From: dada513 Date: Sun, 27 Mar 2022 14:51:48 +0200 Subject: [PATCH 18/18] newline more like waste --- launcher/launch/steps/QuitAfterGameStop.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/launch/steps/QuitAfterGameStop.cpp b/launcher/launch/steps/QuitAfterGameStop.cpp index 257f473d4..f9eced993 100644 --- a/launcher/launch/steps/QuitAfterGameStop.cpp +++ b/launcher/launch/steps/QuitAfterGameStop.cpp @@ -23,4 +23,4 @@ void QuitAfterGameStop::executeTask() { APPLICATION->quit(); -} \ No newline at end of file +}