mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
refactor a bit; works like a charm :3
This commit is contained in:
parent
2689320116
commit
708d1ec873
10 changed files with 266 additions and 153 deletions
|
@ -36,7 +36,9 @@ namespace geode {
|
|||
*/
|
||||
GEODE_DLL cocos2d::CCNode* createModLogo(Mod* mod);
|
||||
/**
|
||||
* Create a logo sprite for an index item
|
||||
* Create a logo sprite for a mod downloaded from the Geode servers. The
|
||||
* logo is initially a loading circle, with the actual sprite downloaded
|
||||
* asynchronously
|
||||
*/
|
||||
// GEODE_DLL cocos2d::CCNode* createIndexItemLogo(IndexItemHandle item);
|
||||
GEODE_DLL cocos2d::CCNode* createServerModLogo(std::string const& id);
|
||||
}
|
||||
|
|
BIN
loader/resources/globe.png
Normal file
BIN
loader/resources/globe.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -9,6 +9,32 @@ using namespace server;
|
|||
#define GEODE_GD_VERSION_STRINGIFY_2(version) GEODE_GD_VERSION_STRINGIFY(version)
|
||||
#define GEODE_GD_VERSION_STR GEODE_GD_VERSION_STRINGIFY_2(GEODE_GD_VERSION)
|
||||
|
||||
static void parseServerError(auto reject, auto error) {
|
||||
// The server should return errors as `{ "error": "...", "payload": "" }`
|
||||
if (auto json = error.json()) {
|
||||
reject(ServerError(
|
||||
"Error code: {}; details: {}",
|
||||
error.code(), json.unwrap().template get<std::string>("error")
|
||||
));
|
||||
}
|
||||
// But if we get something else for some reason, return that
|
||||
else {
|
||||
reject(ServerError(
|
||||
"Error code: {}; details: {}",
|
||||
error.code(), error.string().unwrapOr("Unknown (not a valid string)")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
static void parseServerProgress(auto progress, auto prog, auto msg) {
|
||||
if (auto per = prog.downloadProgress()) {
|
||||
progress({ msg, static_cast<uint8_t>(*per) });
|
||||
}
|
||||
else {
|
||||
progress({ msg });
|
||||
}
|
||||
}
|
||||
|
||||
const char* server::sortToString(ModsSort sorting) {
|
||||
switch (sorting) {
|
||||
default:
|
||||
|
@ -112,12 +138,14 @@ Result<ServerModMetadata> ServerModMetadata::parse(matjson::Value const& raw) {
|
|||
root.has("about").into(res.about);
|
||||
root.has("changelog").into(res.changelog);
|
||||
|
||||
std::vector<std::string> developerNames;
|
||||
for (auto item : root.needs("developers").iterate()) {
|
||||
auto obj = item.obj();
|
||||
auto dev = ServerDeveloper();
|
||||
obj.needs("username").into(dev.username);
|
||||
obj.needs("display_name").into(dev.displayName);
|
||||
res.developers.push_back(dev);
|
||||
developerNames.push_back(dev.displayName);
|
||||
}
|
||||
for (auto item : root.needs("versions").iterate()) {
|
||||
auto versionRes = ServerModVersion::parse(item.json());
|
||||
|
@ -125,6 +153,7 @@ Result<ServerModMetadata> ServerModMetadata::parse(matjson::Value const& raw) {
|
|||
auto version = versionRes.unwrap();
|
||||
version.metadata.setDetails(res.about);
|
||||
version.metadata.setChangelog(res.changelog);
|
||||
version.metadata.setDevelopers(developerNames);
|
||||
res.versions.push_back(version);
|
||||
}
|
||||
else {
|
||||
|
@ -197,7 +226,9 @@ ServerPromise<ServerModsList> server::getMods(ModsQuery query) {
|
|||
if (query.tags.size()) {
|
||||
req.param("tags", ranges::join(query.tags, ","));
|
||||
}
|
||||
req.param("featured", query.featuredOnly ? "true" : "false");
|
||||
if (query.featured) {
|
||||
req.param("featured", query.featured.value() ? "true" : "false");
|
||||
}
|
||||
req.param("sort", sortToString(query.sorting));
|
||||
if (query.developer) {
|
||||
req.param("developer", *query.developer);
|
||||
|
@ -228,28 +259,28 @@ ServerPromise<ServerModsList> server::getMods(ModsQuery query) {
|
|||
if (error.code() == 404) {
|
||||
return resolve(ServerModsList());
|
||||
}
|
||||
// The server should return errors as `{ "error": "...", "payload": "" }`
|
||||
if (auto json = error.json()) {
|
||||
reject(ServerError(
|
||||
"Error code: {}; details: {}",
|
||||
error.code(), json.unwrap().template get<std::string>("error")
|
||||
));
|
||||
}
|
||||
// But if we get something else for some reason, return that
|
||||
else {
|
||||
reject(ServerError(
|
||||
"Error code: {}; details: {}",
|
||||
error.code(), error.string().unwrapOr("Unknown (not a valid string)")
|
||||
));
|
||||
}
|
||||
parseServerError(reject, error);
|
||||
})
|
||||
.progress([progress](auto prog) {
|
||||
if (auto per = prog.downloadProgress()) {
|
||||
progress({ "Downloading mods", static_cast<uint8_t>(*per) });
|
||||
}
|
||||
else {
|
||||
progress({ "Downloading mods" });
|
||||
}
|
||||
parseServerProgress(progress, prog, "Downloading mods");
|
||||
})
|
||||
.link(cancel);
|
||||
});
|
||||
}
|
||||
|
||||
ServerPromise<ByteVector> server::getModLogo(std::string const& id) {
|
||||
auto req = web::WebRequest();
|
||||
req.param("id", id);
|
||||
return ServerPromise<ByteVector>([req = std::move(req), id](auto resolve, auto reject, auto progress, auto cancel) mutable {
|
||||
req.get(getServerAPIBaseURL() + "/mods/" + id + "/logo")
|
||||
.then([resolve](auto response) {
|
||||
resolve(response.data());
|
||||
})
|
||||
.expect([reject](auto error) {
|
||||
parseServerError(reject, error);
|
||||
})
|
||||
.progress([progress, id](auto prog) {
|
||||
parseServerProgress(progress, prog, "Downloading logo for " + id);
|
||||
})
|
||||
.link(cancel);
|
||||
});
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace server {
|
|||
std::optional<std::string> query;
|
||||
std::unordered_set<PlatformID> platforms = { GEODE_PLATFORM_TARGET };
|
||||
std::unordered_set<std::string> tags;
|
||||
bool featuredOnly = false;
|
||||
std::optional<bool> featured;
|
||||
ModsSort sorting = ModsSort::Downloads;
|
||||
std::optional<std::string> developer;
|
||||
size_t page = 0;
|
||||
|
@ -77,4 +77,5 @@ namespace server {
|
|||
|
||||
std::string getServerAPIBaseURL();
|
||||
ServerPromise<ServerModsList> getMods(ModsQuery query);
|
||||
ServerPromise<ByteVector> getModLogo(std::string const& id);
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
#include "mods/ModsLayer.hpp"
|
||||
|
||||
#include <Geode/loader/Dirs.hpp>
|
||||
#include <Geode/ui/GeodeUI.hpp>
|
||||
#include <Geode/ui/MDPopup.hpp>
|
||||
#include <Geode/utils/web.hpp>
|
||||
#include <server/Server.hpp>
|
||||
|
||||
void geode::openModsList() {
|
||||
ModsLayer::scene();
|
||||
|
@ -65,26 +65,95 @@ void geode::openSettingsPopup(Mod* mod) {
|
|||
}
|
||||
}
|
||||
|
||||
CCNode* geode::createDefaultLogo() {
|
||||
CCNode* spr = CCSprite::createWithSpriteFrameName("no-logo.png"_spr);
|
||||
if (!spr) {
|
||||
spr = CCLabelBMFont::create("OwO", "goldFont.fnt");
|
||||
class ModLogoSprite : public CCNode {
|
||||
protected:
|
||||
std::string m_modID;
|
||||
CCNode* m_sprite = nullptr;
|
||||
EventListener<PromiseEventFilter<ByteVector, server::ServerError>> m_listener;
|
||||
|
||||
bool init(std::string const& id, bool fetch) {
|
||||
if (!CCNode::init())
|
||||
return false;
|
||||
|
||||
this->setAnchorPoint({ .5f, .5f });
|
||||
this->setContentSize({ 50, 50 });
|
||||
|
||||
m_modID = id;
|
||||
m_listener.bind(this, &ModLogoSprite::onFetch);
|
||||
|
||||
// Load from Resources
|
||||
if (!fetch) {
|
||||
this->setSprite(id == "geode.loader" ?
|
||||
CCSprite::createWithSpriteFrameName("geode-logo.png"_spr) :
|
||||
CCSprite::create(fmt::format("{}/logo.png", id).c_str())
|
||||
);
|
||||
}
|
||||
// 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)));
|
||||
m_listener.setFilter(server::getModLogo(id).listen());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return spr;
|
||||
|
||||
void setSprite(CCNode* sprite) {
|
||||
// Remove any existing sprite
|
||||
if (m_sprite) {
|
||||
m_sprite->removeFromParent();
|
||||
}
|
||||
// Fallback to default logo if the sprite is null
|
||||
if (!sprite) {
|
||||
sprite = CCSprite::createWithSpriteFrameName("no-logo.png"_spr);
|
||||
}
|
||||
// Fallback to lobotomy if Geode sprites are missing
|
||||
if (!sprite) {
|
||||
sprite = CCSprite::createWithSpriteFrameName("difficulty_02_btn_001.png");
|
||||
}
|
||||
// Set sprite and scale it to node size
|
||||
m_sprite = sprite;
|
||||
limitNodeSize(m_sprite, m_obContentSize, 99.f, .05f);
|
||||
this->addChildAtPosition(m_sprite, Anchor::Center);
|
||||
}
|
||||
|
||||
void onFetch(PromiseEvent<ByteVector, server::ServerError>* event) {
|
||||
// Set default sprite on error
|
||||
if (event->getReject()) {
|
||||
this->setSprite(nullptr);
|
||||
}
|
||||
else if (auto data = event->getResolve()) {
|
||||
auto image = Ref(new CCImage());
|
||||
image->initWithImageData(const_cast<uint8_t*>(data->data()), data->size());
|
||||
|
||||
auto texture = CCTextureCache::get()->addUIImage(image, m_modID.c_str());
|
||||
this->setSprite(CCSprite::createWithTexture(texture));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static ModLogoSprite* create(std::string const& id, bool fetch) {
|
||||
auto ret = new ModLogoSprite();
|
||||
if (ret && ret->init(id, fetch)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
CCNode* geode::createDefaultLogo() {
|
||||
return ModLogoSprite::create("", false);
|
||||
}
|
||||
|
||||
CCNode* geode::createModLogo(Mod* mod) {
|
||||
CCNode* ret = nullptr;
|
||||
if (mod == Mod::get()) {
|
||||
ret = CCSprite::createWithSpriteFrameName("geode-logo.png"_spr);
|
||||
}
|
||||
else {
|
||||
ret = CCSprite::create(fmt::format("{}/logo.png", mod->getID()).c_str());
|
||||
}
|
||||
if (!ret) {
|
||||
ret = createDefaultLogo();
|
||||
}
|
||||
return ret;
|
||||
return ModLogoSprite::create(mod->getID(), false);
|
||||
}
|
||||
|
||||
CCNode* geode::createServerModLogo(std::string const& id) {
|
||||
return ModLogoSprite::create(id, true);
|
||||
}
|
||||
|
||||
// CCNode* geode::createIndexItemLogo(IndexItemHandle item) {
|
||||
|
|
|
@ -138,7 +138,7 @@ ModMetadata ServerModItem::getMetadata() const {
|
|||
}
|
||||
|
||||
CCNode* ServerModItem::createModLogo() const {
|
||||
return CCSprite::create("loadingCircle.png");
|
||||
return createServerModLogo(m_metadata.id);
|
||||
}
|
||||
|
||||
bool ServerModItem::wantsRestart() const {
|
||||
|
|
|
@ -8,11 +8,57 @@ static size_t ceildiv(size_t a, size_t b) {
|
|||
return a / b + (a % b != 0);
|
||||
}
|
||||
|
||||
#define GEODE_GD_VERSION_STRINGIFY(version) # version
|
||||
#define GEODE_GD_VERSION_STRINGIFY_2(version) GEODE_GD_VERSION_STRINGIFY(version)
|
||||
#define GEODE_GD_VERSION_STR GEODE_GD_VERSION_STRINGIFY_2(GEODE_GD_VERSION)
|
||||
static auto loadInstalledModsPage(size_t page) {
|
||||
return ModListSource::ProviderPromise([page](auto resolve, auto, auto, auto const&) {
|
||||
Loader::get()->queueInMainThread([page, resolve = std::move(resolve)] {
|
||||
auto content = ModListSource::Page();
|
||||
auto all = Loader::get()->getAllMods();
|
||||
for (
|
||||
size_t i = page * PAGE_SIZE;
|
||||
i < all.size() && i < (page + 1) * PAGE_SIZE;
|
||||
i += 1
|
||||
) {
|
||||
content.push_back(InstalledModItem::create(all.at(i)));
|
||||
}
|
||||
resolve({ content, all.size() });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static auto loadServerModsPage(size_t page, bool featuredOnly) {
|
||||
return ModListSource::ProviderPromise([page, featuredOnly](auto resolve, auto reject, auto progress, auto cancelled) {
|
||||
server::getMods(server::ModsQuery {
|
||||
.featured = featuredOnly ? std::optional(true) : std::nullopt,
|
||||
.page = page,
|
||||
.pageSize = PAGE_SIZE,
|
||||
})
|
||||
.then([resolve, reject](server::ServerModsList list) {
|
||||
if (list.totalModCount == 0) {
|
||||
return reject(ModListSource::LoadPageError("No mods found :("));
|
||||
}
|
||||
auto content = ModListSource::Page();
|
||||
for (auto mod : list.mods) {
|
||||
content.push_back(ServerModItem::create(mod));
|
||||
}
|
||||
resolve({ content, list.totalModCount });
|
||||
})
|
||||
.expect([reject](auto error) {
|
||||
reject(ModListSource::LoadPageError("Error loading mods", error.details));
|
||||
})
|
||||
.progress([progress](auto prog) {
|
||||
progress(prog.percentage);
|
||||
})
|
||||
.link(cancelled);
|
||||
});
|
||||
}
|
||||
|
||||
typename ModListSource::PagePromise ModListSource::loadPage(size_t page, bool update) {
|
||||
// Return a generic "Coming soon" message if there's no provider set
|
||||
if (!m_provider) {
|
||||
return PagePromise([this, page](auto, auto reject) {
|
||||
reject("Coming soon! ;)");
|
||||
});
|
||||
}
|
||||
if (!update && m_cachedPages.contains(page)) {
|
||||
return PagePromise([this, page](auto resolve, auto) {
|
||||
Loader::get()->queueInMainThread([this, page, resolve] {
|
||||
|
@ -22,10 +68,11 @@ typename ModListSource::PagePromise ModListSource::loadPage(size_t page, bool up
|
|||
}
|
||||
m_cachedPages.erase(page);
|
||||
return PagePromise([this, page](auto resolve, auto reject, auto progress, auto cancelled) {
|
||||
this->reloadPage(page)
|
||||
m_provider(page)
|
||||
.then([page, this, resolve = std::move(resolve)](auto data) {
|
||||
m_cachedPages.insert({ page, data });
|
||||
resolve(data);
|
||||
m_cachedItemCount = data.second;
|
||||
m_cachedPages.insert({ page, data.first });
|
||||
resolve(data.first);
|
||||
})
|
||||
.expect([this, reject = std::move(reject)](auto error) {
|
||||
reject(error);
|
||||
|
@ -45,69 +92,43 @@ std::optional<size_t> ModListSource::getItemCount() const {
|
|||
return m_cachedItemCount;
|
||||
}
|
||||
|
||||
typename ModListSource::PagePromise InstalledModsList::reloadPage(size_t page) {
|
||||
m_cachedItemCount = Loader::get()->getAllMods().size();
|
||||
return PagePromise([page](auto resolve, auto, auto, auto const&) {
|
||||
Loader::get()->queueInMainThread([page, resolve = std::move(resolve)] {
|
||||
auto content = Page();
|
||||
auto all = Loader::get()->getAllMods();
|
||||
for (
|
||||
size_t i = page * PAGE_SIZE;
|
||||
i < all.size() && i < (page + 1) * PAGE_SIZE;
|
||||
i += 1
|
||||
) {
|
||||
content.push_back(InstalledModItem::create(all.at(i)));
|
||||
}
|
||||
resolve(content);
|
||||
});
|
||||
});
|
||||
ModListSource* ModListSource::create(Provider* provider) {
|
||||
auto ret = new ModListSource();
|
||||
ret->m_provider = provider;
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
|
||||
InstalledModsList* InstalledModsList::get() {
|
||||
static auto inst = new InstalledModsList();
|
||||
return inst;
|
||||
}
|
||||
ModListSource* ModListSource::get(ModListSourceType type) {
|
||||
switch (type) {
|
||||
default:
|
||||
case ModListSourceType::Installed: {
|
||||
static auto inst = ModListSource::create(loadInstalledModsPage);
|
||||
return inst;
|
||||
} break;
|
||||
|
||||
typename ModListSource::PagePromise FeaturedModsList::reloadPage(size_t page) {
|
||||
return PagePromise([this, page](auto resolve, auto reject, auto progress, auto cancelled) {
|
||||
server::getMods(server::ModsQuery {
|
||||
.page = page,
|
||||
.pageSize = PAGE_SIZE,
|
||||
})
|
||||
.then([this, resolve, reject](server::ServerModsList list) {
|
||||
m_cachedItemCount = list.totalModCount;
|
||||
if (list.totalModCount == 0) {
|
||||
return reject(LoadPageError("No mods found :("));
|
||||
}
|
||||
auto content = Page();
|
||||
for (auto mod : list.mods) {
|
||||
content.push_back(ServerModItem::create(mod));
|
||||
}
|
||||
resolve(content);
|
||||
})
|
||||
.expect([reject](auto error) {
|
||||
reject(LoadPageError("Error loading mods", error.details));
|
||||
})
|
||||
.progress([progress](auto prog) {
|
||||
progress(prog.percentage);
|
||||
})
|
||||
.link(cancelled);
|
||||
});
|
||||
}
|
||||
case ModListSourceType::Featured: {
|
||||
static auto inst = ModListSource::create(+[](size_t page) {
|
||||
return loadServerModsPage(page, true);
|
||||
});
|
||||
return inst;
|
||||
} break;
|
||||
|
||||
FeaturedModsList* FeaturedModsList::get() {
|
||||
static auto inst = new FeaturedModsList();
|
||||
return inst;
|
||||
}
|
||||
case ModListSourceType::Trending: {
|
||||
static auto inst = ModListSource::create(nullptr);
|
||||
return inst;
|
||||
} break;
|
||||
|
||||
typename ModListSource::PagePromise ModPacksModsList::reloadPage(size_t page) {
|
||||
m_cachedItemCount = 0;
|
||||
return PagePromise([](auto, auto reject) {
|
||||
reject(LoadPageError("Coming soon! ;)"));
|
||||
});
|
||||
}
|
||||
case ModListSourceType::ModPacks: {
|
||||
static auto inst = ModListSource::create(nullptr);
|
||||
return inst;
|
||||
} break;
|
||||
|
||||
ModPacksModsList* ModPacksModsList::get() {
|
||||
static auto inst = new ModPacksModsList();
|
||||
return inst;
|
||||
case ModListSourceType::All: {
|
||||
static auto inst = ModListSource::create(+[](size_t page) {
|
||||
return loadServerModsPage(page, false);
|
||||
});
|
||||
return inst;
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,16 @@
|
|||
|
||||
using namespace geode::prelude;
|
||||
|
||||
enum class ModListSourceType {
|
||||
Installed,
|
||||
Featured,
|
||||
Trending,
|
||||
ModPacks,
|
||||
All,
|
||||
};
|
||||
|
||||
// Handles loading the entries for the mods list
|
||||
class ModListSource {
|
||||
class ModListSource : public CCObject {
|
||||
public:
|
||||
struct LoadPageError {
|
||||
std::string message;
|
||||
|
@ -24,40 +32,23 @@ public:
|
|||
using PageLoadEventListener = EventListener<PageLoadEventFilter>;
|
||||
using PagePromise = Promise<Page, LoadPageError, std::optional<uint8_t>>;
|
||||
|
||||
using ProviderPromise = Promise<std::pair<Page, size_t>, LoadPageError, std::optional<uint8_t>>;
|
||||
using Provider = ProviderPromise(size_t page);
|
||||
|
||||
protected:
|
||||
std::unordered_map<size_t, Page> m_cachedPages;
|
||||
std::optional<size_t> m_cachedItemCount;
|
||||
|
||||
// Load/reload a page. This should also set/update the page count
|
||||
virtual PagePromise reloadPage(size_t page) = 0;
|
||||
Provider* m_provider = nullptr;
|
||||
|
||||
public:
|
||||
// Create a new source with an arbitary provider
|
||||
static ModListSource* create(Provider* provider);
|
||||
|
||||
// Get a standard source (lazily created static instance)
|
||||
static ModListSource* get(ModListSourceType type);
|
||||
|
||||
// Load page, uses cache if possible unless `update` is true
|
||||
PagePromise loadPage(size_t page, bool update = false);
|
||||
std::optional<size_t> getPageCount() const;
|
||||
std::optional<size_t> getItemCount() const;
|
||||
};
|
||||
|
||||
class InstalledModsList : public ModListSource {
|
||||
protected:
|
||||
PagePromise reloadPage(size_t page) override;
|
||||
|
||||
public:
|
||||
static InstalledModsList* get();
|
||||
};
|
||||
|
||||
class FeaturedModsList : public ModListSource {
|
||||
protected:
|
||||
PagePromise reloadPage(size_t page) override;
|
||||
|
||||
public:
|
||||
static FeaturedModsList* get();
|
||||
};
|
||||
|
||||
class ModPacksModsList : public ModListSource {
|
||||
protected:
|
||||
PagePromise reloadPage(size_t page) override;
|
||||
|
||||
public:
|
||||
static ModPacksModsList* get();
|
||||
};
|
||||
|
|
|
@ -365,12 +365,12 @@ bool ModsLayer::init() {
|
|||
mainTabs->setAnchorPoint({ .5f, .0f });
|
||||
mainTabs->setPosition(m_frame->convertToWorldSpace(tabsTop->getPosition() + ccp(0, 10)));
|
||||
|
||||
for (auto item : std::initializer_list<std::tuple<const char*, const char*, ModListSource*>> {
|
||||
{ "download.png"_spr, "Installed", InstalledModsList::get() },
|
||||
{ "GJ_bigStar_noShadow_001.png", "Featured", FeaturedModsList::get() },
|
||||
{ "GJ_sTrendingIcon_001.png", "Trending", nullptr },
|
||||
{ "gj_folderBtn_001.png", "Mod Packs", ModPacksModsList::get() },
|
||||
{ "search.png"_spr, "Search", nullptr },
|
||||
for (auto item : std::initializer_list<std::tuple<const char*, const char*, ModListSourceType>> {
|
||||
{ "download.png"_spr, "Installed", ModListSourceType::Installed },
|
||||
{ "GJ_bigStar_noShadow_001.png", "Featured", ModListSourceType::Featured },
|
||||
{ "GJ_sTrendingIcon_001.png", "Trending", ModListSourceType::Trending },
|
||||
{ "gj_folderBtn_001.png", "Mod Packs", ModListSourceType::ModPacks },
|
||||
{ "globe.png"_spr, "All Mods", ModListSourceType::All },
|
||||
}) {
|
||||
const CCSize itemSize { 100, 35 };
|
||||
const CCSize iconSize { 18, 18 };
|
||||
|
@ -403,7 +403,7 @@ bool ModsLayer::init() {
|
|||
spr->addChildAtPosition(title, Anchor::Left, ccp(28, 0), false);
|
||||
|
||||
auto btn = CCMenuItemSpriteExtra::create(spr, this, menu_selector(ModsLayer::onTab));
|
||||
btn->setUserData(std::get<2>(item));
|
||||
btn->setTag(static_cast<int>(std::get<2>(item)));
|
||||
mainTabs->addChild(btn);
|
||||
m_tabs.push_back(btn);
|
||||
}
|
||||
|
@ -411,7 +411,7 @@ bool ModsLayer::init() {
|
|||
mainTabs->setLayout(RowLayout::create());
|
||||
this->addChild(mainTabs);
|
||||
|
||||
this->gotoTab();
|
||||
this->gotoTab(ModListSourceType::Installed);
|
||||
|
||||
this->setKeypadEnabled(true);
|
||||
cocos::handleTouchPriority(this, true);
|
||||
|
@ -419,19 +419,17 @@ bool ModsLayer::init() {
|
|||
return true;
|
||||
}
|
||||
|
||||
void ModsLayer::gotoTab(ModListSource* src) {
|
||||
// Default to installed mods
|
||||
if (!src) {
|
||||
src = InstalledModsList::get();
|
||||
}
|
||||
|
||||
void ModsLayer::gotoTab(ModListSourceType type) {
|
||||
// Update selected tab
|
||||
for (auto tab : m_tabs) {
|
||||
auto selected = tab->getUserData() == src;
|
||||
auto selected = tab->getTag() == static_cast<int>(type);
|
||||
tab->getNormalImage()->getChildByID("disabled-bg")->setVisible(!selected);
|
||||
tab->getNormalImage()->getChildByID("enabled-bg")->setVisible(selected);
|
||||
tab->setEnabled(!selected);
|
||||
}
|
||||
|
||||
auto src = ModListSource::get(type);
|
||||
|
||||
// Remove current list from UI (it's Ref'd so it stays in memory)
|
||||
if (m_currentSource) {
|
||||
m_lists.at(m_currentSource)->removeFromParent();
|
||||
|
@ -453,7 +451,7 @@ void ModsLayer::gotoTab(ModListSource* src) {
|
|||
}
|
||||
|
||||
void ModsLayer::onTab(CCObject* sender) {
|
||||
this->gotoTab(static_cast<ModListSource*>(static_cast<CCNode*>(sender)->getUserData()));
|
||||
this->gotoTab(static_cast<ModListSourceType>(sender->getTag()));
|
||||
}
|
||||
|
||||
void ModsLayer::keyBackClicked() {
|
||||
|
|
|
@ -17,7 +17,7 @@ using ModListStatus = std::variant<ModListErrorStatus, ModListUnkProgressStatus,
|
|||
|
||||
class ModList : public CCNode, public SetTextPopupDelegate {
|
||||
protected:
|
||||
ModListSource* m_source;
|
||||
Ref<ModListSource> m_source;
|
||||
size_t m_page = 0;
|
||||
ScrollLayer* m_list;
|
||||
CCMenu* m_statusContainer;
|
||||
|
@ -70,5 +70,5 @@ public:
|
|||
void onBack(CCObject*);
|
||||
void onRefreshList(CCObject*);
|
||||
|
||||
void gotoTab(ModListSource* src = nullptr);
|
||||
void gotoTab(ModListSourceType type);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue