mirror of
https://github.com/geode-sdk/geode.git
synced 2024-11-14 19:15:05 -05:00
use tag display names from server
This commit is contained in:
parent
7c4e06d20c
commit
893b03e313
10 changed files with 93 additions and 68 deletions
|
@ -246,6 +246,31 @@ std::string ServerDateTime::toAgoString() const {
|
||||||
return fmt::format("{:%b %d %Y}", value);
|
return fmt::format("{:%b %d %Y}", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Result<ServerTag> ServerTag::parse(matjson::Value const& raw) {
|
||||||
|
auto root = checkJson(raw, "ServerTag");
|
||||||
|
auto res = ServerTag();
|
||||||
|
|
||||||
|
root.needs("id").into(res.id);
|
||||||
|
root.needs("name").into(res.name);
|
||||||
|
root.needs("display_name").into(res.displayName);
|
||||||
|
|
||||||
|
return root.ok(res);
|
||||||
|
}
|
||||||
|
Result<std::vector<ServerTag>> ServerTag::parseList(matjson::Value const& raw) {
|
||||||
|
auto payload = checkJson(raw, "ServerTagsList");
|
||||||
|
std::vector<ServerTag> list {};
|
||||||
|
for (auto& item : payload.items()) {
|
||||||
|
auto mod = ServerTag::parse(item.json());
|
||||||
|
if (mod) {
|
||||||
|
list.push_back(mod.unwrap());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log::error("Unable to parse tag from the server: {}", mod.unwrapErr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return payload.ok(list);
|
||||||
|
}
|
||||||
|
|
||||||
Result<ServerDateTime> ServerDateTime::parse(std::string const& str) {
|
Result<ServerDateTime> ServerDateTime::parse(std::string const& str) {
|
||||||
std::stringstream ss(str);
|
std::stringstream ss(str);
|
||||||
date::sys_seconds seconds;
|
date::sys_seconds seconds;
|
||||||
|
@ -690,33 +715,25 @@ ServerRequest<ByteVector> server::getModLogo(std::string const& id, bool useCach
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerRequest<std::unordered_set<std::string>> server::getTags(bool useCache) {
|
ServerRequest<std::vector<ServerTag>> server::getTags(bool useCache) {
|
||||||
if (useCache) {
|
if (useCache) {
|
||||||
return getCache<getTags>().get();
|
return getCache<getTags>().get();
|
||||||
}
|
}
|
||||||
auto req = web::WebRequest();
|
auto req = web::WebRequest();
|
||||||
req.userAgent(getServerUserAgent());
|
req.userAgent(getServerUserAgent());
|
||||||
return req.get(formatServerURL("/tags")).map(
|
return req.get(formatServerURL("/detailed-tags")).map(
|
||||||
[](web::WebResponse* response) -> Result<std::unordered_set<std::string>, ServerError> {
|
[](web::WebResponse* response) -> Result<std::vector<ServerTag>, ServerError> {
|
||||||
if (response->ok()) {
|
if (response->ok()) {
|
||||||
// Parse payload
|
// Parse payload
|
||||||
auto payload = parseServerPayload(*response);
|
auto payload = parseServerPayload(*response);
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
return Err(payload.unwrapErr());
|
return Err(payload.unwrapErr());
|
||||||
}
|
}
|
||||||
matjson::Value json = payload.unwrap();
|
auto list = ServerTag::parseList(payload.unwrap());
|
||||||
if (!json.isArray()) {
|
if (!list) {
|
||||||
return Err(ServerError(response->code(), "Expected a string array"));
|
return Err(ServerError(response->code(), "Unable to parse response: {}", list.unwrapErr()));
|
||||||
}
|
}
|
||||||
|
return Ok(list.unwrap());
|
||||||
std::unordered_set<std::string> tags;
|
|
||||||
for (auto item : json) {
|
|
||||||
if (!item.isString()) {
|
|
||||||
return Err(ServerError(response->code(), "Expected a string array"));
|
|
||||||
}
|
|
||||||
tags.insert(item.asString().unwrap());
|
|
||||||
}
|
|
||||||
return Ok(tags);
|
|
||||||
}
|
}
|
||||||
return Err(parseServerError(*response));
|
return Err(parseServerError(*response));
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
using namespace geode::prelude;
|
using namespace geode::prelude;
|
||||||
|
|
||||||
namespace server {
|
namespace server {
|
||||||
|
// todo: replace parse()s with Serialize::fromJson now that it uses Results
|
||||||
|
|
||||||
struct ServerDateTime final {
|
struct ServerDateTime final {
|
||||||
using Clock = std::chrono::system_clock;
|
using Clock = std::chrono::system_clock;
|
||||||
using Value = std::chrono::time_point<Clock>;
|
using Value = std::chrono::time_point<Clock>;
|
||||||
|
@ -21,6 +23,15 @@ namespace server {
|
||||||
static Result<ServerDateTime> parse(std::string const& str);
|
static Result<ServerDateTime> parse(std::string const& str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ServerTag final {
|
||||||
|
size_t id;
|
||||||
|
std::string name;
|
||||||
|
std::string displayName;
|
||||||
|
|
||||||
|
static Result<ServerTag> parse(matjson::Value const& json);
|
||||||
|
static Result<std::vector<ServerTag>> parseList(matjson::Value const& json);
|
||||||
|
};
|
||||||
|
|
||||||
struct ServerDeveloper final {
|
struct ServerDeveloper final {
|
||||||
std::string username;
|
std::string username;
|
||||||
std::string displayName;
|
std::string displayName;
|
||||||
|
@ -147,7 +158,7 @@ namespace server {
|
||||||
ServerRequest<ServerModMetadata> getMod(std::string const& id, bool useCache = true);
|
ServerRequest<ServerModMetadata> getMod(std::string const& id, bool useCache = true);
|
||||||
ServerRequest<ServerModVersion> getModVersion(std::string const& id, ModVersion const& version = ModVersionLatest(), bool useCache = true);
|
ServerRequest<ServerModVersion> getModVersion(std::string const& id, ModVersion const& version = ModVersionLatest(), bool useCache = true);
|
||||||
ServerRequest<ByteVector> getModLogo(std::string const& id, bool useCache = true);
|
ServerRequest<ByteVector> getModLogo(std::string const& id, bool useCache = true);
|
||||||
ServerRequest<std::unordered_set<std::string>> getTags(bool useCache = true);
|
ServerRequest<std::vector<ServerTag>> getTags(bool useCache = true);
|
||||||
|
|
||||||
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod const* mod);
|
ServerRequest<std::optional<ServerModUpdate>> checkUpdates(Mod const* mod);
|
||||||
|
|
||||||
|
|
|
@ -196,10 +196,10 @@ ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccCol
|
||||||
label->m_BGSprite->setColor(color.second);
|
label->m_BGSprite->setColor(color.second);
|
||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
ButtonSprite* createGeodeTagLabel(std::string_view tag) {
|
ButtonSprite* createGeodeTagLabel(server::ServerTag const& tag) {
|
||||||
return createTagLabel(geodeTagName(tag), geodeTagColors(tag));
|
return createTagLabel(tag.displayName, geodeTagColors(tag));
|
||||||
}
|
}
|
||||||
std::pair<ccColor3B, ccColor3B> geodeTagColors(std::string_view tag) {
|
std::pair<ccColor3B, ccColor3B> geodeTagColors(server::ServerTag const& tag) {
|
||||||
static std::array TAG_COLORS {
|
static std::array TAG_COLORS {
|
||||||
std::make_pair(ccc3(240, 233, 255), ccc3(130, 123, 163)),
|
std::make_pair(ccc3(240, 233, 255), ccc3(130, 123, 163)),
|
||||||
std::make_pair(ccc3(234, 255, 245), ccc3(123, 163, 136)),
|
std::make_pair(ccc3(234, 255, 245), ccc3(123, 163, 136)),
|
||||||
|
@ -207,20 +207,10 @@ std::pair<ccColor3B, ccColor3B> geodeTagColors(std::string_view tag) {
|
||||||
std::make_pair(ccc3(255, 253, 240), ccc3(163, 157, 123)),
|
std::make_pair(ccc3(255, 253, 240), ccc3(163, 157, 123)),
|
||||||
std::make_pair(ccc3(255, 242, 240), ccc3(163, 128, 123)),
|
std::make_pair(ccc3(255, 242, 240), ccc3(163, 128, 123)),
|
||||||
};
|
};
|
||||||
if (tag == "modtober24") {
|
if (tag.name == "modtober24") {
|
||||||
return std::make_pair(ccc3(225, 236, 245), ccc3(82, 139, 201));
|
return std::make_pair(ccc3(225, 236, 245), ccc3(82, 139, 201));
|
||||||
}
|
}
|
||||||
return TAG_COLORS[hash(tag) % 5932 % TAG_COLORS.size()];
|
return TAG_COLORS[hash(tag.name) % 5932 % TAG_COLORS.size()];
|
||||||
}
|
|
||||||
std::string geodeTagName(std::string_view tag) {
|
|
||||||
// todo in v4: rework tags to use a server-provided display name instead
|
|
||||||
if (tag == "modtober24") {
|
|
||||||
return "Modtober 2024";
|
|
||||||
}
|
|
||||||
// Everything else just capitalize and that's it
|
|
||||||
auto readable = std::string(tag);
|
|
||||||
readable[0] = std::toupper(readable[0]);
|
|
||||||
return readable;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ListBorders* createGeodeListBorders(CCSize const& size, bool forceDisableTheme) {
|
ListBorders* createGeodeListBorders(CCSize const& size, bool forceDisableTheme) {
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <Geode/ui/BasedButtonSprite.hpp>
|
#include <Geode/ui/BasedButtonSprite.hpp>
|
||||||
#include <Geode/ui/Popup.hpp>
|
#include <Geode/ui/Popup.hpp>
|
||||||
#include <Geode/loader/Mod.hpp>
|
#include <Geode/loader/Mod.hpp>
|
||||||
|
#include <server/Server.hpp>
|
||||||
|
|
||||||
using namespace geode::prelude;
|
using namespace geode::prelude;
|
||||||
|
|
||||||
|
@ -87,9 +88,8 @@ ButtonSprite* createGeodeButton(std::string const& text, bool gold = false, Geod
|
||||||
CircleButtonSprite* createGeodeCircleButton(CCSprite* top, float scale = 1.f, CircleBaseSize size = CircleBaseSize::Medium, bool altColor = false, bool forceDisableTheme = false);
|
CircleButtonSprite* createGeodeCircleButton(CCSprite* top, float scale = 1.f, CircleBaseSize size = CircleBaseSize::Medium, bool altColor = false, bool forceDisableTheme = false);
|
||||||
|
|
||||||
ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccColor3B> const& color);
|
ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccColor3B> const& color);
|
||||||
ButtonSprite* createGeodeTagLabel(std::string_view tag);
|
ButtonSprite* createGeodeTagLabel(server::ServerTag const& tag);
|
||||||
std::pair<ccColor3B, ccColor3B> geodeTagColors(std::string_view tag);
|
std::pair<ccColor3B, ccColor3B> geodeTagColors(server::ServerTag const& tag);
|
||||||
std::string geodeTagName(std::string_view tag);
|
|
||||||
|
|
||||||
ListBorders* createGeodeListBorders(CCSize const& size, bool forceDisableTheme = false);
|
ListBorders* createGeodeListBorders(CCSize const& size, bool forceDisableTheme = false);
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ bool FiltersPopup::setup(ModListSource* src) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FiltersPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event) {
|
void FiltersPopup::onLoadTags(typename server::ServerRequest<std::vector<server::ServerTag>>::Event* event) {
|
||||||
if (event->getValue() && event->getValue()->isOk()) {
|
if (event->getValue() && event->getValue()->isOk()) {
|
||||||
auto tags = event->getValue()->unwrap();
|
auto tags = event->getValue()->unwrap();
|
||||||
m_tagsMenu->removeAllChildren();
|
m_tagsMenu->removeAllChildren();
|
||||||
|
@ -157,7 +157,7 @@ void FiltersPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<
|
||||||
offSpr, onSpr, this, menu_selector(FiltersPopup::onSelectTag)
|
offSpr, onSpr, this, menu_selector(FiltersPopup::onSelectTag)
|
||||||
);
|
);
|
||||||
btn->m_notClickable = true;
|
btn->m_notClickable = true;
|
||||||
btn->setUserObject("tag", CCString::create(tag));
|
btn->setUserObject("tag", CCString::create(tag.name));
|
||||||
m_tagsMenu->addChild(btn);
|
m_tagsMenu->addChild(btn);
|
||||||
}
|
}
|
||||||
m_tagsMenu->updateLayout();
|
m_tagsMenu->updateLayout();
|
||||||
|
|
|
@ -13,14 +13,14 @@ protected:
|
||||||
ModListSource* m_source;
|
ModListSource* m_source;
|
||||||
CCMenu* m_tagsMenu;
|
CCMenu* m_tagsMenu;
|
||||||
std::unordered_set<std::string> m_selectedTags;
|
std::unordered_set<std::string> m_selectedTags;
|
||||||
EventListener<server::ServerRequest<std::unordered_set<std::string>>> m_tagsListener;
|
EventListener<server::ServerRequest<std::vector<server::ServerTag>>> m_tagsListener;
|
||||||
CCMenuItemToggler* m_enabledModsOnly = nullptr;
|
CCMenuItemToggler* m_enabledModsOnly = nullptr;
|
||||||
TextInput* m_developerNameInput = nullptr;
|
TextInput* m_developerNameInput = nullptr;
|
||||||
|
|
||||||
bool setup(ModListSource* src) override;
|
bool setup(ModListSource* src) override;
|
||||||
void updateTags();
|
void updateTags();
|
||||||
|
|
||||||
void onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event);
|
void onLoadTags(typename server::ServerRequest<std::vector<server::ServerTag>>::Event* event);
|
||||||
void onResetTags(CCObject*);
|
void onResetTags(CCObject*);
|
||||||
void onResetDevName(CCObject*);
|
void onResetDevName(CCObject*);
|
||||||
void onSelectTag(CCObject* sender);
|
void onSelectTag(CCObject* sender);
|
||||||
|
|
|
@ -885,7 +885,7 @@ void ModPopup::onCheckUpdates(typename server::ServerRequest<std::optional<serve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event) {
|
void ModPopup::onLoadTags(typename server::ServerRequest<std::vector<server::ServerTag>>::Event* event) {
|
||||||
if (event->getValue() && event->getValue()->isOk()) {
|
if (event->getValue() && event->getValue()->isOk()) {
|
||||||
auto data = event->getValue()->unwrap();
|
auto data = event->getValue()->unwrap();
|
||||||
m_tags->removeAllChildren();
|
m_tags->removeAllChildren();
|
||||||
|
@ -904,7 +904,7 @@ void ModPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<std:
|
||||||
// If the build times from the cool popup become too long then we can
|
// If the build times from the cool popup become too long then we can
|
||||||
// probably move that to a normal FLAlert that explains "Modtober was
|
// probably move that to a normal FLAlert that explains "Modtober was
|
||||||
// this contest blah blah this mod was made for it"
|
// this contest blah blah this mod was made for it"
|
||||||
else if (data.contains("modtober24")) {
|
else if (ranges::contains(data, [](auto const& tag) { return tag.name == "modtober24"; })) {
|
||||||
auto menu = CCMenu::create();
|
auto menu = CCMenu::create();
|
||||||
menu->setID("modtober-banner");
|
menu->setID("modtober-banner");
|
||||||
menu->ignoreAnchorPointForPosition(false);
|
menu->ignoreAnchorPointForPosition(false);
|
||||||
|
|
|
@ -38,7 +38,7 @@ protected:
|
||||||
CCNode* m_modtoberBanner = nullptr;
|
CCNode* m_modtoberBanner = nullptr;
|
||||||
std::unordered_map<Tab, std::pair<GeodeTabSprite*, Ref<CCNode>>> m_tabs;
|
std::unordered_map<Tab, std::pair<GeodeTabSprite*, Ref<CCNode>>> m_tabs;
|
||||||
EventListener<server::ServerRequest<server::ServerModMetadata>> m_statsListener;
|
EventListener<server::ServerRequest<server::ServerModMetadata>> m_statsListener;
|
||||||
EventListener<server::ServerRequest<std::unordered_set<std::string>>> m_tagsListener;
|
EventListener<server::ServerRequest<std::vector<server::ServerTag>>> m_tagsListener;
|
||||||
EventListener<server::ServerRequest<std::optional<server::ServerModUpdate>>> m_checkUpdateListener;
|
EventListener<server::ServerRequest<std::optional<server::ServerModUpdate>>> m_checkUpdateListener;
|
||||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||||
EventListener<server::ModDownloadFilter> m_downloadListener;
|
EventListener<server::ModDownloadFilter> m_downloadListener;
|
||||||
|
@ -52,7 +52,7 @@ protected:
|
||||||
void setStatValue(CCNode* stat, std::optional<std::string> const& value);
|
void setStatValue(CCNode* stat, std::optional<std::string> const& value);
|
||||||
|
|
||||||
void onLoadServerInfo(typename server::ServerRequest<server::ServerModMetadata>::Event* event);
|
void onLoadServerInfo(typename server::ServerRequest<server::ServerModMetadata>::Event* event);
|
||||||
void onLoadTags(typename server::ServerRequest<std::unordered_set<std::string>>::Event* event);
|
void onLoadTags(typename server::ServerRequest<std::vector<server::ServerTag>>::Event* event);
|
||||||
void onCheckUpdates(typename server::ServerRequest<std::optional<server::ServerModUpdate>>::Event* event);
|
void onCheckUpdates(typename server::ServerRequest<std::optional<server::ServerModUpdate>>::Event* event);
|
||||||
|
|
||||||
void onTab(CCObject* sender);
|
void onTab(CCObject* sender);
|
||||||
|
|
|
@ -163,34 +163,41 @@ server::ServerRequest<server::ServerModMetadata> ModSource::fetchServerInfo() co
|
||||||
// should deal with performance issues
|
// should deal with performance issues
|
||||||
return server::getMod(this->getID());
|
return server::getMod(this->getID());
|
||||||
}
|
}
|
||||||
server::ServerRequest<std::unordered_set<std::string>> ModSource::fetchValidTags() const {
|
server::ServerRequest<std::vector<server::ServerTag>> ModSource::fetchValidTags() const {
|
||||||
return std::visit(makeVisitor {
|
std::unordered_set<std::string> modTags;
|
||||||
[](server::ServerModMetadata const& metadata) {
|
std::visit(makeVisitor {
|
||||||
// Server info tags are always certain to be valid since the server has already validated them
|
[&](Mod* mod) {
|
||||||
return server::ServerRequest<std::unordered_set<std::string>>::immediate(Ok(metadata.tags));
|
modTags = mod->getMetadata().getTags();
|
||||||
},
|
},
|
||||||
[this](auto const&) {
|
[&](server::ServerModMetadata const& metadata) {
|
||||||
return server::getTags().map(
|
modTags = metadata.tags;
|
||||||
[modTags = this->getMetadata().getTags()](auto* result) -> Result<std::unordered_set<std::string>, server::ServerError> {
|
},
|
||||||
if (result->isOk()) {
|
}, m_value);
|
||||||
std::unordered_set<std::string> fetched = result->unwrap();
|
|
||||||
// Filter out invalid tags
|
|
||||||
auto finalTags = std::unordered_set<std::string>();
|
|
||||||
for (auto& tag : modTags) {
|
|
||||||
if (result->unwrap().contains(tag)) {
|
|
||||||
finalTags.insert(tag);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// This does two things:
|
||||||
|
// 1. For installed mods, it filters out invalid tags
|
||||||
|
// 2. For everything else, it gets the rest of the tag info (display name) from the server
|
||||||
|
return server::getTags().map(
|
||||||
|
[modTags = std::move(modTags)](auto* result) -> Result<std::vector<server::ServerTag>, server::ServerError> {
|
||||||
|
auto finalTags = std::vector<server::ServerTag>();
|
||||||
|
if (result->isOk()) {
|
||||||
|
auto fetched = result->unwrap();
|
||||||
|
// Filter out invalid tags
|
||||||
|
for (auto& tag : modTags) {
|
||||||
|
auto stag = ranges::find(fetched, [&tag](server::ServerTag const& stag) {
|
||||||
|
return stag.name == tag;
|
||||||
|
});
|
||||||
|
if (stag) {
|
||||||
|
finalTags.push_back(*stag);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return Ok(finalTags);
|
return Ok(finalTags);
|
||||||
},
|
},
|
||||||
[](server::ServerProgress* progress) {
|
[](server::ServerProgress* progress) {
|
||||||
return *progress;
|
return *progress;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
|
||||||
}, m_value);
|
|
||||||
}
|
}
|
||||||
server::ServerRequest<std::optional<server::ServerModUpdate>> ModSource::checkUpdates() {
|
server::ServerRequest<std::optional<server::ServerModUpdate>> ModSource::checkUpdates() {
|
||||||
m_availableUpdate = std::nullopt;
|
m_availableUpdate = std::nullopt;
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
server::ServerRequest<server::ServerModMetadata> fetchServerInfo() const;
|
server::ServerRequest<server::ServerModMetadata> fetchServerInfo() const;
|
||||||
server::ServerRequest<std::optional<std::string>> fetchAbout() const;
|
server::ServerRequest<std::optional<std::string>> fetchAbout() const;
|
||||||
server::ServerRequest<std::optional<std::string>> fetchChangelog() const;
|
server::ServerRequest<std::optional<std::string>> fetchChangelog() const;
|
||||||
server::ServerRequest<std::unordered_set<std::string>> fetchValidTags() const;
|
server::ServerRequest<std::vector<server::ServerTag>> fetchValidTags() const;
|
||||||
server::ServerRequest<std::optional<server::ServerModUpdate>> checkUpdates();
|
server::ServerRequest<std::optional<server::ServerModUpdate>> checkUpdates();
|
||||||
void startInstall();
|
void startInstall();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue