diff --git a/sphaira/include/ui/menus/filebrowser.hpp b/sphaira/include/ui/menus/filebrowser.hpp index 902913f..0b73fbc 100644 --- a/sphaira/include/ui/menus/filebrowser.hpp +++ b/sphaira/include/ui/menus/filebrowser.hpp @@ -264,6 +264,9 @@ private: void DisplayHash(hash::Type type); + void DisplayOptions(); + void DisplayAdvancedOptions(); + private: Menu* m_menu{}; ViewSide m_side{}; diff --git a/sphaira/source/ui/menus/filebrowser.cpp b/sphaira/source/ui/menus/filebrowser.cpp index 449b668..8a2fd71 100644 --- a/sphaira/source/ui/menus/filebrowser.cpp +++ b/sphaira/source/ui/menus/filebrowser.cpp @@ -396,310 +396,11 @@ FsView::FsView(Menu* menu, const fs::FsPath& path, const FsEntry& entry, ViewSid }}), std::make_pair(Button::X, Action{"Options"_i18n, [this](){ - auto options = std::make_shared("File Options"_i18n, Sidebar::Side::RIGHT); - ON_SCOPE_EXIT(App::Push(options)); - - options->Add(std::make_shared("Sort By"_i18n, [this](){ - auto options = std::make_shared("Sort Options"_i18n, Sidebar::Side::RIGHT); - ON_SCOPE_EXIT(App::Push(options)); - - SidebarEntryArray::Items sort_items; - sort_items.push_back("Size"_i18n); - sort_items.push_back("Alphabetical"_i18n); - - SidebarEntryArray::Items order_items; - order_items.push_back("Descending"_i18n); - order_items.push_back("Ascending"_i18n); - - options->Add(std::make_shared("Sort"_i18n, sort_items, [this](s64& index_out){ - m_menu->m_sort.Set(index_out); - SortAndFindLastFile(); - }, m_menu->m_sort.Get())); - - options->Add(std::make_shared("Order"_i18n, order_items, [this](s64& index_out){ - m_menu->m_order.Set(index_out); - SortAndFindLastFile(); - }, m_menu->m_order.Get())); - - options->Add(std::make_shared("Show Hidden"_i18n, m_menu->m_show_hidden.Get(), [this](bool& v_out){ - m_menu->m_show_hidden.Set(v_out); - SortAndFindLastFile(); - })); - - options->Add(std::make_shared("Folders First"_i18n, m_menu->m_folders_first.Get(), [this](bool& v_out){ - m_menu->m_folders_first.Set(v_out); - SortAndFindLastFile(); - })); - - options->Add(std::make_shared("Hidden Last"_i18n, m_menu->m_hidden_last.Get(), [this](bool& v_out){ - m_menu->m_hidden_last.Set(v_out); - SortAndFindLastFile(); - })); - })); - - if (m_entries_current.size()) { - options->Add(std::make_shared("Cut"_i18n, [this](){ - m_menu->AddSelectedEntries(SelectedType::Cut); - }, true)); - - options->Add(std::make_shared("Copy"_i18n, [this](){ - m_menu->AddSelectedEntries(SelectedType::Copy); - }, true)); + if (App::GetApp()->m_controller.GotHeld(Button::R2)) { + DisplayAdvancedOptions(); + } else { + DisplayOptions(); } - - if (!m_menu->m_selected.Empty() && (m_menu->m_selected.Type() == SelectedType::Cut || m_menu->m_selected.Type() == SelectedType::Copy)) { - options->Add(std::make_shared("Paste"_i18n, [this](){ - const std::string buf = "Paste file(s)?"_i18n; - App::Push(std::make_shared( - buf, "No"_i18n, "Yes"_i18n, 0, [this](auto op_index){ - if (op_index && *op_index) { - App::PopToMenu(); - OnPasteCallback(); - } - })); - })); - } - - // can't rename more than 1 file - if (m_entries_current.size() && !m_selected_count) { - options->Add(std::make_shared("Rename"_i18n, [this](){ - std::string out; - const auto& entry = GetEntry(); - const auto name = entry.GetName(); - if (R_SUCCEEDED(swkbd::ShowText(out, "Set New File Name"_i18n.c_str(), name.c_str())) && !out.empty() && out != name) { - App::PopToMenu(); - - const auto src_path = GetNewPath(entry); - const auto dst_path = GetNewPath(m_path, out); - - Result rc; - if (entry.IsFile()) { - rc = m_fs->RenameFile(src_path, dst_path); - } else { - rc = m_fs->RenameDirectory(src_path, dst_path); - } - - if (R_SUCCEEDED(rc)) { - Scan(m_path); - } else { - const auto msg = std::string("Failed to rename file: ") + entry.name; - App::PushErrorBox(rc, msg); - } - } - })); - } - - if (m_entries_current.size()) { - options->Add(std::make_shared("Delete"_i18n, [this](){ - m_menu->AddSelectedEntries(SelectedType::Delete); - - log_write("clicked on delete\n"); - App::Push(std::make_shared( - "Delete Selected files?"_i18n, "No"_i18n, "Yes"_i18n, 0, [this](auto op_index){ - if (op_index && *op_index) { - App::PopToMenu(); - OnDeleteCallback(); - } - } - )); - log_write("pushed delete\n"); - })); - } - - // returns true if all entries match the ext array. - const auto check_all_ext = [this](auto& exts){ - const auto entries = GetSelectedEntries(); - for (auto&e : entries) { - if (!IsExtension(e.GetExtension(), exts)) { - return false; - } - } - return true; - }; - - // if install is enabled, check if all currently selected files are installable. - if (m_entries_current.size() && App::GetInstallEnable()) { - if (check_all_ext(INSTALL_EXTENSIONS)) { - options->Add(std::make_shared("Install"_i18n, [this](){ - InstallFiles(); - })); - } - } - - if (IsSd() && m_entries_current.size() && !m_selected_count) { - if (App::GetInstallEnable() && GetEntry().IsFile() && (GetEntry().GetExtension() == "nro" || !m_menu->FindFileAssocFor().empty())) { - options->Add(std::make_shared("Install Forwarder"_i18n, [this](){; - if (App::GetInstallPrompt()) { - App::Push(std::make_shared( - "WARNING: Installing forwarders will lead to a ban!"_i18n, - "Back"_i18n, "Install"_i18n, 0, [this](auto op_index){ - if (op_index && *op_index) { - InstallForwarder(); - } - } - )); - } else { - InstallForwarder(); - } - })); - } - } - - if (m_entries_current.size()) { - if (check_all_ext(ZIP_EXTENSIONS)) { - options->Add(std::make_shared("Extract zip"_i18n, [this](){ - auto options = std::make_shared("Extract Options"_i18n, Sidebar::Side::RIGHT); - ON_SCOPE_EXIT(App::Push(options)); - - options->Add(std::make_shared("Extract here"_i18n, [this](){ - UnzipFiles(""); - })); - - options->Add(std::make_shared("Extract to root"_i18n, [this](){ - App::Push(std::make_shared("Are you sure you want to extract to root?"_i18n, - "No"_i18n, "Yes"_i18n, 0, [this](auto op_index){ - if (op_index && *op_index) { - UnzipFiles(m_fs->Root()); - } - })); - })); - - options->Add(std::make_shared("Extract to..."_i18n, [this](){ - std::string out; - if (R_SUCCEEDED(swkbd::ShowText(out, "Enter the path to the folder to extract into", fs::AppendPath(m_path, ""))) && !out.empty()) { - UnzipFiles(out); - } - })); - })); - } - - if (!check_all_ext(ZIP_EXTENSIONS) || m_selected_count) { - options->Add(std::make_shared("Compress to zip"_i18n, [this](){ - auto options = std::make_shared("Compress Options"_i18n, Sidebar::Side::RIGHT); - ON_SCOPE_EXIT(App::Push(options)); - - options->Add(std::make_shared("Compress"_i18n, [this](){ - ZipFiles(""); - })); - - options->Add(std::make_shared("Compress to..."_i18n, [this](){ - std::string out; - if (R_SUCCEEDED(swkbd::ShowText(out, "Enter the path to the folder to extract into", m_path)) && !out.empty()) { - ZipFiles(out); - } - })); - })); - } - } - - options->Add(std::make_shared("Advanced"_i18n, [this](){ - auto options = std::make_shared("Advanced Options"_i18n, Sidebar::Side::RIGHT); - ON_SCOPE_EXIT(App::Push(options)); - - SidebarEntryArray::Items mount_items; - std::vector fs_entries; - - const auto stdio_locations = location::GetStdio(false); - for (const auto& e: stdio_locations) { - u32 flags{}; - if (e.write_protect) { - flags |= FsEntryFlag_ReadOnly; - } - - fs_entries.emplace_back(e.name, e.mount, FsType::Stdio, flags); - mount_items.push_back(e.name); - } - - for (const auto& e: FS_ENTRIES) { - fs_entries.emplace_back(e); - mount_items.push_back(i18n::get(e.name)); - } - - options->Add(std::make_shared("Mount"_i18n, mount_items, [this, fs_entries](s64& index_out){ - App::PopToMenu(); - SetFs(fs_entries[index_out].root, fs_entries[index_out]); - }, m_fs_entry.name)); - - options->Add(std::make_shared("Create File"_i18n, [this](){ - std::string out; - if (R_SUCCEEDED(swkbd::ShowText(out, "Set File Name"_i18n.c_str(), fs::AppendPath(m_path, ""))) && !out.empty()) { - App::PopToMenu(); - - fs::FsPath full_path; - if (out.starts_with(m_fs_entry.root.s)) { - full_path = out; - } else { - full_path = fs::AppendPath(m_path, out); - } - - m_fs->CreateDirectoryRecursivelyWithPath(full_path); - if (R_SUCCEEDED(m_fs->CreateFile(full_path, 0, 0))) { - log_write("created file: %s\n", full_path.s); - Scan(m_path); - } else { - log_write("failed to create file: %s\n", full_path.s); - } - } - })); - - options->Add(std::make_shared("Create Folder"_i18n, [this](){ - std::string out; - if (R_SUCCEEDED(swkbd::ShowText(out, "Set Folder Name"_i18n.c_str(), fs::AppendPath(m_path, ""))) && !out.empty()) { - App::PopToMenu(); - - fs::FsPath full_path; - if (out.starts_with(m_fs_entry.root.s)) { - full_path = out; - } else { - full_path = fs::AppendPath(m_path, out); - } - - if (R_SUCCEEDED(m_fs->CreateDirectoryRecursively(full_path))) { - log_write("created dir: %s\n", full_path.s); - Scan(m_path); - } else { - log_write("failed to create dir: %s\n", full_path.s); - } - } - })); - - if (IsSd() && m_entries_current.size() && !m_selected_count && GetEntry().IsFile() && GetEntry().file_size < 1024*64) { - options->Add(std::make_shared("View as text (unfinished)"_i18n, [this](){ - App::Push(std::make_shared(GetNewPathCurrent())); - })); - } - - if (m_entries_current.size()) { - options->Add(std::make_shared("Upload"_i18n, [this](){ - UploadFiles(); - })); - } - - if (m_entries_current.size() && !m_selected_count && GetEntry().IsFile()) { - options->Add(std::make_shared("Hash"_i18n, [this](){ - auto options = std::make_shared("Hash Options"_i18n, Sidebar::Side::RIGHT); - ON_SCOPE_EXIT(App::Push(options)); - - options->Add(std::make_shared("CRC32"_i18n, [this](){ - DisplayHash(hash::Type::Crc32); - })); - options->Add(std::make_shared("MD5"_i18n, [this](){ - DisplayHash(hash::Type::Md5); - })); - options->Add(std::make_shared("SHA1"_i18n, [this](){ - DisplayHash(hash::Type::Sha1); - })); - options->Add(std::make_shared("SHA256"_i18n, [this](){ - DisplayHash(hash::Type::Sha256); - })); - })); - } - - options->Add(std::make_shared("Ignore read only"_i18n, m_menu->m_ignore_read_only.Get(), [this](bool& v_out){ - m_menu->m_ignore_read_only.Set(v_out); - m_fs->SetIgnoreReadOnly(v_out); - })); - })); }}) ); @@ -1877,6 +1578,317 @@ void FsView::DisplayHash(hash::Type type) { })); } +void FsView::DisplayOptions() { + auto options = std::make_shared("File Options"_i18n, Sidebar::Side::RIGHT); + ON_SCOPE_EXIT(App::Push(options)); + + options->Add(std::make_shared("Sort By"_i18n, [this](){ + auto options = std::make_shared("Sort Options"_i18n, Sidebar::Side::RIGHT); + ON_SCOPE_EXIT(App::Push(options)); + + SidebarEntryArray::Items sort_items; + sort_items.push_back("Size"_i18n); + sort_items.push_back("Alphabetical"_i18n); + + SidebarEntryArray::Items order_items; + order_items.push_back("Descending"_i18n); + order_items.push_back("Ascending"_i18n); + + options->Add(std::make_shared("Sort"_i18n, sort_items, [this](s64& index_out){ + m_menu->m_sort.Set(index_out); + SortAndFindLastFile(); + }, m_menu->m_sort.Get())); + + options->Add(std::make_shared("Order"_i18n, order_items, [this](s64& index_out){ + m_menu->m_order.Set(index_out); + SortAndFindLastFile(); + }, m_menu->m_order.Get())); + + options->Add(std::make_shared("Show Hidden"_i18n, m_menu->m_show_hidden.Get(), [this](bool& v_out){ + m_menu->m_show_hidden.Set(v_out); + SortAndFindLastFile(); + })); + + options->Add(std::make_shared("Folders First"_i18n, m_menu->m_folders_first.Get(), [this](bool& v_out){ + m_menu->m_folders_first.Set(v_out); + SortAndFindLastFile(); + })); + + options->Add(std::make_shared("Hidden Last"_i18n, m_menu->m_hidden_last.Get(), [this](bool& v_out){ + m_menu->m_hidden_last.Set(v_out); + SortAndFindLastFile(); + })); + })); + + if (m_entries_current.size()) { + options->Add(std::make_shared("Cut"_i18n, [this](){ + m_menu->AddSelectedEntries(SelectedType::Cut); + }, true)); + + options->Add(std::make_shared("Copy"_i18n, [this](){ + m_menu->AddSelectedEntries(SelectedType::Copy); + }, true)); + } + + if (!m_menu->m_selected.Empty() && (m_menu->m_selected.Type() == SelectedType::Cut || m_menu->m_selected.Type() == SelectedType::Copy)) { + options->Add(std::make_shared("Paste"_i18n, [this](){ + const std::string buf = "Paste file(s)?"_i18n; + App::Push(std::make_shared( + buf, "No"_i18n, "Yes"_i18n, 0, [this](auto op_index){ + if (op_index && *op_index) { + App::PopToMenu(); + OnPasteCallback(); + } + })); + })); + } + + // can't rename more than 1 file + if (m_entries_current.size() && !m_selected_count) { + options->Add(std::make_shared("Rename"_i18n, [this](){ + std::string out; + const auto& entry = GetEntry(); + const auto name = entry.GetName(); + if (R_SUCCEEDED(swkbd::ShowText(out, "Set New File Name"_i18n.c_str(), name.c_str())) && !out.empty() && out != name) { + App::PopToMenu(); + + const auto src_path = GetNewPath(entry); + const auto dst_path = GetNewPath(m_path, out); + + Result rc; + if (entry.IsFile()) { + rc = m_fs->RenameFile(src_path, dst_path); + } else { + rc = m_fs->RenameDirectory(src_path, dst_path); + } + + if (R_SUCCEEDED(rc)) { + Scan(m_path); + } else { + const auto msg = std::string("Failed to rename file: ") + entry.name; + App::PushErrorBox(rc, msg); + } + } + })); + } + + if (m_entries_current.size()) { + options->Add(std::make_shared("Delete"_i18n, [this](){ + m_menu->AddSelectedEntries(SelectedType::Delete); + + log_write("clicked on delete\n"); + App::Push(std::make_shared( + "Delete Selected files?"_i18n, "No"_i18n, "Yes"_i18n, 0, [this](auto op_index){ + if (op_index && *op_index) { + App::PopToMenu(); + OnDeleteCallback(); + } + } + )); + log_write("pushed delete\n"); + })); + } + + // returns true if all entries match the ext array. + const auto check_all_ext = [this](auto& exts){ + const auto entries = GetSelectedEntries(); + for (auto&e : entries) { + if (!IsExtension(e.GetExtension(), exts)) { + return false; + } + } + return true; + }; + + // if install is enabled, check if all currently selected files are installable. + if (m_entries_current.size() && App::GetInstallEnable()) { + if (check_all_ext(INSTALL_EXTENSIONS)) { + options->Add(std::make_shared("Install"_i18n, [this](){ + InstallFiles(); + })); + } + } + + if (IsSd() && m_entries_current.size() && !m_selected_count) { + if (App::GetInstallEnable() && GetEntry().IsFile() && (GetEntry().GetExtension() == "nro" || !m_menu->FindFileAssocFor().empty())) { + options->Add(std::make_shared("Install Forwarder"_i18n, [this](){; + if (App::GetInstallPrompt()) { + App::Push(std::make_shared( + "WARNING: Installing forwarders will lead to a ban!"_i18n, + "Back"_i18n, "Install"_i18n, 0, [this](auto op_index){ + if (op_index && *op_index) { + InstallForwarder(); + } + } + )); + } else { + InstallForwarder(); + } + })); + } + } + + if (m_entries_current.size()) { + if (check_all_ext(ZIP_EXTENSIONS)) { + options->Add(std::make_shared("Extract zip"_i18n, [this](){ + auto options = std::make_shared("Extract Options"_i18n, Sidebar::Side::RIGHT); + ON_SCOPE_EXIT(App::Push(options)); + + options->Add(std::make_shared("Extract here"_i18n, [this](){ + UnzipFiles(""); + })); + + options->Add(std::make_shared("Extract to root"_i18n, [this](){ + App::Push(std::make_shared("Are you sure you want to extract to root?"_i18n, + "No"_i18n, "Yes"_i18n, 0, [this](auto op_index){ + if (op_index && *op_index) { + UnzipFiles(m_fs->Root()); + } + })); + })); + + options->Add(std::make_shared("Extract to..."_i18n, [this](){ + std::string out; + if (R_SUCCEEDED(swkbd::ShowText(out, "Enter the path to the folder to extract into", fs::AppendPath(m_path, ""))) && !out.empty()) { + UnzipFiles(out); + } + })); + })); + } + + if (!check_all_ext(ZIP_EXTENSIONS) || m_selected_count) { + options->Add(std::make_shared("Compress to zip"_i18n, [this](){ + auto options = std::make_shared("Compress Options"_i18n, Sidebar::Side::RIGHT); + ON_SCOPE_EXIT(App::Push(options)); + + options->Add(std::make_shared("Compress"_i18n, [this](){ + ZipFiles(""); + })); + + options->Add(std::make_shared("Compress to..."_i18n, [this](){ + std::string out; + if (R_SUCCEEDED(swkbd::ShowText(out, "Enter the path to the folder to extract into", m_path)) && !out.empty()) { + ZipFiles(out); + } + })); + })); + } + } + + options->Add(std::make_shared("Advanced"_i18n, [this](){ + DisplayAdvancedOptions(); + })); +} + +void FsView::DisplayAdvancedOptions() { + auto options = std::make_shared("Advanced Options"_i18n, Sidebar::Side::RIGHT); + ON_SCOPE_EXIT(App::Push(options)); + + SidebarEntryArray::Items mount_items; + std::vector fs_entries; + + const auto stdio_locations = location::GetStdio(false); + for (const auto& e: stdio_locations) { + u32 flags{}; + if (e.write_protect) { + flags |= FsEntryFlag_ReadOnly; + } + + fs_entries.emplace_back(e.name, e.mount, FsType::Stdio, flags); + mount_items.push_back(e.name); + } + + for (const auto& e: FS_ENTRIES) { + fs_entries.emplace_back(e); + mount_items.push_back(i18n::get(e.name)); + } + + options->Add(std::make_shared("Mount"_i18n, mount_items, [this, fs_entries](s64& index_out){ + App::PopToMenu(); + SetFs(fs_entries[index_out].root, fs_entries[index_out]); + }, m_fs_entry.name)); + + options->Add(std::make_shared("Create File"_i18n, [this](){ + std::string out; + if (R_SUCCEEDED(swkbd::ShowText(out, "Set File Name"_i18n.c_str(), fs::AppendPath(m_path, ""))) && !out.empty()) { + App::PopToMenu(); + + fs::FsPath full_path; + if (out.starts_with(m_fs_entry.root.s)) { + full_path = out; + } else { + full_path = fs::AppendPath(m_path, out); + } + + m_fs->CreateDirectoryRecursivelyWithPath(full_path); + if (R_SUCCEEDED(m_fs->CreateFile(full_path, 0, 0))) { + log_write("created file: %s\n", full_path.s); + Scan(m_path); + } else { + log_write("failed to create file: %s\n", full_path.s); + } + } + })); + + options->Add(std::make_shared("Create Folder"_i18n, [this](){ + std::string out; + if (R_SUCCEEDED(swkbd::ShowText(out, "Set Folder Name"_i18n.c_str(), fs::AppendPath(m_path, ""))) && !out.empty()) { + App::PopToMenu(); + + fs::FsPath full_path; + if (out.starts_with(m_fs_entry.root.s)) { + full_path = out; + } else { + full_path = fs::AppendPath(m_path, out); + } + + if (R_SUCCEEDED(m_fs->CreateDirectoryRecursively(full_path))) { + log_write("created dir: %s\n", full_path.s); + Scan(m_path); + } else { + log_write("failed to create dir: %s\n", full_path.s); + } + } + })); + + if (IsSd() && m_entries_current.size() && !m_selected_count && GetEntry().IsFile() && GetEntry().file_size < 1024*64) { + options->Add(std::make_shared("View as text (unfinished)"_i18n, [this](){ + App::Push(std::make_shared(GetNewPathCurrent())); + })); + } + + if (m_entries_current.size()) { + options->Add(std::make_shared("Upload"_i18n, [this](){ + UploadFiles(); + })); + } + + if (m_entries_current.size() && !m_selected_count && GetEntry().IsFile()) { + options->Add(std::make_shared("Hash"_i18n, [this](){ + auto options = std::make_shared("Hash Options"_i18n, Sidebar::Side::RIGHT); + ON_SCOPE_EXIT(App::Push(options)); + + options->Add(std::make_shared("CRC32"_i18n, [this](){ + DisplayHash(hash::Type::Crc32); + })); + options->Add(std::make_shared("MD5"_i18n, [this](){ + DisplayHash(hash::Type::Md5); + })); + options->Add(std::make_shared("SHA1"_i18n, [this](){ + DisplayHash(hash::Type::Sha1); + })); + options->Add(std::make_shared("SHA256"_i18n, [this](){ + DisplayHash(hash::Type::Sha256); + })); + })); + } + + options->Add(std::make_shared("Ignore read only"_i18n, m_menu->m_ignore_read_only.Get(), [this](bool& v_out){ + m_menu->m_ignore_read_only.Set(v_out); + m_fs->SetIgnoreReadOnly(v_out); + })); +} + Menu::Menu(const std::vector& nro_entries) : MenuBase{"FileBrowser"_i18n}, m_nro_entries{nro_entries} { SetAction(Button::L3, Action{"Split"_i18n, [this](){ SetSplitScreen(IsSplitScreen() ^ 1);