add dump options, allow for gamecard menu to be accessed without install enabled.
This commit is contained in:
@@ -115,6 +115,7 @@ public:
|
|||||||
static void DisplayMiscOptions(bool left_side = true);
|
static void DisplayMiscOptions(bool left_side = true);
|
||||||
static void DisplayAdvancedOptions(bool left_side = true);
|
static void DisplayAdvancedOptions(bool left_side = true);
|
||||||
static void DisplayInstallOptions(bool left_side = true);
|
static void DisplayInstallOptions(bool left_side = true);
|
||||||
|
static void DisplayDumpOptions(bool left_side = true);
|
||||||
|
|
||||||
void Draw();
|
void Draw();
|
||||||
void Update();
|
void Update();
|
||||||
@@ -252,6 +253,12 @@ public:
|
|||||||
option::OptionBool m_lower_master_key{INI_SECTION, "lower_master_key", false};
|
option::OptionBool m_lower_master_key{INI_SECTION, "lower_master_key", false};
|
||||||
option::OptionBool m_lower_system_version{INI_SECTION, "lower_system_version", false};
|
option::OptionBool m_lower_system_version{INI_SECTION, "lower_system_version", false};
|
||||||
|
|
||||||
|
// dump options
|
||||||
|
option::OptionBool m_dump_app_folder{"dump", "app_folder", true};
|
||||||
|
option::OptionBool m_dump_append_folder_with_xci{"dump", "append_folder_with_xci", true};
|
||||||
|
option::OptionBool m_dump_trim_xci{"dump", "trim_xci", false};
|
||||||
|
option::OptionBool m_dump_usb_transfer_stream{"dump", "usb_transfer_stream", true};
|
||||||
|
|
||||||
// todo: move this into it's own menu
|
// todo: move this into it's own menu
|
||||||
option::OptionLong m_text_scroll_speed{"accessibility", "text_scroll_speed", 1}; // normal
|
option::OptionLong m_text_scroll_speed{"accessibility", "text_scroll_speed", 1}; // normal
|
||||||
|
|
||||||
|
|||||||
@@ -1590,6 +1590,10 @@ void App::DisplayAdvancedOptions(bool left_side) {
|
|||||||
options->Add(std::make_shared<ui::SidebarEntryCallback>("Install options"_i18n, [left_side](){
|
options->Add(std::make_shared<ui::SidebarEntryCallback>("Install options"_i18n, [left_side](){
|
||||||
App::DisplayInstallOptions(left_side);
|
App::DisplayInstallOptions(left_side);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<ui::SidebarEntryCallback>("Dump options"_i18n, [left_side](){
|
||||||
|
App::DisplayDumpOptions(left_side);
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void App::DisplayInstallOptions(bool left_side) {
|
void App::DisplayInstallOptions(bool left_side) {
|
||||||
@@ -1681,6 +1685,27 @@ void App::DisplayInstallOptions(bool left_side) {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void App::DisplayDumpOptions(bool left_side) {
|
||||||
|
auto options = std::make_shared<ui::Sidebar>("Dump Options"_i18n, left_side ? ui::Sidebar::Side::LEFT : ui::Sidebar::Side::RIGHT);
|
||||||
|
ON_SCOPE_EXIT(App::Push(options));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<ui::SidebarEntryBool>("Created nested folder"_i18n, App::GetApp()->m_dump_app_folder.Get(), [](bool& enable){
|
||||||
|
App::GetApp()->m_dump_app_folder.Set(enable);
|
||||||
|
}));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<ui::SidebarEntryBool>("Append folder with .xci"_i18n, App::GetApp()->m_dump_append_folder_with_xci.Get(), [](bool& enable){
|
||||||
|
App::GetApp()->m_dump_append_folder_with_xci.Set(enable);
|
||||||
|
}));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<ui::SidebarEntryBool>("Trim XCI"_i18n, App::GetApp()->m_dump_trim_xci.Get(), [](bool& enable){
|
||||||
|
App::GetApp()->m_dump_trim_xci.Set(enable);
|
||||||
|
}));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<ui::SidebarEntryBool>("Multi-threaded USB transfer"_i18n, App::GetApp()->m_dump_usb_transfer_stream.Get(), [](bool& enable){
|
||||||
|
App::GetApp()->m_dump_usb_transfer_stream.Set(enable);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
App::~App() {
|
App::~App() {
|
||||||
log_write("starting to exit\n");
|
log_write("starting to exit\n");
|
||||||
|
|
||||||
|
|||||||
@@ -410,7 +410,11 @@ Result DumpNspToUsbS2S(ProgressBox* pbox, std::span<NspEntry> entries) {
|
|||||||
while (!pbox->ShouldExit()) {
|
while (!pbox->ShouldExit()) {
|
||||||
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
|
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
|
||||||
pbox->NewTransfer("USB connected, sending file list");
|
pbox->NewTransfer("USB connected, sending file list");
|
||||||
const u8 flags = usb::tinfoil::USBFlag_STREAM;
|
u8 flags = usb::tinfoil::USBFlag_NONE;
|
||||||
|
if (App::GetApp()->m_dump_usb_transfer_stream.Get()) {
|
||||||
|
flags |= usb::tinfoil::USBFlag_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
|
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
|
||||||
pbox->NewTransfer("Sent file list, waiting for command...");
|
pbox->NewTransfer("Sent file list, waiting for command...");
|
||||||
|
|
||||||
@@ -740,7 +744,12 @@ auto BuildNspPath(const Entry& e, const NsApplicationContentMetaStatus& status)
|
|||||||
}
|
}
|
||||||
|
|
||||||
fs::FsPath path;
|
fs::FsPath path;
|
||||||
std::snprintf(path, sizeof(path), "%s/%s %s[%016lX][v%u][%s].nsp", name_buf.s, name_buf.s, version, status.application_id, status.version, ncm::GetMetaTypeShortStr(status.meta_type));
|
if (App::GetApp()->m_dump_app_folder.Get()) {
|
||||||
|
std::snprintf(path, sizeof(path), "%s/%s %s[%016lX][v%u][%s].nsp", name_buf.s, name_buf.s, version, status.application_id, status.version, ncm::GetMetaTypeShortStr(status.meta_type));
|
||||||
|
} else {
|
||||||
|
std::snprintf(path, sizeof(path), "%s %s[%016lX][v%u][%s].nsp", name_buf.s, version, status.application_id, status.version, ncm::GetMetaTypeShortStr(status.meta_type));
|
||||||
|
}
|
||||||
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1117,6 +1126,10 @@ Menu::Menu() : grid::Menu{"Games"_i18n} {
|
|||||||
}, true));
|
}, true));
|
||||||
}, true));
|
}, true));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("Dump options"_i18n, [this](){
|
||||||
|
App::DisplayDumpOptions(false);
|
||||||
|
}));
|
||||||
|
|
||||||
// completely deletes the application record and all data.
|
// completely deletes the application record and all data.
|
||||||
options->Add(std::make_shared<SidebarEntryCallback>("Delete"_i18n, [this](){
|
options->Add(std::make_shared<SidebarEntryCallback>("Delete"_i18n, [this](){
|
||||||
const auto buf = "Are you sure you want to delete "_i18n + m_entries[m_index].GetName() + "?";
|
const auto buf = "Are you sure you want to delete "_i18n + m_entries[m_index].GetName() + "?";
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include "ui/nvg_util.hpp"
|
#include "ui/nvg_util.hpp"
|
||||||
#include "ui/sidebar.hpp"
|
#include "ui/sidebar.hpp"
|
||||||
#include "ui/popup_list.hpp"
|
#include "ui/popup_list.hpp"
|
||||||
|
#include "ui/option_box.hpp"
|
||||||
|
|
||||||
#include "yati/yati.hpp"
|
#include "yati/yati.hpp"
|
||||||
#include "yati/nx/nca.hpp"
|
#include "yati/nx/nca.hpp"
|
||||||
@@ -150,7 +151,15 @@ auto BuildFilePath(DumpFileType type, std::span<const ApplicationEntry> entries)
|
|||||||
// builds path suiteable for file dumps.
|
// builds path suiteable for file dumps.
|
||||||
auto BuildFullDumpPath(DumpFileType type, std::span<const ApplicationEntry> entries) -> fs::FsPath {
|
auto BuildFullDumpPath(DumpFileType type, std::span<const ApplicationEntry> entries) -> fs::FsPath {
|
||||||
const auto base_path = BuildXciBasePath(entries);
|
const auto base_path = BuildXciBasePath(entries);
|
||||||
return base_path + "/" + base_path + GetDumpTypeStr(type);
|
if (App::GetApp()->m_dump_app_folder.Get()) {
|
||||||
|
if (App::GetApp()->m_dump_append_folder_with_xci.Get()) {
|
||||||
|
return base_path + ".xci/" + base_path + GetDumpTypeStr(type);
|
||||||
|
} else {
|
||||||
|
return base_path + "/" + base_path + GetDumpTypeStr(type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return base_path + GetDumpTypeStr(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Gc is the mount point, S is for secure partion, the remaining is the
|
// @Gc is the mount point, S is for secure partion, the remaining is the
|
||||||
@@ -397,7 +406,11 @@ Result DumpNspToUsbS2S(ProgressBox* pbox, std::span<const fs::FsPath> paths, Xci
|
|||||||
while (!pbox->ShouldExit()) {
|
while (!pbox->ShouldExit()) {
|
||||||
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
|
if (R_SUCCEEDED(usb->IsUsbConnected(timeout))) {
|
||||||
pbox->NewTransfer("USB connected, sending file list");
|
pbox->NewTransfer("USB connected, sending file list");
|
||||||
const u8 flags = usb::tinfoil::USBFlag_STREAM;
|
u8 flags = usb::tinfoil::USBFlag_NONE;
|
||||||
|
if (App::GetApp()->m_dump_usb_transfer_stream.Get()) {
|
||||||
|
flags |= usb::tinfoil::USBFlag_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
|
if (R_SUCCEEDED(usb->WaitForConnection(timeout, flags, file_list))) {
|
||||||
pbox->NewTransfer("Sent file list, waiting for command...");
|
pbox->NewTransfer("Sent file list, waiting for command...");
|
||||||
|
|
||||||
@@ -636,7 +649,16 @@ Menu::Menu() : MenuBase{"GameCard"_i18n} {
|
|||||||
SetPop();
|
SetPop();
|
||||||
}}),
|
}}),
|
||||||
std::make_pair(Button::X, Action{"Options"_i18n, [this](){
|
std::make_pair(Button::X, Action{"Options"_i18n, [this](){
|
||||||
App::DisplayInstallOptions(false);
|
auto options = std::make_shared<Sidebar>("Game Options"_i18n, Sidebar::Side::RIGHT);
|
||||||
|
ON_SCOPE_EXIT(App::Push(options));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("Install options"_i18n, [this](){
|
||||||
|
App::DisplayInstallOptions(false);
|
||||||
|
}));
|
||||||
|
|
||||||
|
options->Add(std::make_shared<SidebarEntryCallback>("Dump options"_i18n, [this](){
|
||||||
|
App::DisplayDumpOptions(false);
|
||||||
|
}));
|
||||||
}})
|
}})
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -875,16 +897,24 @@ Result Menu::GcMount() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (m_option_index == 0) {
|
if (m_option_index == 0) {
|
||||||
App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) -> Result {
|
if (!App::GetInstallEnable()) {
|
||||||
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
|
App::Push(std::make_shared<ui::OptionBox>(
|
||||||
return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
|
"Install disabled...\n"
|
||||||
}, [this](Result rc){
|
"Please enable installing via the install options."_i18n,
|
||||||
App::PushErrorBox(rc, "Gc install failed"_i18n);
|
"OK"_i18n
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
App::Push(std::make_shared<ui::ProgressBox>(m_icon, "Installing "_i18n, m_entries[m_entry_index].lang_entry.name, [this](auto pbox) -> Result {
|
||||||
|
auto source = std::make_shared<GcSource>(m_entries[m_entry_index], m_fs.get());
|
||||||
|
return yati::InstallFromCollections(pbox, source, source->m_collections, source->m_config);
|
||||||
|
}, [this](Result rc){
|
||||||
|
App::PushErrorBox(rc, "Gc install failed"_i18n);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
App::Notify("Gc install success!"_i18n);
|
App::Notify("Gc install success!"_i18n);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
auto options = std::make_shared<Sidebar>("Select content to dump"_i18n, Sidebar::Side::RIGHT);
|
auto options = std::make_shared<Sidebar>("Select content to dump"_i18n, Sidebar::Side::RIGHT);
|
||||||
ON_SCOPE_EXIT(App::Push(options));
|
ON_SCOPE_EXIT(App::Push(options));
|
||||||
@@ -1206,8 +1236,7 @@ void Menu::DumpGames(u32 flags) {
|
|||||||
|
|
||||||
std::vector<fs::FsPath> paths;
|
std::vector<fs::FsPath> paths;
|
||||||
if (flags & DumpFileFlag_XCI) {
|
if (flags & DumpFileFlag_XCI) {
|
||||||
// todo: add config support for full and trimmed.
|
if (App::GetApp()->m_dump_trim_xci.Get()) {
|
||||||
if (1) {
|
|
||||||
entry.xci_size = m_storage_trimmed_size;
|
entry.xci_size = m_storage_trimmed_size;
|
||||||
paths.emplace_back(BuildFullDumpPath(DumpFileType_TrimmedXCI, m_entries));
|
paths.emplace_back(BuildFullDumpPath(DumpFileType_TrimmedXCI, m_entries));
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ const MiscMenuEntry MISC_MENU_ENTRIES[] = {
|
|||||||
{ .name = "GitHub", .title = "GitHub", .func = MiscMenuFuncGenerator<ui::menu::gh::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "GitHub", .title = "GitHub", .func = MiscMenuFuncGenerator<ui::menu::gh::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install },
|
{ .name = "FTP", .title = "FTP Install", .func = MiscMenuFuncGenerator<ui::menu::ftp::Menu>, .flag = MiscMenuFlag_Install },
|
||||||
{ .name = "USB", .title = "USB Install", .func = MiscMenuFuncGenerator<ui::menu::usb::Menu>, .flag = MiscMenuFlag_Install },
|
{ .name = "USB", .title = "USB Install", .func = MiscMenuFuncGenerator<ui::menu::usb::Menu>, .flag = MiscMenuFlag_Install },
|
||||||
{ .name = "GameCard", .title = "GameCard Install", .func = MiscMenuFuncGenerator<ui::menu::gc::Menu>, .flag = MiscMenuFlag_Shortcut|MiscMenuFlag_Install },
|
{ .name = "GameCard", .title = "GameCard", .func = MiscMenuFuncGenerator<ui::menu::gc::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
{ .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut },
|
{ .name = "IRS", .title = "IRS (Infrared Joycon Camera)", .func = MiscMenuFuncGenerator<ui::menu::irs::Menu>, .flag = MiscMenuFlag_Shortcut },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user