This commit is contained in:
Alexandru Ionut Tripon 2026-06-26 17:11:25 +05:00 committed by GitHub
commit 55ce074f8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 766 additions and 1292 deletions

View file

@ -975,8 +975,10 @@ SET(LAUNCHER_SOURCES
ui/pages/modplatform/ResourcePackModel.cpp
# Needed for MOC to find them without a corresponding .cpp
ui/pages/modplatform/TexturePackPage.cpp
ui/pages/modplatform/TexturePackPage.h
ui/pages/modplatform/TexturePackModel.cpp
ui/pages/modplatform/TexturePackModel.h
ui/pages/modplatform/ShaderPackPage.cpp
ui/pages/modplatform/ShaderPackModel.cpp

View file

@ -230,7 +230,7 @@ int DataPack::compare(const Resource& other, SortType type) const
return 0;
}
bool DataPack::applyFilter(QRegularExpression filter) const
bool DataPack::applyFilter(const QRegularExpression& filter) const
{
if (filter.match(description()).hasMatch()) {
return true;
@ -279,7 +279,7 @@ QString DataPack::packFormatStr() const
auto min_version = min_bound.first;
auto max_version = max_bound.second;
if (min_version.isEmpty() || max_version.isEmpty()) {
return tr("Unrecognized");
return QObject::tr("Unrecognized");
}
auto str = QString("[") + QString::number(m_min_format.first);
if (m_min_format.second != 0) {

View file

@ -35,9 +35,7 @@ class Version;
* */
class DataPack : public Resource {
Q_OBJECT
public:
DataPack(QObject* parent = nullptr) : Resource(parent) {}
DataPack(QFileInfo file_info) : Resource(file_info) {}
/** Gets the numerical ID of the pack format. */
@ -61,7 +59,7 @@ class DataPack : public Resource {
bool valid() const override;
[[nodiscard]] int compare(const Resource& other, SortType type) const override;
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
[[nodiscard]] bool applyFilter(const QRegularExpression& filter) const override;
QString packFormatStr() const;

View file

@ -123,7 +123,7 @@ int Mod::compare(const Resource& other, SortType type) const
return 0;
}
bool Mod::applyFilter(QRegularExpression filter) const
bool Mod::applyFilter(const QRegularExpression& filter) const
{
if (filter.match(description()).hasMatch())
return true;
@ -225,8 +225,8 @@ auto Mod::authors() const -> QStringList
void Mod::finishResolvingWithDetails(ModDetails&& details)
{
m_is_resolving = false;
m_is_resolved = true;
m_isResolving = false;
m_isResolved = true;
m_local_details = std::move(details);
if (!iconPath().isEmpty()) {

View file

@ -48,12 +48,7 @@
#include "Resource.h"
class Mod : public Resource {
Q_OBJECT
public:
using Ptr = shared_qobject_ptr<Mod>;
using WeakPtr = QPointer<Mod>;
Mod() = default;
Mod(const QFileInfo& file);
Mod(QString file_path) : Mod(QFileInfo(file_path)) {}
@ -90,7 +85,7 @@ class Mod : public Resource {
bool valid() const override;
[[nodiscard]] int compare(const Resource& other, SortType type) const override;
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
[[nodiscard]] bool applyFilter(const QRegularExpression& filter) const override;
// Delete all the files of this mod
auto destroy(QDir& index_dir, bool preserve_metadata = false, bool attempt_trash = true) -> bool;

View file

@ -1,7 +1,9 @@
#include "Resource.h"
#include <qobject.h>
#include <QDirIterator>
#include <QFileInfo>
#include <QObject>
#include <QRegularExpression>
#include <tuple>
#include <utility>
@ -11,16 +13,14 @@
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"
Resource::Resource(QObject* parent) : QObject(parent), m_size_info(0) {}
Resource::Resource(QFileInfo fileInfo) : m_size_info(0)
Resource::Resource(const QFileInfo& fileInfo)
{
setFile(fileInfo);
}
void Resource::setFile(QFileInfo fileInfo)
{
m_file_info = std::move(fileInfo);
m_fileInfo = std::move(fileInfo);
parseFile();
}
@ -37,23 +37,23 @@ std::tuple<QString, qint64> calculateFileSize(const QFileInfo& file)
}
return { QString("%1 %2").arg(QString::number(count), str), count };
}
return { StringUtils::humanReadableFileSize(file.size(), true), file.size() };
return { StringUtils::humanReadableFileSize(static_cast<double>(file.size()), true), file.size() };
}
} // namespace
void Resource::parseFile()
{
QString fileName{ m_file_info.fileName() };
QString fileName{ m_fileInfo.fileName() };
m_type = ResourceType::UNKNOWN;
m_internal_id = fileName;
m_internalId = fileName;
std::tie(m_size_str, m_size_info) = calculateFileSize(m_file_info);
if (m_file_info.isDir()) {
std::tie(m_sizeStr, m_sizeInfo) = calculateFileSize(m_fileInfo);
if (m_fileInfo.isDir()) {
m_type = ResourceType::FOLDER;
m_name = fileName;
} else if (m_file_info.isFile()) {
} else if (m_fileInfo.isFile()) {
if (fileName.endsWith(".disabled")) {
fileName.chop(9);
m_enabled = false;
@ -75,7 +75,7 @@ void Resource::parseFile()
m_name = fileName;
}
m_changed_date_time = m_file_info.lastModified();
m_changedDateTime = m_fileInfo.lastModified();
}
auto Resource::name() const -> QString
@ -102,7 +102,7 @@ auto Resource::provider() const -> QString
return ModPlatform::ProviderCapabilities::readableName(metadata()->provider);
}
return tr("Unknown");
return QObject::tr("Unknown");
}
auto Resource::homepage() const -> QString
@ -120,7 +120,7 @@ void Resource::setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata)
setStatus(ResourceStatus::Installed);
}
m_metadata = metadata;
m_metadata = std::move(metadata);
}
QStringList Resource::issues() const
@ -129,7 +129,7 @@ QStringList Resource::issues() const
result.reserve(m_issues.length());
for (const char* issue : m_issues) {
result.append(tr(issue));
result.append(QObject::tr(issue));
}
return result;
@ -221,7 +221,7 @@ int Resource::compare(const Resource& other, SortType type) const
return 0;
}
bool Resource::applyFilter(QRegularExpression filter) const
bool Resource::applyFilter(const QRegularExpression& filter) const
{
if (filter.match(name()).hasMatch()) {
return true;
@ -238,7 +238,7 @@ bool Resource::enable(EnableAction action)
return false;
}
QString path = m_file_info.absoluteFilePath();
QString path = m_fileInfo.absoluteFilePath();
QFile file(path);
bool enable = true;
@ -291,7 +291,7 @@ auto Resource::destroy(const QDir& indexDir, bool preserveMetadata, bool attempt
destroyMetadata(indexDir);
}
return (attemptTrash && FS::trash(m_file_info.filePath())) || FS::deletePath(m_file_info.filePath());
return (attemptTrash && FS::trash(m_fileInfo.filePath())) || FS::deletePath(m_fileInfo.filePath());
}
auto Resource::destroyMetadata(const QDir& indexDir) -> void
@ -313,20 +313,20 @@ bool Resource::isSymLinkUnder(const QString& instPath) const
auto instDir = QDir(instPath);
auto relAbsPath = instDir.relativeFilePath(m_file_info.absoluteFilePath());
auto relCanonPath = instDir.relativeFilePath(m_file_info.canonicalFilePath());
auto relAbsPath = instDir.relativeFilePath(m_fileInfo.absoluteFilePath());
auto relCanonPath = instDir.relativeFilePath(m_fileInfo.canonicalFilePath());
return relAbsPath != relCanonPath;
}
bool Resource::isMoreThanOneHardLink() const
{
return FS::hardLinkCount(m_file_info.absoluteFilePath()) > 1;
return FS::hardLinkCount(m_fileInfo.absoluteFilePath()) > 1;
}
auto Resource::getOriginalFileName() const -> QString
{
auto fileName = m_file_info.fileName();
auto fileName = m_fileInfo.fileName();
if (!m_enabled) {
fileName.chop(9);
}

View file

@ -39,9 +39,9 @@
#include <QFileInfo>
#include <QObject>
#include <QPointer>
#include <memory>
#include "MetadataHandler.h"
#include "QObjectPtr.h"
class BaseInstance;
@ -88,29 +88,30 @@ enum class EnableAction : std::uint8_t { ENABLE, DISABLE, TOGGLE };
*
* Subclass it to add additional data / behavior, such as Mods or Resource packs.
*/
class Resource : public QObject {
Q_OBJECT
Q_DISABLE_COPY(Resource)
class Resource {
public:
using Ptr = shared_qobject_ptr<Resource>;
Resource(const Resource&) = delete;
Resource& operator=(const Resource&) = delete;
public:
using Ptr = std::shared_ptr<Resource>;
Resource(const QFileInfo& fileInfo);
Resource(QObject* parent = nullptr);
Resource(QFileInfo fileInfo);
Resource(const QString& filePath) : Resource(QFileInfo(filePath)) {}
~Resource() override = default;
virtual ~Resource() = default;
void setFile(QFileInfo fileInfo);
void parseFile();
auto fileinfo() const -> QFileInfo { return m_file_info; }
auto dateTimeChanged() const -> QDateTime { return m_changed_date_time; }
auto internalId() const -> QString { return m_internal_id; }
auto fileinfo() const -> QFileInfo { return m_fileInfo; }
auto dateTimeChanged() const -> QDateTime { return m_changedDateTime; }
auto internalId() const -> QString { return m_internalId; }
auto type() const -> ResourceType { return m_type; }
bool enabled() const { return m_enabled; }
auto getOriginalFileName() const -> QString;
QString sizeStr() const { return m_size_str; }
qint64 sizeInfo() const { return m_size_info; }
QString sizeStr() const { return m_sizeStr; }
qint64 sizeInfo() const { return m_sizeInfo; }
virtual auto name() const -> QString;
virtual bool valid() const { return m_type != ResourceType::UNKNOWN; }
@ -143,7 +144,7 @@ class Resource : public QObject {
/** Returns whether the given filter should filter out 'this' (false),
* or if such filter includes the Resource (true).
*/
virtual bool applyFilter(QRegularExpression filter) const;
virtual bool applyFilter(const QRegularExpression& filter) const;
/** Changes the enabled property, according to 'action'.
*
@ -151,15 +152,15 @@ class Resource : public QObject {
*/
bool enable(EnableAction action);
auto shouldResolve() const -> bool { return !m_is_resolving && !m_is_resolved; }
auto isResolving() const -> bool { return m_is_resolving; }
auto isResolved() const -> bool { return m_is_resolved; }
auto resolutionTicket() const -> int { return m_resolution_ticket; }
auto shouldResolve() const -> bool { return !m_isResolving && !m_isResolved; }
auto isResolving() const -> bool { return m_isResolving; }
auto isResolved() const -> bool { return m_isResolved; }
auto resolutionTicket() const -> int { return m_resolutionTicket; }
void setResolving(bool resolving, int resolutionTicket)
{
m_is_resolving = resolving;
m_resolution_ticket = resolutionTicket;
m_isResolving = resolving;
m_resolutionTicket = resolutionTicket;
}
// Delete all files of this resource.
@ -167,7 +168,7 @@ class Resource : public QObject {
// Delete the metadata only.
auto destroyMetadata(const QDir& indexDir) -> void;
auto isSymLink() const -> bool { return m_file_info.isSymLink(); }
auto isSymLink() const -> bool { return m_fileInfo.isSymLink(); }
/**
* @brief Take a instance path, checks if the file pointed to by the resource is a symlink or under a symlink in that instance
@ -182,12 +183,12 @@ class Resource : public QObject {
protected:
/* The file corresponding to this resource. */
QFileInfo m_file_info;
QFileInfo m_fileInfo{};
/* The cached date when this file was last changed. */
QDateTime m_changed_date_time;
QDateTime m_changedDateTime;
/* Internal ID for internal purposes. Properties such as human-readability should not be assumed. */
QString m_internal_id;
QString m_internalId;
/* Name as reported via the file name. In the absence of a better name, this is shown to the user. */
QString m_name;
@ -205,9 +206,9 @@ class Resource : public QObject {
QList<const char*> m_issues;
/* Used to keep trach of pending / concluded actions on the resource. */
bool m_is_resolving = false;
bool m_is_resolved = false;
int m_resolution_ticket = 0;
QString m_size_str;
qint64 m_size_info;
bool m_isResolving = false;
bool m_isResolved = false;
int m_resolutionTicket = 0;
QString m_sizeStr;
qint64 m_sizeInfo = 0;
};

View file

@ -890,7 +890,7 @@ void ResourceFolderModel::applyUpdates(QSet<QString>& currentSet, QSet<QString>&
}
}
m_resources[row].reset(newResource);
m_resources[row].swap(newResource);
newResource->updateIssues(m_instance);
resolveResource(m_resources.at(row));

View file

@ -1,6 +1,5 @@
#pragma once
#include "Resource.h"
#include "minecraft/mod/DataPack.h"
#include <QImage>
@ -16,9 +15,7 @@ class Version;
* */
class ResourcePack : public DataPack {
Q_OBJECT
public:
ResourcePack(QObject* parent = nullptr) : DataPack(parent) {}
ResourcePack(QFileInfo file_info) : DataPack(file_info) {}
/** Gets, respectively, the lower and upper versions supported by the set pack format. */

View file

@ -41,13 +41,9 @@
enum class ShaderPackFormat { VALID, INVALID };
class ShaderPack : public Resource {
Q_OBJECT
public:
using Ptr = shared_qobject_ptr<Resource>;
ShaderPackFormat packFormat() const { return m_pack_format; }
ShaderPack(QObject* parent = nullptr) : Resource(parent) {}
ShaderPack(QFileInfo file_info) : Resource(file_info) {}
/** Thread-safe. */

View file

@ -29,11 +29,7 @@
class Version;
class TexturePack : public Resource {
Q_OBJECT
public:
using Ptr = shared_qobject_ptr<Resource>;
TexturePack(QObject* parent = nullptr) : Resource(parent) {}
TexturePack(QFileInfo file_info) : Resource(file_info) {}
/** Gets the description of the texture pack. */

View file

@ -30,11 +30,7 @@ class Version;
enum class WorldSaveFormat { SINGLE, MULTI, INVALID };
class WorldSave : public Resource {
Q_OBJECT
public:
using Ptr = shared_qobject_ptr<Resource>;
WorldSave(QObject* parent = nullptr) : Resource(parent) {}
WorldSave(QFileInfo file_info) : Resource(file_info) {}
/** Gets the format of the save. */

View file

@ -125,10 +125,6 @@ void ResourceFolderLoadTask::executeTask()
}
}
for (const auto& mod : m_result->resources) {
mod->moveToThread(m_thread_to_spawn_into);
}
if (m_aborted) {
emit finished();
} else {

View file

@ -156,4 +156,8 @@ class ResourceAPI {
*/
virtual void loadExtraPackInfo(ModPlatform::IndexedPack&, QJsonObject&) const = 0;
virtual std::pair<Task::Ptr, QByteArray*> getModCategories() = 0;
virtual QList<ModPlatform::Category> loadModCategories(const QByteArray& response) = 0;
};

View file

@ -7,7 +7,6 @@
#include <QList>
#include <cstdint>
#include "BuildConfig.h"
#include "Json.h"
#include "Version.h"
#include "modplatform/ModIndex.h"
#include "modplatform/ResourceAPI.h"
@ -29,12 +28,12 @@ class FlameAPI : public ResourceAPI {
std::pair<Task::Ptr, QByteArray*> getFile(const QString& addonId, const QString& fileId) const;
static std::pair<Task::Ptr, QByteArray*> getCategories(ModPlatform::ResourceType type);
static std::pair<Task::Ptr, QByteArray*> getModCategories();
static QList<ModPlatform::Category> loadModCategories(const QByteArray& response);
std::pair<Task::Ptr, QByteArray*> getModCategories() override;
QList<ModPlatform::Category> loadModCategories(const QByteArray& response) override;
QList<ResourceAPI::SortingMethod> getSortingMethods() const override;
static inline bool validateModLoaders(ModPlatform::ModLoaderTypes loaders)
static bool validateModLoaders(ModPlatform::ModLoaderTypes loaders)
{
return loaders & (ModPlatform::NeoForge | ModPlatform::Forge | ModPlatform::Fabric | ModPlatform::Quilt);
}
@ -85,7 +84,7 @@ class FlameAPI : public ResourceAPI {
return 0;
}
static const QStringList getModLoaderStrings(const ModPlatform::ModLoaderTypes types)
static QStringList getModLoaderStrings(const ModPlatform::ModLoaderTypes types)
{
QStringList l;
for (auto loader : { ModPlatform::NeoForge, ModPlatform::Forge, ModPlatform::Fabric, ModPlatform::Quilt }) {
@ -96,7 +95,7 @@ class FlameAPI : public ResourceAPI {
return l;
}
static const QString getModLoaderFilters(ModPlatform::ModLoaderTypes types) { return "[" + getModLoaderStrings(types).join(',') + "]"; }
static QString getModLoaderFilters(ModPlatform::ModLoaderTypes types) { return "[" + getModLoaderStrings(types).join(',') + "]"; }
public:
std::optional<QString> getSearchURL(const SearchArgs& args) const override
@ -105,22 +104,27 @@ class FlameAPI : public ResourceAPI {
get_arguments.append(QString("classId=%1").arg(getClassId(args.type)));
get_arguments.append(QString("index=%1").arg(args.offset));
get_arguments.append("pageSize=25");
if (args.search.has_value())
if (args.search.has_value()) {
get_arguments.append(QString("searchFilter=%1").arg(args.search.value()));
if (args.sorting.has_value())
}
if (args.sorting.has_value()) {
get_arguments.append(QString("sortField=%1").arg(args.sorting.value().index));
}
get_arguments.append("sortOrder=desc");
if (args.loaders.has_value()) {
ModPlatform::ModLoaderTypes loaders = args.loaders.value();
loaders &= ~static_cast<std::uint16_t>(ModPlatform::ModLoaderType::DataPack);
if (loaders != 0)
if (loaders != 0) {
get_arguments.append(QString("modLoaderTypes=%1").arg(getModLoaderFilters(loaders)));
}
if (args.categoryIds.has_value() && !args.categoryIds->empty())
}
if (args.categoryIds.has_value() && !args.categoryIds->empty()) {
get_arguments.append(QString("categoryIds=[%1]").arg(args.categoryIds->join(",")));
}
if (args.versions.has_value() && !args.versions.value().empty())
if (args.versions.has_value() && !args.versions.value().empty()) {
get_arguments.append(QString("gameVersion=%1").arg(args.versions.value().front().toString()));
}
return BuildConfig.FLAME_BASE_URL + "/mods/search?gameId=432&" + get_arguments.join('&');
}
@ -130,8 +134,9 @@ class FlameAPI : public ResourceAPI {
auto addonId = args.pack->addonId.toString();
QString url = QString(BuildConfig.FLAME_BASE_URL + "/mods/%1/files?pageSize=10000").arg(addonId);
if (args.mcVersions.has_value())
if (args.mcVersions.has_value()) {
url += QString("&gameVersion=%1").arg(args.mcVersions.value().front().toString());
}
if (args.loaders.has_value() && args.loaders.value() != ModPlatform::ModLoaderType::DataPack &&
ModPlatform::hasSingleModLoaderSelected(args.loaders.value())) {
@ -158,7 +163,7 @@ class FlameAPI : public ResourceAPI {
}
return {};
};
void loadExtraPackInfo(ModPlatform::IndexedPack& m, [[maybe_unused]] QJsonObject&) const override { FlameMod::loadBody(m); }
void loadExtraPackInfo(ModPlatform::IndexedPack& m, [[maybe_unused]] QJsonObject& /*unused*/) const override { FlameMod::loadBody(m); }
private:
std::optional<QString> getInfoURL(const QString& id) const override { return QString(BuildConfig.FLAME_BASE_URL + "/mods/%1").arg(id); }

View file

@ -30,9 +30,9 @@ class ModrinthAPI : public ResourceAPI {
std::pair<Task::Ptr, QByteArray*> getProjects(QStringList addonIds) const override;
static std::pair<Task::Ptr, QByteArray*> getModCategories();
std::pair<Task::Ptr, QByteArray*> getModCategories() override;
static QList<ModPlatform::Category> loadCategories(const QByteArray& response, const QString& projectType);
static QList<ModPlatform::Category> loadModCategories(const QByteArray& response);
QList<ModPlatform::Category> loadModCategories(const QByteArray& response) override;
public:
auto getSortingMethods() const -> QList<ResourceAPI::SortingMethod> override;
@ -180,7 +180,7 @@ class ModrinthAPI : public ResourceAPI {
return BuildConfig.MODRINTH_PROD_URL + "/project/" + id;
};
auto getMultipleModInfoURL(const QStringList& ids) const -> QString
static auto getMultipleModInfoURL(const QStringList& ids) -> QString
{
return BuildConfig.MODRINTH_PROD_URL + QString("/projects?ids=[\"%1\"]").arg(ids.join("\",\""));
};

View file

@ -29,9 +29,6 @@
#include "minecraft/PackProfile.h"
#include "minecraft/mod/ModFolderModel.h"
#include "minecraft/mod/ResourcePackFolderModel.h"
#include "minecraft/mod/ShaderPackFolderModel.h"
#include "minecraft/mod/TexturePackFolderModel.h"
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
#include "modplatform/ModIndex.h"
@ -50,12 +47,20 @@
namespace ResourceDownload {
ResourceDownloadDialog::ResourceDownloadDialog(QWidget* parent, ResourceFolderModel* baseModel, bool suppressInitialSearch)
ResourceDownloadDialog::ResourceDownloadDialog(QWidget* parent,
ResourceFolderModel* baseModel,
BaseInstance* instance,
QString resourcesString,
QString geometrySaveKey,
bool suppressInitialSearch)
: QDialog(parent)
, m_base_model(baseModel)
, m_buttons(QDialogButtonBox::Help | QDialogButtonBox::Ok | QDialogButtonBox::Cancel)
, m_vertical_layout(this)
, m_suppressInitialSearch(suppressInitialSearch)
, m_instance(instance)
, m_resourcesString(std::move(resourcesString))
, m_geometrySaveKey(std::move(geometrySaveKey))
{
setObjectName(QStringLiteral("ResourceDownloadDialog"));
@ -85,6 +90,8 @@ ResourceDownloadDialog::ResourceDownloadDialog(QWidget* parent, ResourceFolderMo
helpButton->setAutoDefault(false);
setWindowModality(Qt::WindowModal);
setWindowTitle(dialogTitle());
}
void ResourceDownloadDialog::accept()
@ -288,148 +295,6 @@ void ResourceDownloadDialog::selectedPageChanged(BasePage* previous, BasePage* s
result->setSearchTerm(prevPage->getSearchTerm());
}
ModDownloadDialog::ModDownloadDialog(QWidget* parent, ModFolderModel* mods, BaseInstance* instance, bool suppressInitialSearch)
: ResourceDownloadDialog(parent, mods, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
initializeContainer();
connectButtons();
if (!geometrySaveKey().isEmpty()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toString().toUtf8()));
}
}
QList<BasePage*> ModDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getSupportedModLoaders().value();
if (ModrinthAPI::validateModLoaders(loaders)) {
auto* page = ModrinthModPage::create(this, *m_instance);
page->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(page);
}
if (APPLICATION->capabilities() & Application::SupportsFlame && FlameAPI::validateModLoaders(loaders)) {
auto* page = FlameModPage::create(this, *m_instance);
page->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(page);
}
return pages;
}
GetModDependenciesTask::Ptr ModDownloadDialog::getModDependenciesTask()
{
if (!APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
if (auto* model = dynamic_cast<ModFolderModel*>(getBaseModel()); model) {
QList<std::shared_ptr<GetModDependenciesTask::PackDependency>> selectedVers;
for (const auto& selected : getTasks()) {
selectedVers.append(std::make_shared<GetModDependenciesTask::PackDependency>(selected->getPack(), selected->getVersion()));
}
return makeShared<GetModDependenciesTask>(m_instance, model, selectedVers);
}
}
return nullptr;
}
ResourcePackDownloadDialog::ResourcePackDownloadDialog(QWidget* parent,
ResourcePackFolderModel* resourcePacks,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, resourcePacks, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
initializeContainer();
connectButtons();
if (!geometrySaveKey().isEmpty()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toString().toUtf8()));
}
}
QList<BasePage*> ResourcePackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthResourcePackPage::create(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameResourcePackPage::create(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
return pages;
}
TexturePackDownloadDialog::TexturePackDownloadDialog(QWidget* parent,
TexturePackFolderModel* resourcePacks,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, resourcePacks, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
initializeContainer();
connectButtons();
if (!geometrySaveKey().isEmpty()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toString().toUtf8()));
}
}
QList<BasePage*> TexturePackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthTexturePackPage::create(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameTexturePackPage::create(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
return pages;
}
ShaderPackDownloadDialog::ShaderPackDownloadDialog(QWidget* parent,
ShaderPackFolderModel* shaders,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, shaders, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
initializeContainer();
connectButtons();
if (!geometrySaveKey().isEmpty()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toString().toUtf8()));
}
}
QList<BasePage*> ShaderPackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthShaderPackPage::create(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameShaderPackPage::create(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
return pages;
}
void ResourceDownloadDialog::setResourceMetadata(const std::shared_ptr<Metadata::ModStruct>& meta)
{
switch (meta->provider) {
@ -448,34 +313,138 @@ void ResourceDownloadDialog::setResourceMetadata(const std::shared_ptr<Metadata:
page->openProject(meta->project_id);
}
DataPackDownloadDialog::DataPackDownloadDialog(QWidget* parent,
DataPackFolderModel* dataPacks,
GetModDependenciesTask::Ptr ResourceDownloadDialog::getModDependenciesTask()
{
if (!APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
if (auto* model = dynamic_cast<ModFolderModel*>(getBaseModel()); model) {
QList<std::shared_ptr<GetModDependenciesTask::PackDependency>> selectedVers;
for (auto& selected : getTasks()) {
selectedVers.append(std::make_shared<GetModDependenciesTask::PackDependency>(selected->getPack(), selected->getVersion()));
}
return makeShared<GetModDependenciesTask>(m_instance, model, selectedVers);
}
}
return nullptr;
}
ResourceDownloadDialog* ResourceDownloadDialog::createMod(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch)
: ResourceDownloadDialog(parent, dataPacks, suppressInitialSearch), m_instance(instance)
{
setWindowTitle(dialogTitle());
auto* dialog = new ResourceDownloadDialog(parent, mods, instance, tr("mods"), "ModDownloadGeometry", suppressInitialSearch);
QList<BasePage*> pages;
auto loaders = static_cast<MinecraftInstance*>(instance)->getPackProfile()->getSupportedModLoaders().value();
if (ModrinthAPI::validateModLoaders(loaders)) {
auto* page = Modrinth::createModPage(dialog, *instance);
page->setSuppressInitialSearch(suppressInitialSearch);
pages.append(page);
}
if (APPLICATION->capabilities() & Application::SupportsFlame && FlameAPI::validateModLoaders(loaders)) {
auto* flamePage = Flame::createModPage(dialog, *instance);
flamePage->setSuppressInitialSearch(suppressInitialSearch);
pages.append(flamePage);
}
dialog->initPages(pages);
return dialog;
}
ResourceDownloadDialog* ResourceDownloadDialog::createResourcePack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch)
{
auto* dialog = new ResourceDownloadDialog(parent, mods, instance, tr("resource packs"), "RPDownloadGeometry", suppressInitialSearch);
QList<BasePage*> pages;
auto* page = Modrinth::createResourcePackResourcePage(dialog, *instance);
page->setSuppressInitialSearch(suppressInitialSearch);
pages.append(page);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = Flame::createResourcePackResourcePage(dialog, *instance);
flamePage->setSuppressInitialSearch(suppressInitialSearch);
pages.append(flamePage);
}
dialog->initPages(pages);
return dialog;
}
ResourceDownloadDialog* ResourceDownloadDialog::createTexturePack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch)
{
auto* dialog = new ResourceDownloadDialog(parent, mods, instance, tr("texture packs"), "TPDownloadGeometry", suppressInitialSearch);
QList<BasePage*> pages;
auto* page = Modrinth::createTexturePackResourcePage(dialog, *instance);
page->setSuppressInitialSearch(suppressInitialSearch);
pages.append(page);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = Flame::createTexturePackResourcePage(dialog, *instance);
flamePage->setSuppressInitialSearch(suppressInitialSearch);
pages.append(flamePage);
}
dialog->initPages(pages);
return dialog;
}
ResourceDownloadDialog* ResourceDownloadDialog::createShaderPack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch)
{
auto* dialog = new ResourceDownloadDialog(parent, mods, instance, tr("shader packs"), "ShaderDownloadGeometry", suppressInitialSearch);
QList<BasePage*> pages;
auto* page = Modrinth::createShaderPackResourcePage(dialog, *instance);
page->setSuppressInitialSearch(suppressInitialSearch);
pages.append(page);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = Flame::createShaderPackResourcePage(dialog, *instance);
flamePage->setSuppressInitialSearch(suppressInitialSearch);
pages.append(flamePage);
}
dialog->initPages(pages);
return dialog;
}
ResourceDownloadDialog* ResourceDownloadDialog::createDataPack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch)
{
auto* dialog = new ResourceDownloadDialog(parent, mods, instance, tr("data packs"), "DataPackDownloadGeometry", suppressInitialSearch);
QList<BasePage*> pages;
auto* page = Modrinth::createDataPackResourcePage(dialog, *instance);
page->setSuppressInitialSearch(suppressInitialSearch);
pages.append(page);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = Flame::createDataPackResourcePage(dialog, *instance);
flamePage->setSuppressInitialSearch(suppressInitialSearch);
pages.append(flamePage);
}
dialog->initPages(pages);
return dialog;
}
void ResourceDownloadDialog::initPages(QList<BasePage*> pages)
{
m_pages = std::move(pages);
initializeContainer();
connectButtons();
if (!geometrySaveKey().isEmpty()) {
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toByteArray()));
restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get(geometrySaveKey()).toString().toUtf8()));
}
}
QList<BasePage*> DataPackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthDataPackPage::create(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameDataPackPage::create(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
return pages;
}
} // namespace ResourceDownload

View file

@ -25,7 +25,6 @@
#include <QLayout>
#include "QObjectPtr.h"
#include "minecraft/mod/DataPackFolderModel.h"
#include "minecraft/mod/tasks/GetModDependenciesTask.h"
#include "modplatform/ModIndex.h"
#include "ui/pages/BasePageProvider.h"
@ -51,13 +50,32 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
public:
using DownloadTaskPtr = shared_qobject_ptr<ResourceDownloadTask>;
ResourceDownloadDialog(QWidget* parent, ResourceFolderModel* baseModel, bool suppressInitialSearch = false);
static ResourceDownloadDialog* createMod(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch = false);
static ResourceDownloadDialog* createResourcePack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch = false);
static ResourceDownloadDialog* createTexturePack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch = false);
static ResourceDownloadDialog* createShaderPack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch = false);
static ResourceDownloadDialog* createDataPack(QWidget* parent,
ResourceFolderModel* mods,
BaseInstance* instance,
bool suppressInitialSearch = false);
void initializeContainer();
void connectButtons();
//: String that gets appended to the download dialog title ("Download " + resourcesString())
virtual QString resourcesString() const { return tr("resources"); }
QString resourcesString() const { return m_resourcesString; }
QString dialogTitle() override { return tr("Download %1").arg(resourcesString()); };
@ -72,6 +90,8 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
void setResourceMetadata(const std::shared_ptr<Metadata::ModStruct>& meta);
QList<BasePage*> getPages() override { return m_pages; };
public slots:
void accept() override;
void reject() override;
@ -82,10 +102,19 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
virtual void confirm();
protected:
virtual QString geometrySaveKey() const { return ""; }
ResourceDownloadDialog(QWidget* parent,
ResourceFolderModel* baseModel,
BaseInstance* instance,
QString resourcesString = tr("resources"),
QString geometrySaveKey = "",
bool suppressInitialSearch = false);
QString geometrySaveKey() const { return m_geometrySaveKey; }
void setButtonStatus();
virtual GetModDependenciesTask::Ptr getModDependenciesTask() { return nullptr; }
GetModDependenciesTask::Ptr getModDependenciesTask();
void initPages(QList<BasePage*> pages);
protected:
ResourceFolderModel* m_base_model;
@ -97,104 +126,11 @@ class ResourceDownloadDialog : public QDialog, public BasePageProvider {
protected:
bool m_suppressInitialSearch = false;
};
class ModDownloadDialog final : public ResourceDownloadDialog {
Q_OBJECT
public:
explicit ModDownloadDialog(QWidget* parent, ModFolderModel* mods, BaseInstance* instance, bool suppressInitialSearch = false);
~ModDownloadDialog() override = default;
//: String that gets appended to the mod download dialog title ("Download " + resourcesString())
QString resourcesString() const override { return tr("mods"); }
QString geometrySaveKey() const override { return "ModDownloadGeometry"; }
QList<BasePage*> getPages() override;
GetModDependenciesTask::Ptr getModDependenciesTask() override;
private:
BaseInstance* m_instance;
};
class ResourcePackDownloadDialog final : public ResourceDownloadDialog {
Q_OBJECT
public:
explicit ResourcePackDownloadDialog(QWidget* parent,
ResourcePackFolderModel* resourcePacks,
BaseInstance* instance,
bool suppressInitialSearch = false);
~ResourcePackDownloadDialog() override = default;
//: String that gets appended to the resource pack download dialog title ("Download " + resourcesString())
QString resourcesString() const override { return tr("resource packs"); }
QString geometrySaveKey() const override { return "RPDownloadGeometry"; }
QList<BasePage*> getPages() override;
private:
BaseInstance* m_instance;
};
class TexturePackDownloadDialog final : public ResourceDownloadDialog {
Q_OBJECT
public:
explicit TexturePackDownloadDialog(QWidget* parent,
TexturePackFolderModel* resourcePacks,
BaseInstance* instance,
bool suppressInitialSearch = false);
~TexturePackDownloadDialog() override = default;
//: String that gets appended to the texture pack download dialog title ("Download " + resourcesString())
QString resourcesString() const override { return tr("texture packs"); }
QString geometrySaveKey() const override { return "TPDownloadGeometry"; }
QList<BasePage*> getPages() override;
private:
BaseInstance* m_instance;
};
class ShaderPackDownloadDialog final : public ResourceDownloadDialog {
Q_OBJECT
public:
explicit ShaderPackDownloadDialog(QWidget* parent,
ShaderPackFolderModel* shaders,
BaseInstance* instance,
bool suppressInitialSearch = false);
~ShaderPackDownloadDialog() override = default;
//: String that gets appended to the shader pack download dialog title ("Download " + resourcesString())
QString resourcesString() const override { return tr("shader packs"); }
QString geometrySaveKey() const override { return "ShaderDownloadGeometry"; }
QList<BasePage*> getPages() override;
private:
BaseInstance* m_instance;
};
class DataPackDownloadDialog final : public ResourceDownloadDialog {
Q_OBJECT
public:
explicit DataPackDownloadDialog(QWidget* parent,
DataPackFolderModel* dataPacks,
BaseInstance* instance,
bool suppressInitialSearch = false);
~DataPackDownloadDialog() override = default;
//: String that gets appended to the data pack download dialog title ("Download " + resourcesString())
QString resourcesString() const override { return tr("data packs"); }
QString geometrySaveKey() const override { return "DataPackDownloadGeometry"; }
QList<BasePage*> getPages() override;
private:
BaseInstance* m_instance;
QString m_resourcesString;
QString m_geometrySaveKey;
QList<BasePage*> m_pages;
};
} // namespace ResourceDownload

View file

@ -68,7 +68,7 @@ void DataPackPage::downloadDataPacks()
return; // this is a null instance or a legacy instance
}
m_downloadDialog = new ResourceDownload::DataPackDownloadDialog(this, m_model, m_instance);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createDataPack(this, m_model, m_instance);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &DataPackPage::downloadDialogFinished);
@ -242,9 +242,9 @@ void DataPackPage::changeDataPackVersion()
return;
}
ResourceDownload::DataPackDownloadDialog mdownload(this, m_model, m_instance, true);
mdownload.setResourceMetadata(resource.metadata());
if (mdownload.exec() != 0) {
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createDataPack(this, m_model, m_instance, true);
m_downloadDialog->setResourceMetadata(resource.metadata());
if (m_downloadDialog->exec() != 0) {
auto* tasks = new ConcurrentTask("Download Data Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
connect(tasks, &Task::failed, [this, tasks](const QString& reason) {
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
@ -263,7 +263,7 @@ void DataPackPage::changeDataPackVersion()
tasks->deleteLater();
});
for (auto& task : mdownload.getTasks()) {
for (auto& task : m_downloadDialog->getTasks()) {
tasks->addTask(task);
}

View file

@ -44,7 +44,7 @@ class DataPackPage : public ExternalResourcesPage {
private:
DataPackFolderModel* m_model;
QPointer<ResourceDownload::DataPackDownloadDialog> m_downloadDialog;
QPointer<ResourceDownload::ResourceDownloadDialog> m_downloadDialog;
};
/**

View file

@ -173,7 +173,7 @@ void ModFolderPage::downloadMods()
}
}
m_downloadDialog = new ResourceDownload::ModDownloadDialog(this, m_model, m_instance);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createMod(this, m_model, m_instance);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &ModFolderPage::downloadDialogFinished);
@ -352,7 +352,7 @@ void ModFolderPage::changeModVersion()
return;
}
m_downloadDialog = new ResourceDownload::ModDownloadDialog(this, m_model, m_instance, true);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createMod(this, m_model, m_instance, true);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &ModFolderPage::downloadDialogFinished);

View file

@ -75,7 +75,7 @@ class ModFolderPage : public ExternalResourcesPage {
protected:
ModFolderModel* m_model;
QPointer<ResourceDownload::ModDownloadDialog> m_downloadDialog;
QPointer<ResourceDownload::ResourceDownloadDialog> m_downloadDialog;
};
class CoreModFolderPage : public ModFolderPage {

View file

@ -85,7 +85,7 @@ void ResourcePackPage::downloadResourcePacks()
return; // this is a null instance or a legacy instance
}
m_downloadDialog = new ResourceDownload::ResourcePackDownloadDialog(this, m_model, m_instance);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createResourcePack(this, m_model, m_instance);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &ResourcePackPage::downloadDialogFinished);
@ -259,7 +259,7 @@ void ResourcePackPage::changeResourcePackVersion()
return;
}
m_downloadDialog = new ResourceDownload::ResourcePackDownloadDialog(this, m_model, m_instance, true);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createResourcePack(this, m_model, m_instance, true);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &ResourcePackPage::downloadDialogFinished);

View file

@ -38,8 +38,6 @@
#include "ShaderPackPage.h"
#include "ui_ExternalResourcesPage.h"
#include "ResourceDownloadTask.h"
#include "minecraft/mod/ShaderPackFolderModel.h"
#include "ui/dialogs/CustomMessageBox.h"
@ -82,7 +80,7 @@ void ShaderPackPage::downloadShaderPack()
return; // this is a null instance or a legacy instance
}
m_downloadDialog = new ResourceDownload::ShaderPackDownloadDialog(this, m_model, m_instance);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createShaderPack(this, m_model, m_instance);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &ShaderPackPage::downloadDialogFinished);
@ -256,7 +254,7 @@ void ShaderPackPage::changeShaderPackVersion()
return;
}
m_downloadDialog = new ResourceDownload::ShaderPackDownloadDialog(this, m_model, m_instance, true);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createShaderPack(this, m_model, m_instance, true);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &ShaderPackPage::downloadDialogFinished);

View file

@ -63,5 +63,5 @@ class ShaderPackPage : public ExternalResourcesPage {
private:
ShaderPackFolderModel* m_model;
QPointer<ResourceDownload::ShaderPackDownloadDialog> m_downloadDialog;
QPointer<ResourceDownload::ResourceDownloadDialog> m_downloadDialog;
};

View file

@ -37,10 +37,6 @@
#include "TexturePackPage.h"
#include "ResourceDownloadTask.h"
#include "minecraft/mod/TexturePack.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
@ -91,7 +87,7 @@ void TexturePackPage::downloadTexturePacks()
return; // this is a null instance or a legacy instance
}
m_downloadDialog = new ResourceDownload::TexturePackDownloadDialog(this, m_model, m_instance);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createTexturePack(this, m_model, m_instance);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &TexturePackPage::downloadDialogFinished);
m_downloadDialog->open();
@ -264,7 +260,7 @@ void TexturePackPage::changeTexturePackVersion()
return;
}
m_downloadDialog = new ResourceDownload::TexturePackDownloadDialog(this, m_model, m_instance, true);
m_downloadDialog = ResourceDownload::ResourceDownloadDialog::createTexturePack(this, m_model, m_instance, true);
connect(this, &QObject::destroyed, m_downloadDialog, &QDialog::close);
connect(m_downloadDialog, &QDialog::finished, this, &TexturePackPage::downloadDialogFinished);

View file

@ -67,5 +67,5 @@ class TexturePackPage : public ExternalResourcesPage {
private:
TexturePackFolderModel* m_model;
QPointer<ResourceDownload::TexturePackDownloadDialog> m_downloadDialog;
QPointer<ResourceDownload::ResourceDownloadDialog> m_downloadDialog;
};

View file

@ -14,12 +14,52 @@
namespace ResourceDownload {
DataPackResourcePage::DataPackResourcePage(DataPackDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance) {}
static ResourceDescriptor prepareDataPackDescriptor()
{
QMap<QString, QString> urlHandlers;
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/resourcepack\\/([^\\/]+)\\/?"), "modrinth");
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/texture-packs\\/([^\\/]+)\\/?"),
"curseforge");
urlHandlers.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return {
.helpPage = {},
//: The singular version of 'data packs'
.resourceString = QObject::tr("data pack"),
//: The plural version of 'data pack'
.resourcesString = QObject::tr("data packs"),
.supportsFiltering = false,
.isIndexed = true,
.urlHandlers = urlHandlers,
};
}
DataPackResourcePage::DataPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance, ResourceProviderData p, ResourceAPI* api)
: ResourcePage(dialog, instance, prepareDataPackDescriptor(), p)
{
m_model = new DataPackResourceModel(instance, api, debugName(), metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_model, &ResourceModel::versionListUpdated, this, &ResourcePage::versionListUpdated);
connect(m_model, &ResourceModel::projectInfoUpdated, this, &ResourcePage::updateUi);
connect(m_model, &QAbstractListModel::modelReset, this, &ResourcePage::modelReset);
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &DataPackResourcePage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &DataPackResourcePage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &DataPackResourcePage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &DataPackResourcePage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
}
/******** Callbacks to events in the UI (set up in the derived classes) ********/
void DataPackResourcePage::triggerSearch()
{
m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
m_ui->packView->clearSelection();
m_ui->packDescription->clear();
m_ui->versionSelectionBox->clear();
@ -30,14 +70,4 @@ void DataPackResourcePage::triggerSearch()
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> DataPackResourcePage::urlHandlers() const
{
QMap<QString, QString> map;
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/resourcepack\\/([^\\/]+)\\/?"), "modrinth");
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/texture-packs\\/([^\\/]+)\\/?"),
"curseforge");
map.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return map;
}
} // namespace ResourceDownload

View file

@ -5,45 +5,16 @@
#pragma once
#include "ui/pages/modplatform/DataPackModel.h"
#include "ui/pages/modplatform/ResourcePage.h"
namespace Ui {
class ResourcePage;
}
namespace ResourceDownload {
class DataPackDownloadDialog;
class DataPackResourcePage : public ResourcePage {
Q_OBJECT
public:
template <typename T>
static T* create(DataPackDownloadDialog* dialog, BaseInstance& instance)
{
auto page = new T(dialog, instance);
auto model = static_cast<DataPackResourceModel*>(page->getModel());
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset);
return page;
}
//: The plural version of 'data pack'
inline QString resourcesString() const override { return tr("data packs"); }
//: The singular version of 'data packs'
inline QString resourceString() const override { return tr("data pack"); }
bool supportsFiltering() const override { return false; };
QMap<QString, QString> urlHandlers() const override;
protected:
DataPackResourcePage(DataPackDownloadDialog* dialog, BaseInstance& instance);
DataPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance, ResourceProviderData p, ResourceAPI* api);
protected slots:
void triggerSearch() override;

View file

@ -40,38 +40,79 @@
#include "ModPage.h"
#include "ui_ResourcePage.h"
#include <QDesktopServices>
#include <QKeyEvent>
#include <QRegularExpression>
#include <memory>
#include <utility>
#include "Application.h"
#include "ResourceDownloadTask.h"
#include "minecraft/MinecraftInstance.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
namespace ResourceDownload {
ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance)
namespace {
ResourceDownload::ResourceDescriptor prepareModDescriptor()
{
QMap<QString, QString> urlHandlers;
urlHandlers.insert(QRegularExpression::anchoredPattern(R"((?:www\.)?modrinth\.com\/mod\/([^\/]+)\/?)"), "modrinth");
urlHandlers.insert(QRegularExpression::anchoredPattern(R"((?:www\.)?curseforge\.com\/minecraft\/mc-mods\/([^\/]+)\/?)"), "curseforge");
urlHandlers.insert(QRegularExpression::anchoredPattern(R"(minecraft\.curseforge\.com\/projects\/([^\/]+)\/?)"), "curseforge");
return {
.helpPage = "Mod-platform",
//: The singular version of 'mods'
.resourceString = QObject::tr("mod"),
//: The plural version of 'mod'
.resourcesString = QObject::tr("mods"),
.supportsFiltering = true,
.isIndexed = true,
.urlHandlers = urlHandlers,
};
}
} // namespace
namespace ResourceDownload {
ModPage::ModPage(ResourceDownloadDialog* dialog,
BaseInstance& instance,
ResourceProviderData p,
ResourceAPI* api,
ModFilterWidget* filterWidget)
: ResourcePage(dialog, instance, prepareModDescriptor(), std::move(p)), m_api(api)
{
auto* model = new ModModel(instance, api, debugName(), metaEntryBase());
m_model = model;
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
setFilterWidget(filterWidget);
model->setFilter(getFilter());
connect(m_model, &ResourceModel::versionListUpdated, this, &ResourcePage::versionListUpdated);
connect(m_model, &ResourceModel::projectInfoUpdated, this, &ResourcePage::updateUi);
connect(m_model, &QAbstractListModel::modelReset, this, &ResourcePage::modelReset);
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ModPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ModPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
connect(m_ui->resourceFilterButton, &QPushButton::clicked, this, &ModPage::filterMods);
}
void ModPage::setFilterWidget(std::unique_ptr<ModFilterWidget>& widget)
void ModPage::setFilterWidget(ModFilterWidget* widget)
{
if (m_filter_widget) {
disconnect(m_filter_widget.get(), nullptr, nullptr, nullptr);
}
auto* old = m_ui->splitter->replaceWidget(0, widget.get());
auto* old = m_ui->splitter->replaceWidget(0, widget);
// because we replaced the widget we also need to delete it
if (old) {
old->deleteLater();
}
delete old;
m_filter_widget.swap(widget);
m_filter_widget.reset(widget);
m_filter = m_filter_widget->getFilter();
@ -100,24 +141,14 @@ void ModPage::triggerSearch()
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> ModPage::urlHandlers() const
void ModPage::prepareProviderCategories()
{
QMap<QString, QString> map;
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/mod\\/([^\\/]+)\\/?"), "modrinth");
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/mc-mods\\/([^\\/]+)\\/?"), "curseforge");
map.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return map;
}
/******** Make changes to the UI ********/
void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
ModPlatform::IndexedVersion& version,
ResourceFolderModel* baseModel,
QString downloadReason)
{
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_model->addPack(pack, version, baseModel, isIndexed, downloadReason);
}
auto [task, response] = m_api->getModCategories();
m_categoriesTask = task;
connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = m_api->loadModCategories(*response);
m_filter_widget->setCategories(categories);
});
m_categoriesTask->start();
};
} // namespace ResourceDownload

View file

@ -6,64 +6,30 @@
#include <QWidget>
#include "modplatform/ModIndex.h"
#include "ui/pages/modplatform/ModModel.h"
#include "ui/pages/modplatform/ResourcePage.h"
#include "ui/widgets/ModFilterWidget.h"
namespace Ui {
class ResourcePage;
}
namespace ResourceDownload {
class ModDownloadDialog;
class ResourceDownloadDialog;
/* This page handles most logic related to browsing and selecting mods to download. */
class ModPage : public ResourcePage {
Q_OBJECT
public:
template <typename T>
static T* create(ModDownloadDialog* dialog, BaseInstance& instance)
{
auto page = new T(dialog, instance);
auto* model = static_cast<ModModel*>(page->getModel());
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
auto filterWidget = page->createFilterWidget();
page->setFilterWidget(filterWidget);
model->setFilter(page->getFilter());
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset);
return page;
}
//: The plural version of 'mod'
QString resourcesString() const override { return tr("mods"); }
//: The singular version of 'mods'
QString resourceString() const override { return tr("mod"); }
QMap<QString, QString> urlHandlers() const override;
void addResourceToPage(ModPlatform::IndexedPack::Ptr /*unused*/,
ModPlatform::IndexedVersion& /*unused*/,
ResourceFolderModel* /*unused*/,
QString downloadReason = "standalone") override;
virtual std::unique_ptr<ModFilterWidget> createFilterWidget() = 0;
bool supportsFiltering() const override { return true; };
auto getFilter() const -> std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
void setFilterWidget(std::unique_ptr<ModFilterWidget>&);
ModPage(ResourceDownloadDialog* dialog,
BaseInstance& instance,
ResourceProviderData p,
ResourceAPI* api,
ModFilterWidget* filterWidget);
protected:
ModPage(ModDownloadDialog* dialog, BaseInstance& instance);
virtual void prepareProviderCategories() {};
void prepareProviderCategories();
void setFilterWidget(ModFilterWidget*);
protected slots:
virtual void filterMods();
@ -72,6 +38,8 @@ class ModPage : public ResourcePage {
protected:
std::unique_ptr<ModFilterWidget> m_filter_widget;
std::shared_ptr<ModFilterWidget::Filter> m_filter;
Task::Ptr m_categoriesTask;
ResourceAPI* m_api = nullptr;
};
} // namespace ResourceDownload

View file

@ -13,8 +13,49 @@
namespace ResourceDownload {
ResourcePackResourcePage::ResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance)
{}
static ResourceDescriptor prepareResourcePackDescriptor()
{
QMap<QString, QString> urlHandlers;
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/resourcepack\\/([^\\/]+)\\/?"), "modrinth");
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/texture-packs\\/([^\\/]+)\\/?"),
"curseforge");
urlHandlers.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return {
.helpPage = {},
//: The singular version of 'resource packs'
.resourceString = QObject::tr("resource pack"),
//: The plural version of 'resource pack'
.resourcesString = QObject::tr("resource packs"),
.supportsFiltering = false,
.isIndexed = true,
.urlHandlers = urlHandlers,
};
}
ResourcePackResourcePage::ResourcePackResourcePage(ResourceDownloadDialog* dialog,
BaseInstance& instance,
ResourceProviderData p,
ResourceAPI* api)
: ResourcePage(dialog, instance, prepareResourcePackDescriptor(), p)
{
m_model = new ResourcePackResourceModel(instance, api, debugName(), metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_model, &ResourceModel::versionListUpdated, this, &ResourcePage::versionListUpdated);
connect(m_model, &ResourceModel::projectInfoUpdated, this, &ResourcePage::updateUi);
connect(m_model, &QAbstractListModel::modelReset, this, &ResourcePage::modelReset);
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ResourcePackResourcePage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ResourcePackResourcePage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ResourcePackResourcePage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ResourcePackResourcePage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
}
/******** Callbacks to events in the UI (set up in the derived classes) ********/
@ -31,14 +72,4 @@ void ResourcePackResourcePage::triggerSearch()
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> ResourcePackResourcePage::urlHandlers() const
{
QMap<QString, QString> map;
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/resourcepack\\/([^\\/]+)\\/?"), "modrinth");
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/texture-packs\\/([^\\/]+)\\/?"),
"curseforge");
map.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return map;
}
} // namespace ResourceDownload

View file

@ -4,13 +4,8 @@
#pragma once
#include "ui/pages/modplatform/ResourcePackModel.h"
#include "ui/pages/modplatform/ResourcePage.h"
namespace Ui {
class ResourcePage;
}
namespace ResourceDownload {
class ResourcePackDownloadDialog;
@ -19,32 +14,7 @@ class ResourcePackResourcePage : public ResourcePage {
Q_OBJECT
public:
template <typename T>
static T* create(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
{
auto page = new T(dialog, instance);
auto model = static_cast<ResourcePackResourceModel*>(page->getModel());
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset);
return page;
}
//: The plural version of 'resource pack'
inline QString resourcesString() const override { return tr("resource packs"); }
//: The singular version of 'resource packs'
inline QString resourceString() const override { return tr("resource pack"); }
bool supportsFiltering() const override { return false; };
QMap<QString, QString> urlHandlers() const override;
inline auto helpPage() const -> QString override { return "resourcepack-platform"; }
protected:
ResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
ResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance, ResourceProviderData p, ResourceAPI* api);
protected slots:
void triggerSearch() override;

View file

@ -57,8 +57,17 @@
namespace ResourceDownload {
ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& baseInstance)
: QWidget(parent), m_baseInstance(baseInstance), m_ui(new Ui::ResourcePage), m_parentDialog(parent), m_fetchProgress(this, false)
ResourcePage::ResourcePage(ResourceDownloadDialog* parent,
BaseInstance& baseInstance,
ResourceDescriptor desc,
ResourceProviderData provider)
: QWidget(parent)
, m_baseInstance(baseInstance)
, m_ui(new Ui::ResourcePage)
, m_parentDialog(parent)
, m_fetchProgress(this, false)
, m_desc(std::move(desc))
, m_provider(std::move(provider))
{
m_ui->setupUi(this);
@ -400,7 +409,7 @@ void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
ResourceFolderModel* baseModel,
QString downloadReason)
{
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
bool isIndexed = m_desc.isIndexed && !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_model->addPack(std::move(pack), ver, baseModel, isIndexed, std::move(downloadReason));
}
@ -488,8 +497,18 @@ void ResourcePage::onResourceToggle(const QModelIndex& index)
}
}
void ResourcePage::openUrl(const QUrl& url)
void ResourcePage::openUrl(const QUrl& _url)
{
auto url = _url;
if (url.scheme().isEmpty()) {
QString query = url.query(QUrl::FullyDecoded);
if (query.startsWith("remoteUrl=")) {
// attempt to resolve url from warning page
query.remove(0, 10);
url = QUrl::fromPercentEncoding(query.toUtf8()); // double decoding is necessary
}
}
// do not allow other url schemes for security reasons
if (!(url.scheme() == "http" || url.scheme() == "https")) {
qWarning() << "Unsupported scheme" << url.scheme();

View file

@ -25,6 +25,24 @@ namespace ResourceDownload {
class ResourceDownloadDialog;
class ResourceModel;
struct ResourceProviderData {
QString displayName;
QIcon icon;
QString id;
QString metaEntryBase;
QString debugName;
};
struct ResourceDescriptor {
QString helpPage;
QString resourceString = QObject::tr("resource");
QString resourcesString = QObject::tr("resources");
bool supportsFiltering = false;
bool isIndexed = true;
QMap<QString, QString> urlHandlers;
};
class ResourcePage : public QWidget, public BasePage {
Q_OBJECT
public:
@ -32,23 +50,23 @@ class ResourcePage : public QWidget, public BasePage {
~ResourcePage() override;
/* Affects what the user sees */
auto displayName() const -> QString override = 0;
auto icon() const -> QIcon override = 0;
auto id() const -> QString override = 0;
auto helpPage() const -> QString override = 0;
bool shouldDisplay() const override = 0;
auto displayName() const -> QString override { return m_provider.displayName; };
auto icon() const -> QIcon override { return m_provider.icon; };
auto id() const -> QString override { return m_provider.id; };
auto helpPage() const -> QString override { return m_desc.helpPage; };
bool shouldDisplay() const override { return true; };
/* Used internally */
virtual auto metaEntryBase() const -> QString = 0;
virtual auto debugName() const -> QString = 0;
virtual auto metaEntryBase() const -> QString { return m_provider.metaEntryBase; };
virtual auto debugName() const -> QString { return m_provider.debugName; };
//: The plural version of 'resource'
virtual QString resourcesString() const { return tr("resources"); }
virtual QString resourcesString() const { return m_desc.resourcesString; }
//: The singular version of 'resources'
virtual QString resourceString() const { return tr("resource"); }
virtual QString resourceString() const { return m_desc.resourceString; }
/* Features this resource's page supports */
virtual bool supportsFiltering() const = 0;
virtual bool supportsFiltering() const { return m_desc.supportsFiltering; };
void retranslate() override;
void openedImpl() override;
@ -65,7 +83,10 @@ class ResourcePage : public QWidget, public BasePage {
auto getModel() const -> ResourceModel* { return m_model; }
protected:
ResourcePage(ResourceDownloadDialog* parent, BaseInstance&);
ResourcePage(ResourceDownloadDialog* parent,
BaseInstance& baseInstance,
ResourceDescriptor desc = {},
ResourceProviderData provider = {});
void addSortings();
@ -100,7 +121,7 @@ class ResourcePage : public QWidget, public BasePage {
void onResourceToggle(const QModelIndex& index);
/** Associates regex expressions to pages in the order they're given in the map. */
virtual QMap<QString, QString> urlHandlers() const = 0;
virtual QMap<QString, QString> urlHandlers() const { return m_desc.urlHandlers; };
virtual void openUrl(const QUrl&);
public:
@ -123,6 +144,9 @@ class ResourcePage : public QWidget, public BasePage {
QSet<int> m_enableQueue;
ResourceDescriptor m_desc;
ResourceProviderData m_provider;
private:
bool m_suppressInitialSearch = false;
};

View file

@ -3,19 +3,59 @@
// SPDX-License-Identifier: GPL-3.0-only
#include "ShaderPackPage.h"
#include "modplatform/ModIndex.h"
#include "ui_ResourcePage.h"
#include "ShaderPackModel.h"
#include "Application.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
#include <QRegularExpression>
namespace ResourceDownload {
ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance) {}
static ResourceDescriptor prepareShaderPackDescriptor()
{
QMap<QString, QString> urlHandlers;
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/shaders\\/([^\\/]+)\\/?"), "modrinth");
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/customization\\/([^\\/]+)\\/?"),
"curseforge");
urlHandlers.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return {
.helpPage = {},
//: The singular version of 'shader packs'
.resourceString = QObject::tr("shader pack"),
//: The plural version of 'shader pack'
.resourcesString = QObject::tr("shader packs"),
.supportsFiltering = false,
.isIndexed = true,
.urlHandlers = urlHandlers,
};
}
ShaderPackResourcePage::ShaderPackResourcePage(ResourceDownloadDialog* dialog,
BaseInstance& instance,
ResourceProviderData p,
ResourceAPI* api)
: ResourcePage(dialog, instance, prepareShaderPackDescriptor(), p)
{
m_model = new ShaderPackResourceModel(instance, api, debugName(), metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_model, &ResourceModel::versionListUpdated, this, &ResourcePage::versionListUpdated);
connect(m_model, &ResourceModel::projectInfoUpdated, this, &ResourcePage::updateUi);
connect(m_model, &QAbstractListModel::modelReset, this, &ResourcePage::modelReset);
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ShaderPackResourcePage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ShaderPackResourcePage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ShaderPackResourcePage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ShaderPackResourcePage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
}
/******** Callbacks to events in the UI (set up in the derived classes) ********/
@ -32,22 +72,4 @@ void ShaderPackResourcePage::triggerSearch()
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
QMap<QString, QString> ShaderPackResourcePage::urlHandlers() const
{
QMap<QString, QString> map;
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/shaders\\/([^\\/]+)\\/?"), "modrinth");
map.insert(QRegularExpression::anchoredPattern(R"((?:www\.)?curseforge\.com\/minecraft\/customization\/([^\/]+)\/?)"), "curseforge");
map.insert(QRegularExpression::anchoredPattern(R"(minecraft\.curseforge\.com\/projects\/([^\/]+)\/?)"), "curseforge");
return map;
}
void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
ModPlatform::IndexedVersion& version,
ResourceFolderModel* baseModel,
QString downloadReason)
{
bool isIndexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
m_model->addPack(pack, version, baseModel, isIndexed, downloadReason);
}
} // namespace ResourceDownload

View file

@ -5,51 +5,16 @@
#pragma once
#include "ui/pages/modplatform/ResourcePage.h"
#include "ui/pages/modplatform/ShaderPackModel.h"
namespace Ui {
class ResourcePage;
}
namespace ResourceDownload {
class ShaderPackDownloadDialog;
class ResourceDownloadDialog;
class ShaderPackResourcePage : public ResourcePage {
Q_OBJECT
public:
template <typename T>
static T* create(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
{
auto page = new T(dialog, instance);
auto* model = static_cast<ShaderPackResourceModel*>(page->getModel());
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset);
return page;
}
//: The plural version of 'shader pack'
QString resourcesString() const override { return tr("shader packs"); }
//: The singular version of 'shader packs'
QString resourceString() const override { return tr("shader pack"); }
bool supportsFiltering() const override { return false; };
void addResourceToPage(ModPlatform::IndexedPack::Ptr /*unused*/,
ModPlatform::IndexedVersion& /*unused*/,
ResourceFolderModel* /*unused*/,
QString downloadReason = "standalone") override;
QMap<QString, QString> urlHandlers() const override;
auto helpPage() const -> QString override { return "shaderpack-platform"; }
protected:
ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
ShaderPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance, ResourceProviderData p, ResourceAPI* api);
protected slots:
void triggerSearch() override;

View file

@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
//
// SPDX-License-Identifier: GPL-3.0-only
#include "TexturePackPage.h"
#include "ui_ResourcePage.h"
#include "TexturePackModel.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
#include <QRegularExpression>
namespace ResourceDownload {
static ResourceDescriptor prepareResourcePackDescriptor()
{
QMap<QString, QString> urlHandlers;
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/resourcepack\\/([^\\/]+)\\/?"), "modrinth");
urlHandlers.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/texture-packs\\/([^\\/]+)\\/?"),
"curseforge");
urlHandlers.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
return {
.helpPage = {},
//: The singular version of 'texture packs'
.resourceString = QObject::tr("texture pack"),
//: The plural version of 'texture pack'
.resourcesString = QObject::tr("texture packs"),
.supportsFiltering = false,
.isIndexed = true,
.urlHandlers = urlHandlers,
};
}
TexturePackResourcePage::TexturePackResourcePage(ResourceDownloadDialog* dialog,
BaseInstance& instance,
ResourceProviderData p,
ResourceAPI* api,
TexturePackResourceModel* model)
: ResourcePage(dialog, instance, prepareResourcePackDescriptor(), p)
{
m_model = model;
if (!m_model) {
m_model = new TexturePackResourceModel(instance, api, debugName(), metaEntryBase());
}
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_model, &ResourceModel::versionListUpdated, this, &ResourcePage::versionListUpdated);
connect(m_model, &ResourceModel::projectInfoUpdated, this, &ResourcePage::updateUi);
connect(m_model, &QAbstractListModel::modelReset, this, &ResourcePage::modelReset);
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &TexturePackResourcePage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TexturePackResourcePage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &TexturePackResourcePage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &TexturePackResourcePage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
}
/******** Callbacks to events in the UI (set up in the derived classes) ********/
void TexturePackResourcePage::triggerSearch()
{
m_ui->packView->selectionModel()->setCurrentIndex({}, QItemSelectionModel::SelectionFlag::ClearAndSelect);
m_ui->packView->clearSelection();
m_ui->packDescription->clear();
m_ui->versionSelectionBox->clear();
updateSelectionButton();
static_cast<ResourcePackResourceModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt());
m_fetchProgress.watch(m_model->activeSearchJob().get());
}
} // namespace ResourceDownload

View file

@ -4,43 +4,25 @@
#pragma once
#include "ui/dialogs/ResourceDownloadDialog.h"
#include "ui/pages/modplatform/ResourcePackPage.h"
#include "ui/pages/modplatform/TexturePackModel.h"
#include "ui_ResourcePage.h"
namespace Ui {
class ResourcePage;
}
#include "ui/pages/modplatform/ResourcePage.h"
namespace ResourceDownload {
class TexturePackDownloadDialog;
class TexturePackResourceModel;
class TexturePackResourcePage : public ResourcePackResourcePage {
class TexturePackResourcePage : public ResourcePage {
Q_OBJECT
public:
template <typename T>
static T* create(TexturePackDownloadDialog* dialog, BaseInstance& instance)
{
auto page = new T(dialog, instance);
auto model = static_cast<TexturePackResourceModel*>(page->getModel());
TexturePackResourcePage(ResourceDownloadDialog* dialog,
BaseInstance& instance,
ResourceProviderData p,
ResourceAPI* api,
TexturePackResourceModel* model = nullptr);
connect(model, &ResourceModel::versionListUpdated, page, &ResourcePage::versionListUpdated);
connect(model, &ResourceModel::projectInfoUpdated, page, &ResourcePage::updateUi);
connect(model, &QAbstractListModel::modelReset, page, &ResourcePage::modelReset);
return page;
}
//: The plural version of 'texture pack'
inline QString resourcesString() const override { return tr("texture packs"); }
//: The singular version of 'texture packs'
inline QString resourceString() const override { return tr("texture pack"); }
protected:
TexturePackResourcePage(TexturePackDownloadDialog* dialog, BaseInstance& instance) : ResourcePackResourcePage(dialog, instance) {}
protected slots:
void triggerSearch() override;
};
} // namespace ResourceDownload

View file

@ -51,14 +51,12 @@
#include "ui/dialogs/NewInstanceDialog.h"
#include "ui/widgets/ProjectItem.h"
static FlameAPI api;
FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget* parent)
: QWidget(parent), m_ui(new Ui::FlamePage), m_dialog(dialog), m_fetch_progress(this, false)
: QWidget(parent), m_ui(new Ui::FlamePage), m_dialog(dialog), m_listModel(new Flame::ListModel(this)), m_fetch_progress(this, false)
{
m_ui->setupUi(this);
m_ui->searchEdit->installEventFilter(this);
m_listModel = new Flame::ListModel(this);
m_ui->packView->setModel(m_listModel);
m_ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
@ -101,18 +99,18 @@ FlamePage::~FlamePage()
bool FlamePage::eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_ui->searchEdit && event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
auto* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return) {
triggerSearch();
keyEvent->accept();
return true;
} else {
if (m_search_timer.isActive())
}
if (m_search_timer.isActive()) {
m_search_timer.stop();
}
m_search_timer.start(350);
}
}
return QWidget::eventFilter(watched, event);
}
@ -171,8 +169,9 @@ void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelInde
m_current->versions = doc;
m_current->versionsLoaded = true;
auto pred = [this](const ModPlatform::IndexedVersion& v) {
if (auto filter = m_filterWidget->getFilter())
if (auto filter = m_filterWidget->getFilter()) {
return !filter->checkModpackFilters(v);
}
return false;
};
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
@ -184,15 +183,16 @@ void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelInde
else
++it;
#endif
for (auto version : m_current->versions) {
for (const auto& version : m_current->versions) {
m_ui->versionSelectionBox->addItem(version.getVersionDisplayString(), QVariant(version.downloadUrl));
}
QVariant current_updated;
current_updated.setValue(m_current);
if (!m_listModel->setData(curr, current_updated, Qt::UserRole))
if (!m_listModel->setData(curr, current_updated, Qt::UserRole)) {
qWarning() << "Failed to cache versions for the current pack!";
}
// TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
if (m_current->versionsLoaded && m_ui->versionSelectionBox->count() < 1) {
@ -200,16 +200,16 @@ void FlamePage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelInde
}
suggestCurrent();
};
callbacks.on_fail = [this](QString reason, int) {
callbacks.on_fail = [this](const QString& reason, int) {
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec();
};
auto netJob = api.getProjectVersions({ m_current, {}, {}, ModPlatform::ResourceType::Modpack }, std::move(callbacks));
auto netJob = FlameAPI().getProjectVersions({ m_current, {}, {}, ModPlatform::ResourceType::Modpack }, std::move(callbacks));
m_job = netJob;
netJob->start();
} else {
for (auto version : m_current->versions) {
for (const auto& version : m_current->versions) {
m_ui->versionSelectionBox->addItem(version.version, QVariant(version.downloadUrl));
}
@ -244,7 +244,7 @@ void FlamePage::suggestCurrent()
m_dialog->setSuggestedPack(m_current->name, new InstanceImportTask(version.downloadUrl, this, std::move(extra_info)));
QString editedLogoName = "curseforge_" + m_current->logoName;
m_listModel->getLogo(m_current->logoName, m_current->logoUrl,
[this, editedLogoName](QString logo) { m_dialog->setSuggestedIconFromFile(logo, editedLogoName); });
[this, editedLogoName](const QString& logo) { m_dialog->setSuggestedIconFromFile(logo, editedLogoName); });
}
void FlamePage::onVersionSelectionChanged(int index)
@ -269,10 +269,11 @@ void FlamePage::updateUi()
QString text = "";
QString name = m_current->name;
if (m_current->websiteUrl.isEmpty())
if (m_current->websiteUrl.isEmpty()) {
text = name;
else
} else {
text = "<a href=\"" + m_current->websiteUrl + "\">" + name + "</a>";
}
if (!m_current->authors.empty()) {
auto authorToStr = [](ModPlatform::ModpackAuthor& author) {
if (author.url.isEmpty()) {
@ -293,16 +294,19 @@ void FlamePage::updateUi()
text += "<br><br>" + tr("External links:") + "<br>";
}
if (!m_current->extraData.issuesUrl.isEmpty())
if (!m_current->extraData.issuesUrl.isEmpty()) {
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(m_current->extraData.issuesUrl) + "<br>";
if (!m_current->extraData.wikiUrl.isEmpty())
}
if (!m_current->extraData.wikiUrl.isEmpty()) {
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(m_current->extraData.wikiUrl) + "<br>";
if (!m_current->extraData.sourceUrl.isEmpty())
}
if (!m_current->extraData.sourceUrl.isEmpty()) {
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(m_current->extraData.sourceUrl) + "<br>";
}
}
text += "<hr>";
text += api.getModDescription(m_current->addonId.toInt()).toUtf8();
text += FlameAPI().getModDescription(m_current->addonId.toInt()).toUtf8();
m_ui->packDescription->setHtml(StringUtils::htmlListPatch(text + m_current->description));
m_ui->packDescription->flush();
@ -319,12 +323,12 @@ void FlamePage::setSearchTerm(QString term)
void FlamePage::createFilterWidget()
{
auto widget = ModFilterWidget::create(nullptr, false);
m_filterWidget.swap(widget);
auto old = m_ui->splitter->replaceWidget(0, m_filterWidget.get());
auto* widget = ModFilterWidget::create(nullptr, false);
m_filterWidget.reset(widget);
auto* old = m_ui->splitter->replaceWidget(0, m_filterWidget.get());
// because we replaced the widget we also need to delete it
if (old) {
delete old;
old->deleteLater();
}
connect(m_ui->filterButton, &QPushButton::clicked, this, [this] { m_filterWidget->setHidden(!m_filterWidget->isHidden()); });
@ -333,7 +337,7 @@ void FlamePage::createFilterWidget()
auto [task, response] = FlameAPI::getCategories(ModPlatform::ResourceType::Modpack);
m_categoriesTask = task;
connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = FlameAPI::loadModCategories(*response);
auto categories = FlameAPI().loadModCategories(*response);
m_filterWidget->setCategories(categories);
});
m_categoriesTask->start();

View file

@ -82,7 +82,7 @@ class FlamePage : public QWidget, public ModpackProviderBasePage {
private slots:
void triggerSearch();
void onSelectionChanged(QModelIndex first, QModelIndex second);
void onSelectionChanged(QModelIndex curr, QModelIndex prev);
void onVersionSelectionChanged(int index);
void createFilterWidget();

View file

@ -4,8 +4,7 @@
#pragma once
#include "ui/pages/modplatform/ModModel.h"
#include "ui/pages/modplatform/flame/FlameResourcePages.h"
#include "ui/pages/modplatform/TexturePackModel.h"
namespace ResourceDownload {
@ -19,9 +18,6 @@ class FlameTexturePackModel : public TexturePackResourceModel {
bool optedOut(const ModPlatform::IndexedVersion& ver) const override;
private:
QString debugName() const override { return Flame::debugName() + " (Model)"; }
QString metaEntryBase() const override { return Flame::metaEntryBase(); }
ResourceAPI::SearchArgs createSearchArguments() override;
ResourceAPI::VersionSearchArgs createVersionsArguments(const QModelIndex&) override;
};

View file

@ -38,221 +38,48 @@
*/
#include "FlameResourcePages.h"
#include <QList>
#include <memory>
#include "modplatform/flame/FlameAPI.h"
#include "../ui_ResourcePage.h"
#include "FlameResourceModels.h"
#include "ui/dialogs/ResourceDownloadDialog.h"
namespace ResourceDownload {
FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ModPage(dialog, instance)
static ResourceProviderData prepareFlame()
{
m_model = new ModModel(instance, new FlameAPI(), Flame::debugName(), Flame::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's contructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &FlameModPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameModPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &FlameModPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &FlameModPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return {
.displayName = Flame::displayName(),
.icon = Flame::icon(),
.id = Flame::id(),
.metaEntryBase = Flame::metaEntryBase(),
.debugName = Flame::debugName(),
};
}
void FlameModPage::openUrl(const QUrl& url)
ShaderPackResourcePage* Flame::createShaderPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
if (url.scheme().isEmpty()) {
QString query = url.query(QUrl::FullyDecoded);
if (query.startsWith("remoteUrl=")) {
// attempt to resolve url from warning page
query.remove(0, 10);
ModPage::openUrl({ QUrl::fromPercentEncoding(query.toUtf8()) }); // double decoding is necessary
return;
}
}
ModPage::openUrl(url);
return new ShaderPackResourcePage(dialog, instance, prepareFlame(), new FlameAPI());
}
FlameResourcePackPage::FlameResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
: ResourcePackResourcePage(dialog, instance)
DataPackResourcePage* Flame::createDataPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
m_model = new ResourcePackResourceModel(instance, new FlameAPI(), Flame::debugName(), Flame::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's contructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &FlameResourcePackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameResourcePackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &FlameResourcePackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &FlameResourcePackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return new DataPackResourcePage(dialog, instance, prepareFlame(), new FlameAPI());
}
void FlameResourcePackPage::openUrl(const QUrl& url)
ResourcePackResourcePage* Flame::createResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
if (url.scheme().isEmpty()) {
QString query = url.query(QUrl::FullyDecoded);
if (query.startsWith("remoteUrl=")) {
// attempt to resolve url from warning page
query.remove(0, 10);
ResourcePackResourcePage::openUrl({ QUrl::fromPercentEncoding(query.toUtf8()) }); // double decoding is necessary
return;
}
}
ResourcePackResourcePage::openUrl(url);
return new ResourcePackResourcePage(dialog, instance, prepareFlame(), new FlameAPI());
}
FlameTexturePackPage::FlameTexturePackPage(TexturePackDownloadDialog* dialog, BaseInstance& instance)
: TexturePackResourcePage(dialog, instance)
TexturePackResourcePage* Flame::createTexturePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
m_model = new FlameTexturePackModel(instance);
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's contructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &FlameTexturePackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameTexturePackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &FlameTexturePackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &FlameTexturePackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return new TexturePackResourcePage(dialog, instance, prepareFlame(), new FlameAPI(), new FlameTexturePackModel(instance));
}
void FlameTexturePackPage::openUrl(const QUrl& url)
ModPage* Flame::createModPage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
if (url.scheme().isEmpty()) {
QString query = url.query(QUrl::FullyDecoded);
if (query.startsWith("remoteUrl=")) {
// attempt to resolve url from warning page
query.remove(0, 10);
ResourcePackResourcePage::openUrl({ QUrl::fromPercentEncoding(query.toUtf8()) }); // double decoding is necessary
return;
}
}
TexturePackResourcePage::openUrl(url);
return new ModPage(dialog, instance, prepareFlame(), new FlameAPI(),
ModFilterWidget::create(&static_cast<MinecraftInstance&>(instance), false));
}
void FlameDataPackPage::openUrl(const QUrl& url)
{
if (url.scheme().isEmpty()) {
QString query = url.query(QUrl::FullyDecoded);
if (query.startsWith("remoteUrl=")) {
// attempt to resolve url from warning page
query.remove(0, 10);
DataPackResourcePage::openUrl({ QUrl::fromPercentEncoding(query.toUtf8()) }); // double decoding is necessary
return;
}
}
DataPackResourcePage::openUrl(url);
}
FlameShaderPackPage::FlameShaderPackPage(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
: ShaderPackResourcePage(dialog, instance)
{
m_model = new ShaderPackResourceModel(instance, new FlameAPI(), Flame::debugName(), Flame::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &FlameShaderPackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameShaderPackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &FlameShaderPackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &FlameShaderPackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
}
FlameDataPackPage::FlameDataPackPage(DataPackDownloadDialog* dialog, BaseInstance& instance) : DataPackResourcePage(dialog, instance)
{
m_model = new DataPackResourceModel(instance, new FlameAPI(), Flame::debugName(), Flame::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &FlameDataPackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameDataPackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &FlameDataPackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &FlameDataPackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
}
void FlameShaderPackPage::openUrl(const QUrl& url)
{
if (url.scheme().isEmpty()) {
QString query = url.query(QUrl::FullyDecoded);
if (query.startsWith("remoteUrl=")) {
// attempt to resolve url from warning page
query.remove(0, 10);
ShaderPackResourcePage::openUrl({ QUrl::fromPercentEncoding(query.toUtf8()) }); // double decoding is necessary
return;
}
}
ShaderPackResourcePage::openUrl(url);
}
// I don't know why, but doing this on the parent class makes it so that
// other mod providers start loading before being selected, at least with
// my Qt, so we need to implement this in every derived class...
auto FlameModPage::shouldDisplay() const -> bool
{
return true;
}
auto FlameResourcePackPage::shouldDisplay() const -> bool
{
return true;
}
auto FlameTexturePackPage::shouldDisplay() const -> bool
{
return true;
}
auto FlameShaderPackPage::shouldDisplay() const -> bool
{
return true;
}
auto FlameDataPackPage::shouldDisplay() const -> bool
{
return true;
}
std::unique_ptr<ModFilterWidget> FlameModPage::createFilterWidget()
{
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_baseInstance), false);
}
void FlameModPage::prepareProviderCategories()
{
auto [task, response] = FlameAPI::getModCategories();
m_categoriesTask = task;
connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = FlameAPI::loadModCategories(*response);
m_filter_widget->setCategories(categories);
});
m_categoriesTask->start();
};
} // namespace ResourceDownload

View file

@ -39,12 +39,10 @@
#pragma once
#include <ui/pages/modplatform/DataPackPage.h>
#include "modplatform/ResourceAPI.h"
#include "ui/pages/modplatform/DataPackPage.h"
#include "ui/pages/modplatform/ModPage.h"
#include "ui/pages/modplatform/ResourcePackPage.h"
#include "ui/pages/modplatform/ResourcePage.h"
#include "ui/pages/modplatform/ShaderPackPage.h"
#include "ui/pages/modplatform/TexturePackPage.h"
@ -71,138 +69,12 @@ static inline QString metaEntryBase()
{
return "FlameMods";
}
ShaderPackResourcePage* createShaderPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
DataPackResourcePage* createDataPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
ResourcePackResourcePage* createResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
TexturePackResourcePage* createTexturePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
ModPage* createModPage(ResourceDownloadDialog* dialog, BaseInstance& instance);
} // namespace Flame
class FlameModPage : public ModPage {
Q_OBJECT
public:
static FlameModPage* create(ModDownloadDialog* dialog, BaseInstance& instance)
{
return ModPage::create<FlameModPage>(dialog, instance);
}
FlameModPage(ModDownloadDialog* dialog, BaseInstance& instance);
~FlameModPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Flame::displayName(); }
inline auto icon() const -> QIcon override { return Flame::icon(); }
inline auto id() const -> QString override { return Flame::id(); }
inline auto debugName() const -> QString override { return Flame::debugName(); }
inline auto metaEntryBase() const -> QString override { return Flame::metaEntryBase(); }
inline auto helpPage() const -> QString override { return "Mod-platform"; }
void openUrl(const QUrl& url) override;
std::unique_ptr<ModFilterWidget> createFilterWidget() override;
protected:
virtual void prepareProviderCategories() override;
private:
Task::Ptr m_categoriesTask;
};
class FlameResourcePackPage : public ResourcePackResourcePage {
Q_OBJECT
public:
static FlameResourcePackPage* create(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
{
return ResourcePackResourcePage::create<FlameResourcePackPage>(dialog, instance);
}
FlameResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance);
~FlameResourcePackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Flame::displayName(); }
inline auto icon() const -> QIcon override { return Flame::icon(); }
inline auto id() const -> QString override { return Flame::id(); }
inline auto debugName() const -> QString override { return Flame::debugName(); }
inline auto metaEntryBase() const -> QString override { return Flame::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
void openUrl(const QUrl& url) override;
};
class FlameTexturePackPage : public TexturePackResourcePage {
Q_OBJECT
public:
static FlameTexturePackPage* create(TexturePackDownloadDialog* dialog, BaseInstance& instance)
{
return TexturePackResourcePage::create<FlameTexturePackPage>(dialog, instance);
}
FlameTexturePackPage(TexturePackDownloadDialog* dialog, BaseInstance& instance);
~FlameTexturePackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Flame::displayName(); }
inline auto icon() const -> QIcon override { return Flame::icon(); }
inline auto id() const -> QString override { return Flame::id(); }
inline auto debugName() const -> QString override { return Flame::debugName(); }
inline auto metaEntryBase() const -> QString override { return Flame::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
void openUrl(const QUrl& url) override;
};
class FlameShaderPackPage : public ShaderPackResourcePage {
Q_OBJECT
public:
static FlameShaderPackPage* create(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
{
return ShaderPackResourcePage::create<FlameShaderPackPage>(dialog, instance);
}
FlameShaderPackPage(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
~FlameShaderPackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Flame::displayName(); }
inline auto icon() const -> QIcon override { return Flame::icon(); }
inline auto id() const -> QString override { return Flame::id(); }
inline auto debugName() const -> QString override { return Flame::debugName(); }
inline auto metaEntryBase() const -> QString override { return Flame::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
void openUrl(const QUrl& url) override;
};
class FlameDataPackPage : public DataPackResourcePage {
Q_OBJECT
public:
static FlameDataPackPage* create(DataPackDownloadDialog* dialog, BaseInstance& instance)
{
return DataPackResourcePage::create<FlameDataPackPage>(dialog, instance);
}
FlameDataPackPage(DataPackDownloadDialog* dialog, BaseInstance& instance);
~FlameDataPackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Flame::displayName(); }
inline auto icon() const -> QIcon override { return Flame::icon(); }
inline auto id() const -> QString override { return Flame::id(); }
inline auto debugName() const -> QString override { return Flame::debugName(); }
inline auto metaEntryBase() const -> QString override { return Flame::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
void openUrl(const QUrl& url) override;
};
} // namespace ResourceDownload

View file

@ -43,28 +43,28 @@
#include "ModrinthModel.h"
#include "BuildConfig.h"
#include "InstanceImportTask.h"
#include "Json.h"
#include "Markdown.h"
#include "StringUtils.h"
#include "ui/widgets/ProjectItem.h"
#include "net/ApiDownload.h"
#include <QComboBox>
#include <QKeyEvent>
#include <QPushButton>
ModrinthPage::ModrinthPage(NewInstanceDialog* dialog, QWidget* parent)
: QWidget(parent), m_ui(new Ui::ModrinthPage), m_dialog(dialog), m_fetch_progress(this, false)
: QWidget(parent)
, m_ui(new Ui::ModrinthPage)
, m_dialog(dialog)
, m_model(new Modrinth::ModpackListModel(this))
, m_fetch_progress(this, false)
{
m_ui->setupUi(this);
createFilterWidget();
m_ui->searchEdit->installEventFilter(this);
m_model = new Modrinth::ModpackListModel(this);
m_ui->packView->setModel(m_model);
m_ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
@ -116,18 +116,18 @@ void ModrinthPage::openedImpl()
bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_ui->searchEdit && event->type() == QEvent::KeyPress) {
auto* keyEvent = reinterpret_cast<QKeyEvent*>(event);
auto* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return) {
this->triggerSearch();
keyEvent->accept();
return true;
} else {
if (m_search_timer.isActive())
}
if (m_search_timer.isActive()) {
m_search_timer.stop();
}
m_search_timer.start(350);
}
}
return QObject::eventFilter(watched, event);
}
@ -150,7 +150,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
ResourceAPI::Callback<ModPlatform::IndexedPack::Ptr> callbacks;
auto id = m_current->addonId;
callbacks.on_fail = [this](QString reason, int) {
callbacks.on_fail = [this](const QString& reason, int) {
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec();
};
callbacks.on_succeed = [this, id, curr](auto& pack) {
@ -161,8 +161,9 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
QVariant current_updated;
current_updated.setValue(pack);
if (!m_model->setData(curr, current_updated, Qt::UserRole))
if (!m_model->setData(curr, current_updated, Qt::UserRole)) {
qWarning() << "Failed to cache extra info for the current pack!";
}
suggestCurrent();
updateUI();
@ -172,8 +173,9 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
m_job->start();
}
} else
} else {
updateUI();
}
if (!m_current->versionsLoaded || m_filterWidget->changed()) {
qDebug() << "Loading modrinth modpack versions";
@ -190,8 +192,9 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
m_current->versions = doc;
m_current->versionsLoaded = true;
auto pred = [this](const ModPlatform::IndexedVersion& v) {
if (auto filter = m_filterWidget->getFilter())
if (auto filter = m_filterWidget->getFilter()) {
return !filter->checkModpackFilters(v);
}
return false;
};
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
@ -210,12 +213,13 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
QVariant current_updated;
current_updated.setValue(m_current);
if (!m_model->setData(curr, current_updated, Qt::UserRole))
if (!m_model->setData(curr, current_updated, Qt::UserRole)) {
qWarning() << "Failed to cache versions for the current pack!";
}
suggestCurrent();
};
callbacks.on_fail = [this](QString reason, int) {
callbacks.on_fail = [this](const QString& reason, int) {
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec();
};
@ -225,13 +229,14 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, [[maybe_unused]] QModelI
m_job2->start();
} else {
for (auto version : m_current->versions) {
if (!version.version.contains(version.version))
for (const auto& version : m_current->versions) {
if (!version.version.contains(version.version)) {
m_ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.version, version.version_number),
QVariant(version.fileId));
else
} else {
m_ui->versionSelectionBox->addItem(version.version, QVariant(version.fileId));
}
}
suggestCurrent();
}
@ -283,15 +288,19 @@ void ModrinthPage::updateUI()
text += "<br><br>" + tr("External links:") + "<br>";
}
if (!m_current->extraData.issuesUrl.isEmpty())
if (!m_current->extraData.issuesUrl.isEmpty()) {
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(m_current->extraData.issuesUrl) + "<br>";
if (!m_current->extraData.wikiUrl.isEmpty())
}
if (!m_current->extraData.wikiUrl.isEmpty()) {
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(m_current->extraData.wikiUrl) + "<br>";
if (!m_current->extraData.sourceUrl.isEmpty())
}
if (!m_current->extraData.sourceUrl.isEmpty()) {
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(m_current->extraData.sourceUrl) + "<br>";
if (!m_current->extraData.discordUrl.isEmpty())
}
if (!m_current->extraData.discordUrl.isEmpty()) {
text += "- " + tr("Discord: <a href=%1>%1</a>").arg(m_current->extraData.discordUrl) + "<br>";
}
}
text += "<hr>";
@ -321,7 +330,7 @@ void ModrinthPage::suggestCurrent()
m_dialog->setSuggestedPack(m_current->name, ver.version, new InstanceImportTask(ver.downloadUrl, this, std::move(extra_info)));
QString editedLogoName = "modrinth_" + m_current->logoName;
m_model->getLogo(m_current->logoName, m_current->logoUrl,
[this, editedLogoName](QString logo) { m_dialog->setSuggestedIconFromFile(logo, editedLogoName); });
[this, editedLogoName](const QString& logo) { m_dialog->setSuggestedIconFromFile(logo, editedLogoName); });
break;
}
@ -361,18 +370,18 @@ QString ModrinthPage::getSerachTerm() const
void ModrinthPage::createFilterWidget()
{
auto widget = ModFilterWidget::create(nullptr, true);
m_filterWidget.swap(widget);
auto old = m_ui->splitter->replaceWidget(0, m_filterWidget.get());
auto* widget = ModFilterWidget::create(nullptr, true);
m_filterWidget.reset(widget);
auto* old = m_ui->splitter->replaceWidget(0, m_filterWidget.get());
// because we replaced the widget we also need to delete it
if (old) {
delete old;
old->deleteLater();
}
connect(m_ui->filterButton, &QPushButton::clicked, this, [this] { m_filterWidget->setHidden(!m_filterWidget->isHidden()); });
connect(m_filterWidget.get(), &ModFilterWidget::filterChanged, this, &ModrinthPage::triggerSearch);
auto [categoriesTask, response] = ModrinthAPI::getModCategories();
auto [categoriesTask, response] = ModrinthAPI().getModCategories();
m_categoriesTask = categoriesTask;
connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = ModrinthAPI::loadCategories(*response, "modpack");

View file

@ -67,8 +67,8 @@ class ModrinthPage : public QWidget, public ModpackProviderBasePage {
QString id() const override { return "modrinth"; }
QString helpPage() const override { return "Modrinth-platform"; }
inline QString debugName() const { return "Modrinth"; }
inline QString metaEntryBase() const { return "ModrinthModpacks"; };
static QString debugName() { return "Modrinth"; }
static QString metaEntryBase() { return "ModrinthModpacks"; };
ModPlatform::IndexedPack::Ptr getCurrent() { return m_current; }
void suggestCurrent();
@ -80,12 +80,12 @@ class ModrinthPage : public QWidget, public ModpackProviderBasePage {
bool eventFilter(QObject* watched, QEvent* event) override;
/** Programatically set the term in the search bar. */
virtual void setSearchTerm(QString) override;
void setSearchTerm(QString) override;
/** Get the current term in the search bar. */
virtual QString getSerachTerm() const override;
QString getSerachTerm() const override;
private slots:
void onSelectionChanged(QModelIndex first, QModelIndex second);
void onSelectionChanged(QModelIndex curr, QModelIndex prev);
void onVersionSelectionChanged(int index);
void triggerSearch();
void createFilterWidget();

View file

@ -37,8 +37,6 @@
*/
#include "ModrinthResourcePages.h"
#include "ui/pages/modplatform/DataPackModel.h"
#include "../ui_ResourcePage.h"
#include "modplatform/modrinth/ModrinthAPI.h"
@ -46,131 +44,40 @@
namespace ResourceDownload {
ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ModPage(dialog, instance)
static ResourceProviderData prepareModrinth()
{
m_model = new ModModel(instance, new ModrinthAPI(), Modrinth::debugName(), Modrinth::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ModrinthModPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthModPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ModrinthModPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModrinthModPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return {
.displayName = Modrinth::displayName(),
.icon = Modrinth::icon(),
.id = Modrinth::id(),
.metaEntryBase = Modrinth::metaEntryBase(),
.debugName = Modrinth::debugName(),
};
}
ModrinthResourcePackPage::ModrinthResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
: ResourcePackResourcePage(dialog, instance)
ShaderPackResourcePage* Modrinth::createShaderPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
m_model = new ResourcePackResourceModel(instance, new ModrinthAPI(), Modrinth::debugName(), Modrinth::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ModrinthResourcePackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthResourcePackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ModrinthResourcePackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModrinthResourcePackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return new ShaderPackResourcePage(dialog, instance, prepareModrinth(), new ModrinthAPI());
}
ModrinthTexturePackPage::ModrinthTexturePackPage(TexturePackDownloadDialog* dialog, BaseInstance& instance)
: TexturePackResourcePage(dialog, instance)
DataPackResourcePage* Modrinth::createDataPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
m_model = new TexturePackResourceModel(instance, new ModrinthAPI(), Modrinth::debugName(), Modrinth::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ModrinthTexturePackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthTexturePackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ModrinthTexturePackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModrinthTexturePackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return new DataPackResourcePage(dialog, instance, prepareModrinth(), new ModrinthAPI());
}
ModrinthShaderPackPage::ModrinthShaderPackPage(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
: ShaderPackResourcePage(dialog, instance)
ResourcePackResourcePage* Modrinth::createResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
m_model = new ShaderPackResourceModel(instance, new ModrinthAPI(), Modrinth::debugName(), Modrinth::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ModrinthShaderPackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthShaderPackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ModrinthShaderPackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModrinthShaderPackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return new ResourcePackResourcePage(dialog, instance, prepareModrinth(), new ModrinthAPI());
}
ModrinthDataPackPage::ModrinthDataPackPage(DataPackDownloadDialog* dialog, BaseInstance& instance) : DataPackResourcePage(dialog, instance)
TexturePackResourcePage* Modrinth::createTexturePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
m_model = new DataPackResourceModel(instance, new ModrinthAPI(), Modrinth::debugName(), Modrinth::metaEntryBase());
m_ui->packView->setModel(m_model);
addSortings();
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
// so it's best not to connect them in the parent's constructor...
connect(m_ui->sortByBox, &QComboBox::currentIndexChanged, this, &ModrinthDataPackPage::triggerSearch);
connect(m_ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthDataPackPage::onSelectionChanged);
connect(m_ui->versionSelectionBox, &QComboBox::currentIndexChanged, this, &ModrinthDataPackPage::onVersionSelectionChanged);
connect(m_ui->resourceSelectionButton, &QPushButton::clicked, this, &ModrinthDataPackPage::onResourceSelected);
m_ui->packDescription->setMetaEntry(metaEntryBase());
return new TexturePackResourcePage(dialog, instance, prepareModrinth(), new ModrinthAPI());
}
// I don't know why, but doing this on the parent class makes it so that
// other mod providers start loading before being selected, at least with
// my Qt, so we need to implement this in every derived class...
auto ModrinthModPage::shouldDisplay() const -> bool
ModPage* Modrinth::createModPage(ResourceDownloadDialog* dialog, BaseInstance& instance)
{
return true;
return new ModPage(dialog, instance, prepareModrinth(), new ModrinthAPI(),
ModFilterWidget::create(&static_cast<MinecraftInstance&>(instance), true));
}
auto ModrinthResourcePackPage::shouldDisplay() const -> bool
{
return true;
}
auto ModrinthTexturePackPage::shouldDisplay() const -> bool
{
return true;
}
auto ModrinthShaderPackPage::shouldDisplay() const -> bool
{
return true;
}
auto ModrinthDataPackPage::shouldDisplay() const -> bool
{
return true;
}
std::unique_ptr<ModFilterWidget> ModrinthModPage::createFilterWidget()
{
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_baseInstance), true);
}
void ModrinthModPage::prepareProviderCategories()
{
auto [categoriesTask, response] = ModrinthAPI::getModCategories();
m_categoriesTask = categoriesTask;
connect(m_categoriesTask.get(), &Task::succeeded, [this, response]() {
auto categories = ModrinthAPI::loadModCategories(*response);
m_filter_widget->setCategories(categories);
});
m_categoriesTask->start();
};
} // namespace ResourceDownload

View file

@ -38,8 +38,6 @@
#pragma once
#include "modplatform/ResourceAPI.h"
#include "ui/pages/modplatform/DataPackPage.h"
#include "ui/pages/modplatform/ModPage.h"
#include "ui/pages/modplatform/ResourcePackPage.h"
@ -69,127 +67,12 @@ static inline QString metaEntryBase()
{
return "ModrinthPacks";
}
ShaderPackResourcePage* createShaderPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
DataPackResourcePage* createDataPackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
ResourcePackResourcePage* createResourcePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
TexturePackResourcePage* createTexturePackResourcePage(ResourceDownloadDialog* dialog, BaseInstance& instance);
ModPage* createModPage(ResourceDownloadDialog* dialog, BaseInstance& instance);
} // namespace Modrinth
class ModrinthModPage : public ModPage {
Q_OBJECT
public:
static ModrinthModPage* create(ModDownloadDialog* dialog, BaseInstance& instance)
{
return ModPage::create<ModrinthModPage>(dialog, instance);
}
ModrinthModPage(ModDownloadDialog* dialog, BaseInstance& instance);
~ModrinthModPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Modrinth::displayName(); }
inline auto icon() const -> QIcon override { return Modrinth::icon(); }
inline auto id() const -> QString override { return Modrinth::id(); }
inline auto debugName() const -> QString override { return Modrinth::debugName(); }
inline auto metaEntryBase() const -> QString override { return Modrinth::metaEntryBase(); }
inline auto helpPage() const -> QString override { return "Mod-platform"; }
std::unique_ptr<ModFilterWidget> createFilterWidget() override;
protected:
virtual void prepareProviderCategories() override;
Task::Ptr m_categoriesTask;
};
class ModrinthResourcePackPage : public ResourcePackResourcePage {
Q_OBJECT
public:
static ModrinthResourcePackPage* create(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
{
return ResourcePackResourcePage::create<ModrinthResourcePackPage>(dialog, instance);
}
ModrinthResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance);
~ModrinthResourcePackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Modrinth::displayName(); }
inline auto icon() const -> QIcon override { return Modrinth::icon(); }
inline auto id() const -> QString override { return Modrinth::id(); }
inline auto debugName() const -> QString override { return Modrinth::debugName(); }
inline auto metaEntryBase() const -> QString override { return Modrinth::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
};
class ModrinthTexturePackPage : public TexturePackResourcePage {
Q_OBJECT
public:
static ModrinthTexturePackPage* create(TexturePackDownloadDialog* dialog, BaseInstance& instance)
{
return TexturePackResourcePage::create<ModrinthTexturePackPage>(dialog, instance);
}
ModrinthTexturePackPage(TexturePackDownloadDialog* dialog, BaseInstance& instance);
~ModrinthTexturePackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Modrinth::displayName(); }
inline auto icon() const -> QIcon override { return Modrinth::icon(); }
inline auto id() const -> QString override { return Modrinth::id(); }
inline auto debugName() const -> QString override { return Modrinth::debugName(); }
inline auto metaEntryBase() const -> QString override { return Modrinth::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
};
class ModrinthShaderPackPage : public ShaderPackResourcePage {
Q_OBJECT
public:
static ModrinthShaderPackPage* create(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
{
return ShaderPackResourcePage::create<ModrinthShaderPackPage>(dialog, instance);
}
ModrinthShaderPackPage(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
~ModrinthShaderPackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Modrinth::displayName(); }
inline auto icon() const -> QIcon override { return Modrinth::icon(); }
inline auto id() const -> QString override { return Modrinth::id(); }
inline auto debugName() const -> QString override { return Modrinth::debugName(); }
inline auto metaEntryBase() const -> QString override { return Modrinth::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
};
class ModrinthDataPackPage : public DataPackResourcePage {
Q_OBJECT
public:
static ModrinthDataPackPage* create(DataPackDownloadDialog* dialog, BaseInstance& instance)
{
return DataPackResourcePage::create<ModrinthDataPackPage>(dialog, instance);
}
ModrinthDataPackPage(DataPackDownloadDialog* dialog, BaseInstance& instance);
~ModrinthDataPackPage() override = default;
bool shouldDisplay() const override;
inline auto displayName() const -> QString override { return Modrinth::displayName(); }
inline auto icon() const -> QIcon override { return Modrinth::icon(); }
inline auto id() const -> QString override { return Modrinth::id(); }
inline auto debugName() const -> QString override { return Modrinth::debugName(); }
inline auto metaEntryBase() const -> QString override { return Modrinth::metaEntryBase(); }
inline auto helpPage() const -> QString override { return ""; }
};
} // namespace ResourceDownload

View file

@ -38,7 +38,6 @@
#include <QComboBox>
#include <QListWidget>
#include <algorithm>
#include <list>
#include "BaseVersionList.h"
#include "Json.h"
#include "Version.h"
@ -50,9 +49,9 @@
#include "Application.h"
#include "minecraft/PackProfile.h"
std::unique_ptr<ModFilterWidget> ModFilterWidget::create(MinecraftInstance* instance, bool extended)
ModFilterWidget* ModFilterWidget::create(MinecraftInstance* instance, bool extended)
{
return std::unique_ptr<ModFilterWidget>(new ModFilterWidget(instance, extended));
return new ModFilterWidget(instance, extended);
}
class VersionBasicModel : public QIdentityProxyModel {

View file

@ -91,7 +91,7 @@ class ModFilterWidget : public QTabWidget {
}
};
static std::unique_ptr<ModFilterWidget> create(MinecraftInstance* instance, bool extended);
static ModFilterWidget* create(MinecraftInstance* instance, bool extended);
virtual ~ModFilterWidget();
auto getFilter() -> std::shared_ptr<Filter>;