working on better index filtering

This commit is contained in:
HJfod 2022-09-02 12:22:59 +03:00
parent 59ada9e7f0
commit bfa5206704
7 changed files with 199 additions and 67 deletions

View file

@ -0,0 +1,120 @@
#pragma once
#include <Geode/Bindings.hpp>
namespace geode {
template<class T>
T do_nothing(T t) {
return t;
}
template<class T = std::string, auto Stringify = do_nothing<std::string>>
class SelectList : public cocos2d::CCMenu {
protected:
std::vector<T> m_list;
size_t m_index = 0;
std::function<void(T const&, size_t)> m_onChange;
cocos2d::CCLabelBMFont* m_label;
CCMenuItemSpriteExtra* m_prevBtn;
CCMenuItemSpriteExtra* m_nextBtn;
bool init(
float width,
std::vector<T> const& list,
std::function<void(T const&, size_t)> onChange
) {
if (!cocos2d::CCMenu::init())
return false;
m_list = list;
m_onChange = onChange;
this->setContentSize({ width, 30.f });
auto prevSpr = cocos2d::CCSprite::createWithSpriteFrameName("navArrowBtn_001.png");
prevSpr->setFlipX(true);
prevSpr->setScale(.3f);
m_prevBtn = CCMenuItemSpriteExtra::create(
prevSpr, this, menu_selector(SelectList<T>::onPrev)
);
m_prevBtn->setPosition(-width / 2 + 10.f, 0.f);
this->addChild(m_prevBtn);
auto nextSpr = cocos2d::CCSprite::createWithSpriteFrameName("navArrowBtn_001.png");
nextSpr->setScale(.3f);
m_nextBtn = CCMenuItemSpriteExtra::create(
nextSpr, this, menu_selector(SelectList<T>::onNext)
);
m_nextBtn->setPosition(width / 2 - 10.f, 0.f);
this->addChild(m_nextBtn);
m_label = cocos2d::CCLabelBMFont::create("", "bigFont.fnt");
this->addChild(m_label);
this->updateLabel();
cocos2d::CCDirector::sharedDirector()->getTouchDispatcher()->incrementForcePrio(2);
this->registerWithTouchDispatcher();
return true;
}
void updateLabel() {
if (m_list.size()) {
m_label->setString(Stringify(m_list.at(m_index)).c_str());
m_prevBtn->setEnabled(true);
m_nextBtn->setEnabled(true);
} else {
m_label->setString("-");
m_prevBtn->setEnabled(false);
m_nextBtn->setEnabled(false);
}
m_label->limitLabelWidth(m_obContentSize.width - 40.f, .6f, .1f);
}
void onPrev(CCObject* sender) {
if (m_index == 0) {
m_index = m_list.size() - 1;
} else {
m_index--;
}
this->updateLabel();
m_onChange(m_list.at(m_index), m_index);
}
void onNext(CCObject* sender) {
if (m_index == m_list.size() - 1) {
m_index = 0;
} else {
m_index++;
}
this->updateLabel();
m_onChange(m_list.at(m_index), m_index);
}
public:
static SelectList* create(
float width,
std::vector<T> const& list,
std::function<void(T const&, size_t)> onChange
) {
auto ret = new SelectList();
if (ret && ret->init(width, list, onChange)) {
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
void setItems(std::vector<T> const& list) {
m_index = 0;
m_list = list;
this->updateLabel();
}
};
}

View file

@ -383,31 +383,6 @@ std::vector<IndexItem> const& Index::getItems() const {
return m_items;
}
std::vector<IndexItem> Index::getNoninstalledItems(
std::optional<std::unordered_set<PlatformID>> const& platforms
) const {
std::vector<IndexItem> items;
for (auto& item : m_items) {
if (!Loader::get()->isModInstalled(item.m_info.m_id)) {
// return whatever is available on requested platforms
if (platforms) {
for (auto& plat : platforms.value()) {
if (item.m_download.m_platforms.count(plat)) {
items.push_back(item);
}
}
}
// otherwise just return whatever is available on current platform
else {
if (item.m_download.m_platforms.count(GEODE_PLATFORM_TARGET)) {
items.push_back(item);
}
}
}
}
return items;
}
bool Index::isKnownItem(std::string const& id) const {
for (auto& item : m_items) {
if (item.m_info.m_id == id) return true;

View file

@ -133,9 +133,6 @@ public:
static Index* get();
std::vector<IndexItem> const& getItems() const;
std::vector<IndexItem> getNoninstalledItems(
std::optional<std::unordered_set<PlatformID>> const& platforms
) const;
bool isKnownItem(std::string const& id) const;
IndexItem getKnownItem(std::string const& id) const;
Result<InstallTicket*> installItems(

View file

@ -367,17 +367,13 @@ void ModListView::loadCell(TableViewCell* cell, unsigned int index) {
}
}
bool ModListView::filter(
ModInfo const& info,
std::optional<std::string> const& searchFilter,
int searchFlags
) {
if (!searchFilter) return true;
auto check = [searchFlags, searchFilter](SearchFlags flag, std::string const& name) -> bool {
if (!(searchFlags & flag)) return false;
bool ModListView::filter(ModInfo const& info, ModListQuery const& query) {
if (!query.m_searchFilter) return true;
auto check = [query](SearchFlags flag, std::string const& name) -> bool {
if (!(query.m_searchFlags & flag)) return false;
return string_utils::contains(
string_utils::toLower(name),
string_utils::toLower(searchFilter.value())
string_utils::toLower(query.m_searchFilter.value())
);
};
if (check(SearchFlag::Name, info.m_name)) return true;
@ -388,6 +384,23 @@ bool ModListView::filter(
return false;
}
bool ModListView::filter(IndexItem const& item, ModListQuery const& query) {
if (query.m_installed != ModListQuery::All) {
if (
Loader::get()->isModInstalled(item.m_info.m_id) !=
(query.m_installed == ModListQuery::Installed)
) {
return false;
}
}
for (auto& plat : query.m_platforms) {
if (item.m_download.m_platforms.count(plat)) {
return filter(item.m_info, query);
}
}
return false;
}
static void sortInstalledMods(std::vector<Mod*>& mods) {
if (!mods.size()) return;
// keep track of first object
@ -432,7 +445,7 @@ bool ModListView::init(
}
// internal geode representation always at the top
auto imod = Loader::getInternalMod();
if (this->filter(imod->getModInfo(), query.m_searchFilter, query.m_searchFlags)) {
if (this->filter(imod->getModInfo(), query)) {
mods->addObject(new ModObject(imod));
}
// then other mods
@ -441,7 +454,7 @@ bool ModListView::init(
// loaded, it's as good as not existing
// (because it doesn't)
if (mod->isUninstalled() && !mod->isLoaded()) continue;
if (this->filter(mod->getModInfo(), query.m_searchFilter, query.m_searchFlags)) {
if (this->filter(mod->getModInfo(), query)) {
mods->addObject(new ModObject(mod));
}
}
@ -452,8 +465,8 @@ bool ModListView::init(
case ModListType::Download: {
mods = CCArray::create();
for (auto const& item : Index::get()->getNoninstalledItems(query.m_platforms)) {
if (this->filter(item.m_info, query.m_searchFilter, query.m_searchFlags)) {
for (auto const& item : Index::get()->getItems()) {
if (this->filter(item, query)) {
mods->addObject(new ModObject(item));
}
}
@ -478,7 +491,7 @@ ModListView* ModListView::create(
ModListType type,
float width,
float height,
ModListQuery query
ModListQuery const& query
) {
auto pRet = new ModListView;
if (pRet) {
@ -495,7 +508,7 @@ ModListView* ModListView::create(
ModListType type,
float width,
float height,
ModListQuery query
ModListQuery const& query
) {
return ModListView::create(nullptr, type, width, height, query);
}

View file

@ -100,6 +100,11 @@ static constexpr SearchFlags ALL_FLAGS =
struct ModListQuery {
std::optional<std::string> m_searchFilter = std::nullopt;
int m_searchFlags = ALL_FLAGS;
enum {
Installed,
Noninstalled,
All,
} m_installed = Installed;
std::unordered_set<PlatformID> m_platforms { GEODE_PLATFORM_TARGET };
};
@ -126,11 +131,8 @@ protected:
float height,
ModListQuery query
);
bool filter(
ModInfo const& info,
std::optional<std::string> const& searchFilter,
SearchFlags searchFlags
);
bool filter(ModInfo const& info, ModListQuery const& query);
bool filter(IndexItem const& item, ModListQuery const& query);
public:
static ModListView* create(
@ -138,13 +140,13 @@ public:
ModListType type = ModListType::Installed,
float width = 358.f,
float height = 220.f,
ModListQuery query = ModListQuery()
ModListQuery const& query = ModListQuery()
);
static ModListView* create(
ModListType type,
float width = 358.f,
float height = 220.f,
ModListQuery query = ModListQuery()
ModListQuery const& query = ModListQuery()
);
void updateAllStates(ModCell* toggled = nullptr);

View file

@ -1,6 +1,7 @@
#include "SearchFilterPopup.hpp"
#include "ModListLayer.hpp"
#include "ModListView.hpp"
#include <Geode/ui/SelectList.hpp>
bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
// todo: clean this shitty ass popup up
@ -22,8 +23,8 @@ bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
);
matchBG->setColor({ 0, 0, 0 });
matchBG->setOpacity(90);
matchBG->setContentSize({ 290.f, 300.f });
matchBG->setPosition(winSize.width / 2 - 90.f, winSize.height / 2 - 21.f);
matchBG->setContentSize({ 290.f, 295.f });
matchBG->setPosition(winSize.width / 2 - 90.f, winSize.height / 2 - 21.5f);
matchBG->setScale(.5f);
m_mainLayer->addChild(matchBG);
@ -50,45 +51,67 @@ bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
);
platformBG->setColor({ 0, 0, 0 });
platformBG->setOpacity(90);
platformBG->setContentSize({ 290.f, 300.f });
platformBG->setPosition(winSize.width / 2 + 90.f, winSize.height / 2 - 21.f);
platformBG->setContentSize({ 290.f, 205.f });
platformBG->setPosition(winSize.width / 2 + 90.f, winSize.height / 2 + 1.f);
platformBG->setScale(.5f);
m_mainLayer->addChild(platformBG);
pos = CCPoint { winSize.width / 2 + 45.f, winSize.height / 2 + 35.f };
pos = CCPoint { winSize.width / 2 + 35.f, winSize.height / 2 + 35.f };
this->addPlatformToggle("Windows", PlatformID::Windows, pos);
this->addPlatformToggle("MacOS", PlatformID::MacOS, pos);
this->addPlatformToggle("iOS", PlatformID::iOS, pos);
this->addPlatformToggle("Android", PlatformID::Android, pos);
this->enable(this->addPlatformToggle("Windows", PlatformID::Windows, pos), type);
this->enable(this->addPlatformToggle("MacOS", PlatformID::MacOS, pos), type);
this->enable(this->addPlatformToggle("iOS", PlatformID::iOS, pos), type);
this->enable(this->addPlatformToggle("Android", PlatformID::Android, pos), type);
auto installedBG = CCScale9Sprite::create(
"square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f }
);
installedBG->setColor({ 0, 0, 0 });
installedBG->setOpacity(90);
installedBG->setContentSize({ 290.f, 65.f });
installedBG->setPosition(winSize.width / 2 + 90.f, winSize.height / 2 - 80.f);
installedBG->setScale(.5f);
m_mainLayer->addChild(installedBG);
return true;
}
void SearchFilterPopup::addSearchMatch(const char* title, int flag, CCPoint& pos) {
GameToolbox::createToggleButton(
void SearchFilterPopup::enable(CCMenuItemToggler* toggle, ModListType type) {
if (type == ModListType::Installed) {
toggle->setEnabled(false);
toggle->m_onButton->setColor(cc3x(0x50));
toggle->m_offButton->setColor(cc3x(0x50));
}
}
CCMenuItemToggler* SearchFilterPopup::addSearchMatch(const char* title, int flag, CCPoint& pos) {
auto toggle = GameToolbox::createToggleButton(
title, menu_selector(SearchFilterPopup::onSearchToggle),
m_modLayer->m_query.m_searchFlags & flag,
m_buttonMenu, pos, this,
m_buttonMenu, .5f, .5f, 100.f,
{ 10.f, .0f }, nullptr, false, flag, nullptr
)->setTag(flag);
);
toggle->setTag(flag);
pos.y -= 22.5f;
return toggle;
}
void SearchFilterPopup::addPlatformToggle(
CCMenuItemToggler* SearchFilterPopup::addPlatformToggle(
const char* title,
PlatformID id,
CCPoint& pos
) {
GameToolbox::createToggleButton(
auto toggle = GameToolbox::createToggleButton(
title, menu_selector(SearchFilterPopup::onPlatformToggle),
m_modLayer->m_query.m_platforms.count(id),
m_buttonMenu, pos, this,
m_buttonMenu, .5f, .5f, 100.f,
{ 10.f, .0f }, nullptr, false, id.to<int>(), nullptr
)->setTag(id.to<int>());
);
toggle->setTag(id.to<int>());
pos.y -= 22.5f;
return toggle;
}
void SearchFilterPopup::onSearchToggle(CCObject* sender) {

View file

@ -12,12 +12,14 @@ protected:
ModListLayer* m_modLayer;
bool setup(ModListLayer* layer, ModListType type) override;
void addSearchMatch(const char* title, int flag, CCPoint& pos);
void addPlatformToggle(const char* title, PlatformID id, CCPoint& pos);
CCMenuItemToggler* addSearchMatch(const char* title, int flag, CCPoint& pos);
CCMenuItemToggler* addPlatformToggle(const char* title, PlatformID id, CCPoint& pos);
void onSearchToggle(CCObject*);
void onPlatformToggle(CCObject*);
void enable(CCMenuItemToggler* toggle, ModListType type);
void onClose(CCObject*) override;
public: