diff --git a/Makefile b/Makefile index dce4dff..b0dc0e7 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ DATA := data INCLUDES := include lib/zipper/include /lib/borealis/library/include/borealis/extern/nlohmann APP_TITLE := All-in-One Switch Updater APP_AUTHOR := HamletDuFromage -APP_VERSION := 2.18.1 +APP_VERSION := 2.19.0 TARGET := $(notdir $(CURDIR)) ROMFS := resources diff --git a/include/app_page.hpp b/include/app_page.hpp index 59f726a..c0e46eb 100644 --- a/include/app_page.hpp +++ b/include/app_page.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include static constexpr uint32_t MaxTitleCount = 64000; @@ -32,7 +33,7 @@ protected: uint32_t GetControlData(u64 tid, NsApplicationControlData* controlData, u64& controlSize, std::string& name); virtual void PopulatePage(); virtual void CreateLabel(){}; - virtual void DeclareGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData** controlData); + virtual void AddListItem(const std::string& name, uint64_t tid); public: AppPage(); @@ -53,7 +54,7 @@ class AppPage_CheatSlips : public AppPage { private: void CreateLabel() override; - void DeclareGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData** controlData) override; + void AddListItem(const std::string& name, uint64_t tid) override; public: AppPage_CheatSlips(); @@ -63,7 +64,7 @@ class AppPage_Gbatemp : public AppPage { private: void CreateLabel() override; - void DeclareGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData** controlData) override; + void AddListItem(const std::string& name, uint64_t tid) override; public: AppPage_Gbatemp(); @@ -74,9 +75,19 @@ class AppPage_DownloadedCheats : public AppPage private: std::set titles; void CreateLabel() override; - void DeclareGameListItem(const std::string& name, uint64_t tid, NsApplicationControlData** controlData) override; + void AddListItem(const std::string& name, uint64_t tid) override; void GetExistingCheatsTids(); public: AppPage_DownloadedCheats(); +}; + +class AppPage_OutdatedTitles : public AppPage +{ +private: + nlohmann::ordered_json versions; + void AddListItem(const std::string& name, uint64_t tid) override; + +public: + AppPage_OutdatedTitles(); }; \ No newline at end of file diff --git a/include/download_cheats_page.hpp b/include/download_cheats_page.hpp index 4284b20..8383583 100644 --- a/include/download_cheats_page.hpp +++ b/include/download_cheats_page.hpp @@ -6,14 +6,13 @@ #include #include -namespace show_cheats { - +namespace cheats_util { + u32 GetVersion(uint64_t title_id); void ShowCheatFiles(uint64_t tid, const std::string& name); void ShowCheatSheet(u64 tid, const std::string& bid, const std::string& name); bool CreateCheatList(const std::filesystem::path& path, brls::List** cheatsList); void DeleteCheats(u64 tid, const std::string& bid); - -} // namespace show_cheats +} // namespace cheats_util class DownloadCheatsPage : public brls::AppletFrame { @@ -29,7 +28,6 @@ protected: DownloadCheatsPage(uint64_t tid, const std::string& name); void GetBuildID(); void GetBuildIDFromDmnt(); - void GetVersion(); void GetBuildIDFromFile(); void WriteCheats(const std::string& cheatContent); void AddCheatsfileListItem(); diff --git a/include/hide_tabs_page.hpp b/include/hide_tabs_page.hpp index f2a708f..e6726ed 100644 --- a/include/hide_tabs_page.hpp +++ b/include/hide_tabs_page.hpp @@ -14,6 +14,7 @@ private: brls::ToggleListItem* sigpatches; brls::ToggleListItem* fws; brls::ToggleListItem* cheats; + brls::ToggleListItem* outdatedTitles; brls::ToggleListItem* jccolor; brls::ToggleListItem* pccolor; brls::ToggleListItem* downloadpayload; diff --git a/include/tools_tab.hpp b/include/tools_tab.hpp index d3d8e68..c743eb6 100644 --- a/include/tools_tab.hpp +++ b/include/tools_tab.hpp @@ -7,21 +7,6 @@ class ToolsTab : public brls::List { private: - brls::ListItem* cheats; - brls::ListItem* JCcolor; - brls::ListItem* PCcolor; - brls::ListItem* updateApp; - brls::ListItem* rebootPayload; - brls::ListItem* downloadPayload; - brls::ListItem* changelog; - brls::ListItem* language; - brls::ListItem* cleanUp; - brls::ListItem* hideTabs; - //brls::ListItem* ntcp; - brls::ListItem* netSettings; - brls::ListItem* move; - brls::ListItem* browser; - brls::StagedAppletFrame* stagedFrame; public: diff --git a/lib/borealis b/lib/borealis index b055712..b36542c 160000 --- a/lib/borealis +++ b/lib/borealis @@ -1 +1 @@ -Subproject commit b055712a92a176258dcabc516ce1056bdf3a4730 +Subproject commit b36542c3b610f9657d67df487936334c89d1fabd diff --git a/resources/i18n/en-US/menus.json b/resources/i18n/en-US/menus.json index bd0b28d..569daa1 100644 --- a/resources/i18n/en-US/menus.json +++ b/resources/i18n/en-US/menus.json @@ -160,7 +160,10 @@ "batch_copy": "Batch copy files", "batch_copy_not_found": "The following files were not found and couldn't be copied:\n", "batch_copy_config_not_found": "This tool allows you to automatically copy files to specific locations. This might be useful depending on your bootloader/trinket. Grab copy_files.txt at 'https://git.io/aiosu_copyfiles', edit it and add it to your config folder. This will also be performed after updates.", - "language": "Change app language" + "language": "Change app language", + "outdated_titles": "Missing updates", + "latest_version_not_found": "Couldn't find updates info", + "outdated_titles_desc": "The following titles have available updates:" }, "utils": { "fw_warning": "Because of the size of FW archives, downloading firmwares in Applet Mode is not supported. Please launch the app with full RAM access.", diff --git a/source/app_page.cpp b/source/app_page.cpp index 35cb851..1e98f5e 100644 --- a/source/app_page.cpp +++ b/source/app_page.cpp @@ -8,6 +8,7 @@ #include "confirm_page.hpp" #include "current_cfw.hpp" +#include "download.hpp" #include "download_cheats_page.hpp" #include "extract.hpp" #include "fs.hpp" @@ -43,10 +44,12 @@ void AppPage::PopulatePage() tid = records[i].application_id; - if R_FAILED (GetControlData(tid, controlData, controlSize, name)) continue; + if (R_FAILED(GetControlData(tid, controlData, controlSize, name))) + continue; listItem = new brls::ListItem(name, "", util::formatApplicationId(tid)); - this->DeclareGameListItem(name, tid, &controlData); + listItem->setThumbnail(controlData->icon, sizeof(controlData->icon)); + this->AddListItem(name, tid); } free(controlData); } @@ -54,8 +57,7 @@ void AppPage::PopulatePage() else { tid = GetCurrentApplicationId(); if (R_SUCCEEDED(InitControlData(&controlData)) && R_SUCCEEDED(GetControlData(tid & 0xFFFFFFFFFFFFF000, controlData, controlSize, name))) { - listItem = new brls::ListItem(name, "", util::formatApplicationId(tid)); - this->DeclareGameListItem(name, tid, &controlData); + this->AddListItem(name, tid); } label = new brls::Label(brls::LabelStyle::SMALL, "menus/common/applet_mode_not_supported"_i18n, true); list->addView(label); @@ -130,9 +132,8 @@ u32 AppPage::GetControlData(u64 tid, NsApplicationControlData* controlData, u64& return 0; } -void AppPage::DeclareGameListItem(const std::string& name, u64 tid, NsApplicationControlData** controlData) +void AppPage::AddListItem(const std::string& name, u64 tid) { - listItem->setThumbnail((*controlData)->icon, sizeof((*controlData)->icon)); list->addView(listItem); } @@ -167,10 +168,10 @@ void AppPage_CheatSlips::CreateLabel() list->addView(label); } -void AppPage_CheatSlips::DeclareGameListItem(const std::string& name, u64 tid, NsApplicationControlData** controlData) +void AppPage_CheatSlips::AddListItem(const std::string& name, u64 tid) { listItem->getClickEvent()->subscribe([tid, name](brls::View* view) { brls::Application::pushView(new DownloadCheatsPage_CheatSlips(tid, name)); }); - AppPage::DeclareGameListItem(name, tid, controlData); + list->addView(listItem); } AppPage_Gbatemp::AppPage_Gbatemp() : AppPage() @@ -186,10 +187,10 @@ void AppPage_Gbatemp::CreateLabel() list->addView(label); } -void AppPage_Gbatemp::DeclareGameListItem(const std::string& name, u64 tid, NsApplicationControlData** controlData) +void AppPage_Gbatemp::AddListItem(const std::string& name, u64 tid) { listItem->getClickEvent()->subscribe([tid, name](brls::View* view) { brls::Application::pushView(new DownloadCheatsPage_GbaTemp(tid, name)); }); - AppPage::DeclareGameListItem(name, tid, controlData); + list->addView(listItem); } AppPage_Exclude::AppPage_Exclude() : AppPage() @@ -227,7 +228,8 @@ void AppPage_Exclude::PopulatePage() tid = records[i].application_id; - if R_FAILED (GetControlData(tid, controlData, controlSize, name)) continue; + if (R_FAILED(GetControlData(tid, controlData, controlSize, name))) + continue; brls::ToggleListItem* listItem; listItem = new brls::ToggleListItem(std::string(name), titles.find(util::formatApplicationId(tid)) != titles.end() ? 0 : 1); @@ -273,16 +275,16 @@ void AppPage_DownloadedCheats::CreateLabel() list->addView(label); } -void AppPage_DownloadedCheats::DeclareGameListItem(const std::string& name, u64 tid, NsApplicationControlData** controlData) +void AppPage_DownloadedCheats::AddListItem(const std::string& name, u64 tid) { auto tid_str = util::formatApplicationId(tid); if (titles.find(tid_str) != titles.end()) { - listItem->getClickEvent()->subscribe([tid, name](brls::View* view) { show_cheats::ShowCheatFiles(tid, name); }); + listItem->getClickEvent()->subscribe([tid, name](brls::View* view) { cheats_util::ShowCheatFiles(tid, name); }); listItem->registerAction("menus/cheats/delete_cheats"_i18n, brls::Key::Y, [tid_str] { util::showDialogBoxInfo(extract::removeCheatsDirectory(fmt::format("{}{}", util::getContentsPath(), tid_str)) ? "menus/common/all_done"_i18n : fmt::format("menus/cheats/deletion_error"_i18n, tid_str)); return true; }); - AppPage::DeclareGameListItem(name, tid, controlData); + list->addView(listItem); } } @@ -301,3 +303,26 @@ void AppPage_DownloadedCheats::GetExistingCheatsTids() } } } + +AppPage_OutdatedTitles::AppPage_OutdatedTitles() : AppPage() +{ + download::getRequest(LOOKUP_TABLE_URL, versions); + this->PopulatePage(); +} + +void AppPage_OutdatedTitles::AddListItem(const std::string& name, u64 tid) +{ + u32 version = cheats_util::GetVersion(tid); + std::string tid_string = util::formatApplicationId(tid); + if (versions.find(tid_string) != versions.end()) { + u32 latest = versions.at(tid_string).at("latest"); + if (version < latest) { + listItem->setSubLabel(fmt::format("{}\t|\t v{} (local) → v{} (latest)", tid_string, version, latest)); + list->addView(listItem); + } + } + /* else { + listItem->setSubLabel(fmt::format("{}\t|\t {}", tid_string, "menus/tools/latest_version_not_found"_i18n)); + list->addView(listItem); + } */ +} \ No newline at end of file diff --git a/source/changelog_page.cpp b/source/changelog_page.cpp index 9619179..1728fd6 100644 --- a/source/changelog_page.cpp +++ b/source/changelog_page.cpp @@ -40,13 +40,13 @@ ChangelogPage::ChangelogPage() : AppletFrame(true, true) changes.push_back("\uE016 Added option to set a payload to /bootloader/update.bin"); verTitles.push_back("v1.2.2"); - changes.push_back("\uE016 Added japanese localisation (credits to github.com/yyoossk)."); + changes.push_back("\uE016 Added Japanese localisation (credits to github.com/yyoossk)."); verTitles.push_back("v1.2.4"); changes.push_back("\uE016 Fixed app self-update"); verTitles.push_back("v1.2.5"); - changes.push_back("\uE016 Improved japanese translation"); + changes.push_back("\uE016 Improved Japanese translation"); verTitles.push_back("v1.2.6"); changes.push_back("\uE016 Added spanish translation (credits to github.com/sergiou87"); @@ -223,7 +223,7 @@ ChangelogPage::ChangelogPage() : AppletFrame(true, true) changes.push_back("\uE016 Allow offline extraction of cheats.\n\uE016 Fixed extraction of the the complete cheat archive.\n\uE016 Fixed display bug for cheats extraction."); verTitles.push_back("v2.16.3"); - changes.push_back("\uE016 Fetch default profiles online for joy-con and pro-con color swaps.\n\uE016 Updated french localization (https://github.com/NotaInutilis)."); + changes.push_back("\uE016 Fetch default profiles online for joy-con and pro-con color swaps.\n\uE016 Updated French localization (https://github.com/NotaInutilis)."); verTitles.push_back("v2.17.0"); changes.push_back("\uE016 Add ability to download a basic hekate_ipl file.\n\uE016 Add error messages when cheats are not found for a game."); @@ -237,6 +237,9 @@ ChangelogPage::ChangelogPage() : AppletFrame(true, true) verTitles.push_back("v2.18.1"); changes.push_back("\uE016 Fix some pop-up related bugs."); + verTitles.push_back("v2.19.0"); + changes.push_back("\uE016 Added ability to view games with missing updates.\n\uE016 Updated Japanese localisation (https://github.com/yyoossk).\n\uE016 Updated Chinese localisation (https://github.com/Physton)."); + for (int i = verTitles.size() - 1; i >= 0; i--) { listItem = new brls::ListItem(verTitles[i]); diff --git a/source/download_cheats_page.cpp b/source/download_cheats_page.cpp index 9f92cc9..e04c57f 100644 --- a/source/download_cheats_page.cpp +++ b/source/download_cheats_page.cpp @@ -14,7 +14,18 @@ namespace i18n = brls::i18n; using namespace i18n::literals; using json = nlohmann::json; -namespace show_cheats { +namespace cheats_util { + u32 GetVersion(uint64_t title_id) + { + u32 res = 0; + NsApplicationContentMetaStatus* MetaSatus = new NsApplicationContentMetaStatus[100U]; + s32 out; + nsListApplicationContentMetaStatus(title_id, 0, MetaSatus, 100, &out); + for (int i = 0; i < out; i++) { + if (res < MetaSatus[i].version) res = MetaSatus[i].version; + } + return res; + } void ShowCheatSheet(u64 tid, const std::string& bid, const std::string& name) { @@ -87,17 +98,17 @@ namespace show_cheats { std::filesystem::remove(fmt::format("{}{:016X}/cheats/{}.txt", util::getContentsPath(), tid, bid)); } -} // namespace show_cheats +} // namespace cheats_util DownloadCheatsPage::DownloadCheatsPage(uint64_t tid, const std::string& name) : AppletFrame(true, true), tid(tid), name(name) { this->list = new brls::List(); - this->GetVersion(); + this->version = cheats_util::GetVersion(this->tid); this->GetBuildID(); this->setTitle(this->name); this->setFooterText("v" + std::to_string(this->version / 0x10000)); this->brls::AppletFrame::registerAction("menus/cheats/show_existing"_i18n, brls::Key::X, [this] { - show_cheats::ShowCheatSheet(this->tid, this->bid, this->name); + cheats_util::ShowCheatSheet(this->tid, this->bid, this->name); return true; }); this->rebuildHints(); @@ -126,16 +137,6 @@ void DownloadCheatsPage::GetBuildIDFromDmnt() } } -void DownloadCheatsPage::GetVersion() -{ - NsApplicationContentMetaStatus* MetaSatus = new NsApplicationContentMetaStatus[100U]; - s32 out; - nsListApplicationContentMetaStatus(this->tid, 0, MetaSatus, 100, &out); - for (int i = 0; i < out; i++) { - if (version < MetaSatus[i].version) this->version = MetaSatus[i].version; - } -} - void DownloadCheatsPage::GetBuildIDFromFile() { nlohmann::ordered_json versions_json; @@ -163,7 +164,7 @@ void DownloadCheatsPage::AddCheatsfileListItem() { brls::ListItem* item = new brls::ListItem("menus/cheats/show_cheat_files"_i18n); item->getClickEvent()->subscribe([this](brls::View* view) { - show_cheats::ShowCheatFiles(this->tid, this->name); + cheats_util::ShowCheatFiles(this->tid, this->name); }); this->list->addView(item); } diff --git a/source/hide_tabs_page.cpp b/source/hide_tabs_page.cpp index fc6af57..b9ddc6d 100644 --- a/source/hide_tabs_page.cpp +++ b/source/hide_tabs_page.cpp @@ -41,6 +41,9 @@ HideTabsPage::HideTabsPage() : AppletFrame(true, true) cheats = new brls::ToggleListItem("menus/main/download_cheats"_i18n, util::getBoolValue(hideStatus, "cheats")); list->addView(cheats); + outdatedTitles = new brls::ToggleListItem("menus/main/download_cheats"_i18n, util::getBoolValue(hideStatus, "outdatedtitles")); + list->addView(outdatedTitles); + jccolor = new brls::ToggleListItem("menus/tools/joy_cons"_i18n, util::getBoolValue(hideStatus, "jccolor")); list->addView(jccolor); diff --git a/source/tools_tab.cpp b/source/tools_tab.cpp index 95d214d..a7cc1df 100644 --- a/source/tools_tab.cpp +++ b/source/tools_tab.cpp @@ -5,6 +5,7 @@ #include "JC_page.hpp" #include "PC_page.hpp" +#include "app_page.hpp" #include "changelog_page.hpp" #include "cheats_page.hpp" #include "confirm_page.hpp" @@ -27,7 +28,7 @@ namespace { ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payloads, bool erista, const nlohmann::json& hideStatus) : brls::List() { if (!tag.empty() && tag != AppVersion) { - updateApp = new brls::ListItem(fmt::format("menus/tools/update_app"_i18n, tag)); + brls::ListItem* updateApp = new brls::ListItem(fmt::format("menus/tools/update_app"_i18n, tag)); std::string text("menus/tools/dl_app"_i18n + std::string(APP_URL)); updateApp->getClickEvent()->subscribe([text, tag](brls::View* view) { brls::StagedAppletFrame* stagedFrame = new brls::StagedAppletFrame(); @@ -46,37 +47,43 @@ ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payload this->addView(updateApp); } - cheats = new brls::ListItem("menus/tools/cheats"_i18n); + brls::ListItem* cheats = new brls::ListItem("menus/tools/cheats"_i18n); cheats->getClickEvent()->subscribe([](brls::View* view) { brls::PopupFrame::open("menus/cheats/menu"_i18n, new CheatsPage(), "", ""); }); cheats->setHeight(LISTITEM_HEIGHT); - JCcolor = new brls::ListItem("menus/tools/joy_cons"_i18n); + brls::ListItem* outdatedTitles = new brls::ListItem("menus/tools/outdated_titles"_i18n); + outdatedTitles->getClickEvent()->subscribe([](brls::View* view) { + brls::PopupFrame::open("menus/tools/outdated_titles"_i18n, new AppPage_OutdatedTitles(), "menus/tools/outdated_titles_desc"_i18n, ""); + }); + outdatedTitles->setHeight(LISTITEM_HEIGHT); + + brls::ListItem* JCcolor = new brls::ListItem("menus/tools/joy_cons"_i18n); JCcolor->getClickEvent()->subscribe([](brls::View* view) { brls::Application::pushView(new JCPage()); }); JCcolor->setHeight(LISTITEM_HEIGHT); - PCcolor = new brls::ListItem("menus/tools/pro_cons"_i18n); + brls::ListItem* PCcolor = new brls::ListItem("menus/tools/pro_cons"_i18n); PCcolor->getClickEvent()->subscribe([](brls::View* view) { brls::Application::pushView(new PCPage()); }); PCcolor->setHeight(LISTITEM_HEIGHT); - rebootPayload = new brls::ListItem("menus/tools/inject_payloads"_i18n); + brls::ListItem* rebootPayload = new brls::ListItem("menus/tools/inject_payloads"_i18n); rebootPayload->getClickEvent()->subscribe([](brls::View* view) { brls::PopupFrame::open("menus/tools/inject_payloads"_i18n, new PayloadPage(), "", ""); }); rebootPayload->setHeight(LISTITEM_HEIGHT); - netSettings = new brls::ListItem("menus/tools/internet_settings"_i18n); + brls::ListItem* netSettings = new brls::ListItem("menus/tools/internet_settings"_i18n); netSettings->getClickEvent()->subscribe([](brls::View* view) { brls::PopupFrame::open("menus/tools/internet_settings"_i18n, new NetPage(), "", ""); }); netSettings->setHeight(LISTITEM_HEIGHT); - browser = new brls::ListItem("menus/tools/browser"_i18n); + brls::ListItem* browser = new brls::ListItem("menus/tools/browser"_i18n); browser->getClickEvent()->subscribe([](brls::View* view) { std::string url; if (brls::Swkbd::openForText([&url](std::string text) { url = text; }, "cheatslips.com e-mail", "", 64, "https://duckduckgo.com", 0, "Submit", "https://website.tld")) { @@ -106,7 +113,7 @@ ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payload }); browser->setHeight(LISTITEM_HEIGHT); - move = new brls::ListItem("menus/tools/batch_copy"_i18n); + brls::ListItem* move = new brls::ListItem("menus/tools/batch_copy"_i18n); move->getClickEvent()->subscribe([](brls::View* view) { chdir("/"); std::string error = ""; @@ -120,7 +127,7 @@ ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payload }); move->setHeight(LISTITEM_HEIGHT); - cleanUp = new brls::ListItem("menus/tools/clean_up"_i18n); + brls::ListItem* cleanUp = new brls::ListItem("menus/tools/clean_up"_i18n); cleanUp->getClickEvent()->subscribe([](brls::View* view) { std::filesystem::remove(AMS_ZIP_PATH); std::filesystem::remove(APP_ZIP_PATH); @@ -136,7 +143,7 @@ ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payload }); cleanUp->setHeight(LISTITEM_HEIGHT); - language = new brls::ListItem("menus/tools/language"_i18n); + brls::ListItem* language = new brls::ListItem("menus/tools/language"_i18n); language->getClickEvent()->subscribe([](brls::View* view) { std::vector> languages{ std::make_pair("American English ({})", "en-US"), @@ -187,19 +194,20 @@ ToolsTab::ToolsTab(const std::string& tag, const nlohmann::ordered_json& payload }); language->setHeight(LISTITEM_HEIGHT); - hideTabs = new brls::ListItem("menus/tools/hide_tabs"_i18n); + brls::ListItem* hideTabs = new brls::ListItem("menus/tools/hide_tabs"_i18n); hideTabs->getClickEvent()->subscribe([](brls::View* view) { brls::PopupFrame::open("menus/tools/hide_tabs"_i18n, new HideTabsPage(), "", ""); }); hideTabs->setHeight(LISTITEM_HEIGHT); - changelog = new brls::ListItem("menus/tools/changelog"_i18n); + brls::ListItem* changelog = new brls::ListItem("menus/tools/changelog"_i18n); changelog->getClickEvent()->subscribe([](brls::View* view) { brls::PopupFrame::open("menus/tools/changelog"_i18n, new ChangelogPage(), "", ""); }); changelog->setHeight(LISTITEM_HEIGHT); if (!util::getBoolValue(hideStatus, "cheats")) this->addView(cheats); + if (!util::getBoolValue(hideStatus, "outdatedtitles")) this->addView(outdatedTitles); if (!util::getBoolValue(hideStatus, "jccolor")) this->addView(JCcolor); if (!util::getBoolValue(hideStatus, "pccolor")) this->addView(PCcolor); if (erista && !util::getBoolValue(hideStatus, "rebootpayload")) this->addView(rebootPayload);