1
0
Fork 0
mirror of https://github.com/HamletDuFromage/aio-switch-updater.git synced 2024-12-26 17:56:04 +00:00

Add ability to enter and delete custom links

This commit is contained in:
flb 2022-10-31 19:59:48 +01:00
parent a75694913f
commit 5189684cb3
21 changed files with 197 additions and 100 deletions

View file

@ -22,7 +22,7 @@ DATA := data
INCLUDES := include /lib/borealis/library/include/borealis/extern/nlohmann
APP_TITLE := All-in-One Switch Updater
APP_AUTHOR := HamletDuFromage
APP_VERSION := 2.20.1
APP_VERSION := 2.21.0
TARGET := $(notdir $(CURDIR))
ROMFS := resources

View file

@ -41,6 +41,6 @@ int main(int argc, char* argv[])
std::filesystem::remove(FORWARDER_PATH);
envSetNextLoad(FULL_PATH, ("\"" + std::string(FULL_PATH) + "\"").c_str());
envSetNextLoad(FULL_PATH, FULL_PATH);
return 0;
}

View file

@ -8,20 +8,45 @@
class AmsTab : public brls::List
{
private:
protected:
brls::ListItem* listItem;
bool erista;
contentType type;
nlohmann::ordered_json nxlinks;
nlohmann::ordered_json hekate;
std::string GetRepoName(const std::string& repo);
std::set<std::string> GetLastDownloadedModules(const std::string& json_path);
contentType type;
void CreateStagedFrames(const std::string& text, const std::string& url, bool erista, bool ams = true, bool hekate = false, const std::string& text_hekate = "", const std::string& hekate_url = "");
void CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate = true, bool ams = true);
nlohmann::ordered_json SortDeepseaModules(const nlohmann::ordered_json& modules);
void ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules);
bool CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate = true, bool ams = true);
void CreateNotFoundLabel();
virtual void RegisterListItemAction(brls::ListItem* listItem);
public:
AmsTab(const nlohmann::json& nxlinks, const bool erista = true, const bool custom = false);
AmsTab(const nlohmann::ordered_json& nxlinks, const bool erista = true);
};
class AmsTab_Regular : public AmsTab
{
private:
void CreateLists();
bool CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate = true, bool ams = true);
void ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules);
std::set<std::string> GetLastDownloadedModules(const std::string& json_path);
nlohmann::ordered_json SortDeepseaModules(const nlohmann::ordered_json& modules);
std::string GetRepoName(const std::string& repo);
public:
AmsTab_Regular(const nlohmann::ordered_json& nxlinks, const bool erista = true);
};
class AmsTab_Custom : public AmsTab
{
private:
nlohmann::ordered_json custom_packs;
void CreateLists();
void RegisterListItemAction(brls::ListItem* listItem) override;
void AddLinkCreator();
public:
AmsTab_Custom(const nlohmann::ordered_json& nxlinks, const bool erista = true);
};
class UnTogglableListItem : public brls::ToggleListItem

View file

@ -6,10 +6,10 @@
namespace JC {
int setColor(const std::vector<int>& colors);
int backupToJSON(nlohmann::json& profiles, const std::string& path);
int backupToJSON(nlohmann::ordered_json& profiles, const std::string& path);
std::deque<std::pair<std::string, std::vector<int>>> getProfiles(const std::string& path);
void changeJCColor(const std::vector<int>& values);
nlohmann::json backupProfile();
nlohmann::ordered_json backupProfile();
void backupJCColor(const std::string& path);
} // namespace JC
@ -17,10 +17,10 @@ namespace JC {
namespace PC {
int setColor(const std::vector<int>& colors);
int backupToJSON(nlohmann::json& profiles, const std::string& path);
int backupToJSON(nlohmann::ordered_json& profiles, const std::string& path);
std::deque<std::pair<std::string, std::vector<int>>> getProfiles(const std::string& path);
void changePCColor(const std::vector<int>& values);
nlohmann::json backupProfile();
nlohmann::ordered_json backupProfile();
void backupPCColor(const std::string& path);
} // namespace PC

View file

@ -3,6 +3,7 @@
constexpr const char ROOT_PATH[] = "/";
constexpr const char APP_PATH[] = "/switch/aio-switch-updater/";
constexpr const char NRO_PATH[] = "/switch/aio-switch-updater/aio-switch-updater.nro";
constexpr const char NRO_PATH_REGEX[] = ".*(/switch/.*aio-switch-updater.nro).*";
constexpr const char DOWNLOAD_PATH[] = "/config/aio-switch-updater/";
constexpr const char CONFIG_PATH[] = "/config/aio-switch-updater/";
constexpr const char CONFIG_FILE[] = "/config/aio-switch-updater/config.json";

View file

@ -57,7 +57,7 @@ class DownloadCheatsPage_CheatSlips : public DownloadCheatsPage
private:
brls::ToggleListItem* listItem;
std::vector<std::pair<brls::ToggleListItem*, int>> toggles;
std::string GetCheatsTitle(nlohmann::json cheat);
std::string GetCheatsTitle(nlohmann::ordered_json cheat);
void ShowCheatsContent(nlohmann::ordered_json titles);
public:

View file

@ -9,7 +9,7 @@ namespace fs {
std::vector<std::string> splitString(const std::string& s, char delimiter);
bool removeDir(const std::string& path);
nlohmann::ordered_json parseJsonFile(const std::string& path);
void writeJsonToFile(nlohmann::json& data, const std::string& path);
void writeJsonToFile(nlohmann::ordered_json& data, const std::string& path);
bool copyFile(const std::string& from, const std::string& to);
std::string copyFiles(const std::string& path);
void createTree(std::string path);

View file

@ -10,5 +10,5 @@ private:
brls::StagedAppletFrame* stagedFrame;
public:
ToolsTab(const std::string& tag, const nlohmann::ordered_json& payloads, bool erista = true, const nlohmann::json& hideStatus = {});
ToolsTab(const std::string& tag, const nlohmann::ordered_json& payloads, bool erista = true, const nlohmann::ordered_json& hideStatus = {});
};

View file

@ -41,6 +41,7 @@ namespace util {
void saveToFile(const std::string& text, const std::string& path);
std::string readFile(const std::string& path);
std::string getAppPath();
void restartApp();
bool isErista();
void removeSysmodulesFlags(const std::string& directory);
std::string lowerCase(const std::string& str);
@ -48,6 +49,6 @@ namespace util {
std::string getErrorMessage(long status_code);
bool isApplet();
std::string getContentsPath();
bool getBoolValue(const nlohmann::json& jsonFile, const std::string& key);
bool getBoolValue(const nlohmann::ordered_json& jsonFile, const std::string& key);
const nlohmann::ordered_json getValueFromKey(const nlohmann::ordered_json& jsonFile, const std::string& key);
} // namespace util

View file

@ -189,7 +189,9 @@
"custom_packs_label": "\u25c6 Here are packs listed in the {} file. Be aware that those are not endorsed by AIO-Switch-Updater so make sure you trust their source.",
"custom_packs_ams": "\u25c6 Downloads containing the Atmosphère custom firmware.",
"custom_packs_misc": "\u25c6 Downloads containing homebrew and tools.",
"custom_download" : "Custom download"
"custom_download" : "Custom download",
"add_custom_link": "Add a custom link",
"delete_custom_link": "Delete"
},
"firmware": {
"launch_daybreak": "Do you want to launch Daybreak to install the downloaded sysupdate?"

View file

@ -1,6 +1,7 @@
#include "ams_tab.hpp"
#include <filesystem>
#include <iostream>
#include <string>
#include "confirm_page.hpp"
@ -11,75 +12,30 @@
#include "fs.hpp"
#include "utils.hpp"
#include "worker_page.hpp"
namespace i18n = brls::i18n;
using namespace i18n::literals;
AmsTab::AmsTab(const nlohmann::json& nxlinks, const bool erista, const bool custom) : brls::List()
AmsTab::AmsTab(const nlohmann::ordered_json& nxlinks, const bool erista) : brls::List()
{
this->erista = erista;
this->nxlinks = nxlinks;
this->hekate = util::getValueFromKey(nxlinks, "hekate");
if (!custom) {
this->type = contentType::ams_cfw;
auto cfws = util::getValueFromKey(nxlinks, "cfws");
this->addView(new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/main/ams_text"_i18n + (CurrentCfw::running_cfw == CFW::ams ? "\n" + "menus/ams_update/current_ams"_i18n + CurrentCfw::getAmsInfo() : "") + (erista ? "\n" + "menus/ams_update/erista_rev"_i18n : "\n" + "menus/ams_update/mariko_rev"_i18n), true));
CreateDownloadItems(util::getValueFromKey(cfws, "Atmosphere"));
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/deepsea_label"_i18n,
true));
listItem = new brls::ListItem("menus/ams_update/get_custom_deepsea"_i18n);
listItem->setHeight(LISTITEM_HEIGHT);
listItem->getClickEvent()->subscribe([this](brls::View* view) {
nlohmann::ordered_json modules;
download::getRequest(DEEPSEA_META_JSON, modules);
this->ShowCustomDeepseaBuilder(modules);
});
this->addView(listItem);
CreateDownloadItems(util::getValueFromKey(cfws, "DeepSea"), false);
}
else {
auto custom_pack = fs::parseJsonFile(CUSTOM_PACKS_PATH);
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
fmt::format("menus/ams_update/custom_packs_label"_i18n, CUSTOM_PACKS_PATH),
true));
if (custom_pack.contains("ams") && custom_pack["ams"].size() != 0) {
this->type = contentType::ams_cfw;
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/custom_packs_ams"_i18n,
true));
CreateDownloadItems(custom_pack["ams"], true);
}
if (custom_pack.contains("misc") && custom_pack["misc"].size() != 0) {
this->type = contentType::custom;
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/custom_packs_misc"_i18n,
true));
CreateDownloadItems(custom_pack["misc"], false, false);
}
}
}
void AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate, bool ams)
void AmsTab::RegisterListItemAction(brls::ListItem* listItem) {}
bool AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate, bool ams)
{
std::vector<std::pair<std::string, std::string>> links;
links = download::getLinksFromJson(cfw_links);
if (links.size() && !this->hekate.empty()) { // non-empty this->hekate indicates internet connection
if (links.size() && !this->hekate.empty()) { // non-empty this->hekate indicates internet connection
auto hekate_link = download::getLinksFromJson(this->hekate);
std::string hekate_url = hekate_link[0].second;
std::string text_hekate = "menus/common/download"_i18n + hekate_link[0].first;
for (const auto& link : links) {
std::string url = link.second;
std::string text("menus/common/download"_i18n + link.first + "menus/common/from"_i18n + url);
std::string text("menus/common/download"_i18n + link.second + "menus/common/from"_i18n + url);
listItem = new brls::ListItem(link.first);
listItem->setHeight(LISTITEM_HEIGHT);
listItem->getClickEvent()->subscribe([this, text, text_hekate, url, hekate_url, hekate, ams](brls::View* view) {
@ -90,17 +46,12 @@ void AmsTab::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool h
CreateStagedFrames(text, url, erista, ams, hekate, text_hekate, hekate_url);
}
});
this->RegisterListItemAction(listItem);
this->addView(listItem);
}
return true;
}
else {
brls::Label* description = new brls::Label(
brls::LabelStyle::SMALL,
"menus/main/links_not_found"_i18n,
true);
description->setHorizontalAlign(NVG_ALIGN_CENTER);
this->addView(description);
}
return false;
}
void AmsTab::CreateStagedFrames(const std::string& text, const std::string& url, bool erista, bool ams, bool hekate, const std::string& text_hekate, const std::string& hekate_url)
@ -128,14 +79,56 @@ void AmsTab::CreateStagedFrames(const std::string& text, const std::string& url,
brls::Application::pushView(stagedFrame);
}
std::string AmsTab::GetRepoName(const std::string& repo)
AmsTab_Regular::AmsTab_Regular(const nlohmann::ordered_json& nxlinks, const bool erista) : AmsTab(nxlinks, erista)
{
this->CreateLists();
}
bool AmsTab_Regular::CreateDownloadItems(const nlohmann::ordered_json& cfw_links, bool hekate, bool ams)
{
if (!AmsTab::CreateDownloadItems(cfw_links, hekate, ams)) {
brls::Label* description = new brls::Label(
brls::LabelStyle::SMALL,
"menus/main/links_not_found"_i18n,
true);
description->setHorizontalAlign(NVG_ALIGN_CENTER);
this->addView(description);
return true;
}
return false;
}
void AmsTab_Regular::CreateLists()
{
this->type = contentType::ams_cfw;
auto cfws = util::getValueFromKey(this->nxlinks, "cfws");
this->addView(new brls::Label(brls::LabelStyle::DESCRIPTION, "menus/main/ams_text"_i18n + (CurrentCfw::running_cfw == CFW::ams ? "\n" + "menus/ams_update/current_ams"_i18n + CurrentCfw::getAmsInfo() : "") + (erista ? "\n" + "menus/ams_update/erista_rev"_i18n : "\n" + "menus/ams_update/mariko_rev"_i18n), true));
CreateDownloadItems(util::getValueFromKey(cfws, "Atmosphere"));
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/deepsea_label"_i18n,
true));
listItem = new brls::ListItem("menus/ams_update/get_custom_deepsea"_i18n);
listItem->setHeight(LISTITEM_HEIGHT);
listItem->getClickEvent()->subscribe([this](brls::View* view) {
nlohmann::ordered_json modules;
download::getRequest(DEEPSEA_META_JSON, modules);
this->ShowCustomDeepseaBuilder(modules);
});
this->addView(listItem);
CreateDownloadItems(util::getValueFromKey(cfws, "DeepSea"), false);
}
std::string AmsTab_Regular::GetRepoName(const std::string& repo)
{
return repo.substr(repo.find("/") + 1, repo.length());
}
std::set<std::string> AmsTab::GetLastDownloadedModules(const std::string& json_path)
std::set<std::string> AmsTab_Regular::GetLastDownloadedModules(const std::string& json_path)
{
nlohmann::json package = fs::parseJsonFile(json_path);
nlohmann::ordered_json package = fs::parseJsonFile(json_path);
std::set<std::string> res;
if (package.find("modules") != package.end()) {
for (const auto& module : package.at("modules")) {
@ -145,7 +138,7 @@ std::set<std::string> AmsTab::GetLastDownloadedModules(const std::string& json_p
return res;
}
nlohmann::ordered_json AmsTab::SortDeepseaModules(const nlohmann::ordered_json& modules)
nlohmann::ordered_json AmsTab_Regular::SortDeepseaModules(const nlohmann::ordered_json& modules)
{
nlohmann::ordered_json sorted_modules = nlohmann::ordered_json::object();
if (modules.find("modules") != modules.end()) {
@ -156,7 +149,7 @@ nlohmann::ordered_json AmsTab::SortDeepseaModules(const nlohmann::ordered_json&
return sorted_modules;
}
void AmsTab::ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules)
void AmsTab_Regular::ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules)
{
modules = SortDeepseaModules(modules);
std::map<std::string, std::string> name_map;
@ -228,6 +221,69 @@ void AmsTab::ShowCustomDeepseaBuilder(nlohmann::ordered_json& modules)
brls::PopupFrame::open("menus/ams_update/deepsea_builder"_i18n, appView, modules.empty() ? "menus/ams_update/cant_fetch_deepsea"_i18n : "menus/ams_update/build_your_deepsea"_i18n, "");
}
AmsTab_Custom::AmsTab_Custom(const nlohmann::ordered_json& nxlinks, const bool erista) : AmsTab(nxlinks, erista)
{
this->custom_packs = fs::parseJsonFile(CUSTOM_PACKS_PATH);
this->CreateLists();
}
void AmsTab_Custom::CreateLists()
{
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
fmt::format("menus/ams_update/custom_packs_label"_i18n, CUSTOM_PACKS_PATH),
true));
this->type = contentType::ams_cfw;
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/custom_packs_ams"_i18n,
true));
CreateDownloadItems(util::getValueFromKey(this->custom_packs, "ams"), true);
this->AddLinkCreator();
this->type = contentType::custom;
this->addView(new brls::Label(
brls::LabelStyle::DESCRIPTION,
"menus/ams_update/custom_packs_misc"_i18n,
true));
CreateDownloadItems(util::getValueFromKey(this->custom_packs, "misc"), false, false);
this->AddLinkCreator();
}
void AmsTab_Custom::AddLinkCreator()
{
std::string category = this->type == contentType::ams_cfw ? "ams" : "misc";
listItem = new brls::ListItem("menus/ams_update/add_custom_link"_i18n);
listItem->setHeight(LISTITEM_HEIGHT);
listItem->getClickEvent()->subscribe([this, category](brls::View* view) {
std::string title, link;
brls::Swkbd::openForText([&title](std::string text) { title = text; }, "Enter title", "", 64, "", 0, "Submit", "Title");
brls::Swkbd::openForText([&link](std::string text) { link = text; }, "Enter direct link", "", 64, "", 0, "Submit", "https://site/download.zip");
auto links = util::getValueFromKey(this->custom_packs, category);
links[title] = link;
this->custom_packs[category] = links;
fs::writeJsonToFile(this->custom_packs, CUSTOM_PACKS_PATH);
util::restartApp();
});
this->addView(listItem);
}
void AmsTab_Custom::RegisterListItemAction(brls::ListItem* listItem)
{
std::string label = listItem->getLabel();
std::string category = this->type == contentType::ams_cfw ? "ams" : "misc";
listItem->registerAction("menus/ams_update/delete_custom_link"_i18n, brls::Key::X, [this, label, category] {
brls::Logger::info(label);
brls::Logger::info(category);
auto& links = this->custom_packs.at(category);
links.erase(label);
fs::writeJsonToFile(this->custom_packs, CUSTOM_PACKS_PATH);
util::restartApp();
return true;
});
}
bool UnTogglableListItem::onClick()
{
return true;

View file

@ -12,7 +12,7 @@
#include "progress_event.hpp"
#include "utils.hpp"
using json = nlohmann::json;
using json = nlohmann::ordered_json;
namespace {

View file

@ -35,7 +35,7 @@ ConfirmPage_Done::ConfirmPage_Done(brls::StagedAppletFrame* frame, const std::st
ConfirmPage_AppUpdate::ConfirmPage_AppUpdate(brls::StagedAppletFrame* frame, const std::string& text) : ConfirmPage_Done(frame, text)
{
this->button->getClickEvent()->subscribe([](View* view) {
envSetNextLoad(FORWARDER_PATH, fmt::format("\"{}\"", FORWARDER_PATH).c_str());
envSetNextLoad(FORWARDER_PATH, FORWARDER_PATH);
romfsExit();
brls::Application::quit();
});

View file

@ -22,7 +22,7 @@ using namespace i18n::literals;
constexpr const char API_AGENT[] = "HamletDuFromage";
constexpr int _1MiB = 0x100000;
using json = nlohmann::json;
using json = nlohmann::ordered_json;
namespace download {

View file

@ -12,7 +12,7 @@
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
using json = nlohmann::ordered_json;
namespace cheats_util {
u32 GetVersion(uint64_t title_id)

View file

@ -43,7 +43,7 @@ namespace fs {
return nlohmann::ordered_json::object();
}
void writeJsonToFile(nlohmann::json& data, const std::string& path)
void writeJsonToFile(nlohmann::ordered_json& data, const std::string& path)
{
std::ofstream out(path);
out << data.dump(4);

View file

@ -9,7 +9,7 @@
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
using json = nlohmann::ordered_json;
HideTabsPage::HideTabsPage() : AppletFrame(true, true)
{

View file

@ -25,7 +25,7 @@ int main(int argc, char* argv[])
return EXIT_FAILURE;
}
nlohmann::json languageFile = fs::parseJsonFile(LANGUAGE_JSON);
nlohmann::ordered_json languageFile = fs::parseJsonFile(LANGUAGE_JSON);
if (languageFile.find("language") != languageFile.end())
i18n::loadTranslations(languageFile["language"]);
else

View file

@ -13,7 +13,7 @@
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
using json = nlohmann::ordered_json;
namespace {
constexpr const char AppTitle[] = APP_TITLE;
@ -41,7 +41,7 @@ MainFrame::MainFrame() : TabFrame()
this->addTab("menus/main/about"_i18n, new AboutTab());
if (!util::getBoolValue(hideStatus, "atmosphere"))
this->addTab("menus/main/update_ams"_i18n, new AmsTab(nxlinks, erista, false));
this->addTab("menus/main/update_ams"_i18n, new AmsTab_Regular(nxlinks, erista));
if (!util::getBoolValue(hideStatus, "cfw"))
this->addTab("menus/main/update_bootloaders"_i18n, new ListDownloadTab(contentType::bootloaders, nxlinks));
@ -53,7 +53,7 @@ MainFrame::MainFrame() : TabFrame()
this->addTab("menus/main/download_cheats"_i18n, new ListDownloadTab(contentType::cheats));
if (!util::getBoolValue(hideStatus, "custom"))
this->addTab("menus/main/custom_downloads"_i18n, new AmsTab(nxlinks, erista, true));
this->addTab("menus/main/custom_downloads"_i18n, new AmsTab_Custom(nxlinks, erista));
if (!util::getBoolValue(hideStatus, "tools"))
this->addTab("menus/main/tools"_i18n, new ToolsTab(tag, util::getValueFromKey(nxlinks, "payloads"), erista, hideStatus));

View file

@ -19,13 +19,13 @@
namespace i18n = brls::i18n;
using namespace i18n::literals;
using json = nlohmann::json;
using json = nlohmann::ordered_json;
namespace {
constexpr const char AppVersion[] = APP_VERSION;
}
ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payloads, bool erista, const nlohmann::json& hideStatus) : brls::List()
ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payloads, bool erista, const nlohmann::ordered_json& hideStatus) : brls::List()
{
if (!tag.empty() && tag != AppVersion) {
brls::ListItem* updateApp = new brls::ListItem(fmt::format("menus/tools/update_app"_i18n, tag));

View file

@ -294,12 +294,26 @@ namespace util {
std::string getAppPath()
{
if (envHasArgv()) {
std::smatch match;
std::string argv = (char*)envGetArgv();
return fs::splitString(argv, '\"')[1].substr(5);
if (std::regex_match(argv, match, std::regex(NRO_PATH_REGEX))) {
if (match.size() >= 2) {
return match[1].str();
}
}
}
return NRO_PATH;
}
void restartApp()
{
std::string path = "sdmc:" + getAppPath();
std::string argv = "\"" + path + "\"";
envSetNextLoad(path.c_str(), argv.c_str());
romfsExit();
brls::Application::quit();
}
bool isErista()
{
SetSysProductModel model;
@ -387,10 +401,8 @@ namespace util {
return path;
}
bool getBoolValue(const nlohmann::json& jsonFile, const std::string& key)
bool getBoolValue(const nlohmann::ordered_json& jsonFile, const std::string& key)
{
/* try { return jsonFile.at(key); }
catch (nlohmann::json::out_of_range& e) { return false; } */
return (jsonFile.find(key) != jsonFile.end()) ? jsonFile.at(key).get<bool>() : false;
}