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);
|
||||
}
|
||||
|
||||
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) {
|
||||
std::stringstream ss(str);
|
||||
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) {
|
||||
return getCache<getTags>().get();
|
||||
}
|
||||
auto req = web::WebRequest();
|
||||
req.userAgent(getServerUserAgent());
|
||||
return req.get(formatServerURL("/tags")).map(
|
||||
[](web::WebResponse* response) -> Result<std::unordered_set<std::string>, ServerError> {
|
||||
return req.get(formatServerURL("/detailed-tags")).map(
|
||||
[](web::WebResponse* response) -> Result<std::vector<ServerTag>, ServerError> {
|
||||
if (response->ok()) {
|
||||
// Parse payload
|
||||
auto payload = parseServerPayload(*response);
|
||||
if (!payload) {
|
||||
return Err(payload.unwrapErr());
|
||||
}
|
||||
matjson::Value json = payload.unwrap();
|
||||
if (!json.isArray()) {
|
||||
return Err(ServerError(response->code(), "Expected a string array"));
|
||||
auto list = ServerTag::parseList(payload.unwrap());
|
||||
if (!list) {
|
||||
return Err(ServerError(response->code(), "Unable to parse response: {}", list.unwrapErr()));
|
||||
}
|
||||
|
||||
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 Ok(list.unwrap());
|
||||
}
|
||||
return Err(parseServerError(*response));
|
||||
},
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
using namespace geode::prelude;
|
||||
|
||||
namespace server {
|
||||
// todo: replace parse()s with Serialize::fromJson now that it uses Results
|
||||
|
||||
struct ServerDateTime final {
|
||||
using Clock = std::chrono::system_clock;
|
||||
using Value = std::chrono::time_point<Clock>;
|
||||
|
@ -21,6 +23,15 @@ namespace server {
|
|||
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 {
|
||||
std::string username;
|
||||
std::string displayName;
|
||||
|
@ -147,7 +158,7 @@ namespace server {
|
|||
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<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);
|
||||
|
||||
|
|
|
@ -196,10 +196,10 @@ ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccCol
|
|||
label->m_BGSprite->setColor(color.second);
|
||||
return label;
|
||||
}
|
||||
ButtonSprite* createGeodeTagLabel(std::string_view tag) {
|
||||
return createTagLabel(geodeTagName(tag), geodeTagColors(tag));
|
||||
ButtonSprite* createGeodeTagLabel(server::ServerTag const& 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 {
|
||||
std::make_pair(ccc3(240, 233, 255), ccc3(130, 123, 163)),
|
||||
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, 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 TAG_COLORS[hash(tag) % 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;
|
||||
return TAG_COLORS[hash(tag.name) % 5932 % TAG_COLORS.size()];
|
||||
}
|
||||
|
||||
ListBorders* createGeodeListBorders(CCSize const& size, bool forceDisableTheme) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <Geode/ui/BasedButtonSprite.hpp>
|
||||
#include <Geode/ui/Popup.hpp>
|
||||
#include <Geode/loader/Mod.hpp>
|
||||
#include <server/Server.hpp>
|
||||
|
||||
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);
|
||||
|
||||
ButtonSprite* createTagLabel(std::string const& text, std::pair<ccColor3B, ccColor3B> const& color);
|
||||
ButtonSprite* createGeodeTagLabel(std::string_view tag);
|
||||
std::pair<ccColor3B, ccColor3B> geodeTagColors(std::string_view tag);
|
||||
std::string geodeTagName(std::string_view tag);
|
||||
ButtonSprite* createGeodeTagLabel(server::ServerTag const& tag);
|
||||
std::pair<ccColor3B, ccColor3B> geodeTagColors(server::ServerTag const& tag);
|
||||
|
||||
ListBorders* createGeodeListBorders(CCSize const& size, bool forceDisableTheme = false);
|
||||
|
||||
|
|
|
@ -144,7 +144,7 @@ bool FiltersPopup::setup(ModListSource* src) {
|
|||
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()) {
|
||||
auto tags = event->getValue()->unwrap();
|
||||
m_tagsMenu->removeAllChildren();
|
||||
|
@ -157,7 +157,7 @@ void FiltersPopup::onLoadTags(typename server::ServerRequest<std::unordered_set<
|
|||
offSpr, onSpr, this, menu_selector(FiltersPopup::onSelectTag)
|
||||
);
|
||||
btn->m_notClickable = true;
|
||||
btn->setUserObject("tag", CCString::create(tag));
|
||||
btn->setUserObject("tag", CCString::create(tag.name));
|
||||
m_tagsMenu->addChild(btn);
|
||||
}
|
||||
m_tagsMenu->updateLayout();
|
||||
|
|
|
@ -13,14 +13,14 @@ protected:
|
|||
ModListSource* m_source;
|
||||
CCMenu* m_tagsMenu;
|
||||
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;
|
||||
TextInput* m_developerNameInput = nullptr;
|
||||
|
||||
bool setup(ModListSource* src) override;
|
||||
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 onResetDevName(CCObject*);
|
||||
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()) {
|
||||
auto data = event->getValue()->unwrap();
|
||||
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
|
||||
// probably move that to a normal FLAlert that explains "Modtober was
|
||||
// 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();
|
||||
menu->setID("modtober-banner");
|
||||
menu->ignoreAnchorPointForPosition(false);
|
||||
|
|
|
@ -38,7 +38,7 @@ protected:
|
|||
CCNode* m_modtoberBanner = nullptr;
|
||||
std::unordered_map<Tab, std::pair<GeodeTabSprite*, Ref<CCNode>>> m_tabs;
|
||||
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<UpdateModListStateFilter> m_updateStateListener;
|
||||
EventListener<server::ModDownloadFilter> m_downloadListener;
|
||||
|
@ -52,7 +52,7 @@ protected:
|
|||
void setStatValue(CCNode* stat, std::optional<std::string> const& value);
|
||||
|
||||
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 onTab(CCObject* sender);
|
||||
|
|
|
@ -163,34 +163,41 @@ server::ServerRequest<server::ServerModMetadata> ModSource::fetchServerInfo() co
|
|||
// should deal with performance issues
|
||||
return server::getMod(this->getID());
|
||||
}
|
||||
server::ServerRequest<std::unordered_set<std::string>> ModSource::fetchValidTags() const {
|
||||
return std::visit(makeVisitor {
|
||||
[](server::ServerModMetadata const& metadata) {
|
||||
// Server info tags are always certain to be valid since the server has already validated them
|
||||
return server::ServerRequest<std::unordered_set<std::string>>::immediate(Ok(metadata.tags));
|
||||
server::ServerRequest<std::vector<server::ServerTag>> ModSource::fetchValidTags() const {
|
||||
std::unordered_set<std::string> modTags;
|
||||
std::visit(makeVisitor {
|
||||
[&](Mod* mod) {
|
||||
modTags = mod->getMetadata().getTags();
|
||||
},
|
||||
[this](auto const&) {
|
||||
return server::getTags().map(
|
||||
[modTags = this->getMetadata().getTags()](auto* result) -> Result<std::unordered_set<std::string>, server::ServerError> {
|
||||
if (result->isOk()) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
[&](server::ServerModMetadata const& metadata) {
|
||||
modTags = metadata.tags;
|
||||
},
|
||||
}, m_value);
|
||||
|
||||
// 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);
|
||||
},
|
||||
[](server::ServerProgress* progress) {
|
||||
return *progress;
|
||||
}
|
||||
);
|
||||
},
|
||||
}, m_value);
|
||||
}
|
||||
server::ServerRequest<std::optional<server::ServerModUpdate>> ModSource::checkUpdates() {
|
||||
m_availableUpdate = std::nullopt;
|
||||
|
|
|
@ -47,7 +47,7 @@ public:
|
|||
server::ServerRequest<server::ServerModMetadata> fetchServerInfo() const;
|
||||
server::ServerRequest<std::optional<std::string>> fetchAbout() 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();
|
||||
void startInstall();
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue