diff --git a/Text/Files/ENUS.json b/Text/Files/ENUS.json index d4d5f02..b449ac6 100644 --- a/Text/Files/ENUS.json +++ b/Text/Files/ENUS.json @@ -138,6 +138,9 @@ "RemotePops": [ "0: No internet connection available!" ], + "SaveCreateConfs":[ + "This is a cache type save. Would you like to create it on the SD card instead of NAND?" + ], "SaveCreatePops": [ "0: Save data created for #%s#!", "1: Error creating save data!", diff --git a/include/appstates/ConfirmState.hpp b/include/appstates/ConfirmState.hpp index 12ca17c..553c3d3 100644 --- a/include/appstates/ConfirmState.hpp +++ b/include/appstates/ConfirmState.hpp @@ -39,7 +39,8 @@ class ConfirmState final : public BaseState /// @param dataStruct shared_ptr that is passed to function. I tried templating this and it was a nightmare. ConfirmState(std::string_view query, bool holdRequired, - sys::threadpool::JobFunction function, + sys::threadpool::JobFunction onConfirm, + sys::threadpool::JobFunction onCancel, sys::Task::TaskData taskData) : BaseState(false) , m_query(query) @@ -47,7 +48,8 @@ class ConfirmState final : public BaseState , m_noText(strings::get_by_name(strings::names::YES_NO_OK, 1)) , m_holdRequired(holdRequired) , m_transition(280, 229, 32, 32, 280, 229, 720, 256, 4) - , m_function(function) + , m_onConfirm(onConfirm) + , m_onCancel(onCancel) , m_taskData(taskData) { ConfirmState::initialize_static_members(); @@ -59,20 +61,22 @@ class ConfirmState final : public BaseState /// @brief Returns a new ConfirmState. See constructor. static inline std::shared_ptr create(std::string_view query, bool holdRequired, - sys::threadpool::JobFunction function, + sys::threadpool::JobFunction onConfirm, + sys::threadpool::JobFunction onCancel, sys::Task::TaskData taskData) { - return std::make_shared(query, holdRequired, function, taskData); + return std::make_shared(query, holdRequired, onConfirm, onCancel, taskData); } /// @brief Creates and returns a new ConfirmState and pushes it. static inline std::shared_ptr create_and_push(std::string_view query, bool holdRequired, - sys::threadpool::JobFunction function, + sys::threadpool::JobFunction onConfirm, + sys::threadpool::JobFunction onCancel, sys::Task::TaskData taskData) { // I'm gonna use a sneaky trick here. This shouldn't do this because it's confusing. - auto newState = create(query, holdRequired, function, taskData); + auto newState = create(query, holdRequired, onConfirm, onCancel, taskData); StateManager::push_state(newState); return newState; } @@ -80,10 +84,11 @@ class ConfirmState final : public BaseState /// @brief Same as above but with a fade transition pushed in between. static std::shared_ptr create_push_fade(std::string_view query, bool holdRequired, - sys::threadpool::JobFunction function, + sys::threadpool::JobFunction onConfirm, + sys::threadpool::JobFunction onCancel, sys::Task::TaskData taskData) { - auto newState = ConfirmState::create(query, holdRequired, function, taskData); + auto newState = ConfirmState::create(query, holdRequired, onConfirm, onCancel, taskData); FadeState::create_and_push(colors::DIM_BACKGROUND, colors::ALPHA_FADE_BEGIN, colors::ALPHA_FADE_END, newState); return newState; } @@ -167,7 +172,10 @@ class ConfirmState final : public BaseState bool m_close{}; /// @brief Function to execute if action is confirmed. - const sys::threadpool::JobFunction m_function{}; + const sys::threadpool::JobFunction m_onConfirm{}; + + /// @brief Function to execute if action is cancelled. + const sys::threadpool::JobFunction m_onCancel{}; /// @brief Pointer to data struct passed to ^ const sys::Task::TaskData m_taskData{}; @@ -235,8 +243,10 @@ class ConfirmState final : public BaseState void deactivate_state() { - if (m_confirmed) { StateType::create_and_push(m_function, m_taskData); } - else { + if (m_confirmed && m_onConfirm) { StateType::create_and_push(m_onConfirm, m_taskData); } + else if (!m_confirmed && m_onCancel) { StateType::create_and_push(m_onCancel, m_taskData); } + else + { FadeState::create_and_push(colors::DIM_BACKGROUND, colors::ALPHA_FADE_END, colors::ALPHA_FADE_BEGIN, nullptr); } BaseState::deactivate(); diff --git a/include/appstates/SaveCreateState.hpp b/include/appstates/SaveCreateState.hpp index bc87d0d..0bac497 100644 --- a/include/appstates/SaveCreateState.hpp +++ b/include/appstates/SaveCreateState.hpp @@ -45,6 +45,7 @@ class SaveCreateState final : public BaseState { data::User *user{}; data::TitleInfo *titleInfo{}; + uint16_t saveDataIndex{}; // This is only used for cache type saves. SaveCreateState *spawningState{}; }; // clang-format on diff --git a/include/appstates/TitleInfoState.hpp b/include/appstates/TitleInfoState.hpp index b167143..55b0aee 100644 --- a/include/appstates/TitleInfoState.hpp +++ b/include/appstates/TitleInfoState.hpp @@ -15,18 +15,22 @@ class TitleInfoState final : public BaseState /// @brief Constructs a new title info state. /// @param user User to display info for. /// @param titleInfo Title to display info for. - TitleInfoState(data::User *user, data::TitleInfo *titleInfo); + TitleInfoState(data::User *user, data::TitleInfo *titleInfo, const FsSaveDataInfo *saveInfo); /// @brief Creates a new TitleInfoState. - static inline std::shared_ptr create(data::User *user, data::TitleInfo *titleInfo) + static inline std::shared_ptr create(data::User *user, + data::TitleInfo *titleInfo, + const FsSaveDataInfo *saveInfo) { - return std::make_shared(user, titleInfo); + return std::make_shared(user, titleInfo, saveInfo); } /// @brief Creates, pushes, and returns a new TitleInfoState. - static inline std::shared_ptr create_and_push(data::User *user, data::TitleInfo *titleInfo) + static inline std::shared_ptr create_and_push(data::User *user, + data::TitleInfo *titleInfo, + const FsSaveDataInfo *saveInfo) { - auto newState = TitleInfoState::create(user, titleInfo); + auto newState = TitleInfoState::create(user, titleInfo, saveInfo); StateManager::push_state(newState); return newState; } @@ -44,6 +48,9 @@ class TitleInfoState final : public BaseState /// @brief Pointer to title info. data::TitleInfo *m_titleInfo{}; + /// @brief Save a pointer to the save info. + const FsSaveDataInfo *m_saveInfo{}; + /// @brief This is a pointer to the title's icon. sdl::SharedTexture m_icon{}; diff --git a/include/data/User.hpp b/include/data/User.hpp index 143036f..95b6665 100644 --- a/include/data/User.hpp +++ b/include/data/User.hpp @@ -52,7 +52,7 @@ namespace data /// @brief Pushes data to m_userData /// @param saveInfo SaveDataInfo. /// @param playStats Play statistics. - void add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats); + void add_data(uint64_t applicationID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats); /// @brief Clears the user save info vector. void clear_data_entries() noexcept; diff --git a/include/fs/save_data_functions.hpp b/include/fs/save_data_functions.hpp index 48086d1..68e341e 100644 --- a/include/fs/save_data_functions.hpp +++ b/include/fs/save_data_functions.hpp @@ -9,8 +9,13 @@ namespace fs /// @brief Creates save data for the target user for the title passed. /// @param targetUser User to create save data for. /// @param titleInfo Title to create save data for. + /// @param saveDataIndex Index. Only applicable to cache saves. + /// @param spaceID Save data space ID to create with. Default is 1/User. /// @return True on success. False on failure. - bool create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept; + bool create_save_data_for(data::User *targetUser, + data::TitleInfo *titleInfo, + uint16_t saveDataIndex = 0, + uint8_t spaceID = 1) noexcept; /// @brief Creates save data for the user passed using the meta data passed. bool create_save_data_for(data::User *targetUser, const fs::SaveMetaData &saveMeta) noexcept; diff --git a/include/strings/names.hpp b/include/strings/names.hpp index e502ec0..de91b5d 100644 --- a/include/strings/names.hpp +++ b/include/strings/names.hpp @@ -26,6 +26,7 @@ namespace strings::names inline constexpr std::string_view MAINMENU_POPS = "MainMenuPops"; inline constexpr std::string_view ON_OFF = "OnOff"; inline constexpr std::string_view REMOTE_POPS = "RemotePops"; + inline constexpr std::string_view SAVECREATE_CONFS = "SaveCreateConfs"; inline constexpr std::string_view SAVECREATE_POPS = "SaveCreatePops"; inline constexpr std::string_view SAVE_DATA_TYPES = "SaveDataTypes"; inline constexpr std::string_view SETTINGS_DESCRIPTIONS = "SettingsDescriptions"; diff --git a/include/tasks/savecreate.hpp b/include/tasks/savecreate.hpp index ad949b0..d843b24 100644 --- a/include/tasks/savecreate.hpp +++ b/include/tasks/savecreate.hpp @@ -5,5 +5,11 @@ namespace tasks::savecreate { + /// @brief Default save creating task. + /// @param taskData Data to pass to thread. void create_save_data_for(sys::threadpool::JobData taskData); + + /// @brief Same as above, but creates the save on the SD card instead. Only used for cache type saves. + /// @param taskData Data to pass to thread.kl;' + void create_save_data_for_sd(sys::threadpool::JobData taskData); } diff --git a/source/appstates/BackupMenuState.cpp b/source/appstates/BackupMenuState.cpp index 54228ea..2eba56f 100644 --- a/source/appstates/BackupMenuState.cpp +++ b/source/appstates/BackupMenuState.cpp @@ -264,7 +264,7 @@ void BackupMenuState::confirm_overwrite() const char *itemName = m_dataStruct->remoteItem->get_name().data(); const std::string query = stringutil::get_formatted_string(confirmTemplate, itemName); - ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_remote, nullptr, m_dataStruct); } else if (entry.type == MenuEntryType::Local) { @@ -272,7 +272,7 @@ void BackupMenuState::confirm_overwrite() const char *targetName = m_directoryListing[entry.index].get_filename(); const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName); - ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_local, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_local, nullptr, m_dataStruct); } } @@ -312,7 +312,7 @@ void BackupMenuState::confirm_restore() const char *targetName = m_directoryListing[entry.index].get_filename(); const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName); - ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, nullptr, m_dataStruct); } else if (entry.type == MenuEntryType::Remote) { @@ -321,7 +321,7 @@ void BackupMenuState::confirm_restore() m_dataStruct->remoteItem = target; m_dataStruct->path = m_directoryPath + "//"; // To-do: This is a workaround. - ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, nullptr, m_dataStruct); } } @@ -338,7 +338,7 @@ void BackupMenuState::confirm_delete() const char *targetName = m_directoryListing[entry.index].get_filename(); const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName); - ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_local, m_dataStruct); + ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_local, nullptr, m_dataStruct); } else if (entry.type == MenuEntryType::Remote) { @@ -346,7 +346,7 @@ void BackupMenuState::confirm_delete() const char *itemName = m_dataStruct->remoteItem->get_name().data(); const std::string query = stringutil::get_formatted_string(confirmTemplate, itemName); - ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_remote, m_dataStruct); + ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_remote, nullptr, m_dataStruct); } } @@ -380,7 +380,7 @@ void BackupMenuState::upload_backup() const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE); m_dataStruct->remoteItem = remoteItem; - ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::patch_backup, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::patch_backup, nullptr, m_dataStruct); } else { ProgressState::create_push_fade(tasks::backup::upload_backup, m_dataStruct); } } diff --git a/source/appstates/FileModeState.cpp b/source/appstates/FileModeState.cpp index afcb4e5..6f09034 100644 --- a/source/appstates/FileModeState.cpp +++ b/source/appstates/FileModeState.cpp @@ -15,7 +15,7 @@ FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, i : m_mountA(mountA) , m_mountB(mountB) , m_journalSize(journalSize) - , m_transition(15, 720, 0, 0, 15, 87, 0, 0, ui::Transition::DEFAULT_THRESHOLD) + , m_transition(15, 720, 0, 0, 15, 89, 0, 0, ui::Transition::DEFAULT_THRESHOLD) , m_isSystem(isSystem) , m_allowSystem(config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM)) { @@ -91,11 +91,8 @@ void FileModeState::initialize_static_members() void FileModeState::initialize_paths() { - const std::string pathA = m_mountA + ":/"; - const std::string pathB = m_mountB + ":/"; - - m_pathA = pathA; - m_pathB = pathB; + m_pathA = m_mountA + ":/"; + m_pathB = m_mountB + ":/"; } void FileModeState::initialize_menus() @@ -133,6 +130,7 @@ void FileModeState::initialize_directory_menu(const fslib::Path &path, fslib::Di void FileModeState::hide_dialog() noexcept { if (!m_transition.in_place()) { return; } + sm_controlGuide->reset(); m_transition.set_target_y(720); m_close = true; } @@ -205,7 +203,6 @@ fslib::Directory &FileModeState::get_destination_directory() noexcept { return m void FileModeState::deactivate_state() noexcept { sm_frame->set_y(720); - sm_controlGuide->reset(); fslib::close_file_system(m_mountA); fslib::close_file_system(m_mountB); BaseState::deactivate(); diff --git a/source/appstates/FileOptionState.cpp b/source/appstates/FileOptionState.cpp index e0c97ec..f1cd0dc 100644 --- a/source/appstates/FileOptionState.cpp +++ b/source/appstates/FileOptionState.cpp @@ -214,7 +214,7 @@ void FileOptionState::copy_target() const char *copyFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 0); const std::string query = stringutil::get_formatted_string(copyFormat, sourceString.c_str(), destString.c_str()); - ConfirmProgress::create_push_fade(query, false, tasks::fileoptions::copy_source_to_destination, m_dataStruct); + ConfirmProgress::create_push_fade(query, false, tasks::fileoptions::copy_source_to_destination, nullptr, m_dataStruct); } void FileOptionState::delete_target() @@ -245,7 +245,7 @@ void FileOptionState::delete_target() m_dataStruct->sourcePath = std::move(fullTarget); m_dataStruct->journalSize = m_spawningState->m_journalSize; - ConfirmTask::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, m_dataStruct); + ConfirmTask::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, nullptr, m_dataStruct); } void FileOptionState::rename_target() diff --git a/source/appstates/MainMenuState.cpp b/source/appstates/MainMenuState.cpp index 84a041d..1104e9b 100644 --- a/source/appstates/MainMenuState.cpp +++ b/source/appstates/MainMenuState.cpp @@ -177,9 +177,9 @@ void MainMenuState::backup_all_for_all() const char *query = strings::get_by_name(strings::names::MAINMENU_CONFS, 0); if (remote && autoUpload) { - ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_remote, nullptr, m_dataStruct); } - else { ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_local, m_dataStruct); } + else { ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_local, nullptr, m_dataStruct); } } void MainMenuState::confirm_update() @@ -187,5 +187,5 @@ void MainMenuState::confirm_update() const char *confirmUpdate = strings::get_by_name(strings::names::UPDATE_CONFIRMATION, 0); auto taskData = std::make_shared(); - ConfirmProgress::create_push_fade(confirmUpdate, false, tasks::update::download_update, taskData); + ConfirmProgress::create_push_fade(confirmUpdate, false, tasks::update::download_update, nullptr, taskData); } diff --git a/source/appstates/SaveCreateState.cpp b/source/appstates/SaveCreateState.cpp index 0fe0313..ab3cebe 100644 --- a/source/appstates/SaveCreateState.cpp +++ b/source/appstates/SaveCreateState.cpp @@ -1,11 +1,12 @@ #include "appstates/SaveCreateState.hpp" #include "StateManager.hpp" -#include "appstates/TaskState.hpp" +#include "appstates/ConfirmState.hpp" #include "data/data.hpp" #include "error.hpp" #include "fs/fs.hpp" #include "input.hpp" +#include "keyboard.hpp" #include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" @@ -97,11 +98,29 @@ void SaveCreateState::initialize_data_struct() void SaveCreateState::create_save_data_for() { + static constexpr std::string_view DEFAULT_INDEX = "0"; + + char cacheIndex[3] = {0}; const int selected = m_saveMenu->get_selected(); data::TitleInfo *titleInfo = m_titleInfoVector[selected]; m_dataStruct->titleInfo = titleInfo; - TaskState::create_and_push(tasks::savecreate::create_save_data_for, m_dataStruct); + const char *keyboardString = strings::get_by_name(strings::names::KEYBOARD, 1); + const bool isCache = m_user->get_account_save_type() == FsSaveDataType_Cache; + const bool indexInput = isCache && keyboard::get_input(SwkbdType_QWERTY, DEFAULT_INDEX, keyboardString, cacheIndex, 3); + if (isCache && !indexInput) { return; } + else if (isCache && indexInput) { m_dataStruct->saveDataIndex = std::strtoul(cacheIndex, nullptr, 10); } + + if (!isCache) { TaskState::create_and_push(tasks::savecreate::create_save_data_for, m_dataStruct); } + else + { + const char *confirmString = strings::get_by_name(strings::names::SAVECREATE_CONFS, 0); + ConfirmTask::create_push_fade(confirmString, + false, + tasks::savecreate::create_save_data_for_sd, + tasks::savecreate::create_save_data_for, + m_dataStruct); + } } void SaveCreateState::deactivate_state() diff --git a/source/appstates/SaveImportState.cpp b/source/appstates/SaveImportState.cpp index da2d495..5d009de 100644 --- a/source/appstates/SaveImportState.cpp +++ b/source/appstates/SaveImportState.cpp @@ -76,7 +76,7 @@ void SaveImportState::import_backup() const char *confirmFormat = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 1); std::string query = stringutil::get_formatted_string(confirmFormat, targetName); - ConfirmProgress::create_and_push(query, holdRequired, tasks::saveimport::import_save_backup, sm_taskData); + ConfirmProgress::create_and_push(query, holdRequired, tasks::saveimport::import_save_backup, nullptr, sm_taskData); } void SaveImportState::deactivate_state() diff --git a/source/appstates/TitleInfoState.cpp b/source/appstates/TitleInfoState.cpp index 7d7bdb0..556bd8c 100644 --- a/source/appstates/TitleInfoState.cpp +++ b/source/appstates/TitleInfoState.cpp @@ -25,9 +25,10 @@ namespace constexpr int SIZE_TEXT_TARGET_HEIGHT = 40; } // namespace -TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo) +TitleInfoState::TitleInfoState(data::User *user, data::TitleInfo *titleInfo, const FsSaveDataInfo *saveInfo) : m_user(user) , m_titleInfo(titleInfo) + , m_saveInfo(saveInfo) , m_icon(m_titleInfo->get_icon()) { TitleInfoState::initialize_static_members(); @@ -71,7 +72,7 @@ void TitleInfoState::create_info_scrolls() static constexpr int COORD_INIT_Y = 278; const uint64_t applicationID = m_titleInfo->get_application_id(); - const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID); + const FsSaveDataInfo *saveInfo = m_saveInfo; const PdmPlayStatistics *playStats = m_user->get_play_stats_by_id(applicationID); if (error::is_null(saveInfo) || error::is_null(playStats)) { return; } diff --git a/source/appstates/TitleOptionState.cpp b/source/appstates/TitleOptionState.cpp index d070e8b..19cb5f0 100644 --- a/source/appstates/TitleOptionState.cpp +++ b/source/appstates/TitleOptionState.cpp @@ -136,8 +136,8 @@ void TitleOptionState::initialize_data_struct() void TitleOptionState::create_push_info_state() { sm_slidePanel->hide(); - auto titleInfoState = TitleInfoState::create(m_user, m_titleInfo); - StateManager::push_state(titleInfoState); + + TitleInfoState::create_and_push(m_user, m_titleInfo, m_saveInfo); } void TitleOptionState::add_to_blacklist() @@ -146,7 +146,7 @@ void TitleOptionState::add_to_blacklist() const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 0); const std::string query = stringutil::get_formatted_string(confirmFormat, title); - ConfirmTask::create_push_fade(query, false, tasks::titleoptions::blacklist_title, m_dataStruct); + ConfirmTask::create_push_fade(query, false, tasks::titleoptions::blacklist_title, nullptr, m_dataStruct); } void TitleOptionState::change_output_directory() @@ -201,23 +201,18 @@ void TitleOptionState::change_output_directory() void TitleOptionState::create_push_file_mode() { - const uint64_t applicationID = m_titleInfo->get_application_id(); - const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID); - const data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID); - if (error::is_null(saveInfo)) { return; } - - const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo); + const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *m_saveInfo); if (!saveOpened) { return; } const FsSaveDataType saveType = m_user->get_account_save_type(); const bool isSystem = saveType == FsSaveDataType_System || saveType == FsSaveDataType_SystemBcat; FsSaveDataExtraData extraData{}; - const bool readExtra = fs::read_save_extra_data(saveInfo, extraData); - const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType); + const bool readExtra = fs::read_save_extra_data(m_saveInfo, extraData); + const int64_t journalSize = readExtra ? extraData.journal_size : m_titleInfo->get_journal_size(saveType); - sm_slidePanel->hide(); FileModeState::create_and_push(fs::DEFAULT_SAVE_MOUNT, "sdmc", journalSize, isSystem); + sm_slidePanel->hide(); } void TitleOptionState::delete_all_local_backups() @@ -226,7 +221,7 @@ void TitleOptionState::delete_all_local_backups() const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 1); const std::string query = stringutil::get_formatted_string(confirmFormat, title); - ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_local_backups_for_title, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_local_backups_for_title, nullptr, m_dataStruct); } void TitleOptionState::delete_all_remote_backups() @@ -235,18 +230,14 @@ void TitleOptionState::delete_all_remote_backups() const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 1); const std::string query = stringutil::get_formatted_string(confirmFormat, title); - ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_remote_backups_for_title, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_all_remote_backups_for_title, nullptr, m_dataStruct); } void TitleOptionState::reset_save_data() { - const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - const uint64_t applicationID = m_titleInfo->get_application_id(); - const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID); - if (error::is_null(saveInfo)) { return; } - + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const bool allowSystemWriting = config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM); - if (!allowSystemWriting && fs::is_system_save_data(saveInfo)) + if (!allowSystemWriting && fs::is_system_save_data(m_saveInfo)) { const char *popNoSysWrite = strings::get_by_name(strings::names::TITLEOPTION_POPS, 6); ui::PopMessageManager::push_message(popTicks, popNoSysWrite); @@ -257,18 +248,15 @@ void TitleOptionState::reset_save_data() const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 2); const std::string query = stringutil::get_formatted_string(confirmFormat, title); - ConfirmTask::create_push_fade(query, true, tasks::titleoptions::reset_save_data, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::titleoptions::reset_save_data, nullptr, m_dataStruct); } void TitleOptionState::delete_save_from_system() { - const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - const uint64_t applicationID = m_titleInfo->get_application_id(); - const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID); - if (error::is_null(saveInfo)) { return; } + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; // This isn't allowed at ALL. - if (fs::is_system_save_data(saveInfo)) + if (fs::is_system_save_data(m_saveInfo)) { const char *popUnavailable = strings::get_by_name(strings::names::TITLEOPTION_POPS, 6); ui::PopMessageManager::push_message(popTicks, popUnavailable); @@ -280,17 +268,14 @@ void TitleOptionState::delete_save_from_system() const char *confirmFormat = strings::get_by_name(strings::names::TITLEOPTION_CONFS, 3); const std::string query = stringutil::get_formatted_string(confirmFormat, nickname, title); - ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_save_data_from_system, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_save_data_from_system, nullptr, m_dataStruct); } void TitleOptionState::extend_save_container() { - const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - const uint64_t applicationID = m_titleInfo->get_application_id(); - const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID); - if (error::is_null(saveInfo)) { return; } + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - if (fs::is_system_save_data(saveInfo)) + if (fs::is_system_save_data(m_saveInfo)) { const char *popUnavailable = strings::get_by_name(strings::names::TITLEOPTION_POPS, 6); ui::PopMessageManager::push_message(popTicks, popUnavailable); diff --git a/source/appstates/UserOptionState.cpp b/source/appstates/UserOptionState.cpp index 58745cc..666a122 100644 --- a/source/appstates/UserOptionState.cpp +++ b/source/appstates/UserOptionState.cpp @@ -127,9 +127,12 @@ void UserOptionState::backup_all() const std::string query = stringutil::get_formatted_string(confirmFormat, nickname); if (remote && autoUpload) { - ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_remote, nullptr, m_dataStruct); + } + else + { + ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_local, nullptr, m_dataStruct); } - else { ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_local, m_dataStruct); } } void UserOptionState::create_save_create() @@ -148,7 +151,7 @@ void UserOptionState::create_all_save_data() const char *nickname = m_user->get_nickname(); const std::string query = stringutil::get_formatted_string(confirmFormat, nickname); - ConfirmTask::create_push_fade(query, true, tasks::useroptions::create_all_save_data_for_user, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::useroptions::create_all_save_data_for_user, nullptr, m_dataStruct); } void UserOptionState::delete_all_save_data() @@ -159,7 +162,7 @@ void UserOptionState::delete_all_save_data() const char *confirmFormat = strings::get_by_name(strings::names::USEROPTION_CONFS, 2); const char *nickname = m_user->get_nickname(); const std::string queryString = stringutil::get_formatted_string(confirmFormat, nickname); - ConfirmTask::create_push_fade(queryString, true, tasks::useroptions::delete_all_save_data_for_user, m_dataStruct); + ConfirmTask::create_push_fade(queryString, true, tasks::useroptions::delete_all_save_data_for_user, nullptr, m_dataStruct); } void UserOptionState::create_push_save_import() diff --git a/source/data/User.cpp b/source/data/User.cpp index 263ac34..08b7a66 100644 --- a/source/data/User.cpp +++ b/source/data/User.cpp @@ -19,7 +19,7 @@ namespace constexpr int SIZE_ICON_FONT = 50; /// @brief This is the number of FsSaveDataInfo entries to allocate and try to read. - constexpr size_t SIZE_SAVE_INFO_BUFFER = 256; + constexpr size_t SIZE_SAVE_INFO_BUFFER = 128; // Array of SaveDataSpaceIDs - SaveDataSpaceAll doesn't seem to work as it should... constexpr std::array SAVE_DATA_SPACE_ORDER = {FsSaveDataSpaceId_System, @@ -78,13 +78,9 @@ data::User &data::User::operator=(data::User &&user) noexcept return *this; } -void data::User::add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats) +void data::User::add_data(uint64_t applicationID, const FsSaveDataInfo &saveInfo, const PdmPlayStatistics &playStats) { - const uint64_t saveInfoAppID = saveInfo->application_id; - const uint64_t saveInfoSysID = saveInfo->system_save_data_id; - const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID; - - auto dataPair = std::make_pair(*saveInfo, *playStats); + auto dataPair = std::make_pair(saveInfo, playStats); auto vectorPair = std::make_pair(applicationID, std::move(dataPair)); m_userData.push_back(std::move(vectorPair)); } @@ -180,9 +176,10 @@ void data::User::load_user_data() bool mounted{}; if (!isBlacklisted && !systemFilter && enforceMount) { - fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, &saveInfo, false}; + fs::ScopedSaveMount saveMount{fs::DEFAULT_SAVE_MOUNT, &saveInfo}; mounted = saveMount.is_open(); } + if (isBlacklisted || systemFilter || (enforceMount && !mounted)) { continue; } const bool titleFound = data::title_exists_in_map(applicationID); @@ -194,10 +191,12 @@ void data::User::load_user_data() m_accountID, false, &playStats); - User::add_data(&saveInfo, &playStats); + + User::add_data(applicationID, saveInfo, playStats); } } } + User::sort_data(); } diff --git a/source/fs/save_data_functions.cpp b/source/fs/save_data_functions.cpp index dc1a720..a255a98 100644 --- a/source/fs/save_data_functions.cpp +++ b/source/fs/save_data_functions.cpp @@ -8,7 +8,10 @@ namespace inline constexpr FsSaveDataMetaInfo SAVE_CREATE_META = {.size = 0x40060, .type = FsSaveDataMetaType_Thumbnail}; } -bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo) noexcept +bool fs::create_save_data_for(data::User *targetUser, + data::TitleInfo *titleInfo, + uint16_t saveDataIndex, + uint8_t spaceID) noexcept { const uint8_t saveType = targetUser->get_account_save_type(); @@ -23,14 +26,14 @@ bool fs::create_save_data_for(data::User *targetUser, data::TitleInfo *titleInfo .system_save_data_id = 0, .save_data_type = saveType, .save_data_rank = FsSaveDataRank_Primary, - .save_data_index = 0}; + .save_data_index = saveDataIndex}; const FsSaveDataCreationInfo saveCreation = {.save_data_size = saveSize, .journal_size = journalSize, .available_size = 0x4000, .owner_id = ownerID, .flags = 0, - .save_data_space_id = FsSaveDataSpaceId_User}; + .save_data_space_id = spaceID}; // I want this recorded. return error::libnx(fsCreateSaveDataFileSystem(&saveAttributes, &saveCreation, &SAVE_CREATE_META)) == false; diff --git a/source/tasks/savecreate.cpp b/source/tasks/savecreate.cpp index 89b870a..9523e80 100644 --- a/source/tasks/savecreate.cpp +++ b/source/tasks/savecreate.cpp @@ -15,6 +15,9 @@ void tasks::savecreate::create_save_data_for(sys::threadpool::JobData taskData) data::TitleInfo *titleInfo = castData->titleInfo; SaveCreateState *spawningState = castData->spawningState; + const bool isCache = user->get_account_save_type() == FsSaveDataType_Cache; + const uint16_t saveIndex = isCache ? castData->saveDataIndex : 0; + if (error::is_null(task)) { return; } else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } @@ -29,7 +32,7 @@ void tasks::savecreate::create_save_data_for(sys::threadpool::JobData taskData) task->set_status(status); } - const bool saveCreated = fs::create_save_data_for(user, titleInfo); + const bool saveCreated = fs::create_save_data_for(user, titleInfo, saveIndex); if (!saveCreated) { ui::PopMessageManager::push_message(popTicks, popFailed); } else { @@ -40,3 +43,41 @@ void tasks::savecreate::create_save_data_for(sys::threadpool::JobData taskData) task->complete(); } + +void tasks::savecreate::create_save_data_for_sd(sys::threadpool::JobData taskData) +{ + auto castData = std::static_pointer_cast(taskData); + + sys::Task *task = castData->task; + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + SaveCreateState *spawningState = castData->spawningState; + + bool isCache = user->get_account_save_type() == FsSaveDataType_Cache; + const uint16_t saveIndex = isCache ? castData->saveDataIndex : 0; + + if (error::is_null(task)) { return; } + else if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } + + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; + const char *statusFormat = strings::get_by_name(strings::names::USEROPTION_STATUS, 0); + const char *popSuccess = strings::get_by_name(strings::names::SAVECREATE_POPS, 0); + const char *popFailed = strings::get_by_name(strings::names::SAVECREATE_POPS, 1); + const char *title = titleInfo->get_title(); + + { + std::string status = stringutil::get_formatted_string(statusFormat, title); + task->set_status(status); + } + + const bool saveCreated = fs::create_save_data_for(user, titleInfo, saveIndex, 4); + if (!saveCreated) { ui::PopMessageManager::push_message(popTicks, popFailed); } + else + { + std::string popMessage = stringutil::get_formatted_string(popSuccess, title); + ui::PopMessageManager::push_message(popTicks, popMessage); + spawningState->refresh_required(); + } + + task->complete(); +} \ No newline at end of file diff --git a/source/ui/Menu.cpp b/source/ui/Menu.cpp index 5ae5e9c..3796034 100644 --- a/source/ui/Menu.cpp +++ b/source/ui/Menu.cpp @@ -104,7 +104,8 @@ void ui::Menu::reset(bool full) if (full) { m_selected = 0; - m_y = m_originalY; + m_transition.set_y(m_originalY); + m_transition.set_target_y(m_originalY); } m_options.clear();