mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2026-06-29 01:54:20 +03:00
chore(clang-tidy): fix clang tidy warnings
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
parent
ca721f9d67
commit
a63048d7e2
19 changed files with 494 additions and 405 deletions
|
|
@ -60,11 +60,11 @@ Net::ModrinthDownloadMeta createModrinthMeta(BaseInstance* instance, QString rea
|
||||||
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
ResourceDownloadTask::ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion version,
|
ModPlatform::IndexedVersion version,
|
||||||
ResourceFolderModel* packs,
|
ResourceFolderModel* packs,
|
||||||
bool is_indexed,
|
bool isIndexed,
|
||||||
QString downloadReason)
|
QString downloadReason)
|
||||||
: m_pack(std::move(pack)), m_pack_version(std::move(version)), m_pack_model(packs)
|
: m_pack(std::move(pack)), m_pack_version(std::move(version)), m_pack_model(packs)
|
||||||
{
|
{
|
||||||
if (is_indexed) {
|
if (isIndexed) {
|
||||||
m_update_task.reset(new LocalResourceUpdateTask(m_pack_model->indexDir(), *m_pack, m_pack_version));
|
m_update_task.reset(new LocalResourceUpdateTask(m_pack_model->indexDir(), *m_pack, m_pack_version));
|
||||||
connect(m_update_task.get(), &LocalResourceUpdateTask::hasOldResource, this, &ResourceDownloadTask::hasOldResource);
|
connect(m_update_task.get(), &LocalResourceUpdateTask::hasOldResource, this, &ResourceDownloadTask::hasOldResource);
|
||||||
|
|
||||||
|
|
@ -113,8 +113,9 @@ void ResourceDownloadTask::downloadSucceeded()
|
||||||
auto oldName = std::get<0>(to_delete);
|
auto oldName = std::get<0>(to_delete);
|
||||||
auto oldFilename = std::get<1>(to_delete);
|
auto oldFilename = std::get<1>(to_delete);
|
||||||
|
|
||||||
if (oldName.isEmpty() || oldFilename == m_pack_version.fileName)
|
if (oldName.isEmpty() || oldFilename == m_pack_version.fileName) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
m_pack_model->uninstallResource(oldFilename, true);
|
m_pack_model->uninstallResource(oldFilename, true);
|
||||||
|
|
||||||
|
|
@ -126,8 +127,9 @@ void ResourceDownloadTask::downloadSucceeded()
|
||||||
if (oldConfig.exists() && !newConfig.exists()) {
|
if (oldConfig.exists() && !newConfig.exists()) {
|
||||||
bool success = FS::move(oldConfig.filePath(), newConfig.filePath());
|
bool success = FS::move(oldConfig.filePath(), newConfig.filePath());
|
||||||
|
|
||||||
if (!success)
|
if (!success) {
|
||||||
emit logWarning(tr("Failed to rename shader config from '%1' to '%2'").arg(oldConfig.fileName(), newConfig.fileName()));
|
emit logWarning(tr("Failed to rename shader config from '%1' to '%2'").arg(oldConfig.fileName(), newConfig.fileName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,7 +137,7 @@ void ResourceDownloadTask::downloadSucceeded()
|
||||||
void ResourceDownloadTask::downloadFailed(QString reason)
|
void ResourceDownloadTask::downloadFailed(QString reason)
|
||||||
{
|
{
|
||||||
m_filesNetJob.reset();
|
m_filesNetJob.reset();
|
||||||
emitFailed(reason);
|
emitFailed(std::move(reason));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
void ResourceDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||||
|
|
@ -145,7 +147,7 @@ void ResourceDownloadTask::downloadProgressChanged(qint64 current, qint64 total)
|
||||||
|
|
||||||
// This indirection is done so that we don't delete a mod before being sure it was
|
// This indirection is done so that we don't delete a mod before being sure it was
|
||||||
// downloaded successfully!
|
// downloaded successfully!
|
||||||
void ResourceDownloadTask::hasOldResource(QString name, QString filename)
|
void ResourceDownloadTask::hasOldResource(const QString& name, const QString& filename)
|
||||||
{
|
{
|
||||||
to_delete = { name, filename };
|
to_delete = { name, filename };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "net/NetJob.h"
|
#include "net/NetJob.h"
|
||||||
#include "net/ApiHeaderProxy.h"
|
|
||||||
#include "tasks/SequentialTask.h"
|
#include "tasks/SequentialTask.h"
|
||||||
|
|
||||||
#include "minecraft/mod/tasks/LocalResourceUpdateTask.h"
|
#include "minecraft/mod/tasks/LocalResourceUpdateTask.h"
|
||||||
|
|
@ -34,7 +33,7 @@ class ResourceDownloadTask : public SequentialTask {
|
||||||
explicit ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
explicit ResourceDownloadTask(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion version,
|
ModPlatform::IndexedVersion version,
|
||||||
ResourceFolderModel* packs,
|
ResourceFolderModel* packs,
|
||||||
bool is_indexed = true,
|
bool isIndexed = true,
|
||||||
QString downloadReason = "standalone");
|
QString downloadReason = "standalone");
|
||||||
const QString& getFilename() const { return m_pack_version.fileName; }
|
const QString& getFilename() const { return m_pack_version.fileName; }
|
||||||
const QVariant& getVersionID() const { return m_pack_version.fileId; }
|
const QVariant& getVersionID() const { return m_pack_version.fileId; }
|
||||||
|
|
@ -58,5 +57,5 @@ class ResourceDownloadTask : public SequentialTask {
|
||||||
std::tuple<QString, QString> to_delete{ "", "" };
|
std::tuple<QString, QString> to_delete{ "", "" };
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void hasOldResource(QString name, QString filename);
|
void hasOldResource(const QString& name, const QString& filename);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,114 +32,119 @@
|
||||||
|
|
||||||
bool ModrinthCreationTask::abort()
|
bool ModrinthCreationTask::abort()
|
||||||
{
|
{
|
||||||
if (!canAbort())
|
if (!canAbort()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_task)
|
if (m_task) {
|
||||||
m_task->abort();
|
m_task->abort();
|
||||||
|
}
|
||||||
return InstanceCreationTask::abort();
|
return InstanceCreationTask::abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModrinthCreationTask::updateInstance()
|
bool ModrinthCreationTask::updateInstance()
|
||||||
{
|
{
|
||||||
auto instance_list = APPLICATION->instances();
|
auto* instanceList = APPLICATION->instances();
|
||||||
|
|
||||||
// FIXME: How to handle situations when there's more than one install already for a given modpack?
|
// FIXME: How to handle situations when there's more than one install already for a given modpack?
|
||||||
BaseInstance* inst;
|
BaseInstance* inst = nullptr;
|
||||||
if (auto original_id = originalInstanceID(); !original_id.isEmpty()) {
|
if (auto originalId = originalInstanceID(); !originalId.isEmpty()) {
|
||||||
inst = instance_list->getInstanceById(original_id);
|
inst = instanceList->getInstanceById(originalId);
|
||||||
Q_ASSERT(inst);
|
Q_ASSERT(inst);
|
||||||
} else {
|
} else {
|
||||||
inst = instance_list->getInstanceByManagedName(originalName());
|
inst = instanceList->getInstanceByManagedName(originalName());
|
||||||
|
|
||||||
if (!inst) {
|
if (!inst) {
|
||||||
inst = instance_list->getInstanceById(originalName());
|
inst = instanceList->getInstanceById(originalName());
|
||||||
|
|
||||||
if (!inst)
|
if (!inst) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QString index_path = FS::PathCombine(m_stagingPath, "modrinth.index.json");
|
QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json");
|
||||||
if (!parseManifest(index_path, m_files, true, false))
|
if (!parseManifest(indexPath, m_files, true, false)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
auto version_name = inst->getManagedPackVersionName();
|
auto versionName = inst->getManagedPackVersionName();
|
||||||
m_root_path = QFileInfo(inst->gameRoot()).fileName();
|
m_root_path = QFileInfo(inst->gameRoot()).fileName();
|
||||||
auto version_str = !version_name.isEmpty() ? tr(" (version %1)").arg(version_name) : "";
|
auto versionStr = !versionName.isEmpty() ? tr(" (version %1)").arg(versionName) : "";
|
||||||
|
|
||||||
if (shouldConfirmUpdate()) {
|
if (shouldConfirmUpdate()) {
|
||||||
auto should_update = askIfShouldUpdate(m_parent, version_str);
|
auto shouldUpdate = askIfShouldUpdate(m_parent, versionStr);
|
||||||
if (should_update == ShouldUpdate::SkipUpdating)
|
if (shouldUpdate == ShouldUpdate::SkipUpdating) {
|
||||||
return false;
|
return false;
|
||||||
if (should_update == ShouldUpdate::Cancel) {
|
}
|
||||||
|
if (shouldUpdate == ShouldUpdate::Cancel) {
|
||||||
m_abort = true;
|
m_abort = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove repeated files, we don't need to download them!
|
// Remove repeated files, we don't need to download them!
|
||||||
QDir old_inst_dir(inst->instanceRoot());
|
QDir oldInstDir(inst->instanceRoot());
|
||||||
|
|
||||||
QString old_index_folder(FS::PathCombine(old_inst_dir.absolutePath(), "mrpack"));
|
QString oldIndexFolder(FS::PathCombine(oldInstDir.absolutePath(), "mrpack"));
|
||||||
|
|
||||||
QString old_index_path(FS::PathCombine(old_index_folder, "modrinth.index.json"));
|
QString oldIndexPath(FS::PathCombine(oldIndexFolder, "modrinth.index.json"));
|
||||||
QFileInfo old_index_file(old_index_path);
|
QFileInfo oldIndexFile(oldIndexPath);
|
||||||
if (old_index_file.exists()) {
|
if (oldIndexFile.exists()) {
|
||||||
std::vector<File> old_files;
|
std::vector<File> oldFiles;
|
||||||
parseManifest(old_index_path, old_files, false, false);
|
parseManifest(oldIndexPath, oldFiles, false, false);
|
||||||
|
|
||||||
// Let's remove all duplicated, identical resources!
|
// Let's remove all duplicated, identical resources!
|
||||||
auto files_iterator = m_files.begin();
|
auto filesIterator = m_files.begin();
|
||||||
begin:
|
begin:
|
||||||
while (files_iterator != m_files.end()) {
|
while (filesIterator != m_files.end()) {
|
||||||
auto const& file = *files_iterator;
|
const auto& file = *filesIterator;
|
||||||
|
|
||||||
auto old_files_iterator = old_files.begin();
|
auto oldFilesIterator = oldFiles.begin();
|
||||||
while (old_files_iterator != old_files.end()) {
|
while (oldFilesIterator != oldFiles.end()) {
|
||||||
auto const& old_file = *old_files_iterator;
|
const auto& oldFile = *oldFilesIterator;
|
||||||
|
|
||||||
if (old_file.hash == file.hash) {
|
if (oldFile.hash == file.hash) {
|
||||||
qDebug() << "Removed file at" << file.path << "from list of downloads";
|
qDebug() << "Removed file at" << file.path << "from list of downloads";
|
||||||
files_iterator = m_files.erase(files_iterator);
|
filesIterator = m_files.erase(filesIterator);
|
||||||
old_files_iterator = old_files.erase(old_files_iterator);
|
oldFilesIterator = oldFiles.erase(oldFilesIterator);
|
||||||
goto begin; // Sorry :c
|
goto begin; // Sorry :c
|
||||||
}
|
}
|
||||||
|
|
||||||
old_files_iterator++;
|
oldFilesIterator++;
|
||||||
}
|
}
|
||||||
|
|
||||||
files_iterator++;
|
filesIterator++;
|
||||||
}
|
}
|
||||||
|
|
||||||
QDir old_minecraft_dir(inst->gameRoot());
|
QDir oldMinecraftDir(inst->gameRoot());
|
||||||
|
|
||||||
// Some files were removed from the old version, and some will be downloaded in an updated version,
|
// Some files were removed from the old version, and some will be downloaded in an updated version,
|
||||||
// so we're fine removing them!
|
// so we're fine removing them!
|
||||||
if (!old_files.empty()) {
|
if (!oldFiles.empty()) {
|
||||||
for (auto const& file : old_files) {
|
for (const auto& file : oldFiles) {
|
||||||
scheduleToDelete(m_parent, old_minecraft_dir, file.path, true);
|
scheduleToDelete(m_parent, oldMinecraftDir, file.path, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We will remove all the previous overrides, to prevent duplicate files!
|
// We will remove all the previous overrides, to prevent duplicate files!
|
||||||
// TODO: Currently 'overrides' will always override the stuff on update. How do we preserve unchanged overrides?
|
// TODO: Currently 'overrides' will always override the stuff on update. How do we preserve unchanged overrides?
|
||||||
// FIXME: We may want to do something about disabled mods.
|
// FIXME: We may want to do something about disabled mods.
|
||||||
auto old_overrides = Override::readOverrides("overrides", old_index_folder);
|
auto oldOverrides = Override::readOverrides("overrides", oldIndexFolder);
|
||||||
for (const auto& entry : old_overrides) {
|
for (const auto& entry : oldOverrides) {
|
||||||
scheduleToDelete(m_parent, old_minecraft_dir, entry);
|
scheduleToDelete(m_parent, oldMinecraftDir, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto old_client_overrides = Override::readOverrides("client-overrides", old_index_folder);
|
auto oldClientOverrides = Override::readOverrides("client-overrides", oldIndexFolder);
|
||||||
for (const auto& entry : old_client_overrides) {
|
for (const auto& entry : oldClientOverrides) {
|
||||||
scheduleToDelete(m_parent, old_minecraft_dir, entry);
|
scheduleToDelete(m_parent, oldMinecraftDir, entry);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We don't have an old index file, so we may duplicate stuff!
|
// We don't have an old index file, so we may duplicate stuff!
|
||||||
auto dialog = CustomMessageBox::selectable(m_parent, tr("No index file."),
|
auto* dialog = CustomMessageBox::selectable(m_parent, tr("No index file."),
|
||||||
tr("We couldn't find a suitable index file for the older version. This may cause some "
|
tr("We couldn't find a suitable index file for the older version. This may cause some "
|
||||||
"of the files to be duplicated. Do you want to continue?"),
|
"of the files to be duplicated. Do you want to continue?"),
|
||||||
QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Cancel);
|
QMessageBox::Warning, QMessageBox::Ok | QMessageBox::Cancel);
|
||||||
|
|
||||||
if (dialog->exec() == QDialog::DialogCode::Rejected) {
|
if (dialog->exec() == QDialog::DialogCode::Rejected) {
|
||||||
m_abort = true;
|
m_abort = true;
|
||||||
|
|
@ -161,39 +166,40 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
{
|
{
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
|
|
||||||
QString parent_folder(FS::PathCombine(m_stagingPath, "mrpack"));
|
QString parentFolder(FS::PathCombine(m_stagingPath, "mrpack"));
|
||||||
|
|
||||||
QString index_path = FS::PathCombine(m_stagingPath, "modrinth.index.json");
|
QString indexPath = FS::PathCombine(m_stagingPath, "modrinth.index.json");
|
||||||
if (m_files.empty() && !parseManifest(index_path, m_files, true, true))
|
if (m_files.empty() && !parseManifest(indexPath, m_files, true, true)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
// Keep index file in case we need it some other time (like when changing versions)
|
// Keep index file in case we need it some other time (like when changing versions)
|
||||||
QString new_index_place(FS::PathCombine(parent_folder, "modrinth.index.json"));
|
QString newIndexPlace(FS::PathCombine(parentFolder, "modrinth.index.json"));
|
||||||
FS::ensureFilePathExists(new_index_place);
|
FS::ensureFilePathExists(newIndexPlace);
|
||||||
FS::move(index_path, new_index_place);
|
FS::move(indexPath, newIndexPlace);
|
||||||
|
|
||||||
auto mcPath = FS::PathCombine(m_stagingPath, m_root_path);
|
auto mcPath = FS::PathCombine(m_stagingPath, m_root_path);
|
||||||
|
|
||||||
auto override_path = FS::PathCombine(m_stagingPath, "overrides");
|
auto overridePath = FS::PathCombine(m_stagingPath, "overrides");
|
||||||
if (QFile::exists(override_path)) {
|
if (QFile::exists(overridePath)) {
|
||||||
// Create a list of overrides in "overrides.txt" inside mrpack/
|
// Create a list of overrides in "overrides.txt" inside mrpack/
|
||||||
Override::createOverrides("overrides", parent_folder, override_path);
|
Override::createOverrides("overrides", parentFolder, overridePath);
|
||||||
|
|
||||||
// Apply the overrides
|
// Apply the overrides
|
||||||
if (!FS::move(override_path, mcPath)) {
|
if (!FS::move(overridePath, mcPath)) {
|
||||||
setError(tr("Could not rename the overrides folder:\n") + "overrides");
|
setError(tr("Could not rename the overrides folder:\n") + "overrides");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do client overrides
|
// Do client overrides
|
||||||
auto client_override_path = FS::PathCombine(m_stagingPath, "client-overrides");
|
auto clientOverridePath = FS::PathCombine(m_stagingPath, "client-overrides");
|
||||||
if (QFile::exists(client_override_path)) {
|
if (QFile::exists(clientOverridePath)) {
|
||||||
// Create a list of overrides in "client-overrides.txt" inside mrpack/
|
// Create a list of overrides in "client-overrides.txt" inside mrpack/
|
||||||
Override::createOverrides("client-overrides", parent_folder, client_override_path);
|
Override::createOverrides("client-overrides", parentFolder, clientOverridePath);
|
||||||
|
|
||||||
// Apply the overrides
|
// Apply the overrides
|
||||||
if (!FS::overrideFolder(mcPath, client_override_path)) {
|
if (!FS::overrideFolder(mcPath, clientOverridePath)) {
|
||||||
setError(tr("Could not rename the client overrides folder:\n") + "client overrides");
|
setError(tr("Could not rename the client overrides folder:\n") + "client overrides");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -203,18 +209,22 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
auto instanceSettings = std::make_unique<INISettingsObject>(configPath);
|
auto instanceSettings = std::make_unique<INISettingsObject>(configPath);
|
||||||
auto instance = std::make_unique<MinecraftInstance>(m_globalSettings, std::move(instanceSettings), m_stagingPath);
|
auto instance = std::make_unique<MinecraftInstance>(m_globalSettings, std::move(instanceSettings), m_stagingPath);
|
||||||
|
|
||||||
auto components = instance->getPackProfile();
|
auto* components = instance->getPackProfile();
|
||||||
components->buildingFromScratch();
|
components->buildingFromScratch();
|
||||||
components->setComponentVersion("net.minecraft", m_minecraft_version, true);
|
components->setComponentVersion("net.minecraft", m_minecraft_version, true);
|
||||||
|
|
||||||
if (!m_fabric_version.isEmpty())
|
if (!m_fabric_version.isEmpty()) {
|
||||||
components->setComponentVersion("net.fabricmc.fabric-loader", m_fabric_version);
|
components->setComponentVersion("net.fabricmc.fabric-loader", m_fabric_version);
|
||||||
if (!m_quilt_version.isEmpty())
|
}
|
||||||
|
if (!m_quilt_version.isEmpty()) {
|
||||||
components->setComponentVersion("org.quiltmc.quilt-loader", m_quilt_version);
|
components->setComponentVersion("org.quiltmc.quilt-loader", m_quilt_version);
|
||||||
if (!m_forge_version.isEmpty())
|
}
|
||||||
|
if (!m_forge_version.isEmpty()) {
|
||||||
components->setComponentVersion("net.minecraftforge", m_forge_version);
|
components->setComponentVersion("net.minecraftforge", m_forge_version);
|
||||||
if (!m_neoForge_version.isEmpty())
|
}
|
||||||
|
if (!m_neoForge_version.isEmpty()) {
|
||||||
components->setComponentVersion("net.neoforged", m_neoForge_version);
|
components->setComponentVersion("net.neoforged", m_neoForge_version);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_instIcon != "default") {
|
if (m_instIcon != "default") {
|
||||||
instance->setIconKey(m_instIcon);
|
instance->setIconKey(m_instIcon);
|
||||||
|
|
@ -223,34 +233,35 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't add managed info to packs without an ID (most likely imported from ZIP)
|
// Don't add managed info to packs without an ID (most likely imported from ZIP)
|
||||||
if (!m_managed_id.isEmpty())
|
if (!m_managed_id.isEmpty()) {
|
||||||
instance->setManagedPack("modrinth", m_managed_id, m_managed_name, m_managed_version_id, version());
|
instance->setManagedPack("modrinth", m_managed_id, m_managed_name, m_managed_version_id, version());
|
||||||
else
|
} else {
|
||||||
instance->setManagedPack("modrinth", "", name(), "", "");
|
instance->setManagedPack("modrinth", "", name(), "", "");
|
||||||
|
}
|
||||||
|
|
||||||
instance->setName(name());
|
instance->setName(name());
|
||||||
instance->saveNow();
|
instance->saveNow();
|
||||||
|
|
||||||
auto downloadMods = makeShared<NetJob>(tr("Mod Download Modrinth"), APPLICATION->network());
|
auto downloadMods = makeShared<NetJob>(tr("Mod Download Modrinth"), APPLICATION->network());
|
||||||
|
|
||||||
auto root_modpack_path = FS::PathCombine(m_stagingPath, m_root_path);
|
auto rootModpackPath = FS::PathCombine(m_stagingPath, m_root_path);
|
||||||
auto root_modpack_url = QUrl::fromLocalFile(root_modpack_path);
|
auto rootModpackUrl = QUrl::fromLocalFile(rootModpackPath);
|
||||||
// TODO make this work with other sorts of resource
|
// TODO make this work with other sorts of resource
|
||||||
QHash<QString, Resource*> resources;
|
QHash<QString, Resource*> resources;
|
||||||
for (auto& file : m_files) {
|
for (auto& file : m_files) {
|
||||||
auto fileName = file.path;
|
auto fileName = file.path;
|
||||||
fileName = FS::RemoveInvalidPathChars(fileName);
|
fileName = FS::RemoveInvalidPathChars(fileName);
|
||||||
auto file_path = FS::PathCombine(root_modpack_path, fileName);
|
auto filePath = FS::PathCombine(rootModpackPath, fileName);
|
||||||
if (!root_modpack_url.isParentOf(QUrl::fromLocalFile(file_path))) {
|
if (!rootModpackUrl.isParentOf(QUrl::fromLocalFile(filePath))) {
|
||||||
// This means we somehow got out of the root folder, so abort here to prevent exploits
|
// This means we somehow got out of the root folder, so abort here to prevent exploits
|
||||||
setError(tr("One of the files has a path that leads to an arbitrary location (%1). This is a security risk and isn't allowed.")
|
setError(tr("One of the files has a path that leads to an arbitrary location (%1). This is a security risk and isn't allowed.")
|
||||||
.arg(fileName));
|
.arg(fileName));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (fileName.startsWith("mods/")) {
|
if (fileName.startsWith("mods/")) {
|
||||||
auto mod = new Mod(file_path);
|
auto* mod = new Mod(filePath);
|
||||||
ModDetails d;
|
ModDetails d;
|
||||||
d.mod_id = file_path;
|
d.mod_id = filePath;
|
||||||
mod->setDetails(d);
|
mod->setDetails(d);
|
||||||
resources[file.hash.toHex()] = mod;
|
resources[file.hash.toHex()] = mod;
|
||||||
}
|
}
|
||||||
|
|
@ -258,7 +269,7 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
setError(tr("The file '%1' is missing a download link. This is invalid in the pack format.").arg(fileName));
|
setError(tr("The file '%1' is missing a download link. This is invalid in the pack format.").arg(fileName));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
qDebug() << "Will try to download" << file.downloads.front() << "to" << file_path;
|
qDebug() << "Will try to download" << file.downloads.front() << "to" << filePath;
|
||||||
|
|
||||||
QString loader;
|
QString loader;
|
||||||
if (m_instance.has_value()) {
|
if (m_instance.has_value()) {
|
||||||
|
|
@ -281,29 +292,30 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
};
|
};
|
||||||
|
|
||||||
QUrl downloadUrl = file.downloads.dequeue();
|
QUrl downloadUrl = file.downloads.dequeue();
|
||||||
auto dl = Net::ApiDownload::makeFile(downloadUrl, file_path, Net::Download::Option::NoOptions, meta);
|
auto dl = Net::ApiDownload::makeFile(downloadUrl, filePath, Net::Download::Option::NoOptions, meta);
|
||||||
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
dl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
||||||
downloadMods->addNetAction(dl);
|
downloadMods->addNetAction(dl);
|
||||||
if (!file.downloads.empty()) {
|
if (!file.downloads.empty()) {
|
||||||
// FIXME: This really needs to be put into a ConcurrentTask of
|
// FIXME: This really needs to be put into a ConcurrentTask of
|
||||||
// MultipleOptionsTask's , once those exist :)
|
// MultipleOptionsTask's , once those exist :)
|
||||||
auto param = dl.toWeakRef();
|
auto param = dl.toWeakRef();
|
||||||
connect(dl.get(), &Task::failed, [&file, file_path, param, downloadMods, meta] {
|
connect(dl.get(), &Task::failed, [&file, filePath, param, downloadMods, meta] {
|
||||||
QUrl fallbackUrl = file.downloads.dequeue();
|
QUrl fallbackUrl = file.downloads.dequeue();
|
||||||
auto ndl = Net::ApiDownload::makeFile(fallbackUrl, file_path, Net::Download::Option::NoOptions, meta);
|
auto ndl = Net::ApiDownload::makeFile(fallbackUrl, filePath, Net::Download::Option::NoOptions, meta);
|
||||||
ndl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
ndl->addValidator(new Net::ChecksumValidator(file.hashAlgorithm, file.hash));
|
||||||
downloadMods->addNetAction(ndl);
|
downloadMods->addNetAction(ndl);
|
||||||
if (auto shared = param.lock())
|
if (auto shared = param.lock()) {
|
||||||
shared->succeeded();
|
shared->succeeded();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ended_well = false;
|
bool endedWell = false;
|
||||||
|
|
||||||
connect(downloadMods.get(), &NetJob::succeeded, this, [&ended_well]() { ended_well = true; });
|
connect(downloadMods.get(), &NetJob::succeeded, this, [&endedWell]() { endedWell = true; });
|
||||||
connect(downloadMods.get(), &NetJob::failed, [this, &ended_well](const QString& reason) {
|
connect(downloadMods.get(), &NetJob::failed, [this, &endedWell](const QString& reason) {
|
||||||
ended_well = false;
|
endedWell = false;
|
||||||
setError(reason);
|
setError(reason);
|
||||||
});
|
});
|
||||||
connect(downloadMods.get(), &NetJob::finished, &loop, &QEventLoop::quit);
|
connect(downloadMods.get(), &NetJob::finished, &loop, &QEventLoop::quit);
|
||||||
|
|
@ -319,8 +331,8 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
|
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
if (!ended_well) {
|
if (!endedWell) {
|
||||||
for (auto resource : resources) {
|
for (auto* resource : resources) {
|
||||||
delete resource;
|
delete resource;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
@ -329,7 +341,7 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
QEventLoop ensureMetaLoop;
|
QEventLoop ensureMetaLoop;
|
||||||
QDir folder = FS::PathCombine(instance->modsRoot(), ".index");
|
QDir folder = FS::PathCombine(instance->modsRoot(), ".index");
|
||||||
auto ensureMetadataTask = makeShared<EnsureMetadataTask>(resources, folder, ModPlatform::ResourceProvider::MODRINTH);
|
auto ensureMetadataTask = makeShared<EnsureMetadataTask>(resources, folder, ModPlatform::ResourceProvider::MODRINTH);
|
||||||
connect(ensureMetadataTask.get(), &Task::succeeded, this, [&ended_well]() { ended_well = true; });
|
connect(ensureMetadataTask.get(), &Task::succeeded, this, [&endedWell]() { endedWell = true; });
|
||||||
connect(ensureMetadataTask.get(), &Task::finished, &ensureMetaLoop, &QEventLoop::quit);
|
connect(ensureMetadataTask.get(), &Task::finished, &ensureMetaLoop, &QEventLoop::quit);
|
||||||
connect(ensureMetadataTask.get(), &Task::progress, [this](qint64 current, qint64 total) {
|
connect(ensureMetadataTask.get(), &Task::progress, [this](qint64 current, qint64 total) {
|
||||||
setDetails(tr("%1 out of %2 complete").arg(current).arg(total));
|
setDetails(tr("%1 out of %2 complete").arg(current).arg(total));
|
||||||
|
|
@ -341,40 +353,38 @@ std::unique_ptr<MinecraftInstance> ModrinthCreationTask::createInstance()
|
||||||
m_task = ensureMetadataTask;
|
m_task = ensureMetadataTask;
|
||||||
|
|
||||||
ensureMetaLoop.exec();
|
ensureMetaLoop.exec();
|
||||||
for (auto resource : resources) {
|
for (auto* resource : resources) {
|
||||||
delete resource;
|
delete resource;
|
||||||
}
|
}
|
||||||
resources.clear();
|
resources.clear();
|
||||||
|
|
||||||
// Update information of the already installed instance, if any.
|
// Update information of the already installed instance, if any.
|
||||||
if (m_instance && ended_well) {
|
if (m_instance && endedWell) {
|
||||||
setAbortable(false);
|
setAbortable(false);
|
||||||
auto inst = m_instance.value();
|
auto* inst = m_instance.value();
|
||||||
|
|
||||||
// Only change the name if it didn't use a custom name, so that the previous custom name
|
// Only change the name if it didn't use a custom name, so that the previous custom name
|
||||||
// is preserved, but if we're using the original one, we update the version string.
|
// is preserved, but if we're using the original one, we update the version string.
|
||||||
// NOTE: This needs to come before the copyManagedPack call!
|
// NOTE: This needs to come before the copyManagedPack call!
|
||||||
if (inst->name().contains(inst->getManagedPackVersionName()) && inst->name() != instance->name()) {
|
if (inst->name().contains(inst->getManagedPackVersionName()) && inst->name() != instance->name()) {
|
||||||
if (askForChangingInstanceName(m_parent, inst->name(), instance->name()) == InstanceNameChange::ShouldChange)
|
if (askForChangingInstanceName(m_parent, inst->name(), instance->name()) == InstanceNameChange::ShouldChange) {
|
||||||
inst->setName(instance->name());
|
inst->setName(instance->name());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inst->copyManagedPack(*instance);
|
inst->copyManagedPack(*instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ended_well) {
|
if (endedWell) {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModrinthCreationTask::parseManifest(const QString& index_path,
|
bool ModrinthCreationTask::parseManifest(const QString& indexPath, std::vector<File>& files, bool setInternalData, bool showOptionalDialog)
|
||||||
std::vector<File>& files,
|
|
||||||
bool set_internal_data,
|
|
||||||
bool show_optional_dialog)
|
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
auto doc = Json::requireDocument(index_path);
|
auto doc = Json::requireDocument(indexPath);
|
||||||
auto obj = Json::requireObject(doc, "modrinth.index.json");
|
auto obj = Json::requireObject(doc, "modrinth.index.json");
|
||||||
int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json");
|
int formatVersion = Json::requireInteger(obj, "formatVersion", "modrinth.index.json");
|
||||||
if (formatVersion == 1) {
|
if (formatVersion == 1) {
|
||||||
|
|
@ -383,9 +393,10 @@ bool ModrinthCreationTask::parseManifest(const QString& index_path,
|
||||||
throw JSONValidationError("Unknown game: " + game);
|
throw JSONValidationError("Unknown game: " + game);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (set_internal_data) {
|
if (setInternalData) {
|
||||||
if (m_managed_version_id.isEmpty())
|
if (m_managed_version_id.isEmpty()) {
|
||||||
m_managed_version_id = obj["versionId"].toString();
|
m_managed_version_id = obj["versionId"].toString();
|
||||||
|
}
|
||||||
m_managed_name = obj["name"].toString();
|
m_managed_name = obj["name"].toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -401,7 +412,8 @@ bool ModrinthCreationTask::parseManifest(const QString& index_path,
|
||||||
QString support = env["client"].toString("unsupported");
|
QString support = env["client"].toString("unsupported");
|
||||||
if (support == "unsupported") {
|
if (support == "unsupported") {
|
||||||
continue;
|
continue;
|
||||||
} else if (support == "optional") {
|
}
|
||||||
|
if (support == "optional") {
|
||||||
file.required = false;
|
file.required = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -413,20 +425,21 @@ bool ModrinthCreationTask::parseManifest(const QString& index_path,
|
||||||
// Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode
|
// Do not use requireUrl, which uses StrictMode, instead use QUrl's default TolerantMode
|
||||||
// (as Modrinth seems to incorrectly handle spaces)
|
// (as Modrinth seems to incorrectly handle spaces)
|
||||||
|
|
||||||
auto download_arr = modInfo["downloads"].toArray();
|
auto downloadArr = modInfo["downloads"].toArray();
|
||||||
for (auto download : download_arr) {
|
for (auto download : downloadArr) {
|
||||||
qWarning() << download.toString();
|
qWarning() << download.toString();
|
||||||
bool is_last = download.toString() == download_arr.last().toString();
|
bool isLast = download.toString() == downloadArr.last().toString();
|
||||||
|
|
||||||
auto download_url = QUrl(download.toString());
|
auto downloadUrl = QUrl(download.toString());
|
||||||
|
|
||||||
if (!download_url.isValid()) {
|
if (!downloadUrl.isValid()) {
|
||||||
qDebug()
|
qDebug()
|
||||||
<< QString("Download URL (%1) for %2 is not a correctly formatted URL").arg(download_url.toString(), file.path);
|
<< QString("Download URL (%1) for %2 is not a correctly formatted URL").arg(downloadUrl.toString(), file.path);
|
||||||
if (is_last && file.downloads.isEmpty())
|
if (isLast && file.downloads.isEmpty()) {
|
||||||
throw JSONValidationError(tr("Download URL for %1 is not a correctly formatted URL").arg(file.path));
|
throw JSONValidationError(tr("Download URL for %1 is not a correctly formatted URL").arg(file.path));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
file.downloads.push_back(download_url);
|
file.downloads.push_back(downloadUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -434,10 +447,11 @@ bool ModrinthCreationTask::parseManifest(const QString& index_path,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!optionalFiles.empty()) {
|
if (!optionalFiles.empty()) {
|
||||||
if (show_optional_dialog) {
|
if (showOptionalDialog) {
|
||||||
QStringList oFiles;
|
QStringList oFiles;
|
||||||
for (auto file : optionalFiles)
|
for (const auto& file : optionalFiles) {
|
||||||
oFiles.push_back(file.path);
|
oFiles.push_back(file.path);
|
||||||
|
}
|
||||||
OptionalModDialog optionalModDialog(m_parent, oFiles);
|
OptionalModDialog optionalModDialog(m_parent, oFiles);
|
||||||
if (optionalModDialog.exec() == QDialog::Rejected) {
|
if (optionalModDialog.exec() == QDialog::Rejected) {
|
||||||
emitAborted();
|
emitAborted();
|
||||||
|
|
@ -460,7 +474,7 @@ bool ModrinthCreationTask::parseManifest(const QString& index_path,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (set_internal_data) {
|
if (setInternalData) {
|
||||||
auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json");
|
auto dependencies = Json::requireObject(obj, "dependencies", "modrinth.index.json");
|
||||||
for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) {
|
for (auto it = dependencies.begin(), end = dependencies.end(); it != end; ++it) {
|
||||||
QString name = it.key();
|
QString name = it.key();
|
||||||
|
|
|
||||||
|
|
@ -24,18 +24,18 @@ class ModrinthCreationTask final : public InstanceCreationTask {
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ModrinthCreationTask(QString staging_path,
|
ModrinthCreationTask(const QString& stagingPath,
|
||||||
SettingsObject* global_settings,
|
SettingsObject* globalSettings,
|
||||||
QWidget* parent,
|
QWidget* parent,
|
||||||
QString id,
|
QString id,
|
||||||
QString version_id = {},
|
QString versionId = {},
|
||||||
QString original_instance_id = {})
|
QString originalInstanceId = {})
|
||||||
: InstanceCreationTask(), m_parent(parent), m_managed_id(std::move(id)), m_managed_version_id(std::move(version_id))
|
: m_parent(parent), m_managed_id(std::move(id)), m_managed_version_id(std::move(versionId))
|
||||||
{
|
{
|
||||||
setStagingPath(staging_path);
|
setStagingPath(stagingPath);
|
||||||
setParentSettings(global_settings);
|
setParentSettings(globalSettings);
|
||||||
|
|
||||||
m_original_instance_id = std::move(original_instance_id);
|
m_original_instance_id = std::move(originalInstanceId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool abort() override;
|
bool abort() override;
|
||||||
|
|
@ -44,7 +44,7 @@ class ModrinthCreationTask final : public InstanceCreationTask {
|
||||||
std::unique_ptr<MinecraftInstance> createInstance() override;
|
std::unique_ptr<MinecraftInstance> createInstance() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool parseManifest(const QString&, std::vector<File>&, bool set_internal_data = true, bool show_optional_dialog = true);
|
bool parseManifest(const QString&, std::vector<File>&, bool setInternalData = true, bool showOptionalDialog = true);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* m_parent = nullptr;
|
QWidget* m_parent = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -18,27 +18,29 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include "net/ApiHeaderProxy.h"
|
#include "net/ApiHeaderProxy.h"
|
||||||
|
|
||||||
namespace Net {
|
namespace Net {
|
||||||
|
|
||||||
Download::Ptr ApiDownload::makeCached(QUrl url, MetaEntryPtr entry, Download::Options options)
|
Download::Ptr ApiDownload::makeCached(QUrl url, MetaEntryPtr entry, Download::Options options)
|
||||||
{
|
{
|
||||||
auto dl = Download::makeCached(url, entry, options);
|
auto dl = Download::makeCached(std::move(url), std::move(entry), options);
|
||||||
dl->addHeaderProxy(std::make_unique<ApiHeaderProxy>());
|
dl->addHeaderProxy(std::make_unique<ApiHeaderProxy>());
|
||||||
return dl;
|
return dl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Download::Ptr, QByteArray*> ApiDownload::makeByteArray(QUrl url, Download::Options options)
|
std::pair<Download::Ptr, QByteArray*> ApiDownload::makeByteArray(QUrl url, Download::Options options)
|
||||||
{
|
{
|
||||||
auto [dl, response] = Download::makeByteArray(url, options);
|
auto [dl, response] = Download::makeByteArray(std::move(url), options);
|
||||||
dl->addHeaderProxy(std::make_unique<ApiHeaderProxy>());
|
dl->addHeaderProxy(std::make_unique<ApiHeaderProxy>());
|
||||||
return { dl, response };
|
return { dl, response };
|
||||||
}
|
}
|
||||||
|
|
||||||
Download::Ptr ApiDownload::makeFile(QUrl url, QString path, Download::Options options, ModrinthDownloadMeta meta)
|
Download::Ptr ApiDownload::makeFile(QUrl url, QString path, Download::Options options, ModrinthDownloadMeta meta)
|
||||||
{
|
{
|
||||||
auto dl = Download::makeFile(url, path, options);
|
auto dl = Download::makeFile(std::move(url), std::move(path), options);
|
||||||
dl->addHeaderProxy(std::make_unique<ApiHeaderProxy>(std::move(meta)));
|
dl->addHeaderProxy(std::make_unique<ApiHeaderProxy>(std::move(meta)));
|
||||||
return dl;
|
return dl;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,9 @@ namespace Net {
|
||||||
namespace ApiDownload {
|
namespace ApiDownload {
|
||||||
Download::Ptr makeCached(QUrl url, MetaEntryPtr entry, Download::Options options = Download::Option::NoOptions);
|
Download::Ptr makeCached(QUrl url, MetaEntryPtr entry, Download::Options options = Download::Option::NoOptions);
|
||||||
std::pair<Download::Ptr, QByteArray*> makeByteArray(QUrl url, Download::Options options = Download::Option::NoOptions);
|
std::pair<Download::Ptr, QByteArray*> makeByteArray(QUrl url, Download::Options options = Download::Option::NoOptions);
|
||||||
Download::Ptr makeFile(QUrl url, QString path, Download::Options options = Download::Option::NoOptions,
|
Download::Ptr makeFile(QUrl url,
|
||||||
|
QString path,
|
||||||
|
Download::Options options = Download::Option::NoOptions,
|
||||||
ModrinthDownloadMeta meta = ModrinthDownloadMeta());
|
ModrinthDownloadMeta meta = ModrinthDownloadMeta());
|
||||||
}; // namespace ApiDownload
|
}; // namespace ApiDownload
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,28 +38,31 @@ struct ModrinthDownloadMeta {
|
||||||
QByteArray toJson() const
|
QByteArray toJson() const
|
||||||
{
|
{
|
||||||
QJsonObject obj;
|
QJsonObject obj;
|
||||||
if (!reason.isEmpty())
|
if (!reason.isEmpty()) {
|
||||||
obj["reason"] = reason;
|
obj["reason"] = reason;
|
||||||
if (!gameVersion.isEmpty())
|
}
|
||||||
|
if (!gameVersion.isEmpty()) {
|
||||||
obj["game_version"] = gameVersion;
|
obj["game_version"] = gameVersion;
|
||||||
if (!loader.isEmpty())
|
}
|
||||||
|
if (!loader.isEmpty()) {
|
||||||
obj["loader"] = loader;
|
obj["loader"] = loader;
|
||||||
|
}
|
||||||
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
return QJsonDocument(obj).toJson(QJsonDocument::Compact);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ApiHeaderProxy : public HeaderProxy {
|
class ApiHeaderProxy : public HeaderProxy {
|
||||||
public:
|
public:
|
||||||
ApiHeaderProxy() : HeaderProxy() {}
|
ApiHeaderProxy() = default;
|
||||||
explicit ApiHeaderProxy(ModrinthDownloadMeta meta) : m_meta(std::move(meta)) {}
|
explicit ApiHeaderProxy(ModrinthDownloadMeta meta) : m_meta(std::move(meta)) {}
|
||||||
virtual ~ApiHeaderProxy() = default;
|
~ApiHeaderProxy() override = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual QList<HeaderPair> headers(const QNetworkRequest& request) const override
|
QList<HeaderPair> headers(const QNetworkRequest& request) const override
|
||||||
{
|
{
|
||||||
QList<HeaderPair> hdrs;
|
QList<HeaderPair> hdrs;
|
||||||
if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) {
|
if (APPLICATION->capabilities() & Application::SupportsFlame && request.url().host() == QUrl(BuildConfig.FLAME_BASE_URL).host()) {
|
||||||
hdrs.append({ "x-api-key", APPLICATION->getFlameAPIKey().toUtf8() });
|
hdrs.append({ .headerName = "x-api-key", .headerValue = APPLICATION->getFlameAPIKey().toUtf8() });
|
||||||
} else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() ||
|
} else if (request.url().host() == QUrl(BuildConfig.MODRINTH_PROD_URL).host() ||
|
||||||
request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) {
|
request.url().host() == QUrl(BuildConfig.MODRINTH_STAGING_URL).host()) {
|
||||||
QString token = APPLICATION->getModrinthAPIToken();
|
QString token = APPLICATION->getModrinthAPIToken();
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ ResourcePage* ResourceDownloadDialog::selectedPage()
|
||||||
void ResourceDownloadDialog::addResource(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver, QString downloadReason)
|
void ResourceDownloadDialog::addResource(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& ver, QString downloadReason)
|
||||||
{
|
{
|
||||||
removeResource(pack->name);
|
removeResource(pack->name);
|
||||||
selectedPage()->addResourceToPage(pack, ver, getBaseModel(), downloadReason);
|
selectedPage()->addResourceToPage(pack, ver, getBaseModel(), std::move(downloadReason));
|
||||||
setButtonStatus();
|
setButtonStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,10 @@ class ResourcePackDownloadDialog final : public ResourceDownloadDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ResourcePackDownloadDialog(QWidget* parent, ResourcePackFolderModel* resourcePacks, BaseInstance* instance, bool suppressInitialSearch = false);
|
explicit ResourcePackDownloadDialog(QWidget* parent,
|
||||||
|
ResourcePackFolderModel* resourcePacks,
|
||||||
|
BaseInstance* instance,
|
||||||
|
bool suppressInitialSearch = false);
|
||||||
~ResourcePackDownloadDialog() override = default;
|
~ResourcePackDownloadDialog() override = default;
|
||||||
|
|
||||||
//: String that gets appended to the resource pack download dialog title ("Download " + resourcesString())
|
//: String that gets appended to the resource pack download dialog title ("Download " + resourcesString())
|
||||||
|
|
@ -138,7 +141,10 @@ class TexturePackDownloadDialog final : public ResourceDownloadDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TexturePackDownloadDialog(QWidget* parent, TexturePackFolderModel* resourcePacks, BaseInstance* instance, bool suppressInitialSearch = false);
|
explicit TexturePackDownloadDialog(QWidget* parent,
|
||||||
|
TexturePackFolderModel* resourcePacks,
|
||||||
|
BaseInstance* instance,
|
||||||
|
bool suppressInitialSearch = false);
|
||||||
~TexturePackDownloadDialog() override = default;
|
~TexturePackDownloadDialog() override = default;
|
||||||
|
|
||||||
//: String that gets appended to the texture pack download dialog title ("Download " + resourcesString())
|
//: String that gets appended to the texture pack download dialog title ("Download " + resourcesString())
|
||||||
|
|
@ -155,7 +161,10 @@ class ShaderPackDownloadDialog final : public ResourceDownloadDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ShaderPackDownloadDialog(QWidget* parent, ShaderPackFolderModel* shaders, BaseInstance* instance, bool suppressInitialSearch = false);
|
explicit ShaderPackDownloadDialog(QWidget* parent,
|
||||||
|
ShaderPackFolderModel* shaders,
|
||||||
|
BaseInstance* instance,
|
||||||
|
bool suppressInitialSearch = false);
|
||||||
~ShaderPackDownloadDialog() override = default;
|
~ShaderPackDownloadDialog() override = default;
|
||||||
|
|
||||||
//: String that gets appended to the shader pack download dialog title ("Download " + resourcesString())
|
//: String that gets appended to the shader pack download dialog title ("Download " + resourcesString())
|
||||||
|
|
@ -172,7 +181,10 @@ class DataPackDownloadDialog final : public ResourceDownloadDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DataPackDownloadDialog(QWidget* parent, DataPackFolderModel* dataPacks, BaseInstance* instance, bool suppressInitialSearch = false);
|
explicit DataPackDownloadDialog(QWidget* parent,
|
||||||
|
DataPackFolderModel* dataPacks,
|
||||||
|
BaseInstance* instance,
|
||||||
|
bool suppressInitialSearch = false);
|
||||||
~DataPackDownloadDialog() override = default;
|
~DataPackDownloadDialog() override = default;
|
||||||
|
|
||||||
//: String that gets appended to the data pack download dialog title ("Download " + resourcesString())
|
//: String that gets appended to the data pack download dialog title ("Download " + resourcesString())
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,12 @@
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
static std::vector<Version> mcVersions(BaseInstance* inst)
|
namespace {
|
||||||
|
std::vector<Version> mcVersions(BaseInstance* inst)
|
||||||
{
|
{
|
||||||
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() };
|
return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() };
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
ResourceUpdateDialog::ResourceUpdateDialog(QWidget* parent,
|
ResourceUpdateDialog::ResourceUpdateDialog(QWidget* parent,
|
||||||
BaseInstance* instance,
|
BaseInstance* instance,
|
||||||
|
|
@ -58,8 +60,8 @@ ResourceUpdateDialog::ResourceUpdateDialog(QWidget* parent,
|
||||||
void ResourceUpdateDialog::checkCandidates()
|
void ResourceUpdateDialog::checkCandidates()
|
||||||
{
|
{
|
||||||
// Ensure mods have valid metadata
|
// Ensure mods have valid metadata
|
||||||
auto went_well = ensureMetadata();
|
auto wentWell = ensureMetadata();
|
||||||
if (!went_well) {
|
if (!wentWell) {
|
||||||
m_aborted = true;
|
m_aborted = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -73,12 +75,12 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
text += tr("Mod name: %1<br>File name: %2<br>Reason: %3<br><br>").arg(mod->name(), mod->fileinfo().fileName(), reason);
|
text += tr("Mod name: %1<br>File name: %2<br>Reason: %3<br><br>").arg(mod->name(), mod->fileinfo().fileName(), reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollMessageBox message_dialog(m_parent, tr("Metadata generation failed"),
|
ScrollMessageBox messageDialog(m_parent, tr("Metadata generation failed"),
|
||||||
tr("Could not generate metadata for the following resources:<br>"
|
tr("Could not generate metadata for the following resources:<br>"
|
||||||
"Do you wish to proceed without those resources?"),
|
"Do you wish to proceed without those resources?"),
|
||||||
text);
|
text);
|
||||||
message_dialog.setModal(true);
|
messageDialog.setModal(true);
|
||||||
if (message_dialog.exec() == QDialog::Rejected) {
|
if (messageDialog.exec() == QDialog::Rejected) {
|
||||||
m_aborted = true;
|
m_aborted = true;
|
||||||
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
|
|
@ -87,40 +89,41 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
|
|
||||||
auto versions = mcVersions(m_instance);
|
auto versions = mcVersions(m_instance);
|
||||||
|
|
||||||
SequentialTask check_task(tr("Checking for updates"));
|
SequentialTask checkTask(tr("Checking for updates"));
|
||||||
|
|
||||||
if (!m_modrinthToUpdate.empty()) {
|
if (!m_modrinthToUpdate.empty()) {
|
||||||
m_modrinthCheckTask.reset(new ModrinthCheckUpdate(m_modrinthToUpdate, versions, m_loadersList, m_resourceModel));
|
m_modrinthCheckTask.reset(new ModrinthCheckUpdate(m_modrinthToUpdate, versions, m_loadersList, m_resourceModel));
|
||||||
connect(m_modrinthCheckTask.get(), &CheckUpdateTask::checkFailed, this,
|
connect(m_modrinthCheckTask.get(), &CheckUpdateTask::checkFailed, this,
|
||||||
[this](Resource* resource, QString reason, QUrl recover_url) {
|
[this](Resource* resource, const QString& reason, const QUrl& recoverUrl) {
|
||||||
m_failedCheckUpdate.append({ resource, reason, recover_url });
|
m_failedCheckUpdate.append({ resource, reason, recoverUrl });
|
||||||
});
|
});
|
||||||
check_task.addTask(m_modrinthCheckTask);
|
checkTask.addTask(m_modrinthCheckTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_flameToUpdate.empty()) {
|
if (!m_flameToUpdate.empty()) {
|
||||||
m_flameCheckTask.reset(new FlameCheckUpdate(m_flameToUpdate, versions, m_loadersList, m_resourceModel));
|
m_flameCheckTask.reset(new FlameCheckUpdate(m_flameToUpdate, versions, m_loadersList, m_resourceModel));
|
||||||
connect(m_flameCheckTask.get(), &CheckUpdateTask::checkFailed, this, [this](Resource* resource, QString reason, QUrl recover_url) {
|
connect(m_flameCheckTask.get(), &CheckUpdateTask::checkFailed, this,
|
||||||
m_failedCheckUpdate.append({ resource, reason, recover_url });
|
[this](Resource* resource, const QString& reason, const QUrl& recoverUrl) {
|
||||||
});
|
m_failedCheckUpdate.append({ resource, reason, recoverUrl });
|
||||||
check_task.addTask(m_flameCheckTask);
|
});
|
||||||
|
checkTask.addTask(m_flameCheckTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(&check_task, &Task::failed, this,
|
connect(&checkTask, &Task::failed, this,
|
||||||
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
[this](const QString& reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
||||||
|
|
||||||
connect(&check_task, &Task::succeeded, this, [this, &check_task]() {
|
connect(&checkTask, &Task::succeeded, this, [this, &checkTask]() {
|
||||||
QStringList warnings = check_task.warnings();
|
QStringList warnings = checkTask.warnings();
|
||||||
if (warnings.count()) {
|
if (warnings.count()) {
|
||||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->exec();
|
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->exec();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check for updates
|
// Check for updates
|
||||||
ProgressDialog progress_dialog(m_parent);
|
ProgressDialog progressDialog(m_parent);
|
||||||
progress_dialog.setSkipButton(true, tr("Abort"));
|
progressDialog.setSkipButton(true, tr("Abort"));
|
||||||
progress_dialog.setWindowTitle(tr("Checking for updates..."));
|
progressDialog.setWindowTitle(tr("Checking for updates..."));
|
||||||
auto ret = progress_dialog.execWithTask(&check_task);
|
auto ret = progressDialog.execWithTask(&checkTask);
|
||||||
|
|
||||||
// If the dialog was skipped / some download error happened
|
// If the dialog was skipped / some download error happened
|
||||||
if (ret == QDialog::DialogCode::Rejected) {
|
if (ret == QDialog::DialogCode::Rejected) {
|
||||||
|
|
@ -133,8 +136,8 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
|
|
||||||
// Add found updates for Modrinth
|
// Add found updates for Modrinth
|
||||||
if (m_modrinthCheckTask) {
|
if (m_modrinthCheckTask) {
|
||||||
auto modrinth_updates = m_modrinthCheckTask->getUpdates();
|
auto modrinthUpdates = m_modrinthCheckTask->getUpdates();
|
||||||
for (auto& updatable : modrinth_updates) {
|
for (auto& updatable : modrinthUpdates) {
|
||||||
qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
|
qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
|
||||||
|
|
||||||
appendResource(updatable);
|
appendResource(updatable);
|
||||||
|
|
@ -145,8 +148,8 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
|
|
||||||
// Add found updated for Flame
|
// Add found updated for Flame
|
||||||
if (m_flameCheckTask) {
|
if (m_flameCheckTask) {
|
||||||
auto flame_updates = m_flameCheckTask->getUpdates();
|
auto flameUpdates = m_flameCheckTask->getUpdates();
|
||||||
for (auto& updatable : flame_updates) {
|
for (auto& updatable : flameUpdates) {
|
||||||
qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
|
qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
|
||||||
|
|
||||||
appendResource(updatable);
|
appendResource(updatable);
|
||||||
|
|
@ -161,33 +164,35 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
for (const auto& failed : m_failedCheckUpdate) {
|
for (const auto& failed : m_failedCheckUpdate) {
|
||||||
const auto& mod = std::get<0>(failed);
|
const auto& mod = std::get<0>(failed);
|
||||||
const auto& reason = std::get<1>(failed);
|
const auto& reason = std::get<1>(failed);
|
||||||
const auto& recover_url = std::get<2>(failed);
|
const auto& recoverUrl = std::get<2>(failed);
|
||||||
|
|
||||||
qDebug() << mod->name() << "failed to check for updates!";
|
qDebug() << mod->name() << "failed to check for updates!";
|
||||||
|
|
||||||
text += tr("Mod name: %1").arg(mod->name()) + "<br>";
|
text += tr("Mod name: %1").arg(mod->name()) + "<br>";
|
||||||
if (!reason.isEmpty())
|
if (!reason.isEmpty()) {
|
||||||
text += tr("Reason: %1").arg(reason) + "<br>";
|
text += tr("Reason: %1").arg(reason) + "<br>";
|
||||||
if (!recover_url.isEmpty())
|
}
|
||||||
|
if (!recoverUrl.isEmpty()) {
|
||||||
//: %1 is the link to download it manually
|
//: %1 is the link to download it manually
|
||||||
text += tr("Possible solution: Getting the latest version manually:<br>%1<br>")
|
text += tr("Possible solution: Getting the latest version manually:<br>%1<br>")
|
||||||
.arg(QString("<a href='%1'>%1</a>").arg(recover_url.toString()));
|
.arg(QString("<a href='%1'>%1</a>").arg(recoverUrl.toString()));
|
||||||
|
}
|
||||||
text += "<br>";
|
text += "<br>";
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollMessageBox message_dialog(m_parent, tr("Failed to check for updates"),
|
ScrollMessageBox messageDialog(m_parent, tr("Failed to check for updates"),
|
||||||
tr("Could not check or get the following resources for updates:<br>"
|
tr("Could not check or get the following resources for updates:<br>"
|
||||||
"Do you wish to proceed without those resources?"),
|
"Do you wish to proceed without those resources?"),
|
||||||
text, "Disable unavailable mods");
|
text, "Disable unavailable mods");
|
||||||
message_dialog.setModal(true);
|
messageDialog.setModal(true);
|
||||||
if (message_dialog.exec() == QDialog::Rejected) {
|
if (messageDialog.exec() == QDialog::Rejected) {
|
||||||
m_aborted = true;
|
m_aborted = true;
|
||||||
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disable unavailable mods
|
// Disable unavailable mods
|
||||||
if (message_dialog.isOptionChecked()) {
|
if (messageDialog.isOptionChecked()) {
|
||||||
for (const auto& failed : m_failedCheckUpdate) {
|
for (const auto& failed : m_failedCheckUpdate) {
|
||||||
const auto& mod = std::get<0>(failed);
|
const auto& mod = std::get<0>(failed);
|
||||||
mod->enable(EnableAction::DISABLE);
|
mod->enable(EnableAction::DISABLE);
|
||||||
|
|
@ -196,10 +201,10 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_includeDeps && !APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
|
if (m_includeDeps && !APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
|
||||||
auto* mod_model = dynamic_cast<ModFolderModel*>(m_resourceModel);
|
auto* modModel = dynamic_cast<ModFolderModel*>(m_resourceModel);
|
||||||
|
|
||||||
if (mod_model != nullptr) {
|
if (modModel != nullptr) {
|
||||||
auto depTask = makeShared<GetModDependenciesTask>(m_instance, mod_model, selectedVers);
|
auto depTask = makeShared<GetModDependenciesTask>(m_instance, modModel, selectedVers);
|
||||||
|
|
||||||
connect(depTask.get(), &Task::failed, this, [this](const QString& reason) {
|
connect(depTask.get(), &Task::failed, this, [this](const QString& reason) {
|
||||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec();
|
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec();
|
||||||
|
|
@ -215,10 +220,10 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
ProgressDialog progress_dialog_deps(m_parent);
|
ProgressDialog progressDialogDeps(m_parent);
|
||||||
progress_dialog_deps.setSkipButton(true, tr("Abort"));
|
progressDialogDeps.setSkipButton(true, tr("Abort"));
|
||||||
progress_dialog_deps.setWindowTitle(tr("Checking for dependencies..."));
|
progressDialogDeps.setWindowTitle(tr("Checking for dependencies..."));
|
||||||
auto dret = progress_dialog_deps.execWithTask(depTask.get());
|
auto dret = progressDialogDeps.execWithTask(depTask.get());
|
||||||
|
|
||||||
// If the dialog was skipped / some download error happened
|
// If the dialog was skipped / some download error happened
|
||||||
if (dret == QDialog::DialogCode::Rejected) {
|
if (dret == QDialog::DialogCode::Rejected) {
|
||||||
|
|
@ -226,19 +231,20 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static FlameAPI api;
|
static FlameAPI s_api;
|
||||||
|
|
||||||
auto dependencyExtraInfo = depTask->getExtraInfo();
|
auto dependencyExtraInfo = depTask->getExtraInfo();
|
||||||
|
|
||||||
for (const auto& dep : depTask->getDependecies()) {
|
for (const auto& dep : depTask->getDependecies()) {
|
||||||
auto changelog = dep->version.changelog;
|
auto changelog = dep->version.changelog;
|
||||||
if (dep->pack->provider == ModPlatform::ResourceProvider::FLAME)
|
if (dep->pack->provider == ModPlatform::ResourceProvider::FLAME) {
|
||||||
changelog = api.getModFileChangelog(dep->version.addonId.toInt(), dep->version.fileId.toInt());
|
changelog = s_api.getModFileChangelog(dep->version.addonId.toInt(), dep->version.fileId.toInt());
|
||||||
auto download_task = makeShared<ResourceDownloadTask>(dep->pack, dep->version, m_resourceModel, true, "dependency");
|
}
|
||||||
|
auto downloadTask = makeShared<ResourceDownloadTask>(dep->pack, dep->version, m_resourceModel, true, "dependency");
|
||||||
auto extraInfo = dependencyExtraInfo.value(dep->version.addonId.toString());
|
auto extraInfo = dependencyExtraInfo.value(dep->version.addonId.toString());
|
||||||
CheckUpdateTask::Update updatable = {
|
CheckUpdateTask::Update updatable = {
|
||||||
dep->pack->name, dep->version.hash, tr("Not installed"), dep->version.version, dep->version.version_type,
|
dep->pack->name, dep->version.hash, tr("Not installed"), dep->version.version, dep->version.version_type,
|
||||||
changelog, dep->pack->provider, download_task, !extraInfo.maybe_installed
|
changelog, dep->pack->provider, downloadTask, !extraInfo.maybe_installed
|
||||||
};
|
};
|
||||||
|
|
||||||
appendResource(updatable, extraInfo.required_by);
|
appendResource(updatable, extraInfo.required_by);
|
||||||
|
|
@ -264,56 +270,58 @@ void ResourceUpdateDialog::checkCandidates()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_aborted || m_noUpdates)
|
if (m_aborted || m_noUpdates) {
|
||||||
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Part 1: Ensure we have a valid metadata
|
// Part 1: Ensure we have a valid metadata
|
||||||
auto ResourceUpdateDialog::ensureMetadata() -> bool
|
auto ResourceUpdateDialog::ensureMetadata() -> bool
|
||||||
{
|
{
|
||||||
auto index_dir = indexDir();
|
auto indexDir2 = indexDir();
|
||||||
|
|
||||||
SequentialTask seq(tr("Looking for metadata"));
|
SequentialTask seq(tr("Looking for metadata"));
|
||||||
|
|
||||||
// A better use of data structures here could remove the need for this QHash
|
// A better use of data structures here could remove the need for this QHash
|
||||||
QHash<QString, bool> should_try_others;
|
QHash<QString, bool> shouldTryOthers;
|
||||||
QList<Resource*> modrinth_tmp;
|
QList<Resource*> modrinthTmp;
|
||||||
QList<Resource*> flame_tmp;
|
QList<Resource*> flameTmp;
|
||||||
|
|
||||||
bool confirm_rest = false;
|
bool confirmRest = false;
|
||||||
bool try_others_rest = false;
|
bool tryOthersRest = false;
|
||||||
bool skip_rest = false;
|
bool skipRest = false;
|
||||||
ModPlatform::ResourceProvider provider_rest = ModPlatform::ResourceProvider::MODRINTH;
|
ModPlatform::ResourceProvider providerRest = ModPlatform::ResourceProvider::MODRINTH;
|
||||||
|
|
||||||
// adds resource to list based on provider
|
// adds resource to list based on provider
|
||||||
auto addToTmp = [&modrinth_tmp, &flame_tmp](Resource* resource, ModPlatform::ResourceProvider p) {
|
auto addToTmp = [&modrinthTmp, &flameTmp](Resource* resource, ModPlatform::ResourceProvider p) {
|
||||||
switch (p) {
|
switch (p) {
|
||||||
case ModPlatform::ResourceProvider::MODRINTH:
|
case ModPlatform::ResourceProvider::MODRINTH:
|
||||||
modrinth_tmp.push_back(resource);
|
modrinthTmp.push_back(resource);
|
||||||
break;
|
break;
|
||||||
case ModPlatform::ResourceProvider::FLAME:
|
case ModPlatform::ResourceProvider::FLAME:
|
||||||
flame_tmp.push_back(resource);
|
flameTmp.push_back(resource);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ask the user on what provider to seach for the mod first
|
// ask the user on what provider to seach for the mod first
|
||||||
for (auto candidate : m_candidates) {
|
for (auto* candidate : m_candidates) {
|
||||||
if (candidate->status() != ResourceStatus::NO_METADATA) {
|
if (candidate->status() != ResourceStatus::NO_METADATA) {
|
||||||
onMetadataEnsured(candidate);
|
onMetadataEnsured(candidate);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skip_rest)
|
if (skipRest) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (candidate->type() == ResourceType::FOLDER) {
|
if (candidate->type() == ResourceType::FOLDER) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (confirm_rest) {
|
if (confirmRest) {
|
||||||
addToTmp(candidate, provider_rest);
|
addToTmp(candidate, providerRest);
|
||||||
should_try_others.insert(candidate->internal_id(), try_others_rest);
|
shouldTryOthers.insert(candidate->internal_id(), tryOthersRest);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -326,68 +334,73 @@ auto ResourceUpdateDialog::ensureMetadata() -> bool
|
||||||
|
|
||||||
auto response = chooser.getResponse();
|
auto response = chooser.getResponse();
|
||||||
|
|
||||||
if (response.skip_all)
|
if (response.skip_all) {
|
||||||
skip_rest = true;
|
skipRest = true;
|
||||||
|
}
|
||||||
if (response.confirm_all) {
|
if (response.confirm_all) {
|
||||||
confirm_rest = true;
|
confirmRest = true;
|
||||||
provider_rest = response.chosen;
|
providerRest = response.chosen;
|
||||||
try_others_rest = response.try_others;
|
tryOthersRest = response.try_others;
|
||||||
}
|
}
|
||||||
|
|
||||||
should_try_others.insert(candidate->internal_id(), response.try_others);
|
shouldTryOthers.insert(candidate->internal_id(), response.try_others);
|
||||||
|
|
||||||
if (confirmed)
|
if (confirmed) {
|
||||||
addToTmp(candidate, response.chosen);
|
addToTmp(candidate, response.chosen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare task for the modrinth mods
|
// prepare task for the modrinth mods
|
||||||
if (!modrinth_tmp.empty()) {
|
if (!modrinthTmp.empty()) {
|
||||||
auto modrinth_task = makeShared<EnsureMetadataTask>(modrinth_tmp, index_dir, ModPlatform::ResourceProvider::MODRINTH);
|
auto modrinthTask = makeShared<EnsureMetadataTask>(modrinthTmp, indexDir2, ModPlatform::ResourceProvider::MODRINTH);
|
||||||
connect(modrinth_task.get(), &EnsureMetadataTask::metadataReady, [this](Resource* candidate) { onMetadataEnsured(candidate); });
|
connect(modrinthTask.get(), &EnsureMetadataTask::metadataReady, [this](Resource* candidate) { onMetadataEnsured(candidate); });
|
||||||
connect(modrinth_task.get(), &EnsureMetadataTask::metadataFailed, [this, &should_try_others](Resource* candidate) {
|
connect(modrinthTask.get(), &EnsureMetadataTask::metadataFailed, [this, &shouldTryOthers](Resource* candidate) {
|
||||||
onMetadataFailed(candidate, should_try_others.find(candidate->internal_id()).value(), ModPlatform::ResourceProvider::MODRINTH);
|
onMetadataFailed(candidate, shouldTryOthers.find(candidate->internal_id()).value(), ModPlatform::ResourceProvider::MODRINTH);
|
||||||
});
|
});
|
||||||
connect(modrinth_task.get(), &EnsureMetadataTask::failed,
|
connect(modrinthTask.get(), &EnsureMetadataTask::failed,
|
||||||
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
[this](const QString& reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
||||||
|
|
||||||
if (modrinth_task->getHashingTask())
|
if (modrinthTask->getHashingTask()) {
|
||||||
seq.addTask(modrinth_task->getHashingTask());
|
seq.addTask(modrinthTask->getHashingTask());
|
||||||
|
}
|
||||||
|
|
||||||
seq.addTask(modrinth_task);
|
seq.addTask(modrinthTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepare task for the flame mods
|
// prepare task for the flame mods
|
||||||
if (!flame_tmp.empty()) {
|
if (!flameTmp.empty()) {
|
||||||
auto flame_task = makeShared<EnsureMetadataTask>(flame_tmp, index_dir, ModPlatform::ResourceProvider::FLAME);
|
auto flameTask = makeShared<EnsureMetadataTask>(flameTmp, indexDir2, ModPlatform::ResourceProvider::FLAME);
|
||||||
connect(flame_task.get(), &EnsureMetadataTask::metadataReady, [this](Resource* candidate) { onMetadataEnsured(candidate); });
|
connect(flameTask.get(), &EnsureMetadataTask::metadataReady, [this](Resource* candidate) { onMetadataEnsured(candidate); });
|
||||||
connect(flame_task.get(), &EnsureMetadataTask::metadataFailed, [this, &should_try_others](Resource* candidate) {
|
connect(flameTask.get(), &EnsureMetadataTask::metadataFailed, [this, &shouldTryOthers](Resource* candidate) {
|
||||||
onMetadataFailed(candidate, should_try_others.find(candidate->internal_id()).value(), ModPlatform::ResourceProvider::FLAME);
|
onMetadataFailed(candidate, shouldTryOthers.find(candidate->internal_id()).value(), ModPlatform::ResourceProvider::FLAME);
|
||||||
});
|
});
|
||||||
connect(flame_task.get(), &EnsureMetadataTask::failed,
|
connect(flameTask.get(), &EnsureMetadataTask::failed,
|
||||||
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
[this](const QString& reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
|
||||||
|
|
||||||
if (flame_task->getHashingTask())
|
if (flameTask->getHashingTask()) {
|
||||||
seq.addTask(flame_task->getHashingTask());
|
seq.addTask(flameTask->getHashingTask());
|
||||||
|
}
|
||||||
|
|
||||||
seq.addTask(flame_task);
|
seq.addTask(flameTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
seq.addTask(m_secondTryMetadata);
|
seq.addTask(m_secondTryMetadata);
|
||||||
|
|
||||||
// execute all the tasks
|
// execute all the tasks
|
||||||
ProgressDialog checking_dialog(m_parent);
|
ProgressDialog checkingDialog(m_parent);
|
||||||
checking_dialog.setSkipButton(true, tr("Abort"));
|
checkingDialog.setSkipButton(true, tr("Abort"));
|
||||||
checking_dialog.setWindowTitle(tr("Generating metadata..."));
|
checkingDialog.setWindowTitle(tr("Generating metadata..."));
|
||||||
auto ret_metadata = checking_dialog.execWithTask(&seq);
|
auto retMetadata = checkingDialog.execWithTask(&seq);
|
||||||
|
|
||||||
return (ret_metadata != QDialog::DialogCode::Rejected);
|
return (retMetadata != QDialog::DialogCode::Rejected);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceUpdateDialog::onMetadataEnsured(Resource* resource)
|
void ResourceUpdateDialog::onMetadataEnsured(Resource* resource)
|
||||||
{
|
{
|
||||||
// When the mod is a folder, for instance
|
// When the mod is a folder, for instance
|
||||||
if (!resource->metadata())
|
if (!resource->metadata()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (resource->metadata()->provider) {
|
switch (resource->metadata()->provider) {
|
||||||
case ModPlatform::ResourceProvider::MODRINTH:
|
case ModPlatform::ResourceProvider::MODRINTH:
|
||||||
|
|
@ -411,12 +424,12 @@ ModPlatform::ResourceProvider next(ModPlatform::ResourceProvider p)
|
||||||
return ModPlatform::ResourceProvider::FLAME;
|
return ModPlatform::ResourceProvider::FLAME;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceUpdateDialog::onMetadataFailed(Resource* resource, bool try_others, ModPlatform::ResourceProvider first_choice)
|
void ResourceUpdateDialog::onMetadataFailed(Resource* resource, bool tryOthers, ModPlatform::ResourceProvider firstChoice)
|
||||||
{
|
{
|
||||||
if (try_others) {
|
if (tryOthers) {
|
||||||
auto index_dir = indexDir();
|
auto indexDir2 = indexDir();
|
||||||
|
|
||||||
auto task = makeShared<EnsureMetadataTask>(resource, index_dir, next(first_choice));
|
auto task = makeShared<EnsureMetadataTask>(resource, indexDir2, next(firstChoice));
|
||||||
connect(task.get(), &EnsureMetadataTask::metadataReady, [this](Resource* candidate) { onMetadataEnsured(candidate); });
|
connect(task.get(), &EnsureMetadataTask::metadataReady, [this](Resource* candidate) { onMetadataEnsured(candidate); });
|
||||||
connect(task.get(), &EnsureMetadataTask::metadataFailed, [this](Resource* candidate) { onMetadataFailed(candidate, false); });
|
connect(task.get(), &EnsureMetadataTask::metadataFailed, [this](Resource* candidate) { onMetadataFailed(candidate, false); });
|
||||||
connect(task.get(), &EnsureMetadataTask::failed,
|
connect(task.get(), &EnsureMetadataTask::failed,
|
||||||
|
|
@ -436,57 +449,57 @@ void ResourceUpdateDialog::onMetadataFailed(Resource* resource, bool try_others,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceUpdateDialog::appendResource(CheckUpdateTask::Update const& info, QStringList requiredBy)
|
void ResourceUpdateDialog::appendResource(const CheckUpdateTask::Update& info, QStringList requiredBy)
|
||||||
{
|
{
|
||||||
auto item_top = new QTreeWidgetItem(ui->modTreeWidget);
|
auto* itemTop = new QTreeWidgetItem(ui->modTreeWidget);
|
||||||
item_top->setCheckState(0, info.enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
itemTop->setCheckState(0, info.enabled ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
|
||||||
if (!info.enabled) {
|
if (!info.enabled) {
|
||||||
item_top->setToolTip(0, tr("Mod was disabled as it may be already installed."));
|
itemTop->setToolTip(0, tr("Mod was disabled as it may be already installed."));
|
||||||
}
|
}
|
||||||
item_top->setText(0, info.name);
|
itemTop->setText(0, info.name);
|
||||||
item_top->setExpanded(true);
|
itemTop->setExpanded(true);
|
||||||
|
|
||||||
auto provider_item = new QTreeWidgetItem(item_top);
|
auto* providerItem = new QTreeWidgetItem(itemTop);
|
||||||
QString provider_name = ModPlatform::ProviderCapabilities::readableName(info.provider);
|
QString providerName = ModPlatform::ProviderCapabilities::readableName(info.provider);
|
||||||
provider_item->setText(0, tr("Provider: %1").arg(provider_name));
|
providerItem->setText(0, tr("Provider: %1").arg(providerName));
|
||||||
provider_item->setData(0, Qt::UserRole, provider_name);
|
providerItem->setData(0, Qt::UserRole, providerName);
|
||||||
|
|
||||||
auto old_version_item = new QTreeWidgetItem(item_top);
|
auto* oldVersionItem = new QTreeWidgetItem(itemTop);
|
||||||
old_version_item->setText(0, tr("Old version: %1").arg(info.old_version));
|
oldVersionItem->setText(0, tr("Old version: %1").arg(info.old_version));
|
||||||
old_version_item->setData(0, Qt::UserRole, info.old_version);
|
oldVersionItem->setData(0, Qt::UserRole, info.old_version);
|
||||||
|
|
||||||
auto new_version_item = new QTreeWidgetItem(item_top);
|
auto* newVersionItem = new QTreeWidgetItem(itemTop);
|
||||||
new_version_item->setText(0, tr("New version: %1").arg(info.new_version));
|
newVersionItem->setText(0, tr("New version: %1").arg(info.new_version));
|
||||||
new_version_item->setData(0, Qt::UserRole, info.new_version);
|
newVersionItem->setData(0, Qt::UserRole, info.new_version);
|
||||||
|
|
||||||
if (info.new_version_type.has_value()) {
|
if (info.new_version_type.has_value()) {
|
||||||
auto new_version_type_item = new QTreeWidgetItem(item_top);
|
auto* newVersionTypeItem = new QTreeWidgetItem(itemTop);
|
||||||
new_version_type_item->setText(0, tr("New Version Type: %1").arg(info.new_version_type.value().toString()));
|
newVersionTypeItem->setText(0, tr("New Version Type: %1").arg(info.new_version_type.value().toString()));
|
||||||
new_version_type_item->setData(0, Qt::UserRole, info.new_version_type.value().toString());
|
newVersionTypeItem->setData(0, Qt::UserRole, info.new_version_type.value().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!requiredBy.isEmpty()) {
|
if (!requiredBy.isEmpty()) {
|
||||||
auto requiredByItem = new QTreeWidgetItem(item_top);
|
auto* requiredByItem = new QTreeWidgetItem(itemTop);
|
||||||
if (requiredBy.length() == 1) {
|
if (requiredBy.length() == 1) {
|
||||||
requiredByItem->setText(0, tr("Required by: %1").arg(requiredBy.back()));
|
requiredByItem->setText(0, tr("Required by: %1").arg(requiredBy.back()));
|
||||||
requiredByItem->setData(0, Qt::UserRole, requiredBy.back());
|
requiredByItem->setData(0, Qt::UserRole, requiredBy.back());
|
||||||
} else {
|
} else {
|
||||||
requiredByItem->setText(0, tr("Required by:"));
|
requiredByItem->setText(0, tr("Required by:"));
|
||||||
for (auto req : requiredBy) {
|
for (const auto& req : requiredBy) {
|
||||||
auto reqItem = new QTreeWidgetItem(requiredByItem);
|
auto* reqItem = new QTreeWidgetItem(requiredByItem);
|
||||||
reqItem->setText(0, req);
|
reqItem->setText(0, req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui->toggleDepsButton->show();
|
ui->toggleDepsButton->show();
|
||||||
m_deps << item_top;
|
m_deps << itemTop;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto changelog_item = new QTreeWidgetItem(item_top);
|
auto* changelogItem = new QTreeWidgetItem(itemTop);
|
||||||
changelog_item->setText(0, tr("Changelog of the latest version"));
|
changelogItem->setText(0, tr("Changelog of the latest version"));
|
||||||
|
|
||||||
auto changelog = new QTreeWidgetItem(changelog_item);
|
auto* changelog = new QTreeWidgetItem(changelogItem);
|
||||||
auto changelog_area = new QTextBrowser();
|
auto* changelogArea = new QTextBrowser();
|
||||||
|
|
||||||
QString text = info.changelog;
|
QString text = info.changelog;
|
||||||
changelog->setData(0, Qt::UserRole, text);
|
changelog->setData(0, Qt::UserRole, text);
|
||||||
|
|
@ -494,14 +507,14 @@ void ResourceUpdateDialog::appendResource(CheckUpdateTask::Update const& info, Q
|
||||||
text = markdownToHTML(info.changelog.toUtf8());
|
text = markdownToHTML(info.changelog.toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
changelog_area->setHtml(StringUtils::htmlListPatch(text));
|
changelogArea->setHtml(StringUtils::htmlListPatch(text));
|
||||||
changelog_area->setOpenExternalLinks(true);
|
changelogArea->setOpenExternalLinks(true);
|
||||||
changelog_area->setLineWrapMode(QTextBrowser::LineWrapMode::WidgetWidth);
|
changelogArea->setLineWrapMode(QTextBrowser::LineWrapMode::WidgetWidth);
|
||||||
changelog_area->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
changelogArea->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||||
|
|
||||||
ui->modTreeWidget->setItemWidget(changelog, 0, changelog_area);
|
ui->modTreeWidget->setItemWidget(changelog, 0, changelogArea);
|
||||||
|
|
||||||
ui->modTreeWidget->addTopLevelItem(item_top);
|
ui->modTreeWidget->addTopLevelItem(itemTop);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ResourceUpdateDialog::getTasks() -> const QList<ResourceDownloadTask::Ptr>
|
auto ResourceUpdateDialog::getTasks() -> const QList<ResourceDownloadTask::Ptr>
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ class ResourceUpdateDialog final : public ReviewMessageBox {
|
||||||
private slots:
|
private slots:
|
||||||
void onMetadataEnsured(Resource* resource);
|
void onMetadataEnsured(Resource* resource);
|
||||||
void onMetadataFailed(Resource* resource,
|
void onMetadataFailed(Resource* resource,
|
||||||
bool try_others = false,
|
bool tryOthers = false,
|
||||||
ModPlatform::ResourceProvider firstChoice = ModPlatform::ResourceProvider::MODRINTH);
|
ModPlatform::ResourceProvider firstChoice = ModPlatform::ResourceProvider::MODRINTH);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@
|
||||||
#include "ResourceDownloadTask.h"
|
#include "ResourceDownloadTask.h"
|
||||||
|
|
||||||
#include "minecraft/MinecraftInstance.h"
|
#include "minecraft/MinecraftInstance.h"
|
||||||
#include "minecraft/PackProfile.h"
|
|
||||||
|
|
||||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||||
|
|
||||||
|
|
@ -63,15 +62,15 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ResourcePa
|
||||||
|
|
||||||
void ModPage::setFilterWidget(std::unique_ptr<ModFilterWidget>& widget)
|
void ModPage::setFilterWidget(std::unique_ptr<ModFilterWidget>& widget)
|
||||||
{
|
{
|
||||||
if (m_filter_widget)
|
if (m_filter_widget) {
|
||||||
disconnect(m_filter_widget.get(), nullptr, nullptr, nullptr);
|
disconnect(m_filter_widget.get(), nullptr, nullptr, nullptr);
|
||||||
|
|
||||||
auto old = m_ui->splitter->replaceWidget(0, widget.get());
|
|
||||||
// because we replaced the widget we also need to delete it
|
|
||||||
if (old) {
|
|
||||||
delete old;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* old = m_ui->splitter->replaceWidget(0, widget.get());
|
||||||
|
// because we replaced the widget we also need to delete it
|
||||||
|
|
||||||
|
delete old;
|
||||||
|
|
||||||
m_filter_widget.swap(widget);
|
m_filter_widget.swap(widget);
|
||||||
|
|
||||||
m_filter = m_filter_widget->getFilter();
|
m_filter = m_filter_widget->getFilter();
|
||||||
|
|
@ -112,10 +111,13 @@ QMap<QString, QString> ModPage::urlHandlers() const
|
||||||
|
|
||||||
/******** Make changes to the UI ********/
|
/******** Make changes to the UI ********/
|
||||||
|
|
||||||
void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version, ResourceFolderModel* base_model, QString downloadReason)
|
void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||||
|
ModPlatform::IndexedVersion& version,
|
||||||
|
ResourceFolderModel* baseModel,
|
||||||
|
QString downloadReason)
|
||||||
{
|
{
|
||||||
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
||||||
m_model->addPack(pack, version, base_model, is_indexed, downloadReason);
|
m_model->addPack(pack, version, baseModel, isIndexed, downloadReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ResourceDownload
|
} // namespace ResourceDownload
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,10 @@ class ModPage : public ResourcePage {
|
||||||
static T* create(ModDownloadDialog* dialog, BaseInstance& instance)
|
static T* create(ModDownloadDialog* dialog, BaseInstance& instance)
|
||||||
{
|
{
|
||||||
auto page = new T(dialog, instance);
|
auto page = new T(dialog, instance);
|
||||||
auto model = static_cast<ModModel*>(page->getModel());
|
auto* model = static_cast<ModModel*>(page->getModel());
|
||||||
|
|
||||||
auto filter_widget = page->createFilterWidget();
|
auto filterWidget = page->createFilterWidget();
|
||||||
page->setFilterWidget(filter_widget);
|
page->setFilterWidget(filterWidget);
|
||||||
model->setFilter(page->getFilter());
|
model->setFilter(page->getFilter());
|
||||||
|
|
||||||
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
|
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
|
||||||
|
|
@ -43,18 +43,21 @@ class ModPage : public ResourcePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
//: The plural version of 'mod'
|
//: The plural version of 'mod'
|
||||||
inline QString resourcesString() const override { return tr("mods"); }
|
QString resourcesString() const override { return tr("mods"); }
|
||||||
//: The singular version of 'mods'
|
//: The singular version of 'mods'
|
||||||
inline QString resourceString() const override { return tr("mod"); }
|
QString resourceString() const override { return tr("mod"); }
|
||||||
|
|
||||||
QMap<QString, QString> urlHandlers() const override;
|
QMap<QString, QString> urlHandlers() const override;
|
||||||
|
|
||||||
void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*, QString downloadReason = "standalone") override;
|
void addResourceToPage(ModPlatform::IndexedPack::Ptr /*unused*/,
|
||||||
|
ModPlatform::IndexedVersion& /*unused*/,
|
||||||
|
ResourceFolderModel* /*unused*/,
|
||||||
|
QString downloadReason = "standalone") override;
|
||||||
|
|
||||||
virtual std::unique_ptr<ModFilterWidget> createFilterWidget() = 0;
|
virtual std::unique_ptr<ModFilterWidget> createFilterWidget() = 0;
|
||||||
|
|
||||||
bool supportsFiltering() const override { return true; };
|
bool supportsFiltering() const override { return true; };
|
||||||
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
auto getFilter() const -> std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
||||||
void setFilterWidget(std::unique_ptr<ModFilterWidget>&);
|
void setFilterWidget(std::unique_ptr<ModFilterWidget>&);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,11 @@
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "settings/SettingsObject.h"
|
|
||||||
#include "BuildConfig.h"
|
#include "BuildConfig.h"
|
||||||
|
#include "settings/SettingsObject.h"
|
||||||
|
|
||||||
#include "modplatform/ResourceAPI.h"
|
#include "modplatform/ResourceAPI.h"
|
||||||
#include "net/ApiDownload.h"
|
#include "net/ApiDownload.h"
|
||||||
|
|
@ -29,7 +30,7 @@ namespace ResourceDownload {
|
||||||
|
|
||||||
QHash<ResourceModel*, bool> ResourceModel::s_running_models;
|
QHash<ResourceModel*, bool> ResourceModel::s_running_models;
|
||||||
|
|
||||||
ResourceModel::ResourceModel(ResourceAPI* api) : QAbstractListModel(), m_api(api)
|
ResourceModel::ResourceModel(ResourceAPI* api) : m_api(api)
|
||||||
{
|
{
|
||||||
s_running_models.insert(this, true);
|
s_running_models.insert(this, true);
|
||||||
if (APPLICATION_DYN) {
|
if (APPLICATION_DYN) {
|
||||||
|
|
@ -62,14 +63,14 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant
|
||||||
}
|
}
|
||||||
case Qt::DecorationRole: {
|
case Qt::DecorationRole: {
|
||||||
if (APPLICATION_DYN) {
|
if (APPLICATION_DYN) {
|
||||||
if (auto icon_or_none = const_cast<ResourceModel*>(this)->getIcon(const_cast<QModelIndex&>(index), pack->logoUrl);
|
if (auto iconOrNone = const_cast<ResourceModel*>(this)->getIcon(const_cast<QModelIndex&>(index), pack->logoUrl);
|
||||||
icon_or_none.has_value())
|
iconOrNone.has_value()) {
|
||||||
return icon_or_none.value();
|
return iconOrNone.value();
|
||||||
|
}
|
||||||
|
|
||||||
return QIcon::fromTheme("screenshot-placeholder");
|
return QIcon::fromTheme("screenshot-placeholder");
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
case Qt::SizeHintRole:
|
case Qt::SizeHintRole:
|
||||||
return QSize(0, 58);
|
return QSize(0, 58);
|
||||||
|
|
@ -112,8 +113,9 @@ QHash<int, QByteArray> ResourceModel::roleNames() const
|
||||||
bool ResourceModel::setData(const QModelIndex& index, const QVariant& value, [[maybe_unused]] int role)
|
bool ResourceModel::setData(const QModelIndex& index, const QVariant& value, [[maybe_unused]] int role)
|
||||||
{
|
{
|
||||||
int pos = index.row();
|
int pos = index.row();
|
||||||
if (pos >= m_packs.size() || pos < 0 || !index.isValid())
|
if (pos >= m_packs.size() || pos < 0 || !index.isValid()) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_packs[pos] = value.value<ModPlatform::IndexedPack::Ptr>();
|
m_packs[pos] = value.value<ModPlatform::IndexedPack::Ptr>();
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
|
|
@ -128,45 +130,51 @@ QString ResourceModel::debugName() const
|
||||||
|
|
||||||
void ResourceModel::fetchMore(const QModelIndex& parent)
|
void ResourceModel::fetchMore(const QModelIndex& parent)
|
||||||
{
|
{
|
||||||
if (parent.isValid() || m_search_state == SearchState::Finished)
|
if (parent.isValid() || m_search_state == SearchState::Finished) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
search();
|
search();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceModel::search()
|
void ResourceModel::search()
|
||||||
{
|
{
|
||||||
if (hasActiveSearchJob())
|
if (hasActiveSearchJob()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_search_state != SearchState::ResetRequested && m_search_term.startsWith("#")) {
|
if (m_search_state != SearchState::ResetRequested && m_search_term.startsWith("#")) {
|
||||||
auto projectId = m_search_term.mid(1);
|
auto projectId = m_search_term.mid(1);
|
||||||
if (!projectId.isEmpty()) {
|
if (!projectId.isEmpty()) {
|
||||||
ResourceAPI::Callback<ModPlatform::IndexedPack::Ptr> callbacks;
|
ResourceAPI::Callback<ModPlatform::IndexedPack::Ptr> callbacks;
|
||||||
|
|
||||||
callbacks.on_fail = [this](QString reason, int network_error_code) {
|
callbacks.on_fail = [this](QString reason, int networkErrorCode) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
if (network_error_code == 404) {
|
}
|
||||||
|
if (networkErrorCode == 404) {
|
||||||
m_search_state = SearchState::ResetRequested;
|
m_search_state = SearchState::ResetRequested;
|
||||||
}
|
}
|
||||||
searchRequestFailed(reason, network_error_code);
|
searchRequestFailed(std::move(reason), networkErrorCode);
|
||||||
};
|
};
|
||||||
callbacks.on_abort = [this] {
|
callbacks.on_abort = [this] {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
searchRequestAborted();
|
searchRequestAborted();
|
||||||
};
|
};
|
||||||
|
|
||||||
callbacks.on_succeed = [this](auto& pack) {
|
callbacks.on_succeed = [this](auto& pack) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
searchRequestForOneSucceeded(pack);
|
searchRequestForOneSucceeded(pack);
|
||||||
};
|
};
|
||||||
auto project = std::make_shared<ModPlatform::IndexedPack>();
|
auto project = std::make_shared<ModPlatform::IndexedPack>();
|
||||||
project->addonId = projectId;
|
project->addonId = projectId;
|
||||||
if (auto job = m_api->getProjectInfo({ project }, std::move(callbacks), false); job)
|
if (auto job = m_api->getProjectInfo({ project }, std::move(callbacks), false); job) {
|
||||||
runSearchJob(job);
|
runSearchJob(job);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -175,31 +183,36 @@ void ResourceModel::search()
|
||||||
ResourceAPI::Callback<QList<ModPlatform::IndexedPack::Ptr>> callbacks{};
|
ResourceAPI::Callback<QList<ModPlatform::IndexedPack::Ptr>> callbacks{};
|
||||||
|
|
||||||
callbacks.on_succeed = [this](auto& doc) {
|
callbacks.on_succeed = [this](auto& doc) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
searchRequestSucceeded(doc);
|
searchRequestSucceeded(doc);
|
||||||
};
|
};
|
||||||
callbacks.on_fail = [this](QString reason, int network_error_code) {
|
callbacks.on_fail = [this](QString reason, int networkErrorCode) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
searchRequestFailed(reason, network_error_code);
|
}
|
||||||
|
searchRequestFailed(std::move(reason), networkErrorCode);
|
||||||
};
|
};
|
||||||
callbacks.on_abort = [this] {
|
callbacks.on_abort = [this] {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
searchRequestAborted();
|
searchRequestAborted();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto job = m_api->searchProjects(std::move(args), std::move(callbacks)); job)
|
if (auto job = m_api->searchProjects(std::move(args), std::move(callbacks)); job) {
|
||||||
runSearchJob(job);
|
runSearchJob(job);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceModel::loadEntry(const QModelIndex& entry)
|
void ResourceModel::loadEntry(const QModelIndex& entry)
|
||||||
{
|
{
|
||||||
auto const& pack = m_packs[entry.row()];
|
const auto& pack = m_packs[entry.row()];
|
||||||
|
|
||||||
if (!hasActiveInfoJob())
|
if (!hasActiveInfoJob()) {
|
||||||
m_current_info_job.clear();
|
m_current_info_job.clear();
|
||||||
|
}
|
||||||
|
|
||||||
if (!pack->versionsLoaded) {
|
if (!pack->versionsLoaded) {
|
||||||
auto args{ createVersionsArguments(entry) };
|
auto args{ createVersionsArguments(entry) };
|
||||||
|
|
@ -207,20 +220,24 @@ void ResourceModel::loadEntry(const QModelIndex& entry)
|
||||||
|
|
||||||
auto addonId = pack->addonId;
|
auto addonId = pack->addonId;
|
||||||
// Use default if no callbacks are set
|
// Use default if no callbacks are set
|
||||||
if (!callbacks.on_succeed)
|
if (!callbacks.on_succeed) {
|
||||||
callbacks.on_succeed = [this, entry, addonId](auto& doc) {
|
callbacks.on_succeed = [this, entry, addonId](auto& doc) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
versionRequestSucceeded(doc, addonId, entry);
|
versionRequestSucceeded(doc, addonId, entry);
|
||||||
};
|
};
|
||||||
if (!callbacks.on_fail)
|
}
|
||||||
callbacks.on_fail = [](QString reason, int) {
|
if (!callbacks.on_fail) {
|
||||||
|
callbacks.on_fail = [](const QString& reason, int) {
|
||||||
QMessageBox::critical(nullptr, tr("Error"),
|
QMessageBox::critical(nullptr, tr("Error"),
|
||||||
tr("A network error occurred. Could not load project versions: %1").arg(reason));
|
tr("A network error occurred. Could not load project versions: %1").arg(reason));
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job)
|
if (auto job = m_api->getProjectVersions(std::move(args), std::move(callbacks)); job) {
|
||||||
runInfoJob(job);
|
runInfoJob(job);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pack->extraDataLoaded) {
|
if (!pack->extraDataLoaded) {
|
||||||
|
|
@ -228,41 +245,45 @@ void ResourceModel::loadEntry(const QModelIndex& entry)
|
||||||
ResourceAPI::Callback<ModPlatform::IndexedPack::Ptr> callbacks{};
|
ResourceAPI::Callback<ModPlatform::IndexedPack::Ptr> callbacks{};
|
||||||
|
|
||||||
callbacks.on_succeed = [this, entry](auto& newpack) {
|
callbacks.on_succeed = [this, entry](auto& newpack) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
infoRequestSucceeded(newpack, entry);
|
infoRequestSucceeded(newpack, entry);
|
||||||
};
|
};
|
||||||
callbacks.on_fail = [this](QString reason, int) {
|
callbacks.on_fail = [this](const QString& reason, int) {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info: %1").arg(reason));
|
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load project info: %1").arg(reason));
|
||||||
};
|
};
|
||||||
callbacks.on_abort = [this] {
|
callbacks.on_abort = [this] {
|
||||||
if (!s_running_models.constFind(this).value())
|
if (!s_running_models.constFind(this).value()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
qCritical() << tr("The request was aborted for an unknown reason");
|
qCritical() << tr("The request was aborted for an unknown reason");
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job)
|
if (auto job = m_api->getProjectInfo(std::move(args), std::move(callbacks)); job) {
|
||||||
runInfoJob(job);
|
runInfoJob(job);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceModel::refresh()
|
void ResourceModel::refresh()
|
||||||
{
|
{
|
||||||
bool reset_requested = false;
|
bool resetRequested = false;
|
||||||
|
|
||||||
if (hasActiveInfoJob()) {
|
if (hasActiveInfoJob()) {
|
||||||
m_current_info_job.abort();
|
m_current_info_job.abort();
|
||||||
reset_requested = true;
|
resetRequested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasActiveSearchJob()) {
|
if (hasActiveSearchJob()) {
|
||||||
m_current_search_job->abort();
|
m_current_search_job->abort();
|
||||||
reset_requested = true;
|
resetRequested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reset_requested) {
|
if (resetRequested) {
|
||||||
m_search_state = SearchState::ResetRequested;
|
m_search_state = SearchState::ResetRequested;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -288,13 +309,15 @@ void ResourceModel::runSearchJob(Task::Ptr ptr)
|
||||||
}
|
}
|
||||||
void ResourceModel::runInfoJob(Task::Ptr ptr)
|
void ResourceModel::runInfoJob(Task::Ptr ptr)
|
||||||
{
|
{
|
||||||
if (!m_current_info_job.isRunning())
|
if (!m_current_info_job.isRunning()) {
|
||||||
m_current_info_job.clear();
|
m_current_info_job.clear();
|
||||||
|
}
|
||||||
|
|
||||||
m_current_info_job.addTask(ptr);
|
m_current_info_job.addTask(std::move(ptr));
|
||||||
|
|
||||||
if (!m_current_info_job.isRunning())
|
if (!m_current_info_job.isRunning()) {
|
||||||
m_current_info_job.run();
|
m_current_info_job.run();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<ResourceAPI::SortingMethod> ResourceModel::getCurrentSortingMethodByIndex() const
|
std::optional<ResourceAPI::SortingMethod> ResourceModel::getCurrentSortingMethodByIndex() const
|
||||||
|
|
@ -302,11 +325,12 @@ std::optional<ResourceAPI::SortingMethod> ResourceModel::getCurrentSortingMethod
|
||||||
std::optional<ResourceAPI::SortingMethod> sort{};
|
std::optional<ResourceAPI::SortingMethod> sort{};
|
||||||
|
|
||||||
{ // Find sorting method by ID
|
{ // Find sorting method by ID
|
||||||
auto sorting_methods = getSortingMethods();
|
auto sortingMethods = getSortingMethods();
|
||||||
auto method = std::find_if(sorting_methods.constBegin(), sorting_methods.constEnd(),
|
auto method = std::find_if(sortingMethods.constBegin(), sortingMethods.constEnd(),
|
||||||
[this](auto const& e) { return m_current_sort_index == e.index; });
|
[this](const auto& e) { return m_current_sort_index == e.index; });
|
||||||
if (method != sorting_methods.constEnd())
|
if (method != sortingMethods.constEnd()) {
|
||||||
sort = *method;
|
sort = *method;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sort;
|
return sort;
|
||||||
|
|
@ -315,43 +339,47 @@ std::optional<ResourceAPI::SortingMethod> ResourceModel::getCurrentSortingMethod
|
||||||
std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url)
|
std::optional<QIcon> ResourceModel::getIcon(QModelIndex& index, const QUrl& url)
|
||||||
{
|
{
|
||||||
QPixmap pixmap;
|
QPixmap pixmap;
|
||||||
if (QPixmapCache::find(url.toString(), &pixmap))
|
if (QPixmapCache::find(url.toString(), &pixmap)) {
|
||||||
return { pixmap };
|
return { pixmap };
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_current_icon_job) {
|
if (!m_current_icon_job) {
|
||||||
m_current_icon_job.reset(new NetJob("IconJob", APPLICATION->network()));
|
m_current_icon_job.reset(new NetJob("IconJob", APPLICATION->network()));
|
||||||
m_current_icon_job->setAskRetry(false);
|
m_current_icon_job->setAskRetry(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_currently_running_icon_actions.contains(url))
|
if (m_currently_running_icon_actions.contains(url)) {
|
||||||
return {};
|
return {};
|
||||||
if (m_failed_icon_actions.contains(url))
|
}
|
||||||
|
if (m_failed_icon_actions.contains(url)) {
|
||||||
return {};
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
auto cache_entry = APPLICATION->metacache()->resolveEntry(
|
auto cacheEntry = APPLICATION->metacache()->resolveEntry(
|
||||||
metaEntryBase(),
|
metaEntryBase(),
|
||||||
QString("logos/%1").arg(QString(QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Algorithm::Sha1).toHex())));
|
QString("logos/%1").arg(QString(QCryptographicHash::hash(url.toEncoded(), QCryptographicHash::Algorithm::Sha1).toHex())));
|
||||||
auto icon_fetch_action = Net::ApiDownload::makeCached(url, cache_entry);
|
auto iconFetchAction = Net::ApiDownload::makeCached(url, cacheEntry);
|
||||||
|
|
||||||
auto full_file_path = cache_entry->getFullPath();
|
auto fullFilePath = cacheEntry->getFullPath();
|
||||||
connect(icon_fetch_action.get(), &Task::succeeded, this, [this, url, full_file_path, index] {
|
connect(iconFetchAction.get(), &Task::succeeded, this, [this, url, fullFilePath, index] {
|
||||||
auto icon = QIcon(full_file_path);
|
auto icon = QIcon(fullFilePath);
|
||||||
QPixmapCache::insert(url.toString(), icon.pixmap(icon.actualSize({ 64, 64 })));
|
QPixmapCache::insert(url.toString(), icon.pixmap(icon.actualSize({ 64, 64 })));
|
||||||
|
|
||||||
m_currently_running_icon_actions.remove(url);
|
m_currently_running_icon_actions.remove(url);
|
||||||
|
|
||||||
emit dataChanged(index, index, { Qt::DecorationRole });
|
emit dataChanged(index, index, { Qt::DecorationRole });
|
||||||
});
|
});
|
||||||
connect(icon_fetch_action.get(), &Task::failed, this, [this, url] {
|
connect(iconFetchAction.get(), &Task::failed, this, [this, url] {
|
||||||
m_currently_running_icon_actions.remove(url);
|
m_currently_running_icon_actions.remove(url);
|
||||||
m_failed_icon_actions.insert(url);
|
m_failed_icon_actions.insert(url);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_currently_running_icon_actions.insert(url);
|
m_currently_running_icon_actions.insert(url);
|
||||||
|
|
||||||
m_current_icon_job->addNetAction(icon_fetch_action);
|
m_current_icon_job->addNetAction(iconFetchAction);
|
||||||
if (!m_current_icon_job->isRunning())
|
if (!m_current_icon_job->isRunning()) {
|
||||||
QMetaObject::invokeMethod(m_current_icon_job.get(), &NetJob::start);
|
QMetaObject::invokeMethod(m_current_icon_job.get(), &NetJob::start);
|
||||||
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
@ -363,11 +391,11 @@ void ResourceModel::searchRequestSucceeded(QList<ModPlatform::IndexedPack::Ptr>&
|
||||||
QList<ModPlatform::IndexedPack::Ptr> filteredNewList;
|
QList<ModPlatform::IndexedPack::Ptr> filteredNewList;
|
||||||
for (auto pack : newList) {
|
for (auto pack : newList) {
|
||||||
ModPlatform::IndexedPack::Ptr p;
|
ModPlatform::IndexedPack::Ptr p;
|
||||||
if (auto sel = std::find_if(m_selected.begin(), m_selected.end(),
|
if (auto sel = std::ranges::find_if(m_selected,
|
||||||
[&pack](const DownloadTaskPtr i) {
|
[&pack](const DownloadTaskPtr& i) {
|
||||||
const auto ipack = i->getPack();
|
const auto ipack = i->getPack();
|
||||||
return ipack->provider == pack->provider && ipack->addonId == pack->addonId;
|
return ipack->provider == pack->provider && ipack->addonId == pack->addonId;
|
||||||
});
|
});
|
||||||
sel != m_selected.end()) {
|
sel != m_selected.end()) {
|
||||||
p = sel->get()->getPack();
|
p = sel->get()->getPack();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -386,8 +414,9 @@ void ResourceModel::searchRequestSucceeded(QList<ModPlatform::IndexedPack::Ptr>&
|
||||||
}
|
}
|
||||||
|
|
||||||
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
||||||
if (filteredNewList.size() == 0)
|
if (filteredNewList.size() == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
beginInsertRows(QModelIndex(), m_packs.size(), m_packs.size() + filteredNewList.size() - 1);
|
beginInsertRows(QModelIndex(), m_packs.size(), m_packs.size() + filteredNewList.size() - 1);
|
||||||
m_packs.append(filteredNewList);
|
m_packs.append(filteredNewList);
|
||||||
|
|
@ -403,9 +432,9 @@ void ResourceModel::searchRequestForOneSucceeded(ModPlatform::IndexedPack::Ptr p
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceModel::searchRequestFailed([[maybe_unused]] QString reason, int network_error_code)
|
void ResourceModel::searchRequestFailed([[maybe_unused]] QString reason, int networkErrorCode)
|
||||||
{
|
{
|
||||||
switch (network_error_code) {
|
switch (networkErrorCode) {
|
||||||
default:
|
default:
|
||||||
// Network error
|
// Network error
|
||||||
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load mods."));
|
QMessageBox::critical(nullptr, tr("Error"), tr("A network error occurred. Could not load mods."));
|
||||||
|
|
@ -432,8 +461,9 @@ void ResourceModel::searchRequestFailed([[maybe_unused]] QString reason, int net
|
||||||
|
|
||||||
void ResourceModel::searchRequestAborted()
|
void ResourceModel::searchRequestAborted()
|
||||||
{
|
{
|
||||||
if (m_search_state != SearchState::ResetRequested)
|
if (m_search_state != SearchState::ResetRequested) {
|
||||||
qCritical() << "Search task in" << debugName() << "aborted by an unknown reason!";
|
qCritical() << "Search task in" << debugName() << "aborted by an unknown reason!";
|
||||||
|
}
|
||||||
|
|
||||||
// Retry fetching
|
// Retry fetching
|
||||||
clearData();
|
clearData();
|
||||||
|
|
@ -444,19 +474,20 @@ void ResourceModel::searchRequestAborted()
|
||||||
|
|
||||||
void ResourceModel::versionRequestSucceeded(QVector<ModPlatform::IndexedVersion>& doc, QVariant pack, const QModelIndex& index)
|
void ResourceModel::versionRequestSucceeded(QVector<ModPlatform::IndexedVersion>& doc, QVariant pack, const QModelIndex& index)
|
||||||
{
|
{
|
||||||
auto current_pack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
auto currentPack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
||||||
|
|
||||||
// Check if the index is still valid for this resource or not
|
// Check if the index is still valid for this resource or not
|
||||||
if (pack != current_pack->addonId)
|
if (pack != currentPack->addonId) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
current_pack->versions = doc;
|
currentPack->versions = doc;
|
||||||
current_pack->versionsLoaded = true;
|
currentPack->versionsLoaded = true;
|
||||||
|
|
||||||
// Cache info :^)
|
// Cache info :^)
|
||||||
QVariant new_pack;
|
QVariant newPack;
|
||||||
new_pack.setValue(current_pack);
|
newPack.setValue(currentPack);
|
||||||
if (!setData(index, new_pack, Qt::UserRole)) {
|
if (!setData(index, newPack, Qt::UserRole)) {
|
||||||
qWarning() << "Failed to cache resource versions!";
|
qWarning() << "Failed to cache resource versions!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -466,16 +497,17 @@ void ResourceModel::versionRequestSucceeded(QVector<ModPlatform::IndexedVersion>
|
||||||
|
|
||||||
void ResourceModel::infoRequestSucceeded(ModPlatform::IndexedPack::Ptr pack, const QModelIndex& index)
|
void ResourceModel::infoRequestSucceeded(ModPlatform::IndexedPack::Ptr pack, const QModelIndex& index)
|
||||||
{
|
{
|
||||||
auto current_pack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
auto currentPack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
||||||
|
|
||||||
// Check if the index is still valid for this resource or not
|
// Check if the index is still valid for this resource or not
|
||||||
if (pack->addonId != current_pack->addonId)
|
if (pack->addonId != currentPack->addonId) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Cache info :^)
|
// Cache info :^)
|
||||||
QVariant new_pack;
|
QVariant newPack;
|
||||||
new_pack.setValue(pack);
|
newPack.setValue(pack);
|
||||||
if (!setData(index, new_pack, Qt::UserRole)) {
|
if (!setData(index, newPack, Qt::UserRole)) {
|
||||||
qWarning() << "Failed to cache resource info!";
|
qWarning() << "Failed to cache resource info!";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -486,16 +518,16 @@ void ResourceModel::infoRequestSucceeded(ModPlatform::IndexedPack::Ptr pack, con
|
||||||
void ResourceModel::addPack(ModPlatform::IndexedPack::Ptr pack,
|
void ResourceModel::addPack(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion& version,
|
ModPlatform::IndexedVersion& version,
|
||||||
ResourceFolderModel* packs,
|
ResourceFolderModel* packs,
|
||||||
bool is_indexed,
|
bool isIndexed,
|
||||||
QString downloadReason)
|
QString downloadReason)
|
||||||
{
|
{
|
||||||
version.is_currently_selected = true;
|
version.is_currently_selected = true;
|
||||||
m_selected.append(makeShared<ResourceDownloadTask>(pack, version, packs, is_indexed, downloadReason));
|
m_selected.append(makeShared<ResourceDownloadTask>(std::move(pack), version, packs, isIndexed, std::move(downloadReason)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceModel::removePack(const QString& rem)
|
void ResourceModel::removePack(const QString& rem)
|
||||||
{
|
{
|
||||||
auto pred = [&rem](const DownloadTaskPtr i) { return rem == i->getName(); };
|
auto pred = [&rem](const DownloadTaskPtr& i) { return rem == i->getName(); };
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
|
||||||
m_selected.removeIf(pred);
|
m_selected.removeIf(pred);
|
||||||
#else
|
#else
|
||||||
|
|
@ -507,15 +539,16 @@ void ResourceModel::removePack(const QString& rem)
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
auto pack = std::find_if(m_packs.begin(), m_packs.end(), [&rem](const ModPlatform::IndexedPack::Ptr i) { return rem == i->name; });
|
auto pack = std::ranges::find_if(m_packs, [&rem](const ModPlatform::IndexedPack::Ptr& i) { return rem == i->name; });
|
||||||
if (pack == m_packs.end()) { // ignore it if is not in the current search
|
if (pack == m_packs.end()) { // ignore it if is not in the current search
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!pack->get()->versionsLoaded) {
|
if (!pack->get()->versionsLoaded) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (auto& ver : pack->get()->versions)
|
for (auto& ver : pack->get()->versions) {
|
||||||
ver.is_currently_selected = false;
|
ver.is_currently_selected = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ResourceModel::checkVersionFilters(const ModPlatform::IndexedVersion& v)
|
bool ResourceModel::checkVersionFilters(const ModPlatform::IndexedVersion& v)
|
||||||
|
|
|
||||||
|
|
@ -36,16 +36,16 @@ class ResourceModel : public QAbstractListModel {
|
||||||
ResourceModel(ResourceAPI* api);
|
ResourceModel(ResourceAPI* api);
|
||||||
~ResourceModel() override;
|
~ResourceModel() override;
|
||||||
|
|
||||||
auto data(const QModelIndex&, int role) const -> QVariant override;
|
auto data(const QModelIndex& /*index*/, int role) const -> QVariant override;
|
||||||
auto roleNames() const -> QHash<int, QByteArray> override;
|
auto roleNames() const -> QHash<int, QByteArray> override;
|
||||||
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
|
||||||
|
|
||||||
virtual auto debugName() const -> QString;
|
virtual auto debugName() const -> QString;
|
||||||
virtual auto metaEntryBase() const -> QString = 0;
|
virtual auto metaEntryBase() const -> QString = 0;
|
||||||
|
|
||||||
inline int rowCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : static_cast<int>(m_packs.size()); }
|
int rowCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : static_cast<int>(m_packs.size()); }
|
||||||
inline int columnCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : 1; }
|
int columnCount(const QModelIndex& parent) const override { return parent.isValid() ? 0 : 1; }
|
||||||
inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); }
|
auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); }
|
||||||
|
|
||||||
bool hasActiveSearchJob() const { return m_current_search_job && m_current_search_job->isRunning(); }
|
bool hasActiveSearchJob() const { return m_current_search_job && m_current_search_job->isRunning(); }
|
||||||
bool hasActiveInfoJob() const { return m_current_info_job.isRunning(); }
|
bool hasActiveInfoJob() const { return m_current_info_job.isRunning(); }
|
||||||
|
|
@ -66,7 +66,7 @@ class ResourceModel : public QAbstractListModel {
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void fetchMore(const QModelIndex& parent) override;
|
void fetchMore(const QModelIndex& parent) override;
|
||||||
inline bool canFetchMore(const QModelIndex& parent) const override
|
bool canFetchMore(const QModelIndex& parent) const override
|
||||||
{
|
{
|
||||||
return parent.isValid() ? false : m_search_state == SearchState::CanFetchMore;
|
return parent.isValid() ? false : m_search_state == SearchState::CanFetchMore;
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +94,7 @@ class ResourceModel : public QAbstractListModel {
|
||||||
void addPack(ModPlatform::IndexedPack::Ptr pack,
|
void addPack(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion& version,
|
ModPlatform::IndexedVersion& version,
|
||||||
ResourceFolderModel* packs,
|
ResourceFolderModel* packs,
|
||||||
bool is_indexed = false,
|
bool isIndexed = false,
|
||||||
QString downloadReason = "standalone");
|
QString downloadReason = "standalone");
|
||||||
void removePack(const QString& rem);
|
void removePack(const QString& rem);
|
||||||
QList<DownloadTaskPtr> selectedPacks() { return m_selected; }
|
QList<DownloadTaskPtr> selectedPacks() { return m_selected; }
|
||||||
|
|
|
||||||
|
|
@ -401,7 +401,7 @@ void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||||
QString downloadReason)
|
QString downloadReason)
|
||||||
{
|
{
|
||||||
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
||||||
m_model->addPack(std::move(pack), ver, baseModel, isIndexed);
|
m_model->addPack(std::move(pack), ver, baseModel, isIndexed, std::move(downloadReason));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourcePage::modelReset()
|
void ResourcePage::modelReset()
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include "ResourceDownloadTask.h"
|
#include "ResourceDownloadTask.h"
|
||||||
#include "modplatform/ModIndex.h"
|
#include "modplatform/ModIndex.h"
|
||||||
#include "modplatform/ResourceAPI.h"
|
|
||||||
|
|
||||||
#include "ui/pages/BasePage.h"
|
#include "ui/pages/BasePage.h"
|
||||||
#include "ui/pages/modplatform/ResourceModel.h"
|
#include "ui/pages/modplatform/ResourceModel.h"
|
||||||
|
|
@ -78,7 +77,10 @@ class ResourcePage : public QWidget, public BasePage {
|
||||||
void addResourceToDialog(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&);
|
void addResourceToDialog(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&);
|
||||||
void removeResourceFromDialog(const QString& packName);
|
void removeResourceFromDialog(const QString& packName);
|
||||||
virtual void removeResourceFromPage(const QString& name);
|
virtual void removeResourceFromPage(const QString& name);
|
||||||
virtual void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*, QString downloadReason = "standalone");
|
virtual void addResourceToPage(ModPlatform::IndexedPack::Ptr,
|
||||||
|
ModPlatform::IndexedVersion&,
|
||||||
|
ResourceFolderModel*,
|
||||||
|
QString downloadReason = "standalone");
|
||||||
|
|
||||||
virtual void modelReset();
|
virtual void modelReset();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,19 +36,18 @@ QMap<QString, QString> ShaderPackResourcePage::urlHandlers() const
|
||||||
{
|
{
|
||||||
QMap<QString, QString> map;
|
QMap<QString, QString> map;
|
||||||
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/shaders\\/([^\\/]+)\\/?"), "modrinth");
|
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/shaders\\/([^\\/]+)\\/?"), "modrinth");
|
||||||
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/customization\\/([^\\/]+)\\/?"),
|
map.insert(QRegularExpression::anchoredPattern(R"((?:www\.)?curseforge\.com\/minecraft\/customization\/([^\/]+)\/?)"), "curseforge");
|
||||||
"curseforge");
|
map.insert(QRegularExpression::anchoredPattern(R"(minecraft\.curseforge\.com\/projects\/([^\/]+)\/?)"), "curseforge");
|
||||||
map.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||||
ModPlatform::IndexedVersion& version,
|
ModPlatform::IndexedVersion& version,
|
||||||
ResourceFolderModel* base_model,
|
ResourceFolderModel* baseModel,
|
||||||
QString downloadReason)
|
QString downloadReason)
|
||||||
{
|
{
|
||||||
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
||||||
m_model->addPack(pack, version, base_model, is_indexed, downloadReason);
|
m_model->addPack(pack, version, baseModel, isIndexed, downloadReason);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ResourceDownload
|
} // namespace ResourceDownload
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ class ShaderPackResourcePage : public ResourcePage {
|
||||||
static T* create(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
|
static T* create(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
|
||||||
{
|
{
|
||||||
auto page = new T(dialog, instance);
|
auto page = new T(dialog, instance);
|
||||||
auto model = static_cast<ShaderPackResourceModel*>(page->getModel());
|
auto* model = static_cast<ShaderPackResourceModel*>(page->getModel());
|
||||||
|
|
||||||
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
|
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
|
||||||
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
|
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
|
||||||
|
|
@ -33,17 +33,20 @@ class ShaderPackResourcePage : public ResourcePage {
|
||||||
}
|
}
|
||||||
|
|
||||||
//: The plural version of 'shader pack'
|
//: The plural version of 'shader pack'
|
||||||
inline QString resourcesString() const override { return tr("shader packs"); }
|
QString resourcesString() const override { return tr("shader packs"); }
|
||||||
//: The singular version of 'shader packs'
|
//: The singular version of 'shader packs'
|
||||||
inline QString resourceString() const override { return tr("shader pack"); }
|
QString resourceString() const override { return tr("shader pack"); }
|
||||||
|
|
||||||
bool supportsFiltering() const override { return false; };
|
bool supportsFiltering() const override { return false; };
|
||||||
|
|
||||||
void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, ResourceFolderModel*, QString downloadReason = "standalone") override;
|
void addResourceToPage(ModPlatform::IndexedPack::Ptr /*unused*/,
|
||||||
|
ModPlatform::IndexedVersion& /*unused*/,
|
||||||
|
ResourceFolderModel* /*unused*/,
|
||||||
|
QString downloadReason = "standalone") override;
|
||||||
|
|
||||||
QMap<QString, QString> urlHandlers() const override;
|
QMap<QString, QString> urlHandlers() const override;
|
||||||
|
|
||||||
inline auto helpPage() const -> QString override { return "shaderpack-platform"; }
|
auto helpPage() const -> QString override { return "shaderpack-platform"; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
|
ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue