mirror of
https://github.com/geode-sdk/geode.git
synced 2025-03-23 03:15:58 -04:00
add issues key to mod.json for specifying where to report issues for
mods
This commit is contained in:
parent
d9b7489d66
commit
9881d3e75f
8 changed files with 133 additions and 19 deletions
loader
include/Geode
resources
src
|
@ -13,6 +13,7 @@
|
|||
#include <type_traits>
|
||||
#include <cocos2d.h>
|
||||
#include "Setting.hpp"
|
||||
#include <optional>
|
||||
|
||||
class InternalLoader;
|
||||
class InternalMod;
|
||||
|
@ -41,6 +42,11 @@ namespace geode {
|
|||
bool isUnresolved() const;
|
||||
};
|
||||
|
||||
struct IssuesInfo {
|
||||
std::string m_info;
|
||||
std::optional<std::string> m_url;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents all the data gatherable
|
||||
* from mod.json
|
||||
|
@ -113,9 +119,13 @@ namespace geode {
|
|||
*/
|
||||
std::string m_supportInfo = "";
|
||||
/**
|
||||
* Git Repository of the mod.
|
||||
* Git Repository of the mod
|
||||
*/
|
||||
std::string m_repository = "";
|
||||
/**
|
||||
* Info about where users should report issues and request help
|
||||
*/
|
||||
std::optional<IssuesInfo> m_issues;
|
||||
/**
|
||||
* Dependencies
|
||||
*/
|
||||
|
|
|
@ -11,22 +11,32 @@ namespace geode {
|
|||
class MDPopup : public Popup<
|
||||
std::string const&,
|
||||
std::string const&,
|
||||
std::string const&
|
||||
const char*,
|
||||
const char*,
|
||||
std::function<void(bool)>
|
||||
> {
|
||||
protected:
|
||||
std::function<void(bool)> m_onClick = nullptr;
|
||||
|
||||
bool setup(
|
||||
std::string const& title,
|
||||
std::string const& info,
|
||||
std::string const& btn
|
||||
const char* btn1,
|
||||
const char* btn2,
|
||||
std::function<void(bool)> onClick
|
||||
) override;
|
||||
|
||||
void onBtn(CCObject*);
|
||||
|
||||
static float estimateHeight(std::string const& content);
|
||||
|
||||
public:
|
||||
static MDPopup* create(
|
||||
std::string const& title,
|
||||
std::string const& content,
|
||||
std::string const& button
|
||||
const char* btn1,
|
||||
const char* btn2 = nullptr,
|
||||
std::function<void(bool)> onClick = nullptr
|
||||
);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -52,5 +52,9 @@
|
|||
"name": "Show Platform Console",
|
||||
"description": "Show the native console (if one exists). <cr>This setting is meant for developers</c>."
|
||||
}
|
||||
},
|
||||
"issues": {
|
||||
"info": "Post your issues on the <cp>Geode Github Repository</c>. <cy>Please follow the standard issue format</c>.",
|
||||
"url": "https://github.com/geode-sdk/geode/issues/new"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include <Index.hpp>
|
||||
#include "../ui/internal/list/ModListLayer.hpp"
|
||||
#include <Geode/ui/MDPopup.hpp>
|
||||
#include <InternalMod.hpp>
|
||||
#include "../ui/internal/info/ModInfoLayer.hpp"
|
||||
|
||||
USE_GEODE_NAMESPACE();
|
||||
|
||||
|
@ -188,14 +190,9 @@ class $modify(CustomMenuLayer, MenuLayer) {
|
|||
"No", "Send",
|
||||
[](auto, bool btn2) {
|
||||
if (btn2) {
|
||||
MDPopup::create(
|
||||
"Crash Report",
|
||||
"Please send the latest crash report file from `" +
|
||||
Loader::get()->getCrashLogDirectory().string() + "` to the "
|
||||
"[#support](https://discord.com/channels/911701438269386882/979352389985390603) "
|
||||
"channnel in the [Geode Discord Server](https://discord.gg/9e43WMKzhp)\n\n",
|
||||
"OK"
|
||||
)->show();
|
||||
ModInfoLayer::showIssueReportPopup(
|
||||
InternalMod::get()->getModInfo()
|
||||
);
|
||||
}
|
||||
},
|
||||
false
|
||||
|
|
|
@ -77,6 +77,13 @@ Result<ModInfo> ModInfo::createFromSchemaV010(ModJson const& rawJson) {
|
|||
}
|
||||
}
|
||||
|
||||
if (auto issues = root.has("issues").obj()) {
|
||||
IssuesInfo issuesInfo;
|
||||
issues.needs("info").into(issuesInfo.m_info);
|
||||
issues.has("url").intoAs<std::string>(issuesInfo.m_url);
|
||||
info.m_issues = issuesInfo;
|
||||
}
|
||||
|
||||
root.has("binary").asOneOf<value_t::string, value_t::object>();
|
||||
|
||||
bool autoEndBinaryName = true;
|
||||
|
|
|
@ -192,6 +192,22 @@ bool ModInfoLayer::init(ModObject* obj, ModListView* list) {
|
|||
infoBtn->setPosition(size.width / 2 - 25.f, size.height / 2 - 25.f);
|
||||
m_buttonMenu->addChild(infoBtn);
|
||||
|
||||
// issue report button
|
||||
if (m_info.m_issues) {
|
||||
auto issuesBtnSpr = ButtonSprite::create(
|
||||
"Report an Issue", "goldFont.fnt", "GJ_button_04.png", .8f
|
||||
);
|
||||
issuesBtnSpr->setScale(.75f);
|
||||
|
||||
auto issuesBtn = CCMenuItemSpriteExtra::create(
|
||||
issuesBtnSpr, this, makeMenuSelector([this](CCObject*) {
|
||||
ModInfoLayer::showIssueReportPopup(m_info);
|
||||
})
|
||||
);
|
||||
issuesBtn->setPosition(0.f, -size.height / 2 + 25.f);
|
||||
m_buttonMenu->addChild(issuesBtn);
|
||||
}
|
||||
|
||||
|
||||
if (isInstalledMod) {
|
||||
auto settingsSpr = CCSprite::createWithSpriteFrameName(
|
||||
|
@ -741,3 +757,33 @@ CCNode* ModInfoLayer::createLogoSpr(IndexItem const& item) {
|
|||
|
||||
return spr;
|
||||
}
|
||||
|
||||
|
||||
void ModInfoLayer::showIssueReportPopup(ModInfo const& info) {
|
||||
if (info.m_issues) {
|
||||
MDPopup::create(
|
||||
"Issue Report",
|
||||
info.m_issues.value().m_info + "\n\n"
|
||||
"If your issue relates to a <cr>game crash</c>, <cb>please include</c> the "
|
||||
"latest crash log(s) from `" +
|
||||
Loader::get()->getCrashLogDirectory().string() + "`",
|
||||
"OK", (info.m_issues.value().m_url ? "Open URL" : ""),
|
||||
[info](bool btn2) {
|
||||
if (btn2) {
|
||||
web::openLinkInBrowser(info.m_issues.value().m_url.value());
|
||||
}
|
||||
}
|
||||
)->show();
|
||||
} else {
|
||||
MDPopup::create(
|
||||
"Issue Report",
|
||||
"Please report your issue on the "
|
||||
"[#support](https://discord.com/channels/911701438269386882/979352389985390603) "
|
||||
"channnel in the [Geode Discord Server](https://discord.gg/9e43WMKzhp)\n\n"
|
||||
"If your issue relates to a <cr>game crash</c>, <cb>please include</c> the "
|
||||
"latest crash log(s) from `" +
|
||||
Loader::get()->getCrashLogDirectory().string() + "`",
|
||||
"OK"
|
||||
)->show();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,8 @@ public:
|
|||
static ModInfoLayer* create(Mod* mod, ModListView* list);
|
||||
static ModInfoLayer* create(ModObject* obj, ModListView* list);
|
||||
|
||||
static void showIssueReportPopup(ModInfo const& info);
|
||||
|
||||
static CCNode* createLogoSpr(ModObject* modObj);
|
||||
static CCNode* createLogoSpr(Mod* mod);
|
||||
static CCNode* createLogoSpr(IndexItem const& item);
|
||||
|
|
|
@ -6,10 +6,14 @@ USE_GEODE_NAMESPACE();
|
|||
bool MDPopup::setup(
|
||||
std::string const& title,
|
||||
std::string const& info,
|
||||
std::string const& btnText
|
||||
const char* btn1Text,
|
||||
const char* btn2Text,
|
||||
std::function<void(bool)> onClick
|
||||
) {
|
||||
this->setTitle(title.c_str(), "goldFont.fnt", .9f, 33.f);
|
||||
|
||||
m_onClick = onClick;
|
||||
|
||||
auto winSize = CCDirector::sharedDirector()->getWinSize();
|
||||
|
||||
auto contentSize = CCSize {
|
||||
|
@ -20,18 +24,50 @@ bool MDPopup::setup(
|
|||
content->setPosition(winSize / 2 - contentSize / 2);
|
||||
m_mainLayer->addChild(content);
|
||||
|
||||
auto btnSpr = ButtonSprite::create(btnText.c_str());
|
||||
btnSpr->setScale(1.f);
|
||||
auto btnSpr = ButtonSprite::create(btn1Text);
|
||||
|
||||
auto btn = CCMenuItemSpriteExtra::create(
|
||||
btnSpr, this, menu_selector(MDPopup::onClose)
|
||||
btnSpr, this, menu_selector(MDPopup::onBtn)
|
||||
);
|
||||
btn->setPosition(.0f, -m_size.height / 2 + 35.f);
|
||||
btn->setTag(0);
|
||||
m_buttonMenu->addChild(btn);
|
||||
|
||||
if (btn2Text) {
|
||||
auto btn2Spr = ButtonSprite::create(btn2Text);
|
||||
|
||||
auto btn2 = CCMenuItemSpriteExtra::create(
|
||||
btn2Spr, this, menu_selector(MDPopup::onBtn)
|
||||
);
|
||||
btn2->setTag(1);
|
||||
m_buttonMenu->addChild(btn2);
|
||||
|
||||
auto fullBtnWidth = btnSpr->getContentSize().width +
|
||||
10.f + btn2Spr->getContentSize().width;
|
||||
|
||||
btn->setPosition(
|
||||
-fullBtnWidth / 2 + btnSpr->getContentSize().width / 2,
|
||||
-m_size.height / 2 + 35.f
|
||||
);
|
||||
btn2->setPosition(
|
||||
fullBtnWidth / 2 - btn2Spr->getContentSize().width / 2,
|
||||
-m_size.height / 2 + 35.f
|
||||
);
|
||||
}
|
||||
// position button in the middle
|
||||
else {
|
||||
btn->setPosition(.0f, -m_size.height / 2 + 35.f);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void MDPopup::onBtn(CCObject* sender) {
|
||||
if (m_onClick) {
|
||||
m_onClick(sender->getTag());
|
||||
}
|
||||
this->onClose(nullptr);
|
||||
}
|
||||
|
||||
float MDPopup::estimateHeight(std::string const& content) {
|
||||
return clamp(string::count(content, '\n') * 30.f, 200.f, 360.f);
|
||||
}
|
||||
|
@ -39,12 +75,14 @@ float MDPopup::estimateHeight(std::string const& content) {
|
|||
MDPopup* MDPopup::create(
|
||||
std::string const& title,
|
||||
std::string const& content,
|
||||
std::string const& button
|
||||
const char* btn1,
|
||||
const char* btn2,
|
||||
std::function<void(bool)> onClick
|
||||
) {
|
||||
auto ret = new MDPopup();
|
||||
if (ret && ret->init(
|
||||
320.f, MDPopup::estimateHeight(content),
|
||||
title, content, button,
|
||||
title, content, btn1, btn2, onClick,
|
||||
"square01_001.png", { 0, 0, 94, 94 }
|
||||
)) {
|
||||
ret->autorelease();
|
||||
|
|
Loading…
Reference in a new issue