mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-22 02:45:49 -04:00
Implement UI for multiple version downloading (very cursed)
This commit is contained in:
parent
63027a7f84
commit
5d15eb0215
9 changed files with 399 additions and 205 deletions
loader
include/Geode/loader
src
|
@ -178,12 +178,22 @@ namespace geode {
|
|||
* Get all featured index items
|
||||
*/
|
||||
std::vector<IndexItemHandle> getFeaturedItems() const;
|
||||
/**
|
||||
* Get all latest index items
|
||||
*/
|
||||
std::vector<IndexItemHandle> getLatestItems() const;
|
||||
/**
|
||||
* Get all index items by a developer
|
||||
*/
|
||||
std::vector<IndexItemHandle> getItemsByDeveloper(
|
||||
std::string const& name
|
||||
) const;
|
||||
/**
|
||||
* Get all index items for a specific mod
|
||||
*/
|
||||
std::vector<IndexItemHandle> getItemsByModID(
|
||||
std::string const& modID
|
||||
) const;
|
||||
/**
|
||||
* Check if an item with this ID is found on the index, and optionally
|
||||
* provide the version sought after
|
||||
|
|
|
@ -183,7 +183,14 @@ Result<IndexItemHandle> IndexItem::Impl::create(ghc::filesystem::path const& roo
|
|||
}
|
||||
|
||||
bool IndexItem::Impl::isInstalled() const {
|
||||
return ghc::filesystem::exists(dirs::getModsDir() / (m_metadata.getID() + ".geode"));
|
||||
if (!Loader::get()->isModInstalled(m_metadata.getID())) {
|
||||
return false;
|
||||
}
|
||||
auto installed = Loader::get()->getInstalledMod(m_metadata.getID());
|
||||
if (installed->getVersion() != m_metadata.getVersion()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
@ -449,6 +456,14 @@ std::vector<IndexItemHandle> Index::getItems() const {
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<IndexItemHandle> Index::getLatestItems() const {
|
||||
std::vector<IndexItemHandle> res;
|
||||
for (auto& [modID, versions] : m_impl->m_items) {
|
||||
res.push_back(this->getMajorItem(modID));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<IndexItemHandle> Index::getFeaturedItems() const {
|
||||
std::vector<IndexItemHandle> res;
|
||||
for (auto& items : map::values(m_impl->m_items)) {
|
||||
|
@ -475,6 +490,18 @@ std::vector<IndexItemHandle> Index::getItemsByDeveloper(
|
|||
return res;
|
||||
}
|
||||
|
||||
std::vector<IndexItemHandle> Index::getItemsByModID(
|
||||
std::string const& modID
|
||||
) const {
|
||||
std::vector<IndexItemHandle> res;
|
||||
if (m_impl->m_items.count(modID)) {
|
||||
for (auto& [versionStr, item] : m_impl->m_items[modID]) {
|
||||
res.push_back(item);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
bool Index::isKnownItem(
|
||||
std::string const& id,
|
||||
std::optional<VersionInfo> version
|
||||
|
@ -758,6 +785,10 @@ void Index::cancelInstall(IndexItemHandle item) {
|
|||
}
|
||||
|
||||
void Index::install(IndexInstallList const& list) {
|
||||
if (list.list.empty()) {
|
||||
ModInstallEvent(list.target->getMetadata().getID(), UpdateFinished()).post();
|
||||
return;
|
||||
}
|
||||
Loader::get()->queueInMainThread([this, list]() {
|
||||
m_impl->installNext(0, list);
|
||||
});
|
||||
|
|
|
@ -277,6 +277,95 @@ void ModInfoPopup::setInstallStatus(std::optional<UpdateProgress> const& progres
|
|||
}
|
||||
}
|
||||
|
||||
void ModInfoPopup::popupInstallItem(IndexItemHandle item) {
|
||||
auto deps = item->getMetadata().getDependencies();
|
||||
enum class DepState {
|
||||
None,
|
||||
HasOnlyRequired,
|
||||
HasOptional
|
||||
} depState = DepState::None;
|
||||
for (auto const& dep : deps) {
|
||||
// resolved means it's already installed, so
|
||||
// no need to ask the user whether they want to install it
|
||||
if (Loader::get()->isModLoaded(dep.id))
|
||||
continue;
|
||||
if (dep.importance != ModMetadata::Dependency::Importance::Required) {
|
||||
depState = DepState::HasOptional;
|
||||
break;
|
||||
}
|
||||
depState = DepState::HasOnlyRequired;
|
||||
}
|
||||
|
||||
std::string content;
|
||||
char const* btn1;
|
||||
char const* btn2;
|
||||
switch (depState) {
|
||||
case DepState::None:
|
||||
content = fmt::format(
|
||||
"Are you sure you want to install <cg>{}</c>?",
|
||||
item->getMetadata().getName()
|
||||
);
|
||||
btn1 = "Info";
|
||||
btn2 = "Install";
|
||||
break;
|
||||
case DepState::HasOnlyRequired:
|
||||
content =
|
||||
"Installing this mod requires other mods to be installed. "
|
||||
"Would you like to <cy>proceed</c> with the installation or "
|
||||
"<cb>view</c> which mods are going to be installed?";
|
||||
btn1 = "View";
|
||||
btn2 = "Proceed";
|
||||
break;
|
||||
case DepState::HasOptional:
|
||||
content =
|
||||
"This mod recommends installing other mods alongside it. "
|
||||
"Would you like to continue with <cy>recommended settings</c> or "
|
||||
"<cb>customize</c> which mods to install?";
|
||||
btn1 = "Customize";
|
||||
btn2 = "Recommended";
|
||||
break;
|
||||
}
|
||||
|
||||
createQuickPopup("Confirm Install", content, btn1, btn2, 320.f, [&](FLAlertLayer*, bool btn2) {
|
||||
if (btn2) {
|
||||
auto canInstall = Index::get()->canInstall(m_item);
|
||||
if (!canInstall) {
|
||||
FLAlertLayer::create(
|
||||
"Unable to Install",
|
||||
canInstall.unwrapErr(),
|
||||
"OK"
|
||||
)->show();
|
||||
return;
|
||||
}
|
||||
this->preInstall();
|
||||
Index::get()->install(m_item);
|
||||
}
|
||||
else {
|
||||
InstallListPopup::create(m_item, [&](IndexInstallList const& list) {
|
||||
this->preInstall();
|
||||
Index::get()->install(list);
|
||||
})->show();
|
||||
}
|
||||
}, true, true);
|
||||
}
|
||||
|
||||
void ModInfoPopup::preInstall() {
|
||||
if (m_latestVersionLabel) {
|
||||
m_latestVersionLabel->setVisible(false);
|
||||
}
|
||||
this->setInstallStatus(UpdateProgress(0, "Starting install"));
|
||||
|
||||
m_installBtn->setTarget(
|
||||
this, menu_selector(ModInfoPopup::onCancelInstall)
|
||||
);
|
||||
m_installBtnSpr->setString("Cancel");
|
||||
m_installBtnSpr->setBG("GJ_button_06.png", false);
|
||||
}
|
||||
|
||||
void ModInfoPopup::onCancelInstall(CCObject*) {
|
||||
Index::get()->cancelInstall(m_item);
|
||||
}
|
||||
|
||||
// LocalModInfoPopup
|
||||
LocalModInfoPopup::LocalModInfoPopup()
|
||||
: m_installListener(
|
||||
|
@ -493,61 +582,7 @@ void LocalModInfoPopup::onUpdateProgress(ModInstallEvent* event) {
|
|||
}
|
||||
|
||||
void LocalModInfoPopup::onUpdate(CCObject*) {
|
||||
auto list = Index::get()->getInstallList(m_item);
|
||||
if (!list) {
|
||||
return FLAlertLayer::create(
|
||||
"Unable to Update",
|
||||
list.unwrapErr(),
|
||||
"OK"
|
||||
)->show();
|
||||
}
|
||||
auto layer = FLAlertLayer::create(
|
||||
this,
|
||||
"Confirm Update",
|
||||
fmt::format(
|
||||
"The following mods will be updated:\n {}",
|
||||
// le nest
|
||||
ranges::join(
|
||||
ranges::map<std::vector<std::string>>(
|
||||
list.unwrap().list,
|
||||
[](IndexItemHandle handle) {
|
||||
return fmt::format(
|
||||
" - <cr>{}</c> (<cy>{}</c>)",
|
||||
handle->getMetadata().getName(),
|
||||
handle->getMetadata().getID()
|
||||
);
|
||||
}
|
||||
),
|
||||
"\n "
|
||||
)
|
||||
),
|
||||
"Cancel", "OK"
|
||||
);
|
||||
layer->setTag(TAG_CONFIRM_UPDATE);
|
||||
layer->show();
|
||||
}
|
||||
|
||||
void LocalModInfoPopup::onCancel(CCObject*) {
|
||||
Index::get()->cancelInstall(m_item);
|
||||
}
|
||||
|
||||
void LocalModInfoPopup::doUpdate() {
|
||||
if (m_latestVersionLabel) {
|
||||
m_latestVersionLabel->setVisible(false);
|
||||
}
|
||||
|
||||
if (m_minorVersionLabel) {
|
||||
m_minorVersionLabel->setVisible(false);
|
||||
}
|
||||
this->setInstallStatus(UpdateProgress(0, "Starting update"));
|
||||
|
||||
m_installBtn->setTarget(
|
||||
this, menu_selector(LocalModInfoPopup::onCancel)
|
||||
);
|
||||
m_installBtnSpr->setString("Cancel");
|
||||
m_installBtnSpr->setBG("GJ_button_06.png", false);
|
||||
|
||||
Index::get()->install(m_item);
|
||||
this->popupInstallItem(m_item);
|
||||
}
|
||||
|
||||
void LocalModInfoPopup::onUninstall(CCObject*) {
|
||||
|
@ -631,12 +666,6 @@ void LocalModInfoPopup::FLAlert_Clicked(FLAlertLayer* layer, bool btn2) {
|
|||
}
|
||||
this->onClose(nullptr);
|
||||
} break;
|
||||
|
||||
case TAG_CONFIRM_UPDATE: {
|
||||
if (btn2) {
|
||||
this->doUpdate();
|
||||
}
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,7 +716,8 @@ bool IndexItemInfoPopup::init(IndexItemHandle item, ModListLayer* list) {
|
|||
|
||||
if (!ModInfoPopup::init(item->getMetadata(), list)) return false;
|
||||
|
||||
if (item->isInstalled()) return true;
|
||||
// bruh why is this here if we are allowing for browsing already installed mods
|
||||
// if (item->isInstalled()) return true;
|
||||
|
||||
m_installBtnSpr = IconButtonSprite::create(
|
||||
"GE_button_01.png"_spr,
|
||||
|
@ -750,92 +780,7 @@ void IndexItemInfoPopup::onInstallProgress(ModInstallEvent* event) {
|
|||
}
|
||||
|
||||
void IndexItemInfoPopup::onInstall(CCObject*) {
|
||||
auto deps = m_item->getMetadata().getDependencies();
|
||||
enum class DepState {
|
||||
None,
|
||||
HasOnlyRequired,
|
||||
HasOptional
|
||||
} depState = DepState::None;
|
||||
for (auto const& item : deps) {
|
||||
// resolved means it's already installed, so
|
||||
// no need to ask the user whether they want to install it
|
||||
if (Loader::get()->isModLoaded(item.id))
|
||||
continue;
|
||||
if (item.importance != ModMetadata::Dependency::Importance::Required) {
|
||||
depState = DepState::HasOptional;
|
||||
break;
|
||||
}
|
||||
depState = DepState::HasOnlyRequired;
|
||||
}
|
||||
|
||||
std::string content;
|
||||
char const* btn1;
|
||||
char const* btn2;
|
||||
switch (depState) {
|
||||
case DepState::None:
|
||||
content = fmt::format(
|
||||
"Are you sure you want to install <cg>{}</c>?",
|
||||
m_item->getMetadata().getName()
|
||||
);
|
||||
btn1 = "Info";
|
||||
btn2 = "Install";
|
||||
break;
|
||||
case DepState::HasOnlyRequired:
|
||||
content =
|
||||
"Installing this mod requires other mods to be installed. "
|
||||
"Would you like to <cy>proceed</c> with the installation or "
|
||||
"<cb>view</c> which mods are going to be installed?";
|
||||
btn1 = "View";
|
||||
btn2 = "Proceed";
|
||||
break;
|
||||
case DepState::HasOptional:
|
||||
content =
|
||||
"This mod recommends installing other mods alongside it. "
|
||||
"Would you like to continue with <cy>recommended settings</c> or "
|
||||
"<cb>customize</c> which mods to install?";
|
||||
btn1 = "Customize";
|
||||
btn2 = "Recommended";
|
||||
break;
|
||||
}
|
||||
|
||||
createQuickPopup("Confirm Install", content, btn1, btn2, 320.f, [&](FLAlertLayer*, bool btn2) {
|
||||
if (btn2) {
|
||||
auto canInstall = Index::get()->canInstall(m_item);
|
||||
if (!canInstall) {
|
||||
FLAlertLayer::create(
|
||||
"Unable to Install",
|
||||
canInstall.unwrapErr(),
|
||||
"OK"
|
||||
)->show();
|
||||
return;
|
||||
}
|
||||
this->preInstall();
|
||||
Index::get()->install(m_item);
|
||||
}
|
||||
else {
|
||||
InstallListPopup::create(m_item, [&](IndexInstallList const& list) {
|
||||
this->preInstall();
|
||||
Index::get()->install(list);
|
||||
})->show();
|
||||
}
|
||||
}, true, true);
|
||||
}
|
||||
|
||||
void IndexItemInfoPopup::preInstall() {
|
||||
if (m_latestVersionLabel) {
|
||||
m_latestVersionLabel->setVisible(false);
|
||||
}
|
||||
this->setInstallStatus(UpdateProgress(0, "Starting install"));
|
||||
|
||||
m_installBtn->setTarget(
|
||||
this, menu_selector(IndexItemInfoPopup::onCancel)
|
||||
);
|
||||
m_installBtnSpr->setString("Cancel");
|
||||
m_installBtnSpr->setBG("GJ_button_06.png", false);
|
||||
}
|
||||
|
||||
void IndexItemInfoPopup::onCancel(CCObject*) {
|
||||
Index::get()->cancelInstall(m_item);
|
||||
this->popupInstallItem(m_item);
|
||||
}
|
||||
|
||||
CCNode* IndexItemInfoPopup::createLogo(CCSize const& size) {
|
||||
|
|
|
@ -38,6 +38,7 @@ protected:
|
|||
MDTextArea* m_detailsArea;
|
||||
MDTextArea* m_changelogArea = nullptr;
|
||||
Scrollbar* m_scrollbar;
|
||||
IndexItemHandle m_item;
|
||||
|
||||
void onChangelog(CCObject*);
|
||||
void onRepository(CCObject*);
|
||||
|
@ -51,13 +52,16 @@ protected:
|
|||
|
||||
void setInstallStatus(std::optional<UpdateProgress> const& progress);
|
||||
|
||||
void popupInstallItem(IndexItemHandle item);
|
||||
void preInstall();
|
||||
void onCancelInstall(CCObject*);
|
||||
|
||||
virtual CCNode* createLogo(CCSize const& size) = 0;
|
||||
virtual ModMetadata getMetadata() const = 0;
|
||||
};
|
||||
|
||||
class LocalModInfoPopup : public ModInfoPopup, public FLAlertLayerProtocol {
|
||||
protected:
|
||||
IndexItemHandle m_item;
|
||||
EventListener<ModInstallFilter> m_installListener;
|
||||
Mod* m_mod;
|
||||
|
||||
|
@ -74,8 +78,6 @@ protected:
|
|||
|
||||
void onUpdateProgress(ModInstallEvent* event);
|
||||
void onUpdate(CCObject*);
|
||||
void onCancel(CCObject*);
|
||||
void doUpdate();
|
||||
|
||||
|
||||
void FLAlert_Clicked(FLAlertLayer*, bool) override;
|
||||
|
@ -91,16 +93,12 @@ public:
|
|||
|
||||
class IndexItemInfoPopup : public ModInfoPopup {
|
||||
protected:
|
||||
IndexItemHandle m_item;
|
||||
EventListener<ModInstallFilter> m_installListener;
|
||||
|
||||
bool init(IndexItemHandle item, ModListLayer* list);
|
||||
|
||||
void onInstallProgress(ModInstallEvent* event);
|
||||
void onInstall(CCObject*);
|
||||
void onCancel(CCObject*);
|
||||
|
||||
void preInstall();
|
||||
|
||||
CCNode* createLogo(CCSize const& size) override;
|
||||
ModMetadata getMetadata() const override;
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#include <Geode/ui/GeodeUI.hpp>
|
||||
#include <loader/LoaderImpl.hpp>
|
||||
#include <utility>
|
||||
#include "../info/TagNode.hpp"
|
||||
#include "../info/DevProfilePopup.hpp"
|
||||
|
||||
// InstallListCell
|
||||
|
@ -27,8 +26,11 @@ void InstallListCell::setupInfo(
|
|||
std::variant<VersionInfo, ComparableVersionInfo> version,
|
||||
bool inactive
|
||||
) {
|
||||
m_inactive = inactive;
|
||||
m_menu = CCMenu::create();
|
||||
m_menu->setPosition(m_width - 10.f, m_height / 2);
|
||||
m_menu->setPosition(0, 0);
|
||||
m_menu->setAnchorPoint({ .0f, .0f });
|
||||
m_menu->setContentSize({m_width, m_height});
|
||||
this->addChild(m_menu);
|
||||
|
||||
auto logoSize = this->getLogoSize();
|
||||
|
@ -41,15 +43,15 @@ void InstallListCell::setupInfo(
|
|||
}
|
||||
this->addChild(logoSpr);
|
||||
|
||||
auto titleLabel = CCLabelBMFont::create(name.c_str(), "bigFont.fnt");
|
||||
titleLabel->setAnchorPoint({ .0f, .5f });
|
||||
titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
||||
titleLabel->setPositionY(m_height / 2);
|
||||
titleLabel->limitLabelWidth(m_width / 2 - 70.f, .4f, .1f);
|
||||
m_titleLabel = CCLabelBMFont::create(name.c_str(), "bigFont.fnt");
|
||||
m_titleLabel->setAnchorPoint({ .0f, .5f });
|
||||
m_titleLabel->setPositionX(m_height / 2 + logoSize / 2 + 13.f);
|
||||
m_titleLabel->setPositionY(m_height / 2);
|
||||
m_titleLabel->limitLabelWidth(m_width / 2 - 70.f, .4f, .1f);
|
||||
if (inactive) {
|
||||
titleLabel->setColor({ 163, 163, 163 });
|
||||
m_titleLabel->setColor({ 163, 163, 163 });
|
||||
}
|
||||
this->addChild(titleLabel);
|
||||
this->addChild(m_titleLabel);
|
||||
|
||||
m_developerBtn = nullptr;
|
||||
if (developer) {
|
||||
|
@ -64,43 +66,55 @@ void InstallListCell::setupInfo(
|
|||
creatorLabel, this, menu_selector(InstallListCell::onViewDev)
|
||||
);
|
||||
m_developerBtn->setPosition(
|
||||
titleLabel->getPositionX() + titleLabel->getScaledContentSize().width + 3.f +
|
||||
creatorLabel->getScaledContentSize().width / 2 -
|
||||
m_menu->getPositionX(),
|
||||
-0.5f
|
||||
m_titleLabel->getPositionX() + m_titleLabel->getScaledContentSize().width + 3.f +
|
||||
creatorLabel->getScaledContentSize().width / 2,
|
||||
m_height / 2
|
||||
);
|
||||
m_menu->addChild(m_developerBtn);
|
||||
}
|
||||
|
||||
auto versionLabel = CCLabelBMFont::create(
|
||||
this->setupVersion(version);
|
||||
}
|
||||
|
||||
void InstallListCell::setupVersion(std::variant<VersionInfo, ComparableVersionInfo> version) {
|
||||
if (m_versionLabel) {
|
||||
m_versionLabel->removeFromParent();
|
||||
m_versionLabel = nullptr;
|
||||
}
|
||||
if (m_tagLabel) {
|
||||
m_tagLabel->removeFromParent();
|
||||
m_tagLabel = nullptr;
|
||||
}
|
||||
|
||||
m_versionLabel = CCLabelBMFont::create(
|
||||
std::holds_alternative<VersionInfo>(version) ?
|
||||
std::get<VersionInfo>(version).toString(false).c_str() :
|
||||
std::get<ComparableVersionInfo>(version).toString().c_str(),
|
||||
"bigFont.fnt"
|
||||
);
|
||||
versionLabel->setAnchorPoint({ .0f, .5f });
|
||||
versionLabel->setScale(.2f);
|
||||
versionLabel->setPosition(
|
||||
titleLabel->getPositionX() + titleLabel->getScaledContentSize().width + 3.f +
|
||||
m_versionLabel->setAnchorPoint({ .0f, .5f });
|
||||
m_versionLabel->setScale(.2f);
|
||||
m_versionLabel->setPosition(
|
||||
m_titleLabel->getPositionX() + m_titleLabel->getScaledContentSize().width + 3.f +
|
||||
(m_developerBtn ? m_developerBtn->getScaledContentSize().width + 3.f : 0.f),
|
||||
titleLabel->getPositionY() - 1.f
|
||||
m_titleLabel->getPositionY() - 1.f
|
||||
);
|
||||
versionLabel->setColor({ 0, 255, 0 });
|
||||
if (inactive) {
|
||||
versionLabel->setColor({ 0, 163, 0 });
|
||||
m_versionLabel->setColor({ 0, 255, 0 });
|
||||
if (m_inactive) {
|
||||
m_versionLabel->setColor({ 0, 163, 0 });
|
||||
}
|
||||
this->addChild(versionLabel);
|
||||
this->addChild(m_versionLabel);
|
||||
|
||||
if (!std::holds_alternative<VersionInfo>(version)) return;
|
||||
if (auto tag = std::get<VersionInfo>(version).getTag()) {
|
||||
auto tagLabel = TagNode::create(tag->toString());
|
||||
tagLabel->setAnchorPoint({.0f, .5f});
|
||||
tagLabel->setScale(.2f);
|
||||
tagLabel->setPosition(
|
||||
versionLabel->getPositionX() + versionLabel->getScaledContentSize().width + 3.f,
|
||||
versionLabel->getPositionY()
|
||||
m_tagLabel = TagNode::create(tag->toString());
|
||||
m_tagLabel->setAnchorPoint({.0f, .5f});
|
||||
m_tagLabel->setScale(.2f);
|
||||
m_tagLabel->setPosition(
|
||||
m_versionLabel->getPositionX() + m_versionLabel->getScaledContentSize().width + 3.f,
|
||||
m_versionLabel->getPositionY()
|
||||
);
|
||||
this->addChild(tagLabel);
|
||||
this->addChild(m_tagLabel);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,7 +148,7 @@ bool ModInstallListCell::init(Mod* mod, InstallListPopup* list, CCSize const& si
|
|||
this->setupInfo(mod->getMetadata(), true);
|
||||
auto message = CCLabelBMFont::create("Installed", "bigFont.fnt");
|
||||
message->setAnchorPoint({ 1.f, .5f });
|
||||
message->setPositionX(m_menu->getPositionX());
|
||||
message->setPositionX(m_width - 10.0f);
|
||||
message->setPositionY(16.f);
|
||||
message->setScale(0.4f);
|
||||
message->setColor({ 163, 163, 163 });
|
||||
|
@ -174,23 +188,38 @@ bool IndexItemInstallListCell::init(
|
|||
return false;
|
||||
m_item = item;
|
||||
this->setupInfo(item->getMetadata(), item->isInstalled());
|
||||
if (item->isInstalled()) {
|
||||
auto message = CCLabelBMFont::create("Installed", "bigFont.fnt");
|
||||
message->setAnchorPoint({ 1.f, .5f });
|
||||
message->setPositionX(m_menu->getPositionX());
|
||||
message->setPositionY(16.f);
|
||||
message->setScale(0.4f);
|
||||
message->setColor({ 163, 163, 163 });
|
||||
this->addChild(message);
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: show installed label properly
|
||||
// if (item->isInstalled()) {
|
||||
// auto message = CCLabelBMFont::create("Installed", "bigFont.fnt");
|
||||
// message->setAnchorPoint({ 1.f, .5f });
|
||||
// message->setPositionX(m_width - 10.0f);
|
||||
// message->setPositionY(16.f);
|
||||
// message->setScale(0.4f);
|
||||
// message->setColor({ 163, 163, 163 });
|
||||
// this->addChild(message);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
m_toggle = CCMenuItemToggler::createWithStandardSprites(
|
||||
m_layer,
|
||||
menu_selector(InstallListPopup::onCellToggle),
|
||||
.6f
|
||||
);
|
||||
m_toggle->setPosition(-m_toggle->getScaledContentSize().width / 2, 0.f);
|
||||
m_toggle->setAnchorPoint({1.f, .5f});
|
||||
m_toggle->setPosition(m_width - 5, m_height / 2);
|
||||
|
||||
// recycling sprites in my Geode?? noo never
|
||||
auto versionSelectSpr = EditorButtonSprite::createWithSpriteFrameName(
|
||||
"filters.png"_spr, 1.0f, EditorBaseColor::Gray
|
||||
);
|
||||
versionSelectSpr->setScale(.7f);
|
||||
|
||||
auto versionSelectBtn =
|
||||
CCMenuItemSpriteExtra::create(versionSelectSpr, this, menu_selector(IndexItemInstallListCell::onSelectVersion));
|
||||
versionSelectBtn->setAnchorPoint({1.f, .5f});
|
||||
versionSelectBtn->setPosition({m_toggle->getPositionX() - m_toggle->getContentSize().width - 5, m_height / 2});
|
||||
m_menu->addChild(versionSelectBtn);
|
||||
|
||||
switch (importance) {
|
||||
case ModMetadata::Dependency::Importance::Required:
|
||||
|
@ -207,13 +236,18 @@ bool IndexItemInstallListCell::init(
|
|||
break;
|
||||
}
|
||||
|
||||
if (item->isInstalled()) {
|
||||
m_toggle->setClickable(false);
|
||||
m_toggle->toggle(true);
|
||||
}
|
||||
|
||||
if (m_item->getAvailablePlatforms().count(GEODE_PLATFORM_TARGET) == 0) {
|
||||
m_toggle->setClickable(false);
|
||||
m_toggle->toggle(false);
|
||||
|
||||
auto message = CCLabelBMFont::create("N/A", "bigFont.fnt");
|
||||
message->setAnchorPoint({ 1.f, .5f });
|
||||
message->setPositionX(m_menu->getPositionX() - m_toggle->getScaledContentSize().width - 5.f);
|
||||
message->setPositionX(m_width - 5.f);
|
||||
message->setPositionY(16.f);
|
||||
message->setScale(0.4f);
|
||||
message->setColor({ 240, 31, 31 });
|
||||
|
@ -269,6 +303,15 @@ IndexItemHandle IndexItemInstallListCell::getItem() {
|
|||
return m_item;
|
||||
}
|
||||
|
||||
void IndexItemInstallListCell::setVersionFromItem(IndexItemHandle item) {
|
||||
this->setupVersion(item->getMetadata().getVersion());
|
||||
m_item = item;
|
||||
}
|
||||
|
||||
void IndexItemInstallListCell::onSelectVersion(CCObject*) {
|
||||
SelectVersionPopup::create(m_item->getMetadata().getID(), this)->show();
|
||||
}
|
||||
|
||||
// UnknownInstallListCell
|
||||
|
||||
bool UnknownInstallListCell::init(
|
||||
|
@ -317,3 +360,50 @@ std::string UnknownInstallListCell::getID() const {
|
|||
std::string UnknownInstallListCell::getDeveloper() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
// SelectVersionCell
|
||||
|
||||
bool SelectVersionCell::init(IndexItemHandle item, SelectVersionPopup* versionPopup, CCSize const& size) {
|
||||
if (!InstallListCell::init(nullptr, size))
|
||||
return false;
|
||||
m_item = item;
|
||||
m_versionPopup = versionPopup;
|
||||
this->setupInfo(item->getMetadata(), item->isInstalled());
|
||||
|
||||
auto selectSpr = ButtonSprite::create(
|
||||
"Select", 0, 0, "bigFont.fnt", "GJ_button_01.png", 0, .6f
|
||||
);
|
||||
selectSpr->setScale(.6f);
|
||||
|
||||
auto selectBtn = CCMenuItemSpriteExtra::create(
|
||||
selectSpr, this, menu_selector(SelectVersionCell::onSelected)
|
||||
);
|
||||
selectBtn->setAnchorPoint({1.f, .5f});
|
||||
selectBtn->setPosition({m_width - 5, m_height / 2});
|
||||
m_menu->addChild(selectBtn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SelectVersionCell::onSelected(CCObject*) {
|
||||
m_versionPopup->selectItem(m_item);
|
||||
}
|
||||
|
||||
SelectVersionCell* SelectVersionCell::create(IndexItemHandle item, SelectVersionPopup* versionPopup, CCSize const& size) {
|
||||
auto ret = new SelectVersionCell();
|
||||
if (ret->init(item, versionPopup, size)) {
|
||||
return ret;
|
||||
}
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CCNode* SelectVersionCell::createLogo(CCSize const& size) {
|
||||
return geode::createIndexItemLogo(m_item, size);
|
||||
}
|
||||
std::string SelectVersionCell::getID() const {
|
||||
return m_item->getMetadata().getID();
|
||||
}
|
||||
std::string SelectVersionCell::getDeveloper() const {
|
||||
return m_item->getMetadata().getDeveloper();
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
#include <Geode/loader/ModMetadata.hpp>
|
||||
#include <Geode/loader/Index.hpp>
|
||||
|
||||
#include "../info/TagNode.hpp"
|
||||
|
||||
using namespace geode::prelude;
|
||||
|
||||
class InstallListPopup;
|
||||
|
@ -17,10 +19,14 @@ class InstallListCell : public CCLayer {
|
|||
protected:
|
||||
float m_width;
|
||||
float m_height;
|
||||
InstallListPopup* m_layer;
|
||||
CCMenu* m_menu;
|
||||
CCMenuItemSpriteExtra* m_developerBtn;
|
||||
InstallListPopup* m_layer = nullptr;
|
||||
CCMenu* m_menu = nullptr;
|
||||
CCMenuItemSpriteExtra* m_developerBtn = nullptr;
|
||||
CCLabelBMFont* m_titleLabel = nullptr;
|
||||
CCLabelBMFont* m_versionLabel = nullptr;
|
||||
TagNode* m_tagLabel = nullptr;
|
||||
CCMenuItemToggler* m_toggle = nullptr;
|
||||
bool m_inactive = false;
|
||||
|
||||
void setupInfo(
|
||||
std::string name,
|
||||
|
@ -29,6 +35,8 @@ protected:
|
|||
bool inactive
|
||||
);
|
||||
|
||||
void setupVersion(std::variant<VersionInfo, ComparableVersionInfo> version);
|
||||
|
||||
bool init(InstallListPopup* list, CCSize const& size);
|
||||
void setupInfo(ModMetadata const& metadata, bool inactive);
|
||||
void draw() override;
|
||||
|
@ -90,6 +98,9 @@ public:
|
|||
[[nodiscard]] std::string getDeveloper() const override;
|
||||
|
||||
IndexItemHandle getItem();
|
||||
void setVersionFromItem(IndexItemHandle item);
|
||||
|
||||
void onSelectVersion(CCObject*);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -112,3 +123,23 @@ public:
|
|||
[[nodiscard]] std::string getID() const override;
|
||||
[[nodiscard]] std::string getDeveloper() const override;
|
||||
};
|
||||
|
||||
class SelectVersionPopup;
|
||||
/**
|
||||
* Select version list item
|
||||
*/
|
||||
class SelectVersionCell : public InstallListCell {
|
||||
protected:
|
||||
IndexItemHandle m_item;
|
||||
SelectVersionPopup* m_versionPopup;
|
||||
|
||||
bool init(IndexItemHandle item, SelectVersionPopup* versionPopup, CCSize const& size);
|
||||
|
||||
void onSelected(CCObject*);
|
||||
public:
|
||||
static SelectVersionCell* create(IndexItemHandle item, SelectVersionPopup* versionPopup, CCSize const& size);
|
||||
|
||||
CCNode* createLogo(CCSize const& size) override;
|
||||
[[nodiscard]] std::string getID() const override;
|
||||
[[nodiscard]] std::string getDeveloper() const override;
|
||||
};
|
|
@ -112,7 +112,8 @@ CCArray* InstallListPopup::createCells(std::unordered_map<std::string, InstallLi
|
|||
queued.insert(item.id);
|
||||
|
||||
// installed
|
||||
if (item.mod && !item.mod->isUninstalled()) {
|
||||
// TODO: we should be able to select a different version even if its installed
|
||||
if (/*item.mod && !item.mod->isUninstalled()*/item.mod->getMetadata().getID() == "geode.loader") {
|
||||
bottom.push_back(ModInstallListCell::create(item.mod, this, this->getCellSize()));
|
||||
for (auto const& dep : item.mod->getMetadata().getDependencies()) {
|
||||
queue.push(dep);
|
||||
|
@ -204,7 +205,7 @@ void InstallListPopup::onInstall(cocos2d::CCObject* obj) {
|
|||
CCArray* entries = m_list->m_entries;
|
||||
for (size_t i = entries->count(); i > 0; i--) {
|
||||
auto* itemCell = typeinfo_cast<IndexItemInstallListCell*>(entries->objectAtIndex(i - 1));
|
||||
if (!itemCell || !itemCell->isIncluded())
|
||||
if (!itemCell || !itemCell->isIncluded() || itemCell->getItem()->isInstalled())
|
||||
continue;
|
||||
IndexItemHandle item = itemCell->getItem();
|
||||
list.list.push_back(item);
|
||||
|
@ -227,3 +228,70 @@ InstallListPopup* InstallListPopup::create(
|
|||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// SelectVersionPopup
|
||||
|
||||
bool SelectVersionPopup::setup(std::string const& modID, IndexItemInstallListCell* installCell) {
|
||||
m_modID = modID;
|
||||
m_installCell = installCell;
|
||||
|
||||
this->setTitle("Select Version");
|
||||
|
||||
this->createList();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SelectVersionPopup::createList() {
|
||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
|
||||
if (m_listParent) {
|
||||
m_listParent->removeFromParent();
|
||||
}
|
||||
|
||||
m_listParent = CCNode::create();
|
||||
m_mainLayer->addChild(m_listParent);
|
||||
|
||||
auto items = this->createCells();
|
||||
m_list = ListView::create(
|
||||
items,
|
||||
this->getCellSize().height,
|
||||
this->getListSize().width,
|
||||
this->getListSize().height
|
||||
);
|
||||
m_list->setPosition(winSize / 2 - m_list->getScaledContentSize() / 2);
|
||||
m_listParent->addChild(m_list);
|
||||
|
||||
addListBorders(m_listParent, winSize / 2, m_list->getScaledContentSize());
|
||||
}
|
||||
|
||||
CCArray* SelectVersionPopup::createCells() {
|
||||
auto cells = CCArray::create();
|
||||
for (auto& item : ranges::reverse(Index::get()->getItemsByModID(m_modID))) {
|
||||
cells->addObject(SelectVersionCell::create(item, this, this->getCellSize()));
|
||||
}
|
||||
return cells;
|
||||
}
|
||||
|
||||
CCSize SelectVersionPopup::getCellSize() const {
|
||||
return { getListSize().width, 30.f };
|
||||
}
|
||||
CCSize SelectVersionPopup::getListSize() const {
|
||||
return { 340.f, 170.f };
|
||||
}
|
||||
|
||||
void SelectVersionPopup::selectItem(IndexItemHandle item) {
|
||||
this->onBtn2(nullptr);
|
||||
|
||||
m_installCell->setVersionFromItem(item);
|
||||
}
|
||||
|
||||
SelectVersionPopup* SelectVersionPopup::create(std::string const& modID, IndexItemInstallListCell* installCell) {
|
||||
auto ret = new SelectVersionPopup();
|
||||
if (!ret->init(380.f, 250.f, modID, installCell)) {
|
||||
CC_SAFE_DELETE(ret);
|
||||
return nullptr;
|
||||
}
|
||||
ret->autorelease();
|
||||
return ret;
|
||||
}
|
|
@ -28,3 +28,24 @@ public:
|
|||
|
||||
static InstallListPopup* create(IndexItemHandle item, MiniFunction<void(IndexInstallList const&)> onInstall);
|
||||
};
|
||||
|
||||
class SelectVersionPopup : public Popup<std::string const&, IndexItemInstallListCell*> {
|
||||
protected:
|
||||
std::string m_modID;
|
||||
CCNode* m_listParent;
|
||||
ListView* m_list;
|
||||
IndexItemInstallListCell* m_installCell;
|
||||
|
||||
bool setup(std::string const& modID, IndexItemInstallListCell* installCell) override;
|
||||
|
||||
void createList();
|
||||
CCArray* createCells();
|
||||
CCSize getCellSize() const;
|
||||
CCSize getListSize() const;
|
||||
|
||||
|
||||
public:
|
||||
void selectItem(IndexItemHandle item);
|
||||
|
||||
static SelectVersionPopup* create(std::string const& modID, IndexItemInstallListCell* installCell);
|
||||
};
|
||||
|
|
|
@ -198,7 +198,7 @@ CCArray* ModListLayer::createModCells(ModListType type, ModListQuery const& quer
|
|||
std::multimap<int, IndexItemHandle> sorted;
|
||||
|
||||
auto index = Index::get();
|
||||
for (auto const& item : index->getItems()) {
|
||||
for (auto const& item : index->getLatestItems()) {
|
||||
if (auto match = queryMatch(query, item)) {
|
||||
sorted.insert({ match.value(), item });
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue