remove extra encapsulations

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2026-02-06 23:17:16 +02:00
parent 323c25d83b
commit e0b8d6e0fc
No known key found for this signature in database
GPG key ID: 55EF5DA53DB36318
28 changed files with 517 additions and 925 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

@ -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);
}
@ -84,7 +83,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 }) {
@ -95,7 +94,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
@ -104,22 +103,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('&');
}
@ -129,8 +133,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())) {
@ -157,7 +162,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();
static QList<ModPlatform::Category> loadCategories(const QByteArray& response, const QString& projectType);
static QList<ModPlatform::Category> loadModCategories(const QByteArray& response);
std::pair<Task::Ptr, QByteArray*> getModCategories() override;
static QList<ModPlatform::Category> loadCategories(const QByteArray& response, QString projectType);
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

@ -308,12 +308,12 @@ QList<BasePage*> ModDownloadDialog::getPages()
auto loaders = static_cast<MinecraftInstance*>(m_instance)->getPackProfile()->getSupportedModLoaders().value();
if (ModrinthAPI::validateModLoaders(loaders)) {
auto* page = ModrinthModPage::create(this, *m_instance);
auto* page = Modrinth::createModPage(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);
auto* page = Flame::createModPage(this, *m_instance);
page->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(page);
}
@ -356,11 +356,11 @@ QList<BasePage*> ResourcePackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthResourcePackPage::create(this, *m_instance);
auto* modrinthPage = Modrinth::createResourcePackResourcePage(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameResourcePackPage::create(this, *m_instance);
auto* flamePage = Flame::createResourcePackResourcePage(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
@ -388,11 +388,11 @@ QList<BasePage*> TexturePackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthTexturePackPage::create(this, *m_instance);
auto* modrinthPage =Modrinth::createTexturePackResourcePage(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameTexturePackPage::create(this, *m_instance);
auto* flamePage = Flame::createTexturePackResourcePage(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
@ -419,11 +419,11 @@ ShaderPackDownloadDialog::ShaderPackDownloadDialog(QWidget* parent,
QList<BasePage*> ShaderPackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthShaderPackPage::create(this, *m_instance);
auto* modrinthPage = Modrinth::createShaderPackResourcePage(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameShaderPackPage::create(this, *m_instance);
auto* flamePage = Flame::createShaderPackResourcePage(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}
@ -467,11 +467,11 @@ DataPackDownloadDialog::DataPackDownloadDialog(QWidget* parent,
QList<BasePage*> DataPackDownloadDialog::getPages()
{
QList<BasePage*> pages;
auto* modrinthPage = ModrinthDataPackPage::create(this, *m_instance);
auto* modrinthPage =Modrinth::createDataPackResourcePage(this, *m_instance);
modrinthPage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(modrinthPage);
if (APPLICATION->capabilities() & Application::SupportsFlame) {
auto* flamePage = FlameDataPackPage::create(this, *m_instance);
auto* flamePage = Flame::createDataPackResourcePage(this, *m_instance);
flamePage->setSuppressInitialSearch(m_suppressInitialSearch);
pages.append(flamePage);
}

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(DataPackDownloadDialog* 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(DataPackDownloadDialog* dialog, BaseInstance& instance, ResourceProviderData p, ResourceAPI* api);
protected slots:
void triggerSearch() override;

View file

@ -40,38 +40,75 @@
#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(ModDownloadDialog* 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 +137,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,16 +6,10 @@
#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;
@ -25,45 +19,13 @@ 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(ModDownloadDialog* 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 +34,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(ShaderPackDownloadDialog* 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,11 +5,6 @@
#pragma once
#include "ui/pages/modplatform/ResourcePage.h"
#include "ui/pages/modplatform/ShaderPackModel.h"
namespace Ui {
class ResourcePage;
}
namespace ResourceDownload {
@ -19,37 +14,7 @@ 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(ShaderPackDownloadDialog* 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(TexturePackDownloadDialog* 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(TexturePackDownloadDialog* 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,17 +99,17 @@ 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())
m_search_timer.stop();
m_search_timer.start(350);
}
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(ShaderPackDownloadDialog* 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(DataPackDownloadDialog* 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(ResourcePackDownloadDialog* 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(TexturePackDownloadDialog* 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(ModDownloadDialog* 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(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
DataPackResourcePage* createDataPackResourcePage(DataPackDownloadDialog* dialog, BaseInstance& instance);
ResourcePackResourcePage* createResourcePackResourcePage(ResourcePackDownloadDialog* dialog, BaseInstance& instance);
TexturePackResourcePage* createTexturePackResourcePage(TexturePackDownloadDialog* dialog, BaseInstance& instance);
ModPage* createModPage(ModDownloadDialog* 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,17 +116,17 @@ 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())
m_search_timer.stop();
m_search_timer.start(350);
}
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,12 +229,13 @@ 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,14 +288,18 @@ 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(ShaderPackDownloadDialog* 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(DataPackDownloadDialog* 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(ResourcePackDownloadDialog* 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(TexturePackDownloadDialog* 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(ModDownloadDialog* 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(ShaderPackDownloadDialog* dialog, BaseInstance& instance);
DataPackResourcePage* createDataPackResourcePage(DataPackDownloadDialog* dialog, BaseInstance& instance);
ResourcePackResourcePage* createResourcePackResourcePage(ResourcePackDownloadDialog* dialog, BaseInstance& instance);
TexturePackResourcePage* createTexturePackResourcePage(TexturePackDownloadDialog* dialog, BaseInstance& instance);
ModPage* createModPage(ModDownloadDialog* 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>;