mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-26 17:36:05 -05:00
make mod list state updating use events instead of poor man's delegates
This commit is contained in:
parent
e13091115b
commit
54e9763631
14 changed files with 100 additions and 64 deletions
|
@ -167,6 +167,10 @@ bool ModsLayer::init() {
|
|||
|
||||
this->updateState();
|
||||
|
||||
// The overall mods layer only cares about page number updates
|
||||
m_updateStateListener.setFilter(UpdateModListStateFilter(UpdatePageNumberState()));
|
||||
m_updateStateListener.bind([this](auto) { this->updateState(); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -190,7 +194,6 @@ void ModsLayer::gotoTab(ModListSourceType type) {
|
|||
// Lazily create new list and add it to UI
|
||||
if (!m_lists.contains(src)) {
|
||||
auto list = ModList::create(src, m_frame->getContentSize() - ccp(30, 0));
|
||||
list->onUpdateParentState(std::bind(&ModsLayer::updateState, this));
|
||||
list->setPosition(m_frame->getPosition());
|
||||
this->addChild(list);
|
||||
m_lists.emplace(src, list);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "list/ModItem.hpp"
|
||||
#include "list/ModList.hpp"
|
||||
#include "sources/ModListSource.hpp"
|
||||
#include "UpdateModListState.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
|
@ -19,6 +20,7 @@ protected:
|
|||
CCLabelBMFont* m_pageLabel;
|
||||
CCMenuItemSpriteExtra* m_goToPageBtn;
|
||||
CCMenuItemSpriteExtra* m_restartBtn;
|
||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
bool m_showSearch = false;
|
||||
bool m_bigView = false;
|
||||
|
||||
|
|
20
loader/src/ui/mods/UpdateModListState.cpp
Normal file
20
loader/src/ui/mods/UpdateModListState.cpp
Normal file
|
@ -0,0 +1,20 @@
|
|||
#include "UpdateModListState.hpp"
|
||||
|
||||
UpdateModListStateEvent::UpdateModListStateEvent(UpdateState&& target) : target(target) {}
|
||||
|
||||
ListenerResult UpdateModListStateFilter::handle(MiniFunction<Callback> fn, UpdateModListStateEvent* event) {
|
||||
if (
|
||||
// If the listener wants to hear all state updates then let it
|
||||
std::holds_alternative<UpdateWholeState>(m_target) ||
|
||||
// If the event is update everything then update everything
|
||||
std::holds_alternative<UpdateWholeState>(event->target) ||
|
||||
// Otherwise only run if the event is what is asked for
|
||||
m_target == event->target
|
||||
) {
|
||||
fn(event);
|
||||
}
|
||||
return ListenerResult::Propagate;
|
||||
}
|
||||
|
||||
UpdateModListStateFilter::UpdateModListStateFilter() : m_target(UpdateWholeState()) {}
|
||||
UpdateModListStateFilter::UpdateModListStateFilter(UpdateState&& target) : m_target(target) {}
|
39
loader/src/ui/mods/UpdateModListState.hpp
Normal file
39
loader/src/ui/mods/UpdateModListState.hpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/loader/Event.hpp>
|
||||
#include "sources/ModSource.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
struct UpdatePageNumberState final {
|
||||
constexpr bool operator==(UpdatePageNumberState const&) const = default;
|
||||
};
|
||||
struct UpdateWholeState final {
|
||||
constexpr bool operator==(UpdateWholeState const&) const = default;
|
||||
};
|
||||
struct UpdateModState final {
|
||||
std::string modID;
|
||||
inline explicit UpdateModState(std::string const& modID) : modID(modID) {};
|
||||
constexpr bool operator==(UpdateModState const&) const = default;
|
||||
};
|
||||
using UpdateState = std::variant<UpdatePageNumberState, UpdateWholeState, UpdateModState>;
|
||||
|
||||
struct UpdateModListStateEvent : public Event {
|
||||
UpdateState target;
|
||||
|
||||
UpdateModListStateEvent(UpdateState&& target);
|
||||
};
|
||||
|
||||
class UpdateModListStateFilter : public EventFilter<UpdateModListStateEvent> {
|
||||
public:
|
||||
using Callback = void(UpdateModListStateEvent*);
|
||||
|
||||
protected:
|
||||
UpdateState m_target;
|
||||
|
||||
public:
|
||||
ListenerResult handle(MiniFunction<Callback> fn, UpdateModListStateEvent* event);
|
||||
|
||||
UpdateModListStateFilter();
|
||||
UpdateModListStateFilter(UpdateState&& target);
|
||||
};
|
|
@ -126,6 +126,10 @@ bool ModItem::init(ModSource&& source) {
|
|||
|
||||
this->updateState();
|
||||
|
||||
// Only listen for updates on this mod specifically
|
||||
m_updateStateListener.setFilter(UpdateModListStateFilter(UpdateModState(m_source.getID())));
|
||||
m_updateStateListener.bind([this](auto) { this->updateState(); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -161,11 +165,6 @@ void ModItem::updateState() {
|
|||
m_bg->setOpacity(40);
|
||||
}
|
||||
|
||||
// Propagate update up the chain
|
||||
if (m_updateParentState) {
|
||||
m_updateParentState();
|
||||
}
|
||||
|
||||
// Update enable toggle state
|
||||
if (m_enableToggle && m_source.asMod()) {
|
||||
m_enableToggle->toggle(m_source.asMod()->isOrWillBeEnabled());
|
||||
|
@ -216,10 +215,6 @@ void ModItem::updateSize(float width, bool big) {
|
|||
this->updateLayout();
|
||||
}
|
||||
|
||||
void ModItem::onUpdateParentState(MiniFunction<void()> listener) {
|
||||
m_updateParentState = listener;
|
||||
}
|
||||
|
||||
ModItem* ModItem::create(ModSource&& source) {
|
||||
auto ret = new ModItem();
|
||||
if (ret && ret->init(std::move(source))) {
|
||||
|
@ -232,11 +227,7 @@ ModItem* ModItem::create(ModSource&& source) {
|
|||
|
||||
void ModItem::onView(CCObject*) {
|
||||
// Always open up the popup for the installed mod page if that is possible
|
||||
auto popup = ModPopup::create(m_source.tryConvertToMod());
|
||||
popup->onUpdateParentState([this]() {
|
||||
this->updateState();
|
||||
});
|
||||
popup->show();
|
||||
ModPopup::create(m_source.tryConvertToMod())->show();
|
||||
}
|
||||
|
||||
void ModItem::onEnable(CCObject*) {
|
||||
|
@ -252,6 +243,6 @@ void ModItem::onEnable(CCObject*) {
|
|||
}
|
||||
}
|
||||
|
||||
// Update whole state of the mod item
|
||||
this->updateState();
|
||||
// Update state of the mod item
|
||||
UpdateModListStateEvent(UpdateModState(m_source.getID())).post();
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include <Geode/ui/General.hpp>
|
||||
#include <server/Server.hpp>
|
||||
#include "../sources/ModSource.hpp"
|
||||
#include "../UpdateModListState.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
|
@ -19,9 +20,9 @@ protected:
|
|||
CCLabelBMFont* m_developerLabel;
|
||||
ButtonSprite* m_restartRequiredLabel = nullptr;
|
||||
CCMenu* m_viewMenu;
|
||||
MiniFunction<void()> m_updateParentState = nullptr;
|
||||
CCMenuItemToggler* m_enableToggle = nullptr;
|
||||
CCScale9Sprite* m_checkmark = nullptr;
|
||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
|
||||
/**
|
||||
* @warning Make sure `getMetadata` and `createModLogo` are callable
|
||||
|
@ -29,8 +30,6 @@ protected:
|
|||
*/
|
||||
bool init(ModSource&& source);
|
||||
|
||||
// This should never be exposed outside, so the parent can't call this and
|
||||
// cause an infinite loop during state updating
|
||||
void updateState();
|
||||
|
||||
void onEnable(CCObject*);
|
||||
|
@ -40,6 +39,4 @@ public:
|
|||
static ModItem* create(ModSource&& source);
|
||||
|
||||
void updateSize(float width, bool big);
|
||||
|
||||
void onUpdateParentState(MiniFunction<void()> listener);
|
||||
};
|
||||
|
|
|
@ -194,7 +194,6 @@ void ModList::onPromise(typename ModListSource::PageLoadEvent* event) {
|
|||
}
|
||||
first = false;
|
||||
m_list->m_contentLayer->addChild(item);
|
||||
item->onUpdateParentState(m_updateParentState);
|
||||
}
|
||||
this->updateSize(m_bigSize);
|
||||
|
||||
|
@ -319,10 +318,8 @@ void ModList::updatePageNumber() {
|
|||
m_pagePrevBtn->setVisible(pageCount && m_page > 0);
|
||||
m_pageNextBtn->setVisible(pageCount && m_page < pageCount.value() - 1);
|
||||
|
||||
// Notify container about page count update
|
||||
if (m_updateParentState) {
|
||||
m_updateParentState();
|
||||
}
|
||||
// Post the update page number event
|
||||
UpdateModListStateEvent(UpdatePageNumberState()).post();
|
||||
}
|
||||
|
||||
void ModList::reloadPage() {
|
||||
|
@ -373,10 +370,6 @@ void ModList::showStatus(ModListStatus status, std::string const& message, std::
|
|||
m_statusContainer->updateLayout();
|
||||
}
|
||||
|
||||
void ModList::onUpdateParentState(MiniFunction<void()> listener) {
|
||||
m_updateParentState = listener;
|
||||
}
|
||||
|
||||
void ModList::onFilters(CCObject*) {
|
||||
TagsPopup::create(m_source, [this]() {
|
||||
this->gotoPage(0);
|
||||
|
|
|
@ -32,7 +32,7 @@ protected:
|
|||
CCMenuItemSpriteExtra* m_pageNextBtn;
|
||||
Ref<CCNode> m_searchMenu;
|
||||
TextInput* m_searchInput;
|
||||
MiniFunction<void()> m_updateParentState = nullptr;
|
||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
bool m_bigSize = false;
|
||||
std::atomic<size_t> m_searchInputThreads = 0;
|
||||
|
||||
|
@ -47,8 +47,6 @@ protected:
|
|||
public:
|
||||
static ModList* create(ModListSource* src, CCSize const& size);
|
||||
|
||||
// poor man's delegate
|
||||
void onUpdateParentState(MiniFunction<void()> listener);
|
||||
size_t getPage() const;
|
||||
|
||||
void reloadPage();
|
||||
|
|
|
@ -55,9 +55,7 @@ void ConfirmUninstallPopup::onUninstall(CCObject*) {
|
|||
)->show();
|
||||
}
|
||||
|
||||
if (m_updateParentState) {
|
||||
m_updateParentState();
|
||||
}
|
||||
UpdateModListStateEvent(UpdateModState(m_mod->getID())).post();
|
||||
|
||||
this->onClose(nullptr);
|
||||
}
|
||||
|
@ -71,7 +69,3 @@ ConfirmUninstallPopup* ConfirmUninstallPopup::create(Mod* mod) {
|
|||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ConfirmUninstallPopup::onUpdateParentState(MiniFunction<void()> listener) {
|
||||
m_updateParentState = listener;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
#include "../UpdateModListState.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
|
@ -8,7 +9,7 @@ class ConfirmUninstallPopup : public Popup<Mod*> {
|
|||
protected:
|
||||
Mod* m_mod;
|
||||
CCMenuItemToggler* m_deleteDataToggle;
|
||||
MiniFunction<void()> m_updateParentState = nullptr;
|
||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
|
||||
bool setup(Mod* mod) override;
|
||||
|
||||
|
@ -16,7 +17,4 @@ protected:
|
|||
|
||||
public:
|
||||
static ConfirmUninstallPopup* create(Mod* mod);
|
||||
|
||||
// todo: replace all of these with a single event
|
||||
void onUpdateParentState(MiniFunction<void()> listener);
|
||||
};
|
||||
|
|
|
@ -434,6 +434,10 @@ bool ModPopup::setup(ModSource&& src) {
|
|||
m_tagsListener.bind(this, &ModPopup::onLoadTags);
|
||||
m_tagsListener.setFilter(m_source.fetchValidTags().listen());
|
||||
|
||||
// Only listen for updates on this mod specifically
|
||||
m_updateStateListener.setFilter(UpdateModListStateFilter(UpdateModState(m_source.getID())));
|
||||
m_updateStateListener.bind([this](auto) { this->updateState(); });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -463,11 +467,6 @@ void ModPopup::updateState() {
|
|||
}
|
||||
|
||||
m_installMenu->updateLayout();
|
||||
|
||||
// Propagate update up the chain
|
||||
if (m_updateParentState) {
|
||||
m_updateParentState();
|
||||
}
|
||||
}
|
||||
|
||||
void ModPopup::setStatIcon(CCNode* stat, const char* spr) {
|
||||
|
@ -653,17 +652,12 @@ void ModPopup::onEnable(CCObject*) {
|
|||
else {
|
||||
FLAlertLayer::create("Error Toggling Mod", "This mod can not be toggled!", "OK")->show();
|
||||
}
|
||||
this->updateState();
|
||||
UpdateModListStateEvent(UpdateModState(m_source.getID())).post();
|
||||
}
|
||||
|
||||
void ModPopup::onUninstall(CCObject*) {
|
||||
if (auto mod = m_source.asMod()) {
|
||||
auto popup = ConfirmUninstallPopup::create(mod);
|
||||
popup->onUpdateParentState([this] {
|
||||
this->updateState();
|
||||
this->onClose(nullptr);
|
||||
});
|
||||
popup->show();
|
||||
ConfirmUninstallPopup::create(mod)->show();
|
||||
}
|
||||
else {
|
||||
FLAlertLayer::create(
|
||||
|
@ -693,7 +687,3 @@ ModPopup* ModPopup::create(ModSource&& src) {
|
|||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ModPopup::onUpdateParentState(MiniFunction<void()> listener) {
|
||||
m_updateParentState = listener;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <Geode/ui/MDTextArea.hpp>
|
||||
#include "../sources/ModSource.hpp"
|
||||
#include "../GeodeStyle.hpp"
|
||||
#include "../UpdateModListState.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
|
@ -31,7 +32,7 @@ protected:
|
|||
std::unordered_map<Tab, std::pair<GeodeTabSprite*, Ref<CCNode>>> m_tabs;
|
||||
EventListener<PromiseEventFilter<server::ServerModMetadata, server::ServerError>> m_statsListener;
|
||||
EventListener<PromiseEventFilter<std::unordered_set<std::string>, server::ServerError>> m_tagsListener;
|
||||
MiniFunction<void()> m_updateParentState = nullptr;
|
||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
|
||||
bool setup(ModSource&& src) override;
|
||||
void updateState();
|
||||
|
@ -52,6 +53,4 @@ protected:
|
|||
|
||||
public:
|
||||
static ModPopup* create(ModSource&& src);
|
||||
|
||||
void onUpdateParentState(MiniFunction<void()> listener);
|
||||
};
|
||||
|
|
|
@ -4,6 +4,17 @@
|
|||
ModSource::ModSource(Mod* mod) : m_value(mod) {}
|
||||
ModSource::ModSource(server::ServerModMetadata&& metadata) : m_value(metadata) {}
|
||||
|
||||
std::string ModSource::getID() const {
|
||||
return std::visit(makeVisitor {
|
||||
[](Mod* mod) {
|
||||
return mod->getID();
|
||||
},
|
||||
[](server::ServerModMetadata const& metadata) {
|
||||
// Versions should be guaranteed to have at least one item
|
||||
return metadata.id;
|
||||
}
|
||||
}, m_value);
|
||||
}
|
||||
ModMetadata ModSource::getMetadata() const {
|
||||
return std::visit(makeVisitor {
|
||||
[](Mod* mod) {
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
ModSource(Mod* mod);
|
||||
ModSource(server::ServerModMetadata&& metadata);
|
||||
|
||||
std::string getID() const;
|
||||
ModMetadata getMetadata() const;
|
||||
std::optional<std::string> getAbout() const;
|
||||
std::optional<std::string> getChangelog() const;
|
||||
|
|
Loading…
Reference in a new issue