mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-19 17:39:50 -04:00
impl filtering by tags
This commit is contained in:
parent
a7a4dd9a91
commit
730729ccd5
13 changed files with 242 additions and 99 deletions
|
@ -5,6 +5,7 @@
|
|||
#include <Geode/ui/MDPopup.hpp>
|
||||
#include <Geode/utils/web.hpp>
|
||||
#include <server/Server.hpp>
|
||||
#include "mods/GeodeStyle.hpp"
|
||||
|
||||
void geode::openModsList() {
|
||||
ModsLayer::scene();
|
||||
|
@ -98,9 +99,7 @@ protected:
|
|||
}
|
||||
// Asynchronously fetch from server
|
||||
else {
|
||||
this->setSprite(CCSprite::create("loadingCircle.png"));
|
||||
static_cast<CCSprite*>(m_sprite)->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
m_sprite->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
|
||||
this->setSprite(createLoadingCircle(25));
|
||||
m_listener.setFilter(server::ServerResultCache<&server::getModLogo>::shared().get(id).listen());
|
||||
}
|
||||
|
||||
|
|
|
@ -63,6 +63,21 @@ GeodeSquareSprite* GeodeSquareSprite::createWithSpriteFrameName(const char* top,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
CCNode* createLoadingCircle(float sideLength, const char* id) {
|
||||
auto spinnerContainer = CCNode::create();
|
||||
spinnerContainer->setContentSize({ sideLength, sideLength });
|
||||
spinnerContainer->setID(id);
|
||||
spinnerContainer->setAnchorPoint({ .5f, .5f });
|
||||
|
||||
auto spinner = CCSprite::create("loadingCircle.png");
|
||||
spinner->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
spinner->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
|
||||
limitNodeSize(spinner, spinnerContainer->getContentSize(), 1.f, .1f);
|
||||
spinnerContainer->addChildAtPosition(spinner, Anchor::Center);
|
||||
|
||||
return spinnerContainer;
|
||||
}
|
||||
|
||||
IconButtonSprite* createGeodeButton(CCNode* icon, std::string const& text, std::string const& bg) {
|
||||
return IconButtonSprite::create(bg.c_str(), icon, text.c_str(), "bigFont.fnt");
|
||||
}
|
||||
|
@ -89,10 +104,17 @@ CircleButtonSprite* createGeodeCircleButton(const char* topFrameName) {
|
|||
return CircleButtonSprite::createWithSpriteFrameName(topFrameName, 1.f, CircleBaseColor::DarkPurple);
|
||||
}
|
||||
|
||||
ButtonSprite* createGeodeTagLabel(std::string const& text, ccColor3B color, ccColor3B bg) {
|
||||
ButtonSprite* createGeodeTagLabel(std::string const& text, std::optional<std::pair<ccColor3B, ccColor3B>> const& color) {
|
||||
auto label = ButtonSprite::create(text.c_str(), "bigFont.fnt", "white-square.png"_spr, .8f);
|
||||
label->m_label->setColor(color);
|
||||
label->m_BGSprite->setColor(bg);
|
||||
if (color) {
|
||||
label->m_label->setColor(color->first);
|
||||
label->m_BGSprite->setColor(color->second);
|
||||
}
|
||||
else {
|
||||
auto def = geodeTagColor(text);
|
||||
label->m_label->setColor(def.first);
|
||||
label->m_BGSprite->setColor(def.second);
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ protected:
|
|||
|
||||
// Replace the close button with a Geode style one
|
||||
auto spr = CircleButtonSprite::createWithSpriteFrameName(
|
||||
"close.png"_spr, 1.f,
|
||||
"close.png"_spr, .85f,
|
||||
(altBG ? CircleBaseColor::DarkAqua : CircleBaseColor::DarkPurple)
|
||||
);
|
||||
Popup<Args...>::m_closeBtn->setNormalImage(spr);
|
||||
|
@ -48,13 +48,15 @@ public:
|
|||
static GeodeSquareSprite* createWithSpriteFrameName(const char* top, bool* state = nullptr);
|
||||
};
|
||||
|
||||
CCNode* createLoadingCircle(float sideLength, const char* id = "loading-spinner");
|
||||
|
||||
IconButtonSprite* createGeodeButton(CCNode* icon, std::string const& text, std::string const& bg = "GE_button_05.png"_spr);
|
||||
CCNode* createGeodeButton(CCNode* icon, float width, std::string const& text, std::string const& bg = "GE_button_05.png"_spr);
|
||||
ButtonSprite* createGeodeButton(std::string const& text, std::string const& bg = "GE_button_05.png"_spr);
|
||||
|
||||
CircleButtonSprite* createGeodeCircleButton(const char* topFrameName);
|
||||
|
||||
ButtonSprite* createGeodeTagLabel(std::string const& text, ccColor3B color, ccColor3B bg);
|
||||
ButtonSprite* createGeodeTagLabel(std::string const& text, std::optional<std::pair<ccColor3B, ccColor3B>> const& color = std::nullopt);
|
||||
std::pair<ccColor3B, ccColor3B> geodeTagColor(std::string_view const& text);
|
||||
|
||||
class GeodeTabSprite : public CCNode {
|
||||
|
|
|
@ -68,8 +68,10 @@ bool ModItem::init(ModSource&& source) {
|
|||
|
||||
m_restartRequiredLabel = createGeodeTagLabel(
|
||||
"Restart Required",
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)),
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr))
|
||||
{{
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)),
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr))
|
||||
}}
|
||||
);
|
||||
m_restartRequiredLabel->setLayoutOptions(AxisLayoutOptions::create()->setMaxScale(.75f));
|
||||
m_infoContainer->addChild(m_restartRequiredLabel);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "ModList.hpp"
|
||||
#include <Geode/utils/ColorProvider.hpp>
|
||||
#include "../popups/TagsPopup.hpp"
|
||||
#include "../popups/FiltersPopup.hpp"
|
||||
#include "../GeodeStyle.hpp"
|
||||
#include "../ModsLayer.hpp"
|
||||
|
||||
|
@ -218,9 +218,7 @@ bool ModList::init(ModListSource* src, CCSize const& size) {
|
|||
m_statusDetails->setAlignment(kCCTextAlignmentCenter);
|
||||
m_statusContainer->addChild(m_statusDetails);
|
||||
|
||||
m_statusLoadingCircle = CCSprite::create("loadingCircle.png");
|
||||
m_statusLoadingCircle->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
m_statusLoadingCircle->setScale(.6f);
|
||||
m_statusLoadingCircle = createLoadingCircle(50);
|
||||
m_statusContainer->addChild(m_statusLoadingCircle);
|
||||
|
||||
m_statusLoadingBar = Slider::create(this, nullptr);
|
||||
|
@ -452,10 +450,6 @@ void ModList::showStatus(ModListStatus status, std::string const& message, std::
|
|||
m_statusLoadingCircle->setVisible(std::holds_alternative<ModListUnkProgressStatus>(status));
|
||||
m_statusLoadingBar->setVisible(std::holds_alternative<ModListProgressStatus>(status));
|
||||
|
||||
// The loading circle action gets stopped for some reason so just reactivate it
|
||||
if (m_statusLoadingCircle->isVisible()) {
|
||||
m_statusLoadingCircle->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
|
||||
}
|
||||
// Update progress bar
|
||||
if (auto per = std::get_if<ModListProgressStatus>(&status)) {
|
||||
m_statusLoadingBar->setValue(per->percentage / 100.f);
|
||||
|
@ -467,7 +461,7 @@ void ModList::showStatus(ModListStatus status, std::string const& message, std::
|
|||
}
|
||||
|
||||
void ModList::onFilters(CCObject*) {
|
||||
TagsPopup::create(m_source)->show();
|
||||
FiltersPopup::create(m_source)->show();
|
||||
}
|
||||
|
||||
void ModList::onClearFilters(CCObject*) {
|
||||
|
|
|
@ -25,7 +25,7 @@ protected:
|
|||
CCLabelBMFont* m_statusTitle;
|
||||
SimpleTextArea* m_statusDetails;
|
||||
CCMenuItemSpriteExtra* m_statusDetailsBtn;
|
||||
CCSprite* m_statusLoadingCircle;
|
||||
CCNode* m_statusLoadingCircle;
|
||||
Slider* m_statusLoadingBar;
|
||||
ModListSource::PageLoadEventListener m_listener;
|
||||
CCMenuItemSpriteExtra* m_pagePrevBtn;
|
||||
|
|
126
loader/src/ui/mods/popups/FiltersPopup.cpp
Normal file
126
loader/src/ui/mods/popups/FiltersPopup.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include "FiltersPopup.hpp"
|
||||
|
||||
bool FiltersPopup::setup(ModListSource* src) {
|
||||
m_noElasticity = true;
|
||||
m_source = src;
|
||||
m_selectedTags = src->getModTags();
|
||||
|
||||
this->setTitle("Select Filters");
|
||||
|
||||
auto tagsContainer = CCNode::create();
|
||||
tagsContainer->setContentSize(ccp(220, 80));
|
||||
tagsContainer->setAnchorPoint({ .5f, .5f });
|
||||
|
||||
auto tagsBG = CCScale9Sprite::create("square02b_001.png");
|
||||
tagsBG->setColor({ 0, 0, 0 });
|
||||
tagsBG->setOpacity(75);
|
||||
tagsBG->setScale(.3f);
|
||||
tagsBG->setContentSize(tagsContainer->getContentSize() / tagsBG->getScale());
|
||||
tagsContainer->addChildAtPosition(tagsBG, Anchor::Center);
|
||||
|
||||
m_tagsMenu = CCMenu::create();
|
||||
m_tagsMenu->setContentSize(tagsContainer->getContentSize() - ccp(10, 10));
|
||||
m_tagsMenu->addChild(createLoadingCircle(40));
|
||||
m_tagsMenu->setLayout(
|
||||
RowLayout::create()
|
||||
->setDefaultScaleLimits(.1f, 1.f)
|
||||
->setGrowCrossAxis(true)
|
||||
->setCrossAxisOverflow(false)
|
||||
->setAxisAlignment(AxisAlignment::Center)
|
||||
->setCrossAxisAlignment(AxisAlignment::Center)
|
||||
);
|
||||
tagsContainer->addChildAtPosition(m_tagsMenu, Anchor::Center);
|
||||
|
||||
auto tagsResetMenu = CCMenu::create();
|
||||
tagsResetMenu->setAnchorPoint({ .5f, 1 });
|
||||
tagsResetMenu->setContentWidth(tagsContainer->getContentWidth());
|
||||
|
||||
auto resetSpr = createGeodeButton("Reset Tags");
|
||||
auto resetBtn = CCMenuItemSpriteExtra::create(
|
||||
resetSpr, this, menu_selector(FiltersPopup::onResetTags)
|
||||
);
|
||||
tagsResetMenu->addChild(resetBtn);
|
||||
|
||||
tagsResetMenu->setLayout(
|
||||
RowLayout::create()
|
||||
->setDefaultScaleLimits(.1f, .5f)
|
||||
->setAxisAlignment(AxisAlignment::End)
|
||||
->setAxisReverse(true)
|
||||
);
|
||||
tagsContainer->addChildAtPosition(tagsResetMenu, Anchor::Bottom, ccp(0, -2));
|
||||
|
||||
m_mainLayer->addChildAtPosition(tagsContainer, Anchor::Center);
|
||||
|
||||
m_tagsListener.bind(this, &FiltersPopup::onLoadTags);
|
||||
m_tagsListener.setFilter(server::ServerResultCache<&server::getTags>::shared().get().listen());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FiltersPopup::onLoadTags(PromiseEvent<std::unordered_set<std::string>, server::ServerError>* event) {
|
||||
if (auto tags = event->getResolve()) {
|
||||
m_tagsMenu->removeAllChildren();
|
||||
for (auto& tag : *tags) {
|
||||
auto offSpr = createGeodeTagLabel(tag);
|
||||
offSpr->m_BGSprite->setOpacity(105);
|
||||
offSpr->m_label->setOpacity(105);
|
||||
auto onSpr = createGeodeTagLabel(tag);
|
||||
auto btn = CCMenuItemToggler::create(
|
||||
offSpr, onSpr, this, menu_selector(FiltersPopup::onSelectTag)
|
||||
);
|
||||
btn->m_notClickable = true;
|
||||
btn->setUserObject("tag", CCString::create(tag));
|
||||
m_tagsMenu->addChild(btn);
|
||||
}
|
||||
m_tagsMenu->updateLayout();
|
||||
this->updateTags();
|
||||
}
|
||||
else if (event->getReject()) {
|
||||
m_tagsMenu->removeAllChildren();
|
||||
auto label = CCLabelBMFont::create("Unable to load tags", "bigFont.fnt");
|
||||
label->setOpacity(105);
|
||||
m_tagsMenu->addChild(label);
|
||||
m_tagsMenu->updateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
void FiltersPopup::updateTags() {
|
||||
for (auto node : CCArrayExt<CCNode*>(m_tagsMenu->getChildren())) {
|
||||
if (auto toggle = typeinfo_cast<CCMenuItemToggler*>(node)) {
|
||||
auto tag = static_cast<CCString*>(toggle->getUserObject("tag"))->getCString();
|
||||
toggle->toggle(m_selectedTags.contains(tag));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FiltersPopup::onSelectTag(CCObject* sender) {
|
||||
auto toggle = static_cast<CCMenuItemToggler*>(sender);
|
||||
auto tag = static_cast<CCString*>(toggle->getUserObject("tag"))->getCString();
|
||||
if (m_selectedTags.contains(tag)) {
|
||||
m_selectedTags.erase(tag);
|
||||
}
|
||||
else {
|
||||
m_selectedTags.insert(tag);
|
||||
}
|
||||
this->updateTags();
|
||||
}
|
||||
|
||||
void FiltersPopup::onResetTags(CCObject*) {
|
||||
m_selectedTags.clear();
|
||||
this->updateTags();
|
||||
}
|
||||
|
||||
void FiltersPopup::onClose(CCObject* sender) {
|
||||
m_source->setModTags(m_selectedTags);
|
||||
Popup::onClose(sender);
|
||||
}
|
||||
|
||||
FiltersPopup* FiltersPopup::create(ModListSource* src) {
|
||||
auto ret = new FiltersPopup();
|
||||
if (ret && ret->init(310, 250, src)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
27
loader/src/ui/mods/popups/FiltersPopup.hpp
Normal file
27
loader/src/ui/mods/popups/FiltersPopup.hpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
#include "../sources/ModListSource.hpp"
|
||||
#include "../GeodeStyle.hpp"
|
||||
#include <server/Server.hpp>
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class FiltersPopup : public GeodePopup<ModListSource*> {
|
||||
protected:
|
||||
ModListSource* m_source;
|
||||
CCMenu* m_tagsMenu;
|
||||
std::unordered_set<std::string> m_selectedTags;
|
||||
EventListener<PromiseEventFilter<std::unordered_set<std::string>, server::ServerError>> m_tagsListener;
|
||||
|
||||
bool setup(ModListSource* src) override;
|
||||
void updateTags();
|
||||
|
||||
void onLoadTags(PromiseEvent<std::unordered_set<std::string>, server::ServerError>* event);
|
||||
void onResetTags(CCObject*);
|
||||
void onSelectTag(CCObject* sender);
|
||||
void onClose(CCObject* sender) override;
|
||||
|
||||
public:
|
||||
static FiltersPopup* create(ModListSource* src);
|
||||
};
|
|
@ -109,21 +109,7 @@ bool ModPopup::setup(ModSource&& src) {
|
|||
valueLabel->setID("value-label");
|
||||
labelContainer->addChild(valueLabel);
|
||||
|
||||
// todo: refactor these spinners into a reusable class that's not the ass LoadingCircle is
|
||||
auto spinnerContainer = CCNode::create();
|
||||
spinnerContainer->setContentSize({
|
||||
container->getContentHeight() / labelContainer->getScale(),
|
||||
container->getContentHeight() / labelContainer->getScale()
|
||||
});
|
||||
spinnerContainer->setID("loading-spinner");
|
||||
|
||||
auto spinner = CCSprite::create("loadingCircle.png");
|
||||
spinner->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
spinner->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
|
||||
limitNodeSize(spinner, spinnerContainer->getContentSize(), 1.f, .1f);
|
||||
spinnerContainer->addChildAtPosition(spinner, Anchor::Center);
|
||||
|
||||
labelContainer->addChild(spinnerContainer);
|
||||
labelContainer->addChild(createLoadingCircle(container->getContentHeight() / labelContainer->getScale()));
|
||||
|
||||
this->setStatIcon(container, std::get<0>(stat));
|
||||
this->setStatLabel(container, std::get<1>(stat));
|
||||
|
@ -165,18 +151,7 @@ bool ModPopup::setup(ModSource&& src) {
|
|||
m_tags->setContentSize(tagsContainer->getContentSize() - ccp(10, 10));
|
||||
m_tags->setAnchorPoint({ .5f, .5f });
|
||||
|
||||
// todo: refactor these spinners into a reusable class that's not the ass LoadingCircle is
|
||||
auto tagsSpinnerContainer = CCNode::create();
|
||||
tagsSpinnerContainer->setContentSize({ 50, 50 });
|
||||
tagsSpinnerContainer->setID("loading-spinner");
|
||||
|
||||
auto tagsSpinner = CCSprite::create("loadingCircle.png");
|
||||
tagsSpinner->setBlendFunc({ GL_ONE, GL_ONE });
|
||||
tagsSpinner->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
|
||||
limitNodeSize(tagsSpinner, tagsSpinnerContainer->getContentSize(), 1.f, .1f);
|
||||
tagsSpinnerContainer->addChildAtPosition(tagsSpinner, Anchor::Center);
|
||||
|
||||
m_tags->addChild(tagsSpinnerContainer);
|
||||
m_tags->addChild(createLoadingCircle(50));
|
||||
|
||||
m_tags->setLayout(
|
||||
RowLayout::create()
|
||||
|
@ -202,8 +177,10 @@ bool ModPopup::setup(ModSource&& src) {
|
|||
|
||||
m_restartRequiredLabel = createGeodeTagLabel(
|
||||
"Restart Required",
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)),
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr))
|
||||
{{
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label"_spr)),
|
||||
to3B(ColorProvider::get()->color("mod-list-restart-required-label-bg"_spr))
|
||||
}}
|
||||
);
|
||||
m_restartRequiredLabel->setLayoutOptions(AxisLayoutOptions::create()->setMaxScale(.75f));
|
||||
m_restartRequiredLabel->setScale(.3f);
|
||||
|
@ -578,7 +555,7 @@ void ModPopup::onLoadTags(PromiseEvent<std::unordered_set<std::string>, server::
|
|||
auto readable = tag;
|
||||
readable[0] = std::toupper(readable[0]);
|
||||
auto colors = geodeTagColor(tag);
|
||||
m_tags->addChild(createGeodeTagLabel(readable, colors.first, colors.second));
|
||||
m_tags->addChild(createGeodeTagLabel(readable));
|
||||
}
|
||||
|
||||
if (data->empty()) {
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
#include "TagsPopup.hpp"
|
||||
|
||||
bool TagsPopup::setup(ModListSource* src) {
|
||||
m_noElasticity = true;
|
||||
m_source = src;
|
||||
|
||||
this->setTitle("Select Tags");
|
||||
|
||||
// todo: need a "get available tags" endpoint first...
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TagsPopup::onClose(CCObject* sender) {
|
||||
InvalidateCacheEvent(m_source).post();
|
||||
Popup::onClose(sender);
|
||||
}
|
||||
|
||||
TagsPopup* TagsPopup::create(ModListSource* src) {
|
||||
auto ret = new TagsPopup();
|
||||
if (ret && ret->init(260, 200, src)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
#include "../sources/ModListSource.hpp"
|
||||
#include "../GeodeStyle.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class TagsPopup : public GeodePopup<ModListSource*> {
|
||||
protected:
|
||||
ModListSource* m_source;
|
||||
|
||||
bool setup(ModListSource* src) override;
|
||||
|
||||
void onClose(CCObject*) override;
|
||||
|
||||
public:
|
||||
static TagsPopup* create(ModListSource* src);
|
||||
};
|
|
@ -33,6 +33,15 @@ static void filterModsWithQuery(InstalledModListSource::ProvidedMods& mods, Inst
|
|||
if (auto updates = src.hasUpdates(); query.onlyUpdates && !(updates && updates->hasUpdateForInstalledMod())) {
|
||||
addToList = false;
|
||||
}
|
||||
// If some tags are provided, only return mods that match
|
||||
if (addToList && query.tags.size()) {
|
||||
auto compare = mod->getMetadata().getTags();
|
||||
for (auto& tag : query.tags) {
|
||||
if (!compare.contains(tag)) {
|
||||
addToList = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't bother with unnecessary fuzzy match calculations if this mod isn't going to be added anyway
|
||||
if (addToList && query.query) {
|
||||
// By default don't add anything
|
||||
|
@ -221,6 +230,14 @@ void InstalledModListSource::setSearchQuery(std::string const& query) {
|
|||
m_query.query = query.size() ? std::optional(query) : std::nullopt;
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> InstalledModListSource::getModTags() const {
|
||||
return m_query.tags;
|
||||
}
|
||||
void InstalledModListSource::setModTags(std::unordered_set<std::string> const& tags) {
|
||||
m_query.tags = tags;
|
||||
this->clearCache();
|
||||
}
|
||||
|
||||
InstalledModsQuery const& InstalledModListSource::getQuery() const {
|
||||
return m_query;
|
||||
}
|
||||
|
@ -323,6 +340,14 @@ void ServerModListSource::setSearchQuery(std::string const& query) {
|
|||
m_query.query = query.size() ? std::optional(query) : std::nullopt;
|
||||
}
|
||||
|
||||
std::unordered_set<std::string> ServerModListSource::getModTags() const {
|
||||
return m_query.tags;
|
||||
}
|
||||
void ServerModListSource::setModTags(std::unordered_set<std::string> const& tags) {
|
||||
m_query.tags = tags;
|
||||
this->clearCache();
|
||||
}
|
||||
|
||||
server::ModsQuery const& ServerModListSource::getQuery() const {
|
||||
return m_query;
|
||||
}
|
||||
|
@ -355,6 +380,11 @@ ModPackListSource* ModPackListSource::get() {
|
|||
|
||||
void ModPackListSource::setSearchQuery(std::string const& query) {}
|
||||
|
||||
std::unordered_set<std::string> ModPackListSource::getModTags() const {
|
||||
return {};
|
||||
}
|
||||
void ModPackListSource::setModTags(std::unordered_set<std::string> const& set) {}
|
||||
|
||||
bool ModPackListSource::isInstalledMods() const {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
struct InstalledModsQuery final {
|
||||
std::optional<std::string> query;
|
||||
bool onlyUpdates = false;
|
||||
std::unordered_set<std::string> tags = {};
|
||||
size_t page = 0;
|
||||
size_t pageSize = 10;
|
||||
};
|
||||
|
@ -77,6 +78,9 @@ public:
|
|||
void clearCache();
|
||||
void search(std::string const& query);
|
||||
|
||||
virtual std::unordered_set<std::string> getModTags() const = 0;
|
||||
virtual void setModTags(std::unordered_set<std::string> const& tags) = 0;
|
||||
|
||||
// Load page, uses cache if possible unless `update` is true
|
||||
PagePromise loadPage(size_t page, bool update = false);
|
||||
std::optional<size_t> getPageCount() const;
|
||||
|
@ -112,13 +116,15 @@ protected:
|
|||
|
||||
void resetQuery() override;
|
||||
ProviderPromise fetchPage(size_t page, size_t pageSize) override;
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
|
||||
InstalledModListSource(bool onlyUpdates);
|
||||
|
||||
public:
|
||||
static InstalledModListSource* get(bool onlyUpdates);
|
||||
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
std::unordered_set<std::string> getModTags() const override;
|
||||
void setModTags(std::unordered_set<std::string> const& tags) override;
|
||||
|
||||
InstalledModsQuery const& getQuery() const;
|
||||
InvalidateQueryAfter<InstalledModsQuery> getQueryMut();
|
||||
|
@ -141,13 +147,15 @@ protected:
|
|||
|
||||
void resetQuery() override;
|
||||
ProviderPromise fetchPage(size_t page, size_t pageSize) override;
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
|
||||
ServerModListSource(ServerModListType type);
|
||||
|
||||
public:
|
||||
static ServerModListSource* get(ServerModListType type);
|
||||
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
std::unordered_set<std::string> getModTags() const override;
|
||||
void setModTags(std::unordered_set<std::string> const& tags) override;
|
||||
|
||||
server::ModsQuery const& getQuery() const;
|
||||
InvalidateQueryAfter<server::ModsQuery> getQueryMut();
|
||||
|
@ -160,13 +168,15 @@ class ModPackListSource : public ModListSource {
|
|||
protected:
|
||||
void resetQuery() override;
|
||||
ProviderPromise fetchPage(size_t page, size_t pageSize) override;
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
|
||||
ModPackListSource();
|
||||
|
||||
public:
|
||||
static ModPackListSource* get();
|
||||
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
std::unordered_set<std::string> getModTags() const override;
|
||||
void setModTags(std::unordered_set<std::string> const& tags) override;
|
||||
|
||||
bool isInstalledMods() const override;
|
||||
bool wantsRestart() const override;
|
||||
|
|
Loading…
Reference in a new issue