From 571d33fa9b8ed7866b7a698ca003d2cfbdb45434 Mon Sep 17 00:00:00 2001
From: HJfod <60038575+HJfod@users.noreply.github.com>
Date: Mon, 12 Dec 2022 00:36:26 +0200
Subject: [PATCH] add filtering by developer (will rework later)  - rn how it
 works is that it just filters the list when you click the dev name, although
 honestly this is kinda neat too

---
 loader/include/Geode/loader/Index.hpp         |  6 ++++
 loader/src/loader/Index.cpp                   | 14 ++++++++
 loader/src/ui/internal/list/ModListCell.cpp   | 36 +++++++++++++++----
 loader/src/ui/internal/list/ModListCell.hpp   |  5 +++
 loader/src/ui/internal/list/ModListLayer.cpp  | 11 +++++-
 loader/src/ui/internal/list/ModListLayer.hpp  |  3 +-
 .../ui/internal/list/SearchFilterPopup.cpp    | 16 ++++-----
 7 files changed, 74 insertions(+), 17 deletions(-)

diff --git a/loader/include/Geode/loader/Index.hpp b/loader/include/Geode/loader/Index.hpp
index af703780..7ab3a995 100644
--- a/loader/include/Geode/loader/Index.hpp
+++ b/loader/include/Geode/loader/Index.hpp
@@ -128,6 +128,12 @@ namespace geode {
          * Get all featured index items
          */
         std::vector<IndexItemHandle> getFeaturedItems() const;
+        /**
+         * Get all index items by a developer
+         */
+        std::vector<IndexItemHandle> getItemsByDeveloper(
+            std::string const& name
+        ) const;
         /**
          * Check if an item with this ID is found on the index, and optionally 
          * provide the version sought after
diff --git a/loader/src/loader/Index.cpp b/loader/src/loader/Index.cpp
index 609d418c..03a074c5 100644
--- a/loader/src/loader/Index.cpp
+++ b/loader/src/loader/Index.cpp
@@ -478,6 +478,20 @@ std::vector<IndexItemHandle> Index::getFeaturedItems() const {
     return res;
 }
 
+std::vector<IndexItemHandle> Index::getItemsByDeveloper(
+    std::string const& name
+) const {
+    std::vector<IndexItemHandle> res;
+    for (auto& items : map::values(m_items)) {
+        if (items.size()) {
+            if (items.rbegin()->second->info.developer == name) {
+                res.push_back(items.rbegin()->second);
+            }
+        }
+    }
+    return res;
+}
+
 bool Index::isKnownItem(
     std::string const& id,
     std::optional<VersionInfo> version
diff --git a/loader/src/ui/internal/list/ModListCell.cpp b/loader/src/ui/internal/list/ModListCell.cpp
index 8c98963a..0206b1b6 100644
--- a/loader/src/ui/internal/list/ModListCell.cpp
+++ b/loader/src/ui/internal/list/ModListCell.cpp
@@ -71,19 +71,26 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) {
 
     auto creatorStr = "by " + info.developer;
     auto creatorLabel = CCLabelBMFont::create(creatorStr.c_str(), "goldFont.fnt");
-    creatorLabel->setAnchorPoint({ .0f, .5f });
     creatorLabel->setScale(.43f);
-    creatorLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
+
+    auto creatorBtn = CCMenuItemSpriteExtra::create(
+        creatorLabel, this, menu_selector(ModListCell::onViewDev)
+    );
+    creatorBtn->setPositionX(
+        m_height / 2 + logoSize / 2 + 13.f 
+         + creatorLabel->getScaledContentSize().width / 2 
+         - m_menu->getPositionX()
+    );
     if (hasDesc && spaceForTags) {
-        creatorLabel->setPositionY(m_height / 2 + 7.5f);
+        creatorBtn->setPositionY(+7.5f);
     }
     else if (hasDesc || spaceForTags) {
-        creatorLabel->setPositionY(m_height / 2);
+        creatorBtn->setPositionY(0.f);
     }
     else {
-        creatorLabel->setPositionY(m_height / 2 - 7.f);
+        creatorBtn->setPositionY(-7.f);
     }
-    this->addChild(creatorLabel);
+    m_menu->addChild(creatorBtn);
 
     if (hasDesc) {
         auto descBG = CCScale9Sprite::create("square02b_001.png", { 0.0f, 0.0f, 80.0f, 80.0f });
@@ -109,6 +116,11 @@ void ModListCell::setupInfo(ModInfo const& info, bool spaceForTags) {
     }
 }
 
+void ModListCell::onViewDev(CCObject*) {
+    m_layer->getQuery().developer = this->getDeveloper();
+    m_layer->reloadList();
+}
+
 bool ModListCell::init(ModListLayer* list, CCSize const& size) {
     m_width = size.width;
     m_height = size.height;
@@ -244,6 +256,10 @@ bool ModCell::init(
     return true;
 }
 
+std::string ModCell::getDeveloper() const {
+    return m_mod->getDeveloper();
+}
+
 CCNode* ModCell::createLogo(CCSize const& size) {
     return geode::createModLogo(m_mod, size);
 }
@@ -315,6 +331,10 @@ bool IndexItemCell::init(
 
 void IndexItemCell::updateState() {}
 
+std::string IndexItemCell::getDeveloper() const {
+    return m_item->info.developer;
+}
+
 CCNode* IndexItemCell::createLogo(CCSize const& size) {
     return geode::createIndexItemLogo(m_item, size);
 }
@@ -416,6 +436,10 @@ InvalidGeodeFileCell* InvalidGeodeFileCell::create(
 
 void InvalidGeodeFileCell::updateState() {}
 
+std::string InvalidGeodeFileCell::getDeveloper() const {
+    return "";
+}
+
 CCNode* InvalidGeodeFileCell::createLogo(CCSize const& size) {
     return nullptr;
 }
diff --git a/loader/src/ui/internal/list/ModListCell.hpp b/loader/src/ui/internal/list/ModListCell.hpp
index e96d06ba..bf521651 100644
--- a/loader/src/ui/internal/list/ModListCell.hpp
+++ b/loader/src/ui/internal/list/ModListCell.hpp
@@ -29,10 +29,12 @@ protected:
     void draw() override;
 
     float getLogoSize() const;
+    void onViewDev(CCObject*);
 
 public:
     virtual void updateState() = 0;
     virtual CCNode* createLogo(CCSize const& size) = 0;
+    virtual std::string getDeveloper() const = 0;
 };
 
 /**
@@ -61,6 +63,7 @@ public:
 
     void updateState() override;
     CCNode* createLogo(CCSize const& size) override;
+    std::string getDeveloper() const override;
 };
 
 /**
@@ -87,6 +90,7 @@ public:
 
     void updateState() override;
     CCNode* createLogo(CCSize const& size) override;
+    std::string getDeveloper() const override;
 };
 
 /**
@@ -114,4 +118,5 @@ public:
 
     void updateState() override;
     CCNode* createLogo(CCSize const& size) override;
+    std::string getDeveloper() const override;
 };
diff --git a/loader/src/ui/internal/list/ModListLayer.cpp b/loader/src/ui/internal/list/ModListLayer.cpp
index 76619043..8fd2a642 100644
--- a/loader/src/ui/internal/list/ModListLayer.cpp
+++ b/loader/src/ui/internal/list/ModListLayer.cpp
@@ -487,7 +487,10 @@ void ModListLayer::reloadList(std::optional<ModListQuery> const& query) {
 
     // check if the user has searched something,
     // and show visual indicator if so
-    auto hasQuery = m_searchInput->getString() && strlen(m_searchInput->getString());
+    auto hasQuery =
+        (m_searchInput->getString() &&
+        strlen(m_searchInput->getString())) ||
+        m_query.developer;
     m_searchBtn->setVisible(!hasQuery);
     m_searchClearBtn->setVisible(hasQuery);
 
@@ -545,6 +548,10 @@ ModListDisplay ModListLayer::getDisplay() const {
     return m_display;
 }
 
+ModListQuery& ModListLayer::getQuery() {
+    return m_query;
+}
+
 // Callbacks & Vtable impls
 
 void ModListLayer::onCheckForUpdates(CCObject*) {
@@ -599,6 +606,8 @@ void ModListLayer::onOpenFolder(CCObject*) {
 }
 
 void ModListLayer::onResetSearch(CCObject*) {
+    // todo: remove when implementing more reasonable developer view
+    m_query.developer = std::nullopt;
     m_searchInput->setString("");
 }
 
diff --git a/loader/src/ui/internal/list/ModListLayer.hpp b/loader/src/ui/internal/list/ModListLayer.hpp
index 505829c7..323ea6a3 100644
--- a/loader/src/ui/internal/list/ModListLayer.hpp
+++ b/loader/src/ui/internal/list/ModListLayer.hpp
@@ -82,14 +82,13 @@ protected:
     CCSize getCellSize() const;
     CCSize getListSize() const;
 
-    friend class SearchFilterPopup;
-
 public:
     static ModListLayer* create();
     static ModListLayer* scene();
     void updateAllStates(ModListCell* except = nullptr);
 
     ModListDisplay getDisplay() const;
+    ModListQuery& getQuery();
 
     void reloadList(std::optional<ModListQuery> const& query = std::nullopt);
 };
diff --git a/loader/src/ui/internal/list/SearchFilterPopup.cpp b/loader/src/ui/internal/list/SearchFilterPopup.cpp
index 7000620a..4ca332be 100644
--- a/loader/src/ui/internal/list/SearchFilterPopup.cpp
+++ b/loader/src/ui/internal/list/SearchFilterPopup.cpp
@@ -55,7 +55,7 @@ bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
 
     this->addToggle(
         "Show Installed", menu_selector(SearchFilterPopup::onShowInstalled),
-        m_modLayer->m_query.forceVisibility, 0, pos
+        m_modLayer->getQuery().forceVisibility, 0, pos
     );
 
     // tags
@@ -79,7 +79,7 @@ bool SearchFilterPopup::setup(ModListLayer* layer, ModListType type) {
         auto toggle = CCMenuItemToggler::createWithStandardSprites(
             this, menu_selector(SearchFilterPopup::onTag), .5f
         );
-        toggle->toggle(m_modLayer->m_query.tags.count(tag));
+        toggle->toggle(m_modLayer->getQuery().tags.count(tag));
         toggle->setPosition(pos - winSize / 2);
         toggle->setUserObject(CCString::create(tag));
         m_buttonMenu->addChild(toggle);
@@ -101,10 +101,10 @@ void SearchFilterPopup::onTag(CCObject* sender) {
         auto toggle = static_cast<CCMenuItemToggler*>(sender);
         auto tag = static_cast<CCString*>(toggle->getUserObject())->getCString();
         if (!toggle->isToggled()) {
-            m_modLayer->m_query.tags.insert(tag);
+            m_modLayer->getQuery().tags.insert(tag);
         }
         else {
-            m_modLayer->m_query.tags.erase(tag);
+            m_modLayer->getQuery().tags.erase(tag);
         }
     }
     catch (...) {
@@ -113,7 +113,7 @@ void SearchFilterPopup::onTag(CCObject* sender) {
 
 void SearchFilterPopup::onShowInstalled(CCObject* sender) {
     auto toggle = static_cast<CCMenuItemToggler*>(sender);
-    m_modLayer->m_query.forceVisibility = !toggle->isToggled();
+    m_modLayer->getQuery().forceVisibility = !toggle->isToggled();
 }
 
 void SearchFilterPopup::enable(CCMenuItemToggler* toggle, ModListType type) {
@@ -141,17 +141,17 @@ CCMenuItemToggler* SearchFilterPopup::addPlatformToggle(
 ) {
     return this->addToggle(
         title, menu_selector(SearchFilterPopup::onPlatformToggle),
-        m_modLayer->m_query.platforms.count(id), id.to<int>(), pos
+        m_modLayer->getQuery().platforms.count(id), id.to<int>(), pos
     );
     return nullptr;
 }
 
 void SearchFilterPopup::onPlatformToggle(CCObject* sender) {
     if (static_cast<CCMenuItemToggler*>(sender)->isToggled()) {
-        m_modLayer->m_query.platforms.erase(PlatformID::from(sender->getTag()));
+        m_modLayer->getQuery().platforms.erase(PlatformID::from(sender->getTag()));
     }
     else {
-        m_modLayer->m_query.platforms.insert(PlatformID::from(sender->getTag()));
+        m_modLayer->getQuery().platforms.insert(PlatformID::from(sender->getTag()));
     }
 }