mirror of
https://github.com/geode-sdk/geode.git
synced 2025-07-29 15:40:06 -04:00
Replace "Recommended" with "Featured" tab (#897)
* replace recommended with featured * remove suggested source, update popup * remove featured from isDefaultQuery
This commit is contained in:
parent
9679b4010d
commit
274b8d743f
9 changed files with 83 additions and 141 deletions
|
@ -16,6 +16,7 @@
|
|||
#include <Geode/binding/MenuLayer.hpp>
|
||||
#include "popups/ConfirmInstall.hpp"
|
||||
#include "GeodeStyle.hpp"
|
||||
#include "ui/mods/sources/ModListSource.hpp"
|
||||
|
||||
bool ModsStatusNode::init() {
|
||||
if (!CCNode::init())
|
||||
|
@ -427,7 +428,7 @@ bool ModsLayer::init() {
|
|||
|
||||
for (auto item : std::initializer_list<std::tuple<const char*, const char*, ModListSource*, const char*>> {
|
||||
{ "download.png"_spr, "Installed", InstalledModListSource::get(InstalledModListType::All), "installed-button" },
|
||||
{ "GJ_starsIcon_001.png", "Recommended", SuggestedModListSource::get(), "recommended-button" },
|
||||
{ "GJ_starsIcon_001.png", "Featured", ServerModListSource::get(ServerModListType::Featured), "featured-button" },
|
||||
{ "globe.png"_spr, "Download", ServerModListSource::get(ServerModListType::Download), "download-button" },
|
||||
{ "GJ_timeIcon_001.png", "Recent", ServerModListSource::get(ServerModListType::Recent), "recent-button" },
|
||||
}) {
|
||||
|
|
|
@ -52,7 +52,7 @@ protected:
|
|||
CCMenuItemSpriteExtra* m_goToPageBtn;
|
||||
ModsStatusNode* m_statusNode;
|
||||
EventListener<UpdateModListStateFilter> m_updateStateListener;
|
||||
bool m_showSearch = false;
|
||||
bool m_showSearch = true;
|
||||
bool m_bigView = false;
|
||||
|
||||
bool init();
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
#include <Geode/utils/ColorProvider.hpp>
|
||||
#include <Geode/binding/ButtonSprite.hpp>
|
||||
#include <Geode/loader/Loader.hpp>
|
||||
#include <vector>
|
||||
#include "../GeodeStyle.hpp"
|
||||
#include "../popups/ModPopup.hpp"
|
||||
#include "../popups/DevPopup.hpp"
|
||||
#include "ui/mods/popups/ModErrorPopup.hpp"
|
||||
#include "ui/mods/sources/ModSource.hpp"
|
||||
|
||||
bool ModItem::init(ModSource&& source) {
|
||||
if (!CCNode::init())
|
||||
|
@ -213,29 +215,48 @@ bool ModItem::init(ModSource&& source) {
|
|||
});
|
||||
downloadsContainer->updateLayout();
|
||||
m_viewMenu->addChild(downloadsContainer);
|
||||
},
|
||||
[this](ModSuggestion const& suggestion) {
|
||||
m_recommendedBy = CCNode::create();
|
||||
m_recommendedBy->setID("recommended-container");
|
||||
m_recommendedBy->setContentWidth(225);
|
||||
|
||||
auto byLabel = CCLabelBMFont::create("Recommended by ", "bigFont.fnt");
|
||||
byLabel->setID("recommended-label");
|
||||
byLabel->setColor("mod-list-recommended-by"_cc3b);
|
||||
m_recommendedBy->addChild(byLabel);
|
||||
// Check if mod is recommended by any others, only if not installed
|
||||
if (!Loader::get()->isModInstalled(metadata.id)) {
|
||||
std::vector<Mod*> recommends {};
|
||||
for (auto& recommend : Loader::get()->getRecommendations()) {
|
||||
auto suggestionID = recommend.message.substr(0, recommend.message.find(' '));
|
||||
if (suggestionID != metadata.id) {
|
||||
continue;
|
||||
}
|
||||
recommends.push_back(std::get<2>(recommend.cause));
|
||||
}
|
||||
|
||||
auto nameLabel = CCLabelBMFont::create(suggestion.forMod->getName().c_str(), "bigFont.fnt");
|
||||
nameLabel->setID("recommended-name-label");
|
||||
nameLabel->setColor("mod-list-recommended-by-2"_cc3b);
|
||||
m_recommendedBy->addChild(nameLabel);
|
||||
if (recommends.size() > 0) {
|
||||
m_recommendedBy = CCNode::create();
|
||||
m_recommendedBy->setID("recommended-container");
|
||||
m_recommendedBy->setContentWidth(225);
|
||||
auto byLabel = CCLabelBMFont::create("Recommended by ", "bigFont.fnt");
|
||||
byLabel->setID("recommended-label");
|
||||
byLabel->setColor("mod-list-recommended-by"_cc3b);
|
||||
m_recommendedBy->addChild(byLabel);
|
||||
|
||||
m_recommendedBy->setLayout(
|
||||
std::string recommendStr = "";
|
||||
if (recommends.size() == 1) {
|
||||
recommendStr = recommends[0]->getName();
|
||||
} else {
|
||||
recommendStr = fmt::format("{} installed mods", recommends.size());
|
||||
}
|
||||
|
||||
auto nameLabel = CCLabelBMFont::create(recommendStr.c_str(), "bigFont.fnt");
|
||||
nameLabel->setID("recommended-name-label");
|
||||
nameLabel->setColor("mod-list-recommended-by-2"_cc3b);
|
||||
m_recommendedBy->addChild(nameLabel);
|
||||
|
||||
m_recommendedBy->setLayout(
|
||||
RowLayout::create()
|
||||
->setDefaultScaleLimits(.1f, 1.f)
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
m_infoContainer->addChild(m_recommendedBy);
|
||||
},
|
||||
->setDefaultScaleLimits(.1f, 1.f)
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
m_infoContainer->addChild(m_recommendedBy);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
auto updateSpr = createGeodeCircleButton(
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <Geode/binding/ButtonSprite.hpp>
|
||||
#include <Geode/ui/MDTextArea.hpp>
|
||||
#include <Geode/utils/web.hpp>
|
||||
#include <Geode/loader/Loader.hpp>
|
||||
#include <Geode/ui/GeodeUI.hpp>
|
||||
#include <Geode/utils/ColorProvider.hpp>
|
||||
#include "ConfirmUninstallPopup.hpp"
|
||||
|
@ -105,28 +106,47 @@ bool ModPopup::setup(ModSource&& src) {
|
|||
dev->setAnchorPoint({ .0f, .5f });
|
||||
titleContainer->addChildAtPosition(dev, Anchor::BottomLeft, ccp(devAndTitlePos, titleContainer->getContentHeight() * .25f));
|
||||
|
||||
if (auto suggestion = m_source.asSuggestion()) {
|
||||
title->updateAnchoredPosition(Anchor::TopLeft, ccp(devAndTitlePos, -2));
|
||||
dev->updateAnchoredPosition(Anchor::Left, ccp(devAndTitlePos, 0));
|
||||
// Suggestions
|
||||
if (!Loader::get()->isModInstalled(m_source.getMetadata().getID())) {
|
||||
std::vector<Mod*> recommends {};
|
||||
for (auto& problem : Loader::get()->getRecommendations()) {
|
||||
auto suggestionID = problem.message.substr(0, problem.message.find(' '));
|
||||
if (suggestionID != m_source.getMetadata().getID()) {
|
||||
continue;
|
||||
}
|
||||
recommends.push_back(std::get<2>(problem.cause));
|
||||
}
|
||||
|
||||
auto recommendedBy = CCNode::create();
|
||||
recommendedBy->setContentWidth(titleContainer->getContentWidth() - devAndTitlePos);
|
||||
recommendedBy->setAnchorPoint({ .0f, .5f });
|
||||
if (recommends.size() > 0) {
|
||||
title->updateAnchoredPosition(Anchor::TopLeft, ccp(devAndTitlePos, -2));
|
||||
dev->updateAnchoredPosition(Anchor::Left, ccp(devAndTitlePos, 0));
|
||||
|
||||
auto byLabel = CCLabelBMFont::create("Recommended by ", "bigFont.fnt");
|
||||
byLabel->setColor("mod-list-recommended-by"_cc3b);
|
||||
recommendedBy->addChild(byLabel);
|
||||
auto recommendedBy = CCNode::create();
|
||||
recommendedBy->setContentWidth(titleContainer->getContentWidth() - devAndTitlePos);
|
||||
recommendedBy->setAnchorPoint({ .0f, .5f });
|
||||
|
||||
auto nameLabel = CCLabelBMFont::create(suggestion->forMod->getName().c_str(), "bigFont.fnt");
|
||||
nameLabel->setColor("mod-list-recommended-by-2"_cc3b);
|
||||
recommendedBy->addChild(nameLabel);
|
||||
auto byLabel = CCLabelBMFont::create("Recommended by ", "bigFont.fnt");
|
||||
byLabel->setColor("mod-list-recommended-by"_cc3b);
|
||||
recommendedBy->addChild(byLabel);
|
||||
|
||||
recommendedBy->setLayout(
|
||||
RowLayout::create()
|
||||
->setDefaultScaleLimits(.1f, 1.f)
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
titleContainer->addChildAtPosition(recommendedBy, Anchor::BottomLeft, ccp(devAndTitlePos, 4));
|
||||
std::string suggestionStr {};
|
||||
if (recommends.size() == 1) {
|
||||
suggestionStr = recommends[0]->getName();
|
||||
} else {
|
||||
suggestionStr = fmt::format("{} installed mods", recommends.size());
|
||||
}
|
||||
|
||||
auto nameLabel = CCLabelBMFont::create(suggestionStr.c_str(), "bigFont.fnt");
|
||||
nameLabel->setColor("mod-list-recommended-by-2"_cc3b);
|
||||
recommendedBy->addChild(nameLabel);
|
||||
|
||||
recommendedBy->setLayout(
|
||||
RowLayout::create()
|
||||
->setDefaultScaleLimits(.1f, 1.f)
|
||||
->setAxisAlignment(AxisAlignment::Start)
|
||||
);
|
||||
titleContainer->addChildAtPosition(recommendedBy, Anchor::BottomLeft, ccp(devAndTitlePos, 4));
|
||||
}
|
||||
}
|
||||
|
||||
leftColumn->addChild(titleContainer);
|
||||
|
@ -575,7 +595,7 @@ void ModPopup::updateState() {
|
|||
m_reenableBtn->setVisible(asMod && modRequestedActionIsToggle(asMod->getRequestedAction()));
|
||||
|
||||
m_updateBtn->setVisible(m_source.hasUpdates().has_value() && asMod->getRequestedAction() == ModRequestedAction::None);
|
||||
m_installBtn->setVisible(m_source.asServer() || m_source.asSuggestion());
|
||||
m_installBtn->setVisible(m_source.asServer());
|
||||
m_uninstallBtn->setVisible(asMod && asMod->getRequestedAction() == ModRequestedAction::None);
|
||||
|
||||
if (asMod && modRequestedActionIsUninstall(asMod->getRequestedAction())) {
|
||||
|
@ -923,9 +943,6 @@ ModPopup* ModPopup::create(ModSource&& src) {
|
|||
if (src.asServer()) {
|
||||
style = GeodePopupStyle::Alt;
|
||||
}
|
||||
else if (src.asSuggestion()) {
|
||||
style = GeodePopupStyle::Alt2;
|
||||
}
|
||||
if (ret && ret->init(440, 280, std::move(src), style)) {
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
|
|
|
@ -138,30 +138,6 @@ public:
|
|||
bool isDefaultQuery() const override;
|
||||
};
|
||||
|
||||
struct SuggestedModsQuery final : public LocalModsQueryBase {
|
||||
bool preCheck(ModSource const& src) const;
|
||||
bool queryCheck(ModSource const& src, double& weighted) const;
|
||||
bool isDefault() const;
|
||||
};
|
||||
|
||||
class SuggestedModListSource : public ModListSource {
|
||||
protected:
|
||||
SuggestedModsQuery m_query;
|
||||
|
||||
void resetQuery() override;
|
||||
ProviderTask fetchPage(size_t page, size_t pageSize, bool forceUpdate) override;
|
||||
void setSearchQuery(std::string const& query) override;
|
||||
|
||||
SuggestedModListSource();
|
||||
|
||||
public:
|
||||
static SuggestedModListSource* get();
|
||||
|
||||
std::unordered_set<std::string> getModTags() const override;
|
||||
void setModTags(std::unordered_set<std::string> const& tags) override;
|
||||
bool isDefaultQuery() const override;
|
||||
};
|
||||
|
||||
enum class ServerModListType {
|
||||
Download,
|
||||
Featured,
|
||||
|
|
|
@ -41,7 +41,6 @@ LoadModSuggestionTask loadModSuggestion(LoadProblem const& problem) {
|
|||
|
||||
ModSource::ModSource(Mod* mod) : m_value(mod) {}
|
||||
ModSource::ModSource(server::ServerModMetadata&& metadata) : m_value(metadata) {}
|
||||
ModSource::ModSource(ModSuggestion&& suggestion) : m_value(suggestion) {}
|
||||
|
||||
std::string ModSource::getID() const {
|
||||
return std::visit(makeVisitor {
|
||||
|
@ -145,9 +144,6 @@ Mod* ModSource::asMod() const {
|
|||
server::ServerModMetadata const* ModSource::asServer() const {
|
||||
return std::get_if<server::ServerModMetadata>(&m_value);
|
||||
}
|
||||
ModSuggestion const* ModSource::asSuggestion() const {
|
||||
return std::get_if<ModSuggestion>(&m_value);
|
||||
}
|
||||
|
||||
server::ServerRequest<std::optional<std::string>> ModSource::fetchAbout() const {
|
||||
if (auto mod = this->asMod()) {
|
||||
|
|
|
@ -16,7 +16,7 @@ LoadModSuggestionTask loadModSuggestion(LoadProblem const& problem);
|
|||
|
||||
class ModSource final {
|
||||
private:
|
||||
std::variant<Mod*, server::ServerModMetadata, ModSuggestion> m_value;
|
||||
std::variant<Mod*, server::ServerModMetadata> m_value;
|
||||
std::optional<server::ServerModUpdate> m_availableUpdate;
|
||||
|
||||
public:
|
||||
|
@ -42,7 +42,6 @@ public:
|
|||
|
||||
Mod* asMod() const;
|
||||
server::ServerModMetadata const* asServer() const;
|
||||
ModSuggestion const* asSuggestion() const;
|
||||
|
||||
std::string formatDevelopers() const;
|
||||
server::ServerRequest<server::ServerModMetadata> fetchServerInfo() const;
|
||||
|
|
|
@ -99,7 +99,6 @@ InvalidateQueryAfter<server::ModsQuery> ServerModListSource::getQueryMut() {
|
|||
}
|
||||
bool ServerModListSource::isDefaultQuery() const {
|
||||
return !m_query.query.has_value() &&
|
||||
!m_query.featured.has_value() &&
|
||||
m_query.tags.empty() &&
|
||||
!m_query.developer.has_value();
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
#include "ModListSource.hpp"
|
||||
|
||||
bool SuggestedModsQuery::preCheck(ModSource const& src) const {
|
||||
// There are no extra fields in SuggestedModsQuery
|
||||
return true;
|
||||
}
|
||||
bool SuggestedModsQuery::queryCheck(ModSource const& src, double& weighted) const {
|
||||
if (query) {
|
||||
if (!modFuzzyMatch(src.asSuggestion()->suggestion, *query, weighted)) {
|
||||
return false;
|
||||
}
|
||||
return modFuzzyMatch(src.asSuggestion()->forMod->getMetadata(), *query, weighted);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool SuggestedModsQuery::isDefault() const {
|
||||
return LocalModsQueryBase::isDefault();
|
||||
}
|
||||
|
||||
void SuggestedModListSource::resetQuery() {
|
||||
m_query = SuggestedModsQuery();
|
||||
}
|
||||
SuggestedModListSource::ProviderTask SuggestedModListSource::fetchPage(size_t page, size_t pageSize, bool forceUpdate) {
|
||||
m_query.page = page;
|
||||
m_query.pageSize = pageSize;
|
||||
std::vector<LoadModSuggestionTask> tasks;
|
||||
for (auto problem : Loader::get()->getRecommendations()) {
|
||||
tasks.push_back(loadModSuggestion(problem));
|
||||
}
|
||||
return LoadModSuggestionTask::all(std::move(tasks)).map(
|
||||
[query = m_query](auto* results) -> ProviderTask::Value {
|
||||
auto content = ProvidedMods();
|
||||
for (auto& result : *results) {
|
||||
if (result && *result) {
|
||||
content.mods.push_back(ModSource(ModSuggestion(**result)));
|
||||
}
|
||||
}
|
||||
// Filter the results based on the current search
|
||||
// query and return them
|
||||
filterModsWithLocalQuery(content, query);
|
||||
return Ok(std::move(content));
|
||||
},
|
||||
[](auto*) -> ProviderTask::Progress { return std::nullopt; }
|
||||
);
|
||||
}
|
||||
|
||||
SuggestedModListSource::SuggestedModListSource() {}
|
||||
|
||||
SuggestedModListSource* SuggestedModListSource::get() {
|
||||
static auto inst = new SuggestedModListSource();
|
||||
return inst;
|
||||
}
|
||||
|
||||
void SuggestedModListSource::setSearchQuery(std::string const& query) {
|
||||
m_query.query = query.size() ? std::optional(query) : std::nullopt;
|
||||
}
|
||||
std::unordered_set<std::string> SuggestedModListSource::getModTags() const {
|
||||
return m_query.tags;
|
||||
}
|
||||
void SuggestedModListSource::setModTags(std::unordered_set<std::string> const& tags) {
|
||||
m_query.tags = tags;
|
||||
this->clearCache();
|
||||
}
|
||||
|
||||
bool SuggestedModListSource::isDefaultQuery() const {
|
||||
return m_query.isDefault();
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue