Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into feat/acknowledge_release_type

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97
2023-09-28 22:50:12 +03:00
323 changed files with 5800 additions and 2912 deletions

View File

@ -38,10 +38,12 @@
#include "BuildConfig.h"
#include "Json.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
#include "modplatform/modrinth/ModrinthAPI.h"
#include "net/NetJob.h"
#include "ui/widgets/ProjectItem.h"
#include "net/ApiDownload.h"
#include <QMessageBox>
namespace Modrinth {
@ -115,7 +117,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
return {};
}
bool ModpackListModel::setData(const QModelIndex& index, const QVariant& value, int role)
bool ModpackListModel::setData(const QModelIndex& index, const QVariant& value, [[maybe_unused]] int role)
{
int pos = index.row();
if (pos >= modpacks.size() || pos < 0 || !index.isValid())
@ -128,7 +130,24 @@ bool ModpackListModel::setData(const QModelIndex& index, const QVariant& value,
void ModpackListModel::performPaginatedSearch()
{
// TODO: Move to standalone API
if (hasActiveSearchJob())
return;
if (currentSearchTerm.startsWith("#")) {
auto projectId = currentSearchTerm.mid(1);
if (!projectId.isEmpty()) {
ResourceAPI::ProjectInfoCallbacks callbacks;
callbacks.on_fail = [this](QString reason) { searchRequestFailed(reason); };
callbacks.on_succeed = [this](auto& doc, auto& pack) { searchRequestForOneSucceeded(doc); };
static const ModrinthAPI api;
if (auto job = api.getProjectInfo({ projectId }, std::move(callbacks)); job) {
jobPtr = job;
jobPtr->start();
}
return;
}
} // TODO: Move to standalone API
auto netJob = makeShared<NetJob>("Modrinth::SearchModpack", APPLICATION->network());
auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL +
"/search?"
@ -142,7 +161,7 @@ void ModpackListModel::performPaginatedSearch()
.arg(currentSearchTerm)
.arg(currentSort);
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), m_all_response));
netJob->addNetAction(Net::ApiDownload::makeByteArray(QUrl(searchAllUrl), m_all_response));
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this] {
QJsonParseError parse_error_all{};
@ -165,16 +184,17 @@ void ModpackListModel::performPaginatedSearch()
void ModpackListModel::refresh()
{
if (jobPtr) {
if (hasActiveSearchJob()) {
jobPtr->abort();
searchState = ResetRequested;
return;
} else {
beginResetModel();
modpacks.clear();
endResetModel();
searchState = None;
}
beginResetModel();
modpacks.clear();
endResetModel();
searchState = None;
nextSearchOffset = 0;
performPaginatedSearch();
}
@ -194,8 +214,6 @@ static auto sortFromIndex(int index) -> QString
case 4:
return "updated";
}
return {};
}
void ModpackListModel::searchWithTerm(const QString& term, const int sort)
@ -218,9 +236,7 @@ void ModpackListModel::searchWithTerm(const QString& term, const int sort)
void ModpackListModel::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))->getFullPath());
} else {
requestLogo(logo, logoUrl);
}
@ -232,10 +248,9 @@ void ModpackListModel::requestLogo(QString logo, QString url)
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));
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));
job->addNetAction(Net::ApiDownload::makeCached(QUrl(url), entry));
auto fullPath = entry->getFullPath();
QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] {
@ -310,9 +325,29 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all)
endInsertRows();
}
void ModpackListModel::searchRequestForOneSucceeded(QJsonDocument& doc)
{
jobPtr.reset();
auto packObj = doc.object();
Modrinth::Modpack pack;
try {
Modrinth::loadIndexedPack(pack, packObj);
pack.id = Json::ensureString(packObj, "id", pack.id);
} catch (const JSONValidationError& e) {
qWarning() << "Error while loading mod from " << m_parent->debugName() << ": " << e.cause();
return;
}
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + 1);
modpacks.append({ pack });
endInsertRows();
}
void ModpackListModel::searchRequestFailed(QString reason)
{
auto failed_action = jobPtr->getFailedActions().at(0);
auto failed_action = dynamic_cast<NetJob*>(jobPtr.get())->getFailedActions().at(0);
if (!failed_action->m_reply) {
// Network error
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load modpacks."));

View File

@ -73,6 +73,9 @@ class ModpackListModel : public QAbstractListModel {
void refresh();
void searchWithTerm(const QString& term, const int sort);
[[nodiscard]] bool hasActiveSearchJob() const { return jobPtr && jobPtr->isRunning(); }
[[nodiscard]] Task::Ptr activeSearchJob() { return hasActiveSearchJob() ? jobPtr : nullptr; }
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
inline auto canFetchMore(const QModelIndex& parent) const -> bool override
@ -83,6 +86,7 @@ class ModpackListModel : public QAbstractListModel {
public slots:
void searchRequestFinished(QJsonDocument& doc_all);
void searchRequestFailed(QString reason);
void searchRequestForOneSucceeded(QJsonDocument&);
protected slots:
@ -111,7 +115,7 @@ class ModpackListModel : public QAbstractListModel {
int nextSearchOffset = 0;
enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None;
NetJob::Ptr jobPtr;
Task::Ptr jobPtr;
std::shared_ptr<QByteArray> m_all_response = std::make_shared<QByteArray>();
QByteArray m_specific_response;

View File

@ -46,11 +46,14 @@
#include "ui/widgets/ProjectItem.h"
#include "net/ApiDownload.h"
#include <QComboBox>
#include <QKeyEvent>
#include <QPushButton>
ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog)
ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent)
: QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog), m_fetch_progress(this, false)
{
ui->setupUi(this);
@ -62,6 +65,17 @@ ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent) : QWidget
ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300);
m_search_timer.setTimerType(Qt::TimerType::CoarseTimer);
m_search_timer.setSingleShot(true);
connect(&m_search_timer, &QTimer::timeout, this, &ModrinthPage::triggerSearch);
m_fetch_progress.hideIfInactive(true);
m_fetch_progress.setFixedHeight(24);
m_fetch_progress.progressFormat("");
ui->gridLayout->addWidget(&m_fetch_progress, 2, 0, 1, ui->gridLayout->columnCount());
ui->sortByBox->addItem(tr("Sort by Relevance"));
ui->sortByBox->addItem(tr("Sort by Total Downloads"));
ui->sortByBox->addItem(tr("Sort by Follows"));
@ -100,12 +114,17 @@ bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
this->triggerSearch();
keyEvent->accept();
return true;
} else {
if (m_search_timer.isActive())
m_search_timer.stop();
m_search_timer.start(350);
}
}
return QObject::eventFilter(watched, event);
}
void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelIndex prev)
{
ui->versionSelectionBox->clear();
@ -127,7 +146,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
QString id = current.id;
netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
netJob->addNetAction(Net::ApiDownload::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
if (id != current.id) {
@ -176,7 +195,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
QString id = current.id;
netJob->addNetAction(
Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
Net::ApiDownload::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
if (id != current.id) {
@ -308,11 +327,12 @@ void ModrinthPage::suggestCurrent()
void ModrinthPage::triggerSearch()
{
m_model->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
m_fetch_progress.watch(m_model->activeSearchJob().get());
}
void ModrinthPage::onVersionSelectionChanged(QString data)
void ModrinthPage::onVersionSelectionChanged(QString version)
{
if (data.isNull() || data.isEmpty()) {
if (version.isNull() || version.isEmpty()) {
selectedVersion = "";
return;
}

View File

@ -41,7 +41,9 @@
#include "ui/pages/BasePage.h"
#include "modplatform/modrinth/ModrinthPackManifest.h"
#include "ui/widgets/ProgressWidget.h"
#include <QTimer>
#include <QWidget>
namespace Ui {
@ -88,4 +90,9 @@ class ModrinthPage : public QWidget, public BasePage {
Modrinth::Modpack current;
QString selectedVersion;
ProgressWidget m_fetch_progress;
// Used to do instant searching with a delay to cache quick changes
QTimer m_search_timer;
};

View File

@ -10,8 +10,8 @@
<height>600</height>
</rect>
</property>
<layout class="QVBoxLayout">
<item>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="font">
<font>
@ -29,7 +29,7 @@
</property>
</widget>
</item>
<item>
<item row="1" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QLineEdit" name="searchEdit">
@ -47,7 +47,7 @@
</item>
</layout>
</item>
<item>
<item row="3" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QListView" name="packView">
@ -77,7 +77,7 @@
</item>
</layout>
</item>
<item>
<item row="4" column="0">
<layout class="QHBoxLayout">
<item>
<widget class="QComboBox" name="sortByBox"/>

View File

@ -39,13 +39,13 @@ void ModrinthModModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObjec
void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
{
return ::Modrinth::loadDependencyVersions(m, arr);
};
return ::Modrinth::loadDependencyVersions(m, arr, &m_base_instance);
}
auto ModrinthModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
{
@ -66,7 +66,7 @@ void ModrinthResourcePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, Q
void ModrinthResourcePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@ -88,7 +88,7 @@ void ModrinthTexturePackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJ
void ModrinthTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
@ -110,7 +110,7 @@ void ModrinthShaderPackModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJs
void ModrinthShaderPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
{
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
::Modrinth::loadIndexedPackVersions(m, arr, &m_base_instance);
}
auto ModrinthShaderPackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray

View File

@ -65,21 +65,9 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance& instan
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver,
QString mineVer,
std::optional<ResourceAPI::ModLoaderTypes> loaders) const -> bool
std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
{
auto loaderCompatible = !loaders.has_value();
if (!loaderCompatible) {
auto loaderStrings = ModrinthAPI::getModLoaderStrings(loaders.value());
for (auto remoteLoader : ver.loaders) {
if (loaderStrings.contains(remoteLoader)) {
loaderCompatible = true;
break;
}
}
}
return ver.mcVersion.contains(mineVer) && loaderCompatible;
return ver.mcVersion.contains(mineVer) && (!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
}
ModrinthResourcePackPage::ModrinthResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance)

View File

@ -93,7 +93,7 @@ class ModrinthModPage : public ModPage {
[[nodiscard]] inline auto helpPage() const -> QString override { return "Mod-platform"; }
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const
-> bool override;
};