Connected filters
Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
@ -27,16 +27,16 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
|
||||
std::optional<std::list<Version>> versions{};
|
||||
auto loaders = profile->getSupportedModLoaders();
|
||||
|
||||
{ // Version filter
|
||||
if (!m_filter->versions.empty())
|
||||
versions = m_filter->versions;
|
||||
if (m_filter->loaders)
|
||||
loaders = m_filter->loaders;
|
||||
}
|
||||
// Version filter
|
||||
if (!m_filter->versions.empty())
|
||||
versions = m_filter->versions;
|
||||
if (m_filter->loaders)
|
||||
loaders = m_filter->loaders;
|
||||
auto side = m_filter->side;
|
||||
|
||||
auto sort = getCurrentSortingMethodByIndex();
|
||||
|
||||
return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, loaders, versions };
|
||||
return { ModPlatform::ResourceType::MOD, m_next_search_offset, m_search_term, sort, loaders, versions, side };
|
||||
}
|
||||
|
||||
ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry)
|
||||
@ -85,4 +85,43 @@ bool ModModel::isPackInstalled(ModPlatform::IndexedPack::Ptr pack) const
|
||||
});
|
||||
}
|
||||
|
||||
bool checkSide(QString filter, QString value)
|
||||
{
|
||||
return filter.isEmpty() || value.isEmpty() || filter == "both" || value == "both" || filter == value;
|
||||
}
|
||||
|
||||
bool checkMcVersions(std::list<Version> filter, QStringList value)
|
||||
{
|
||||
bool valid = false;
|
||||
for (auto mcVersion : filter) {
|
||||
if (value.contains(mcVersion.toString())) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filter.empty() || valid;
|
||||
}
|
||||
|
||||
bool ModModel::checkFilters(ModPlatform::IndexedPack::Ptr pack)
|
||||
{
|
||||
if (!m_filter)
|
||||
return true;
|
||||
return !(m_filter->hideInstalled && isPackInstalled(pack)) && checkSide(m_filter->side, pack->side);
|
||||
}
|
||||
|
||||
bool ModModel::checkVersionFilters(const ModPlatform::IndexedVersion& v)
|
||||
{
|
||||
if (!m_filter)
|
||||
return true;
|
||||
auto loaders = static_cast<MinecraftInstance&>(m_base_instance).getPackProfile()->getSupportedModLoaders();
|
||||
if (m_filter->loaders)
|
||||
loaders = m_filter->loaders;
|
||||
return (!optedOut(v) && // is opted out(aka curseforge download link)
|
||||
(!loaders.has_value() || !v.loaders || loaders.value() & v.loaders) && // loaders
|
||||
checkSide(m_filter->side, v.side) && // side
|
||||
(m_filter->releases.empty() || // releases
|
||||
std::find(m_filter->releases.cbegin(), m_filter->releases.cend(), v.version_type) != m_filter->releases.cend()) &&
|
||||
checkMcVersions(m_filter->versions, v.mcVersion)); // mcVersions
|
||||
}
|
||||
|
||||
} // namespace ResourceDownload
|
||||
|
@ -45,6 +45,9 @@ class ModModel : public ResourceModel {
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override = 0;
|
||||
virtual bool isPackInstalled(ModPlatform::IndexedPack::Ptr) const override;
|
||||
|
||||
virtual bool checkFilters(ModPlatform::IndexedPack::Ptr) override;
|
||||
virtual bool checkVersionFilters(const ModPlatform::IndexedVersion&) override;
|
||||
|
||||
protected:
|
||||
BaseInstance& m_base_instance;
|
||||
|
||||
|
@ -73,6 +73,7 @@ void ModPage::setFilterWidget(unique_qobject_ptr<ModFilterWidget>& widget)
|
||||
|
||||
m_filter = m_filter_widget->getFilter();
|
||||
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterChanged, this, &ResourcePage::updateVersionList);
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterChanged, this,
|
||||
[&] { m_ui->searchButton->setStyleSheet("text-decoration: underline"); });
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterUnchanged, this,
|
||||
@ -110,43 +111,6 @@ QMap<QString, QString> ModPage::urlHandlers() const
|
||||
|
||||
/******** Make changes to the UI ********/
|
||||
|
||||
void ModPage::updateVersionList()
|
||||
{
|
||||
m_ui->versionSelectionBox->clear();
|
||||
auto packProfile = (dynamic_cast<MinecraftInstance&>(m_base_instance)).getPackProfile();
|
||||
|
||||
QString mcVersion = packProfile->getComponentVersion("net.minecraft");
|
||||
auto loaders = packProfile->getSupportedModLoaders();
|
||||
if (m_filter->loaders)
|
||||
loaders = m_filter->loaders;
|
||||
|
||||
auto current_pack = getCurrentPack();
|
||||
if (!current_pack)
|
||||
return;
|
||||
for (int i = 0; i < current_pack->versions.size(); i++) {
|
||||
auto version = current_pack->versions[i];
|
||||
bool valid = false;
|
||||
for (auto& mcVer : m_filter->versions) {
|
||||
if (validateVersion(version, mcVer.toString(), loaders)) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Only add the version if it's valid or using the 'Any' filter, but never if the version is opted out
|
||||
if ((valid || m_filter->versions.empty()) && !optedOut(version)) {
|
||||
auto release_type = version.version_type.isValid() ? QString(" [%1]").arg(version.version_type.toString()) : "";
|
||||
m_ui->versionSelectionBox->addItem(QString("%1%2").arg(version.version, release_type), QVariant(i));
|
||||
}
|
||||
}
|
||||
if (m_ui->versionSelectionBox->count() == 0) {
|
||||
m_ui->versionSelectionBox->addItem(tr("No valid version found!"), QVariant(-1));
|
||||
m_ui->resourceSelectionButton->setText(tr("Cannot select invalid version :("));
|
||||
}
|
||||
|
||||
updateSelectionButton();
|
||||
}
|
||||
|
||||
void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||
ModPlatform::IndexedVersion& version,
|
||||
const std::shared_ptr<ResourceFolderModel> base_model)
|
||||
|
@ -31,7 +31,7 @@ class ModPage : public ResourcePage {
|
||||
auto page = new T(dialog, instance);
|
||||
auto model = static_cast<ModModel*>(page->getModel());
|
||||
|
||||
auto filter_widget = ModFilterWidget::create(&static_cast<MinecraftInstance&>(instance), page);
|
||||
auto filter_widget = page->createFilterWidget();
|
||||
page->setFilterWidget(filter_widget);
|
||||
model->setFilter(page->getFilter());
|
||||
|
||||
@ -52,17 +52,12 @@ class ModPage : public ResourcePage {
|
||||
ModPlatform::IndexedVersion&,
|
||||
const std::shared_ptr<ResourceFolderModel>) override;
|
||||
|
||||
virtual auto validateVersion(ModPlatform::IndexedVersion& ver,
|
||||
QString mineVer,
|
||||
std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const -> bool = 0;
|
||||
virtual unique_qobject_ptr<ModFilterWidget> createFilterWidget() = 0;
|
||||
|
||||
[[nodiscard]] bool supportsFiltering() const override { return true; };
|
||||
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
||||
void setFilterWidget(unique_qobject_ptr<ModFilterWidget>&);
|
||||
|
||||
public slots:
|
||||
void updateVersionList() override;
|
||||
|
||||
protected:
|
||||
ModPage(ModDownloadDialog* dialog, BaseInstance& instance);
|
||||
|
||||
|
@ -399,12 +399,17 @@ void ResourceModel::searchRequestSucceeded(QJsonDocument& doc)
|
||||
m_search_state = SearchState::CanFetchMore;
|
||||
}
|
||||
|
||||
QList<ModPlatform::IndexedPack::Ptr> filteredNewList;
|
||||
for (auto p : newList)
|
||||
if (checkFilters(p))
|
||||
filteredNewList << p;
|
||||
|
||||
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
||||
if (newList.size() == 0)
|
||||
if (filteredNewList.size() == 0)
|
||||
return;
|
||||
|
||||
beginInsertRows(QModelIndex(), m_packs.size(), m_packs.size() + newList.size() - 1);
|
||||
m_packs.append(newList);
|
||||
beginInsertRows(QModelIndex(), m_packs.size(), m_packs.size() + filteredNewList.size() - 1);
|
||||
m_packs.append(filteredNewList);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
@ -547,4 +552,8 @@ void ResourceModel::removePack(const QString& rem)
|
||||
ver.is_currently_selected = false;
|
||||
}
|
||||
|
||||
bool ResourceModel::checkVersionFilters(const ModPlatform::IndexedVersion& v)
|
||||
{
|
||||
return (!optedOut(v));
|
||||
}
|
||||
} // namespace ResourceDownload
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "QObjectPtr.h"
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
@ -55,6 +56,16 @@ class ResourceModel : public QAbstractListModel {
|
||||
|
||||
[[nodiscard]] auto getSortingMethods() const { return m_api->getSortingMethods(); }
|
||||
|
||||
/** Whether the version is opted out or not. Currently only makes sense in CF. */
|
||||
virtual bool optedOut(const ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
Q_UNUSED(ver);
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual bool checkFilters(ModPlatform::IndexedPack::Ptr) { return true; }
|
||||
virtual bool checkVersionFilters(const ModPlatform::IndexedVersion&);
|
||||
|
||||
public slots:
|
||||
void fetchMore(const QModelIndex& parent) override;
|
||||
// NOTE: Can't use [[nodiscard]] here because of https://bugreports.qt.io/browse/QTBUG-58628 on Qt 5.12
|
||||
|
@ -263,7 +263,7 @@ void ResourcePage::updateVersionList()
|
||||
if (current_pack)
|
||||
for (int i = 0; i < current_pack->versions.size(); i++) {
|
||||
auto& version = current_pack->versions[i];
|
||||
if (optedOut(version))
|
||||
if (!m_model->checkVersionFilters(version))
|
||||
continue;
|
||||
|
||||
auto release_type = current_pack->versions[i].version_type.isValid()
|
||||
|
@ -96,13 +96,6 @@ class ResourcePage : public QWidget, public BasePage {
|
||||
virtual QMap<QString, QString> urlHandlers() const = 0;
|
||||
virtual void openUrl(const QUrl&);
|
||||
|
||||
/** Whether the version is opted out or not. Currently only makes sense in CF. */
|
||||
virtual bool optedOut(ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
Q_UNUSED(ver);
|
||||
return false;
|
||||
};
|
||||
|
||||
public:
|
||||
BaseInstance& m_base_instance;
|
||||
|
||||
|
@ -12,6 +12,11 @@
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
static bool isOptedOut(const ModPlatform::IndexedVersion& ver)
|
||||
{
|
||||
return ver.downloadUrl.isEmpty();
|
||||
}
|
||||
|
||||
FlameModModel::FlameModModel(BaseInstance& base) : ModModel(base, new FlameAPI) {}
|
||||
|
||||
void FlameModModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
@ -35,6 +40,11 @@ auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJs
|
||||
return FlameMod::loadDependencyVersions(m, arr, &m_base_instance);
|
||||
}
|
||||
|
||||
bool FlameModModel::optedOut(const ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
auto FlameModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return Json::ensureArray(obj.object(), "data");
|
||||
@ -58,6 +68,11 @@ void FlameResourcePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m
|
||||
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
|
||||
}
|
||||
|
||||
bool FlameResourcePackModel::optedOut(const ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
auto FlameResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return Json::ensureArray(obj.object(), "data");
|
||||
@ -117,6 +132,11 @@ ResourceAPI::VersionSearchArgs FlameTexturePackModel::createVersionsArguments(QM
|
||||
return args;
|
||||
}
|
||||
|
||||
bool FlameTexturePackModel::optedOut(const ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
auto FlameTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return Json::ensureArray(obj.object(), "data");
|
||||
@ -140,6 +160,11 @@ void FlameShaderPackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m,
|
||||
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
|
||||
}
|
||||
|
||||
bool FlameShaderPackModel::optedOut(const ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
auto FlameShaderPackModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return Json::ensureArray(obj.object(), "data");
|
||||
|
@ -17,6 +17,8 @@ class FlameModModel : public ModModel {
|
||||
FlameModModel(BaseInstance&);
|
||||
~FlameModModel() override = default;
|
||||
|
||||
bool optedOut(const ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] QString debugName() const override { return Flame::debugName() + " (Model)"; }
|
||||
[[nodiscard]] QString metaEntryBase() const override { return Flame::metaEntryBase(); }
|
||||
@ -36,6 +38,8 @@ class FlameResourcePackModel : public ResourcePackResourceModel {
|
||||
FlameResourcePackModel(const BaseInstance&);
|
||||
~FlameResourcePackModel() override = default;
|
||||
|
||||
bool optedOut(const ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] QString debugName() const override { return Flame::debugName() + " (Model)"; }
|
||||
[[nodiscard]] QString metaEntryBase() const override { return Flame::metaEntryBase(); }
|
||||
@ -54,6 +58,8 @@ class FlameTexturePackModel : public TexturePackResourceModel {
|
||||
FlameTexturePackModel(const BaseInstance&);
|
||||
~FlameTexturePackModel() override = default;
|
||||
|
||||
bool optedOut(const ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] QString debugName() const override { return Flame::debugName() + " (Model)"; }
|
||||
[[nodiscard]] QString metaEntryBase() const override { return Flame::metaEntryBase(); }
|
||||
@ -75,6 +81,8 @@ class FlameShaderPackModel : public ShaderPackResourceModel {
|
||||
FlameShaderPackModel(const BaseInstance&);
|
||||
~FlameShaderPackModel() override = default;
|
||||
|
||||
bool optedOut(const ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] QString debugName() const override { return Flame::debugName() + " (Model)"; }
|
||||
[[nodiscard]] QString metaEntryBase() const override { return Flame::metaEntryBase(); }
|
||||
|
@ -44,11 +44,6 @@
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
static bool isOptedOut(ModPlatform::IndexedVersion const& ver)
|
||||
{
|
||||
return ver.downloadUrl.isEmpty();
|
||||
}
|
||||
|
||||
FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ModPage(dialog, instance)
|
||||
{
|
||||
m_model = new FlameModModel(instance);
|
||||
@ -66,19 +61,6 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance& instance) :
|
||||
m_ui->packDescription->setMetaEntry(metaEntryBase());
|
||||
}
|
||||
|
||||
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver,
|
||||
QString mineVer,
|
||||
std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
|
||||
{
|
||||
return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty() &&
|
||||
(!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
|
||||
}
|
||||
|
||||
bool FlameModPage::optedOut(ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
void FlameModPage::openUrl(const QUrl& url)
|
||||
{
|
||||
if (url.scheme().isEmpty()) {
|
||||
@ -113,11 +95,6 @@ FlameResourcePackPage::FlameResourcePackPage(ResourcePackDownloadDialog* dialog,
|
||||
m_ui->packDescription->setMetaEntry(metaEntryBase());
|
||||
}
|
||||
|
||||
bool FlameResourcePackPage::optedOut(ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
void FlameResourcePackPage::openUrl(const QUrl& url)
|
||||
{
|
||||
if (url.scheme().isEmpty()) {
|
||||
@ -152,11 +129,6 @@ FlameTexturePackPage::FlameTexturePackPage(TexturePackDownloadDialog* dialog, Ba
|
||||
m_ui->packDescription->setMetaEntry(metaEntryBase());
|
||||
}
|
||||
|
||||
bool FlameTexturePackPage::optedOut(ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
void FlameTexturePackPage::openUrl(const QUrl& url)
|
||||
{
|
||||
if (url.scheme().isEmpty()) {
|
||||
@ -191,11 +163,6 @@ FlameShaderPackPage::FlameShaderPackPage(ShaderPackDownloadDialog* dialog, BaseI
|
||||
m_ui->packDescription->setMetaEntry(metaEntryBase());
|
||||
}
|
||||
|
||||
bool FlameShaderPackPage::optedOut(ModPlatform::IndexedVersion& ver) const
|
||||
{
|
||||
return isOptedOut(ver);
|
||||
}
|
||||
|
||||
void FlameShaderPackPage::openUrl(const QUrl& url)
|
||||
{
|
||||
if (url.scheme().isEmpty()) {
|
||||
@ -232,4 +199,9 @@ auto FlameShaderPackPage::shouldDisplay() const -> bool
|
||||
return true;
|
||||
}
|
||||
|
||||
unique_qobject_ptr<ModFilterWidget> FlameModPage::createFilterWidget()
|
||||
{
|
||||
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_base_instance), false, this);
|
||||
}
|
||||
|
||||
} // namespace ResourceDownload
|
||||
|
@ -94,12 +94,8 @@ class FlameModPage : public ModPage {
|
||||
|
||||
[[nodiscard]] inline auto helpPage() const -> QString override { return "Mod-platform"; }
|
||||
|
||||
bool validateVersion(ModPlatform::IndexedVersion& ver,
|
||||
QString mineVer,
|
||||
std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const override;
|
||||
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
void openUrl(const QUrl& url) override;
|
||||
unique_qobject_ptr<ModFilterWidget> createFilterWidget() override;
|
||||
};
|
||||
|
||||
class FlameResourcePackPage : public ResourcePackResourcePage {
|
||||
@ -124,8 +120,6 @@ class FlameResourcePackPage : public ResourcePackResourcePage {
|
||||
|
||||
[[nodiscard]] inline auto helpPage() const -> QString override { return ""; }
|
||||
|
||||
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
void openUrl(const QUrl& url) override;
|
||||
};
|
||||
|
||||
@ -151,8 +145,6 @@ class FlameTexturePackPage : public TexturePackResourcePage {
|
||||
|
||||
[[nodiscard]] inline auto helpPage() const -> QString override { return ""; }
|
||||
|
||||
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
void openUrl(const QUrl& url) override;
|
||||
};
|
||||
|
||||
@ -178,8 +170,6 @@ class FlameShaderPackPage : public ShaderPackResourcePage {
|
||||
|
||||
[[nodiscard]] inline auto helpPage() const -> QString override { return ""; }
|
||||
|
||||
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
void openUrl(const QUrl& url) override;
|
||||
};
|
||||
|
||||
|
@ -63,13 +63,6 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance& instan
|
||||
m_ui->packDescription->setMetaEntry(metaEntryBase());
|
||||
}
|
||||
|
||||
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver,
|
||||
QString mineVer,
|
||||
std::optional<ModPlatform::ModLoaderTypes> loaders) const -> bool
|
||||
{
|
||||
return ver.mcVersion.contains(mineVer) && (!loaders.has_value() || !ver.loaders || loaders.value() & ver.loaders);
|
||||
}
|
||||
|
||||
ModrinthResourcePackPage::ModrinthResourcePackPage(ResourcePackDownloadDialog* dialog, BaseInstance& instance)
|
||||
: ResourcePackResourcePage(dialog, instance)
|
||||
{
|
||||
@ -144,4 +137,8 @@ auto ModrinthShaderPackPage::shouldDisplay() const -> bool
|
||||
return true;
|
||||
}
|
||||
|
||||
unique_qobject_ptr<ModFilterWidget> ModrinthModPage::createFilterWidget()
|
||||
{
|
||||
return ModFilterWidget::create(&static_cast<MinecraftInstance&>(m_base_instance), true, this);
|
||||
}
|
||||
} // namespace ResourceDownload
|
||||
|
@ -93,8 +93,7 @@ class ModrinthModPage : public ModPage {
|
||||
|
||||
[[nodiscard]] inline auto helpPage() const -> QString override { return "Mod-platform"; }
|
||||
|
||||
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ModPlatform::ModLoaderTypes> loaders = {}) const
|
||||
-> bool override;
|
||||
unique_qobject_ptr<ModFilterWidget> createFilterWidget() override;
|
||||
};
|
||||
|
||||
class ModrinthResourcePackPage : public ResourcePackResourcePage {
|
||||
|
Reference in New Issue
Block a user