From 3c54474e5b48d864a217a805d4f3a9e9f48aa78b Mon Sep 17 00:00:00 2001 From: J-D-K Date: Tue, 16 Sep 2025 17:59:33 -0400 Subject: [PATCH] Thread pooled & fslib update. --- Libraries/FsLib | 2 +- include/appstates/BackupMenuState.hpp | 5 +- include/appstates/ConfirmState.hpp | 42 ++--- include/appstates/DataLoadingState.hpp | 26 +-- include/appstates/FileOptionState.hpp | 6 +- include/appstates/MainMenuState.hpp | 6 +- include/appstates/ProgressState.hpp | 25 +-- include/appstates/SaveCreateState.hpp | 15 ++ include/appstates/TaskState.hpp | 29 ++-- include/appstates/TitleOptionState.hpp | 4 +- include/appstates/UserOptionState.hpp | 4 +- include/curl/DownloadStruct.hpp | 23 ++- include/curl/curl.hpp | 2 +- include/sys/ProgressTask.hpp | 18 +-- include/sys/Task.hpp | 32 ++-- include/tasks/backup.hpp | 30 ++-- include/tasks/fileoptions.hpp | 4 +- include/tasks/mainmenu.hpp | 4 +- include/tasks/savecreate.hpp | 2 +- include/tasks/titleoptions.hpp | 12 +- include/tasks/useroptions.hpp | 8 +- include/ui/Menu.hpp | 7 +- include/ui/PopMessage.hpp | 3 + include/ui/PopMessageManager.hpp | 3 + source/JKSV.cpp | 3 +- source/appstates/BackupMenuState.cpp | 38 ++--- source/appstates/BlacklistEditState.cpp | 2 +- source/appstates/DataLoadingState.cpp | 12 ++ source/appstates/ExtrasMenuState.cpp | 2 +- source/appstates/FileModeState.cpp | 4 +- source/appstates/FileOptionState.cpp | 14 +- source/appstates/MainMenuState.cpp | 13 +- source/appstates/ProgressState.cpp | 8 + source/appstates/SaveCreateState.cpp | 14 +- source/appstates/SettingsState.cpp | 12 +- source/appstates/TaskState.cpp | 7 +- source/appstates/TextTitleSelectState.cpp | 6 +- source/appstates/TitleOptionState.cpp | 15 +- source/appstates/UserOptionState.cpp | 12 +- source/config/ConfigContext.cpp | 4 - source/config/config.cpp | 3 - source/curl/curl.cpp | 48 +++--- source/data/DataContext.cpp | 19 +-- source/data/data.cpp | 21 ++- source/fs/io.cpp | 10 +- source/fs/zip.cpp | 4 +- source/logging/logger.cpp | 2 +- source/remote/GoogleDrive.cpp | 13 +- source/remote/WebDav.cpp | 14 +- source/remote/remote.cpp | 24 ++- source/stringutil.cpp | 2 +- source/sys/ProgressTask.cpp | 9 ++ source/sys/Task.cpp | 16 +- source/sys/threadpool.cpp | 4 +- source/tasks/backup.cpp | 186 ++++++++++++++-------- source/tasks/fileoptions.cpp | 44 ++--- source/tasks/mainmenu.cpp | 39 +++-- source/tasks/savecreate.cpp | 16 +- source/tasks/titleoptions.cpp | 86 +++++----- source/tasks/useroptions.cpp | 70 +++++--- source/ui/Menu.cpp | 18 ++- source/ui/PopMessage.cpp | 11 ++ source/ui/PopMessageManager.cpp | 23 +++ 63 files changed, 694 insertions(+), 466 deletions(-) diff --git a/Libraries/FsLib b/Libraries/FsLib index 995054e..382c7d4 160000 --- a/Libraries/FsLib +++ b/Libraries/FsLib @@ -1 +1 @@ -Subproject commit 995054e0d28ca9d4bf5134b10493ecebb51a7ab9 +Subproject commit 382c7d490a68e4897fdc7d1ba37ac6e49cd6ac0e diff --git a/include/appstates/BackupMenuState.hpp b/include/appstates/BackupMenuState.hpp index f8c3114..c40dfee 100644 --- a/include/appstates/BackupMenuState.hpp +++ b/include/appstates/BackupMenuState.hpp @@ -61,17 +61,18 @@ class BackupMenuState final : public BaseState int index{}; }; - struct DataStruct + struct DataStruct : sys::Task::DataStruct { data::User *user{}; data::TitleInfo *titleInfo{}; fslib::Path path{}; // This and + std::string remoteName{}; // and this and remote::Item *remoteItem{}; // this are set when needed. BackupMenuState *spawningState{}; + bool killTask = false; // Some tasks use other tasks instead of repeating code. }; // clang-format on - // This makes some things elsewhere easier to type. using TaskData = std::shared_ptr; private: diff --git a/include/appstates/ConfirmState.hpp b/include/appstates/ConfirmState.hpp index 7b90bf8..607b5d4 100644 --- a/include/appstates/ConfirmState.hpp +++ b/include/appstates/ConfirmState.hpp @@ -28,27 +28,26 @@ namespace /// @tparam TaskType The type of task spawned on confirmation. Ex: Task, ProgressTask /// @tparam StateType The state type spawned on confirmation. Ex: TaskState, ProgressState /// @tparam StructType The type of struct passed to the state on confirmation. -template +template class ConfirmState final : public BaseState { public: - /// @brief All functions passed to this state need to follow this signature: void function( *, - /// std::shared_ptr<>) - using TaskFunction = void (*)(TaskType *, std::shared_ptr); - /// @brief Constructor for new ConfirmState. /// @param query The string displayed. /// @param holdRequired Whether or not confirmation requires holding A for three seconds. /// @param function Function executed on confirmation. /// @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, TaskFunction function, std::shared_ptr dataStruct) + ConfirmState(std::string_view query, + bool holdRequired, + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) : BaseState(false) , m_query(query) , m_yesText(strings::get_by_name(strings::names::YES_NO_OK, 0)) , m_noText(strings::get_by_name(strings::names::YES_NO_OK, 1)) , m_holdRequired(holdRequired) , m_function(function) - , m_dataStruct(dataStruct) + , m_taskData(taskData) { ConfirmState::initialize_static_members(); ConfirmState::center_no(); @@ -59,20 +58,20 @@ class ConfirmState final : public BaseState /// @brief Returns a new ConfirmState. See constructor. static inline std::shared_ptr create(std::string_view query, bool holdRequired, - TaskFunction function, - std::shared_ptr dataStruct) + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) { - return std::make_shared(query, holdRequired, function, dataStruct); + return std::make_shared(query, holdRequired, function, 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, - TaskFunction function, - std::shared_ptr dataStruct) + sys::threadpool::JobFunction function, + 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, dataStruct); + auto newState = create(query, holdRequired, function, taskData); StateManager::push_state(newState); return newState; } @@ -80,10 +79,10 @@ 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, - TaskFunction function, - std::shared_ptr dataStruct) + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) { - auto newState = ConfirmState::create(query, holdRequired, function, dataStruct); + auto newState = ConfirmState::create(query, holdRequired, function, taskData); FadeState::create_and_push(colors::DIM_BACKGROUND, 0x00, 0x88, newState); return newState; } @@ -151,10 +150,10 @@ class ConfirmState final : public BaseState int m_stage{}; /// @brief Function to execute if action is confirmed. - const TaskFunction m_function{}; + const sys::threadpool::JobFunction m_function{}; /// @brief Pointer to data struct passed to ^ - const std::shared_ptr m_dataStruct{}; + const sys::Task::TaskData m_taskData{}; static inline std::shared_ptr sm_dialog{}; @@ -188,8 +187,8 @@ class ConfirmState final : public BaseState void confirmed() { - auto newState = std::make_shared(m_function, m_dataStruct); - StateManager::push_state(newState); + // auto newState = std::make_shared(m_function, m_taskData); + auto newState = StateType::create_and_push(m_function, m_taskData); BaseState::deactivate(); } @@ -229,3 +228,6 @@ class ConfirmState final : public BaseState ConfirmState::center_yes(); } }; + +using ConfirmTask = ConfirmState; +using ConfirmProgress = ConfirmState; \ No newline at end of file diff --git a/include/appstates/DataLoadingState.hpp b/include/appstates/DataLoadingState.hpp index e685c17..e7d6857 100644 --- a/include/appstates/DataLoadingState.hpp +++ b/include/appstates/DataLoadingState.hpp @@ -14,35 +14,25 @@ class DataLoadingState final : public BaseTask /// @brief This is a definition for functions that are called at destruction. using DestructFunction = std::function; - template DataLoadingState(data::DataContext &context, DestructFunction destructFunction, - void (*function)(sys::Task *, Args...), - Args... args) - : BaseTask() - , m_context(context) - , m_destructFunction(destructFunction) - { - DataLoadingState::initialize_static_members(); - m_task = std::make_unique(function, std::forward(args)...); - } + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData); - template static inline std::shared_ptr create(data::DataContext &context, DestructFunction destructFunction, - void (*function)(sys::Task *, Args...), - Args... args) + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) { - return std::make_shared(context, destructFunction, function, std::forward(args)...); + return std::make_shared(context, destructFunction, function, taskData); } - template static inline std::shared_ptr create_and_push(data::DataContext &context, DestructFunction destructFunction, - void (*function)(sys::Task *, Args...), - Args... args) + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) { - auto newState = DataLoadingState::create(context, destructFunction, function, std::forward(args)...); + auto newState = DataLoadingState::create(context, destructFunction, function, taskData); StateManager::push_state(newState); return newState; } diff --git a/include/appstates/FileOptionState.hpp b/include/appstates/FileOptionState.hpp index fd3fede..8871c2b 100644 --- a/include/appstates/FileOptionState.hpp +++ b/include/appstates/FileOptionState.hpp @@ -3,6 +3,7 @@ #include "appstates/BaseState.hpp" #include "appstates/FileModeState.hpp" #include "fslib.hpp" +#include "sys/sys.hpp" #include "ui/ui.hpp" #include @@ -41,7 +42,7 @@ class FileOptionState final : public BaseState void update_destination(); // clang-format off - struct DataStruct + struct DataStruct : sys::Task::DataStruct { fslib::Path sourcePath{}; fslib::Path destPath{}; @@ -50,9 +51,6 @@ class FileOptionState final : public BaseState }; // clang-format on - /// @brief This makes some other stuff easier to read and type. - using TaskData = std::shared_ptr; - private: /// @brief Pointer to spawning FileMode state. FileModeState *m_spawningState{}; diff --git a/include/appstates/MainMenuState.hpp b/include/appstates/MainMenuState.hpp index b1b82b7..40271ab 100644 --- a/include/appstates/MainMenuState.hpp +++ b/include/appstates/MainMenuState.hpp @@ -42,14 +42,12 @@ class MainMenuState final : public BaseState static void refresh_view_states(); // clang-format off - struct DataStruct + struct DataStruct : sys::Task::DataStruct { data::UserList userList; }; // clang-format on - using TaskData = std::shared_ptr; - private: /// @brief Render target this state renders to. sdl::SharedTexture m_renderTarget{}; @@ -70,7 +68,7 @@ class MainMenuState final : public BaseState std::shared_ptr m_controlGuide{}; /// @brief This is the data struct passed to tasks. - MainMenuState::TaskData m_dataStruct{}; + std::shared_ptr m_dataStruct{}; /// @brief Records the size of the sm_users vector. static inline int sm_userCount{}; diff --git a/include/appstates/ProgressState.hpp b/include/appstates/ProgressState.hpp index 9b922fa..5f42a2d 100644 --- a/include/appstates/ProgressState.hpp +++ b/include/appstates/ProgressState.hpp @@ -14,30 +14,19 @@ class ProgressState final : public BaseTask { public: /// @brief Constructs a new ProgressState. - /// @param function Function for the task to run. - /// @param args Variadic arguments to be forwarded to the function passed. - /// @note All functions passed to this must follow this signature: void function(sys::ProgressTask *, ) - template - ProgressState(void (*function)(sys::ProgressTask *, Args...), Args... args) - : BaseTask() - { - ProgressState::initialize_static_members(); - m_task = std::make_unique(function, std::forward(args)...); - } + ProgressState(sys::threadpool::JobFunction function, sys::Task::TaskData taskData); - /// @brief Creates and returns a new progress state. - template - static inline std::shared_ptr create(void (*function)(sys::ProgressTask *, Args...), Args... args) + /// @brief Creates and returns a new ProgressState + static inline std::shared_ptr create(sys::threadpool::JobFunction function, sys::Task::TaskData taskData) { - return std::make_shared(function, std::forward(args)...); + return std::make_shared(function, taskData); } /// @brief Creates, pushes, then returns a new ProgressState. - template - static inline std::shared_ptr create_and_push(void (*function)(sys::ProgressTask *, Args...), - Args... args) + static inline std::shared_ptr create_and_push(sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) { - auto newState = ProgressState::create(function, std::forward(args)...); + auto newState = ProgressState::create(function, taskData); StateManager::push_state(newState); return newState; } diff --git a/include/appstates/SaveCreateState.hpp b/include/appstates/SaveCreateState.hpp index c40c744..bc87d0d 100644 --- a/include/appstates/SaveCreateState.hpp +++ b/include/appstates/SaveCreateState.hpp @@ -40,6 +40,15 @@ class SaveCreateState final : public BaseState /// @brief This signals so data and the view can be refreshed on the next update() to avoid threading shenanigans. void refresh_required(); + // clang-format off + struct DataStruct : sys::Task::DataStruct + { + data::User *user{}; + data::TitleInfo *titleInfo{}; + SaveCreateState *spawningState{}; + }; + // clang-format on + private: /// @brief Pointer to target user. data::User *m_user{}; @@ -56,6 +65,9 @@ class SaveCreateState final : public BaseState /// @brief Whether or not a refresh is required on the next update() call. std::atomic m_refreshRequired{}; + /// @brief Data struct passed to the task. + std::shared_ptr m_dataStruct{}; + /// @brief Shared slide panel all instances use. There's no point in allocating a new one every time. static inline std::unique_ptr sm_slidePanel{}; @@ -68,6 +80,9 @@ class SaveCreateState final : public BaseState /// @brief Pushes the titles to the menu void initialize_menu(); + /// @brief Assigns the user and title info. + void initialize_data_struct(); + /// @brief Launches the save creation task. void create_save_data_for(); diff --git a/include/appstates/TaskState.hpp b/include/appstates/TaskState.hpp index f796e93..70d9298 100644 --- a/include/appstates/TaskState.hpp +++ b/include/appstates/TaskState.hpp @@ -9,29 +9,20 @@ class TaskState final : public BaseTask { public: - /// @brief Constructs and spawns a new TaskState. - /// @param function Function to run in the thread. - /// @param args Variadic templated arguments to forward. - /// @note All functions passed must follow this signature: void function(sys::Task *, ) - template - TaskState(void (*function)(sys::Task *, Args...), Args... args) - : BaseTask() + /// @brief Constructs a new TaskState. + TaskState(sys::threadpool::JobFunction function, sys::Task::TaskData taskData); + + /// @brief Constructs and returns a TaskState. + static inline std::shared_ptr create(sys::threadpool::JobFunction function, sys::Task::TaskData taskData) { - m_task = std::make_unique(function, std::forward(args)...); + return std::make_shared(function, taskData); } - /// @brief Creates and returns a new TaskState. - template - static inline std::shared_ptr create(void (*function)(sys::Task *, Args...), Args... args) + /// @brief Constructs, pushes, then returns a new TaskState. + static inline std::shared_ptr create_and_push(sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) { - return std::make_shared(function, std::forward(args)...); - } - - /// @brief Creates, pushes, then returns and new TaskState. - template - static inline std::shared_ptr create_and_push(void (*function)(sys::Task *, Args...), Args... args) - { - auto newState = TaskState::create(function, std::forward(args)...); + auto newState = TaskState::create(function, taskData); StateManager::push_state(newState); return newState; } diff --git a/include/appstates/TitleOptionState.hpp b/include/appstates/TitleOptionState.hpp index afa0dc0..27d8c21 100644 --- a/include/appstates/TitleOptionState.hpp +++ b/include/appstates/TitleOptionState.hpp @@ -49,7 +49,7 @@ class TitleOptionState final : public BaseState void refresh_required(); // clang-format off - struct DataStruct + struct DataStruct : sys::Task::DataStruct { data::User *user{}; data::TitleInfo *titleInfo{}; @@ -58,8 +58,6 @@ class TitleOptionState final : public BaseState }; // clang-format on - using TaskData = std::shared_ptr; - private: /// @brief This is just in case the option should only apply to the current user. data::User *m_user{}; diff --git a/include/appstates/UserOptionState.hpp b/include/appstates/UserOptionState.hpp index b71a7bf..0cd1afa 100644 --- a/include/appstates/UserOptionState.hpp +++ b/include/appstates/UserOptionState.hpp @@ -44,15 +44,13 @@ class UserOptionState final : public BaseState void refresh_required(); // clang-format off - struct DataStruct + struct DataStruct : sys::Task::DataStruct { data::User *user{}; UserOptionState *spawningState{}; }; // clang-format on - using TaskData = std::shared_ptr; - private: /// @brief Pointer to the target user. data::User *m_user{}; diff --git a/include/curl/DownloadStruct.hpp b/include/curl/DownloadStruct.hpp index e83292c..ac0e459 100644 --- a/include/curl/DownloadStruct.hpp +++ b/include/curl/DownloadStruct.hpp @@ -2,14 +2,17 @@ #include "fslib.hpp" #include "sys/sys.hpp" +#include #include +#include #include -#include namespace curl { + inline constexpr size_t SHARED_BUFFER_SIZE = 0x500000; + // clang-format off - struct DownloadStruct + struct DownloadStruct : sys::threadpool::DataStruct { /// @brief Buffer mutex. std::mutex lock{}; @@ -18,7 +21,10 @@ namespace curl std::condition_variable condition{}; /// @brief Shared buffer that is read into. - std::vector sharedBuffer{}; + std::array sharedBuffer{}; + + /// @brief Current offset in the shared buffer. + size_t sharedOffset{}; /// @brief Bool to signal when the buffer is ready/empty. bool bufferReady{}; @@ -36,4 +42,15 @@ namespace curl int64_t fileSize{}; }; // clang-format on + + static inline std::shared_ptr create_download_struct(fslib::File &dest, + sys::ProgressTask *task, + int64_t fileSize) + { + auto downloadStruct = std::make_shared(); + downloadStruct->dest = &dest; + downloadStruct->task = task; + downloadStruct->offset = fileSize; + return downloadStruct; + } } diff --git a/include/curl/curl.hpp b/include/curl/curl.hpp index e84a209..2030f37 100644 --- a/include/curl/curl.hpp +++ b/include/curl/curl.hpp @@ -111,7 +111,7 @@ namespace curl /// @brief Function used to download files threaded. /// @param download Struct shared by both threads. - void download_write_thread_function(curl::DownloadStruct &download); + void download_write_thread_function(sys::threadpool::JobData jobData); /// @brief Gets the value of a header from an array of headers. /// @param array Array of headers to search. diff --git a/include/sys/ProgressTask.hpp b/include/sys/ProgressTask.hpp index 27c5bed..e4dd36d 100644 --- a/include/sys/ProgressTask.hpp +++ b/include/sys/ProgressTask.hpp @@ -1,26 +1,16 @@ #pragma once #include "sys/Task.hpp" -#include -#include - namespace sys { /// @brief Derived class of Task that has methods for tracking progress. class ProgressTask final : public sys::Task { public: - /// @brief Contstructs a new ProgressTask - /// @param function Function for thread to execute. - /// @param args Arguments to forward to the thread function. - /// @note All functions passed to this must follow this signature: void function(sys::ProgressTask *, - //) - template - ProgressTask(void (*function)(sys::ProgressTask *, Args...), Args... args) - { - m_thread = std::thread(function, this, std::forward(args)...); - m_isRunning.store(true); - } + /// @brief Creates a Progress task. + /// @param function + /// @param taskData + ProgressTask(sys::threadpool::JobFunction function, sys::ProgressTask::TaskData taskData); /// @brief Resets the progress and sets a new goal. /// @param goal The goal we all strive for. diff --git a/include/sys/Task.hpp b/include/sys/Task.hpp index fd3c855..59ecfef 100644 --- a/include/sys/Task.hpp +++ b/include/sys/Task.hpp @@ -1,9 +1,10 @@ #pragma once +#include "sys/threadpool.hpp" + #include #include #include #include -#include // This macro helps keep things a bit easier to read and cuts down on repetition. #define TASK_FINISH_RETURN(x) \ @@ -16,18 +17,21 @@ namespace sys class Task { public: - /// @brief Default constructor. - Task() = default; - - template - Task(void (*function)(sys::Task *, Args...), Args... args) + // clang-format off + struct DataStruct : sys::threadpool::DataStruct { - m_thread = std::thread(function, this, std::forward(args)...); - m_isRunning.store(true); - } + sys::Task *task{}; + }; + // clang-format on - /// @brief Required destructor. - virtual ~Task(); + /// @brief This makes some things easier to type and read in other places. + using TaskData = std::shared_ptr; + + /// @brief Default constructor. + Task(); + + /// @brief Starts a new task. + Task(sys::threadpool::JobFunction function, sys::Task::TaskData taskData); /// @brief Returns if the thread has signaled it's finished running. /// @return True if the thread is still running. False if it isn't. @@ -40,6 +44,9 @@ namespace sys /// @brief Sets the task/threads current status string. Thread safe. void set_status(std::string_view status); + /// @brief Moves the status string instead of creating a copy. + void set_status(std::string &status); + /// @brief Returns the status string. Thread safe. /// @return Copy of the status string. std::string get_status() noexcept; @@ -48,9 +55,6 @@ namespace sys // Whether task is still running. std::atomic m_isRunning{}; - // Thread - std::thread m_thread{}; - private: // Status string the thread can set that the main thread can display. std::string m_status{}; diff --git a/include/tasks/backup.hpp b/include/tasks/backup.hpp index 1559275..ad2a373 100644 --- a/include/tasks/backup.hpp +++ b/include/tasks/backup.hpp @@ -7,34 +7,24 @@ namespace tasks::backup { /// @brief Task/thread function executed when a new backup is created. - void create_new_backup_local(sys::ProgressTask *task, - data::User *user, - data::TitleInfo *titleInfo, - fslib::Path target, - BackupMenuState *spawningState, - bool killTask = true); - void create_new_backup_remote(sys::ProgressTask *task, - data::User *user, - data::TitleInfo *titleInfo, - std::string remoteName, - BackupMenuState *spawningState, - bool killTask = true); + void create_new_backup_local(sys::threadpool::JobData taskData); + void create_new_backup_remote(sys::threadpool::JobData taskData); /// @brief Overwrites a pre-existing backup. - void overwrite_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - void overwrite_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + void overwrite_backup_local(sys::threadpool::JobData taskData); + void overwrite_backup_remote(sys::threadpool::JobData taskData); /// @brief Restores a backup - void restore_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData); - void restore_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + void restore_backup_local(sys::threadpool::JobData taskData); + void restore_backup_remote(sys::threadpool::JobData taskData); /// @brief Deletes a backup - void delete_backup_local(sys::Task *task, BackupMenuState::TaskData taskData); - void delete_backup_remote(sys::Task *task, BackupMenuState::TaskData taskData); + void delete_backup_local(sys::threadpool::JobData taskData); + void delete_backup_remote(sys::threadpool::JobData taskData); /// @brief Uploads a backup - void upload_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + void upload_backup(sys::threadpool::JobData taskData); /// @brief Patches a pre-existing backup on the remote storage. - void patch_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData); + void patch_backup(sys::threadpool::JobData taskData); } diff --git a/include/tasks/fileoptions.hpp b/include/tasks/fileoptions.hpp index bf7b922..c49f926 100644 --- a/include/tasks/fileoptions.hpp +++ b/include/tasks/fileoptions.hpp @@ -5,8 +5,8 @@ namespace tasks::fileoptions { /// @brief Copies the source to destination passed through taskData. - void copy_source_to_destination(sys::ProgressTask *task, FileOptionState::TaskData taskData); + void copy_source_to_destination(sys::threadpool::JobData taskData); /// @brief Deletes the source path passed through taskData - void delete_target(sys::Task *task, FileOptionState::TaskData taskData); + void delete_target(sys::threadpool::JobData taskData); } \ No newline at end of file diff --git a/include/tasks/mainmenu.hpp b/include/tasks/mainmenu.hpp index 9696ccb..469f1c2 100644 --- a/include/tasks/mainmenu.hpp +++ b/include/tasks/mainmenu.hpp @@ -4,6 +4,6 @@ namespace tasks::mainmenu { - void backup_all_for_all_local(sys::ProgressTask *task, MainMenuState::TaskData taskData); - void backup_all_for_all_remote(sys::ProgressTask *task, MainMenuState::TaskData taskData); + void backup_all_for_all_local(sys::threadpool::JobData taskData); + void backup_all_for_all_remote(sys::threadpool::JobData taskData); } diff --git a/include/tasks/savecreate.hpp b/include/tasks/savecreate.hpp index 468df2f..ad949b0 100644 --- a/include/tasks/savecreate.hpp +++ b/include/tasks/savecreate.hpp @@ -5,5 +5,5 @@ namespace tasks::savecreate { - void create_save_data_for(sys::Task *task, data::User *user, data::TitleInfo *titleInfo, SaveCreateState *spawningState); + void create_save_data_for(sys::threadpool::JobData taskData); } diff --git a/include/tasks/titleoptions.hpp b/include/tasks/titleoptions.hpp index bc9e364..8e76e40 100644 --- a/include/tasks/titleoptions.hpp +++ b/include/tasks/titleoptions.hpp @@ -6,20 +6,20 @@ namespace tasks::titleoptions { /// @brief Adds a title to the blacklist. Needs to be task formatted to work with confirmations. - void blacklist_title(sys::Task *task, TitleOptionState::TaskData taskData); + void blacklist_title(sys::threadpool::JobData taskData); /// @brief Wipes deletes all local backups for the current title. - void delete_all_local_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData); + void delete_all_local_backups_for_title(sys::threadpool::JobData taskData); /// @brief Deletes all backups found on the remote storage service. - void delete_all_remote_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData); + void delete_all_remote_backups_for_title(sys::threadpool::JobData taskData); /// @brief Resets save data for the current title. - void reset_save_data(sys::Task *task, TitleOptionState::TaskData taskData); + void reset_save_data(sys::threadpool::JobData taskData); /// @brief Deletes the save data from the system the same way Data Management does. - void delete_save_data_from_system(sys::Task *task, TitleOptionState::TaskData taskData); + void delete_save_data_from_system(sys::threadpool::JobData taskData); /// @brief Extends the save container for the current save info. - void extend_save_data(sys::Task *task, TitleOptionState::TaskData taskData); + void extend_save_data(sys::threadpool::JobData taskData); } diff --git a/include/tasks/useroptions.hpp b/include/tasks/useroptions.hpp index fbdefc8..9d24b30 100644 --- a/include/tasks/useroptions.hpp +++ b/include/tasks/useroptions.hpp @@ -4,8 +4,8 @@ namespace tasks::useroptions { - void backup_all_for_user_local(sys::ProgressTask *task, UserOptionState::TaskData taskData); - void backup_all_for_user_remote(sys::ProgressTask *task, UserOptionState::TaskData taskData); - void create_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData); - void delete_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData); + void backup_all_for_user_local(sys::threadpool::JobData taskData); + void backup_all_for_user_remote(sys::threadpool::JobData taskData); + void create_all_save_data_for_user(sys::threadpool::JobData taskData); + void delete_all_save_data_for_user(sys::threadpool::JobData taskData); } diff --git a/include/ui/Menu.hpp b/include/ui/Menu.hpp index 18bb0ff..d7ee700 100644 --- a/include/ui/Menu.hpp +++ b/include/ui/Menu.hpp @@ -41,10 +41,13 @@ namespace ui /// @param hasFocus Whether or not the calling state has focus. void render(sdl::SharedTexture &target, bool hasFocus) override; - /// @brief Adds and option to the menu. + /// @brief Adds an option to the menu. /// @param newOption Option to add to menu. void add_option(std::string_view newOption); + /// @brief Adds an option to the menu. Moves the string instead of creating a new one. + void add_option(std::string &newOption); + /// @brief Allows updating and editing the option. /// @param newOption Option to change text to. void edit_option(int index, std::string_view newOption); @@ -71,7 +74,7 @@ namespace ui bool is_empty() const noexcept; /// @brief Resets the menu and returns it to an empty, default state. - void reset(); + void reset(bool full = true); protected: /// @brief X coordinate menu is rendered to. diff --git a/include/ui/PopMessage.hpp b/include/ui/PopMessage.hpp index f75d3fd..7018e79 100644 --- a/include/ui/PopMessage.hpp +++ b/include/ui/PopMessage.hpp @@ -12,6 +12,9 @@ namespace ui /// @brief PopMessage constructor. PopMessage(int ticks, std::string_view message); + /// @brief Same as above. Moves string instead of copying. + PopMessage(int ticks, std::string &message); + /// @brief Updates the width, target, and typing. void update(double targetY); diff --git a/include/ui/PopMessageManager.hpp b/include/ui/PopMessageManager.hpp index 8163fd9..6841ad9 100644 --- a/include/ui/PopMessageManager.hpp +++ b/include/ui/PopMessageManager.hpp @@ -27,6 +27,9 @@ namespace ui /// @brief Pushes a new message to the queue for processing. static void push_message(int displayTicks, std::string_view message); + /// @brief Move version of above. + static void push_message(int displayTicks, std::string &message); + /// @brief The default duration of ticks for messages to be shown. static constexpr int DEFAULT_TICKS = 2500; diff --git a/source/JKSV.cpp b/source/JKSV.cpp index 27a6a84..f34ec73 100644 --- a/source/JKSV.cpp +++ b/source/JKSV.cpp @@ -87,7 +87,6 @@ JKSV::JKSV() // This needs the config init'd or read to work. JKSV::create_directories(); - sys::threadpool::initialize(); data::launch_initialization(false, finish_initialization); @@ -105,6 +104,7 @@ JKSV::~JKSV() sdl::exit(); appletSetCpuBoostMode(ApmCpuBoostMode_Normal); + appletUnlockExit(); } bool JKSV::is_running() const noexcept { return m_isRunning && appletMainLoop(); } @@ -170,6 +170,7 @@ bool JKSV::initialize_services() serviceInit = serviceInit && initialize_service(setsysInitialize, "SetSys"); serviceInit = serviceInit && initialize_service(socketInitialize, "Socket", &SOCKET_INIT_CONFIG); serviceInit = serviceInit && initialize_service(nifmInitialize, "NIFM", NifmServiceType_User); + serviceInit = serviceInit && initialize_service(appletLockExit, "AppletLockExit"); return serviceInit; } diff --git a/source/appstates/BackupMenuState.cpp b/source/appstates/BackupMenuState.cpp index 30b9614..7efa639 100644 --- a/source/appstates/BackupMenuState.cpp +++ b/source/appstates/BackupMenuState.cpp @@ -21,13 +21,6 @@ #include -namespace -{ - // These make some things cleaner and easier to type. - using TaskConfirm = ConfirmState; - using ProgressConfirm = ConfirmState; -} // namespace - BackupMenuState::BackupMenuState(data::User *user, data::TitleInfo *titleInfo) : m_user(user) , m_titleInfo(titleInfo) @@ -238,23 +231,21 @@ void BackupMenuState::name_and_create_backup() const bool named = autoNamed || keyboard::get_input(SwkbdType_QWERTY, name, keyboardHeader, name, SIZE_NAME_LENGTH); if (!named) { return; } - const bool hasZipExt = std::strstr(name, STRING_ZIP_EXT); // This might not be the best check. + m_dataStruct->killTask = true; // Need to make sure these kill the task. + const bool hasZipExt = std::strstr(name, STRING_ZIP_EXT); // This might not be the best check. if (autoUpload && remote) { if (!hasZipExt) { std::strncat(name, STRING_ZIP_EXT, SIZE_NAME_LENGTH); } - ProgressState::create_and_push(tasks::backup::create_new_backup_remote, - m_user, - m_titleInfo, - std::string{name}, - this, - true); + + ProgressState::create_and_push(tasks::backup::create_new_backup_remote, m_dataStruct); } else { fslib::Path target{m_directoryPath / name}; if (!hasZipExt && (autoUpload || exportZip)) { target += STRING_ZIP_EXT; } // We're going to append zip either way. - ProgressState::create_and_push(tasks::backup::create_new_backup_local, m_user, m_titleInfo, target, this, true); + m_dataStruct->path = std::move(target); + ProgressState::create_and_push(tasks::backup::create_new_backup_local, m_dataStruct); } } @@ -270,14 +261,16 @@ void BackupMenuState::confirm_overwrite() m_dataStruct->remoteItem = m_remoteListing.at(entry.index); const char *itemName = m_dataStruct->remoteItem->get_name().data(); const std::string query = stringutil::get_formatted_string(confirmTemplate, itemName); - ProgressConfirm::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_remote, m_dataStruct); + + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_remote, m_dataStruct); } else if (entry.type == MenuEntryType::Local) { m_dataStruct->path = m_directoryPath / m_directoryListing[entry.index]; const char *targetName = m_directoryListing[entry.index].get_filename(); const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName); - ProgressConfirm::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_local, m_dataStruct); + + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::overwrite_backup_local, m_dataStruct); } } @@ -317,7 +310,7 @@ void BackupMenuState::confirm_restore() const char *targetName = m_directoryListing[entry.index].get_filename(); const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName); - ProgressConfirm::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, m_dataStruct); } else if (entry.type == MenuEntryType::Remote) { @@ -326,7 +319,7 @@ void BackupMenuState::confirm_restore() m_dataStruct->remoteItem = target; m_dataStruct->path = m_directoryPath + "//"; // To-do: This is a workaround. - ProgressConfirm::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, m_dataStruct); } } @@ -337,14 +330,13 @@ void BackupMenuState::confirm_delete() const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_DELETION); const char *confirmTemplate = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 2); - std::shared_ptr confirm{}; if (entry.type == MenuEntryType::Local) { m_dataStruct->path = m_directoryPath / m_directoryListing[entry.index]; const char *targetName = m_directoryListing[entry.index].get_filename(); const std::string query = stringutil::get_formatted_string(confirmTemplate, targetName); - TaskConfirm::create_and_push(query, holdRequired, tasks::backup::delete_backup_local, m_dataStruct); + ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_local, m_dataStruct); } else if (entry.type == MenuEntryType::Remote) { @@ -352,7 +344,7 @@ void BackupMenuState::confirm_delete() const char *itemName = m_dataStruct->remoteItem->get_name().data(); const std::string query = stringutil::get_formatted_string(confirmTemplate, itemName); - TaskConfirm::create_and_push(query, holdRequired, tasks::backup::delete_backup_remote, m_dataStruct); + ConfirmTask::create_push_fade(query, holdRequired, tasks::backup::delete_backup_remote, m_dataStruct); } } @@ -386,7 +378,7 @@ void BackupMenuState::upload_backup() const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE); m_dataStruct->remoteItem = remoteItem; - ProgressConfirm::create_and_push(query, holdRequired, tasks::backup::patch_backup, m_dataStruct); + ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::patch_backup, m_dataStruct); } else { ProgressState::create_and_push(tasks::backup::upload_backup, m_dataStruct); } } diff --git a/source/appstates/BlacklistEditState.cpp b/source/appstates/BlacklistEditState.cpp index 1962ce3..38eabad 100644 --- a/source/appstates/BlacklistEditState.cpp +++ b/source/appstates/BlacklistEditState.cpp @@ -25,7 +25,7 @@ void BlacklistEditState::update() sm_slidePanel->update(hasFocus); if (aPressed) { BlacklistEditState::remove_from_blacklist(); } - else if (bPressed) { sm_slidePanel->close(); } + else if (bPressed || m_blacklist.empty()) { sm_slidePanel->close(); } else if (sm_slidePanel->is_closed()) { BlacklistEditState::deactivate_state(); } } diff --git a/source/appstates/DataLoadingState.cpp b/source/appstates/DataLoadingState.cpp index ec5fad3..71a3ad5 100644 --- a/source/appstates/DataLoadingState.cpp +++ b/source/appstates/DataLoadingState.cpp @@ -8,6 +8,18 @@ namespace constexpr int SCREEN_CENTER = 640; } +DataLoadingState::DataLoadingState(data::DataContext &context, + DestructFunction destructFunction, + sys::threadpool::JobFunction function, + sys::Task::TaskData taskData) + : BaseTask() + , m_context(context) + , m_destructFunction(destructFunction) +{ + DataLoadingState::initialize_static_members(); + m_task = std::make_unique(function, taskData); +} + void DataLoadingState::update() { BaseTask::update_loading_glyph(); diff --git a/source/appstates/ExtrasMenuState.cpp b/source/appstates/ExtrasMenuState.cpp index e3dc6e0..3972f8d 100644 --- a/source/appstates/ExtrasMenuState.cpp +++ b/source/appstates/ExtrasMenuState.cpp @@ -79,7 +79,7 @@ void ExtrasMenuState::render() void ExtrasMenuState::initialize_menu() { - if (!m_extrasMenu) { m_extrasMenu = ui::Menu::create(32, 8, 1000, 24, 555); } + if (!m_extrasMenu) { m_extrasMenu = ui::Menu::create(32, 10, 1000, 23, 555); } for (int i = 0; const char *option = strings::get_by_name(strings::names::EXTRASMENU_MENU, i); i++) { diff --git a/source/appstates/FileModeState.cpp b/source/appstates/FileModeState.cpp index c65abcf..bad1bdc 100644 --- a/source/appstates/FileModeState.cpp +++ b/source/appstates/FileModeState.cpp @@ -102,8 +102,8 @@ void FileModeState::initialize_paths() void FileModeState::initialize_menus() { - m_dirMenuA = ui::Menu::create(8, 8, 594, 22, 538); - m_dirMenuB = ui::Menu::create(626, 8, 594, 22, 538); + m_dirMenuA = ui::Menu::create(8, 5, 594, 20, 538); + m_dirMenuB = ui::Menu::create(626, 5, 594, 20, 538); FileModeState::initialize_directory_menu(m_pathA, m_dirA, *m_dirMenuA.get()); FileModeState::initialize_directory_menu(m_pathB, m_dirB, *m_dirMenuB.get()); diff --git a/source/appstates/FileOptionState.cpp b/source/appstates/FileOptionState.cpp index bce615c..842e56a 100644 --- a/source/appstates/FileOptionState.cpp +++ b/source/appstates/FileOptionState.cpp @@ -30,10 +30,6 @@ namespace PROPERTIES, CLOSE }; - - // These make things easier to read and type. - using TaskConfirm = ConfirmState; - using ProgressConfirm = ConfirmState; } // Defined at bottom. @@ -183,7 +179,7 @@ void FileOptionState::copy_target() if (!entry.is_directory()) { const char *errorFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 4); - const std::string pop = stringutil::get_formatted_string(errorFormat, entry.get_filename()); + std::string pop = stringutil::get_formatted_string(errorFormat, entry.get_filename()); ui::PopMessageManager::push_message(popTicks, pop); return; } @@ -202,7 +198,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()); - ProgressConfirm::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, m_dataStruct); } void FileOptionState::delete_target() @@ -233,7 +229,7 @@ void FileOptionState::delete_target() m_dataStruct->sourcePath = std::move(fullTarget); m_dataStruct->journalSize = m_spawningState->m_journalSize; - TaskConfirm::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, m_dataStruct); + ConfirmTask::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, m_dataStruct); } void FileOptionState::rename_target() @@ -278,7 +274,7 @@ void FileOptionState::rename_target() if (dirError && fileError && commitError) { const char *popFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 2); - const std::string pop = stringutil::get_formatted_string(popFormat, filename); + std::string pop = stringutil::get_formatted_string(popFormat, filename); ui::PopMessageManager::push_message(popTicks, pop); } @@ -312,7 +308,7 @@ void FileOptionState::create_directory() if (createError || (commitRequired && commitError)) { const char *popFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 3); - const std::string pop = stringutil::get_formatted_string(popFormat, nameBuffer); + std::string pop = stringutil::get_formatted_string(popFormat, nameBuffer); ui::PopMessageManager::push_message(popTicks, pop); } diff --git a/source/appstates/MainMenuState.cpp b/source/appstates/MainMenuState.cpp index b8dbb8d..cd85cf7 100644 --- a/source/appstates/MainMenuState.cpp +++ b/source/appstates/MainMenuState.cpp @@ -19,11 +19,6 @@ #include "tasks/mainmenu.hpp" #include "ui/PopMessageManager.hpp" -namespace -{ - using ProgressConfirm = ConfirmState; -} - MainMenuState::MainMenuState() : m_renderTarget(sdl::TextureManager::load("mainMenuTarget", 200, 555, SDL_TEXTUREACCESS_TARGET)) , m_background(sdl::TextureManager::load("mainBackground", "romfs:/Textures/MenuBackground.png")) @@ -138,8 +133,8 @@ void MainMenuState::push_target_state() const int titleCount = user->get_total_data_entries(); if (titleCount <= 0) { - const char *nickname = user->get_nickname(); - const std::string popError = stringutil::get_formatted_string(popNoSaveFormat, nickname); + const char *nickname = user->get_nickname(); + std::string popError = stringutil::get_formatted_string(popNoSaveFormat, nickname); ui::PopMessageManager::push_message(popTicks, popError); return; } @@ -166,7 +161,7 @@ void MainMenuState::backup_all_for_all() const char *query = strings::get_by_name(strings::names::MAINMENU_CONFS, 0); if (remote && autoUpload) { - ProgressConfirm::create_and_push(query, true, tasks::mainmenu::backup_all_for_all_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, true, tasks::mainmenu::backup_all_for_all_remote, m_dataStruct); } - else { ProgressConfirm::create_and_push(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, m_dataStruct); } } diff --git a/source/appstates/ProgressState.cpp b/source/appstates/ProgressState.cpp index 41d2776..b1b8fe5 100644 --- a/source/appstates/ProgressState.cpp +++ b/source/appstates/ProgressState.cpp @@ -21,6 +21,12 @@ namespace constexpr double SIZE_BAR_WIDTH = 656.0f; } +ProgressState::ProgressState(sys::threadpool::JobFunction function, sys::Task::TaskData taskData) +{ + initialize_static_members(); + m_task = std::make_unique(function, taskData); +} + void ProgressState::update() { sys::ProgressTask *task = static_cast(m_task.get()); @@ -53,8 +59,10 @@ void ProgressState::render() sdl::render_line(sdl::Texture::Null, 280, 454, 999, 454, colors::DIV_COLOR); sdl::render_rect_fill(sdl::Texture::Null, COORD_BAR_X, COORD_BAR_Y, barWidth, 32, colors::BLACK); sdl::render_rect_fill(sdl::Texture::Null, COORD_BAR_X, COORD_BAR_Y, m_progressBarWidth, 32, colors::GREEN); + sm_barEdges->render_part(sdl::Texture::Null, COORD_BAR_X, COORD_BAR_Y, 0, 0, 16, 32); sm_barEdges->render_part(sdl::Texture::Null, RIGHT_EDGE_X, COORD_BAR_Y, 16, 0, 16, 32); + sdl::text::render(sdl::Texture::Null, m_percentageX, COORD_TEXT_Y, diff --git a/source/appstates/SaveCreateState.cpp b/source/appstates/SaveCreateState.cpp index 0e0ac26..0fe0313 100644 --- a/source/appstates/SaveCreateState.cpp +++ b/source/appstates/SaveCreateState.cpp @@ -24,11 +24,13 @@ static bool compare_info(data::TitleInfo *infoA, data::TitleInfo *infoB); SaveCreateState::SaveCreateState(data::User *user, TitleSelectCommon *titleSelect) : m_user(user) , m_titleSelect(titleSelect) - , m_saveMenu(ui::Menu::create(8, 8, 624, 22, 720)) + , m_saveMenu(ui::Menu::create(8, 8, 624, 23, 720)) + , m_dataStruct(std::make_shared()) { SaveCreateState::initialize_static_members(); SaveCreateState::initialize_title_info_vector(); SaveCreateState::initialize_menu(); + SaveCreateState::initialize_data_struct(); } void SaveCreateState::update() @@ -87,13 +89,19 @@ void SaveCreateState::initialize_menu() sm_slidePanel->push_new_element(m_saveMenu); } +void SaveCreateState::initialize_data_struct() +{ + m_dataStruct->user = m_user; + m_dataStruct->spawningState = this; +} + void SaveCreateState::create_save_data_for() { const int selected = m_saveMenu->get_selected(); data::TitleInfo *titleInfo = m_titleInfoVector[selected]; - auto createTask = TaskState::create(tasks::savecreate::create_save_data_for, m_user, titleInfo, this); + m_dataStruct->titleInfo = titleInfo; - StateManager::push_state(createTask); + TaskState::create_and_push(tasks::savecreate::create_save_data_for, m_dataStruct); } void SaveCreateState::deactivate_state() diff --git a/source/appstates/SettingsState.cpp b/source/appstates/SettingsState.cpp index f1b0b8b..db1468b 100644 --- a/source/appstates/SettingsState.cpp +++ b/source/appstates/SettingsState.cpp @@ -62,7 +62,7 @@ namespace } // namespace SettingsState::SettingsState() - : m_settingsMenu(ui::Menu::create(32, 8, 1000, 24, 555)) + : m_settingsMenu(ui::Menu::create(32, 10, 1000, 23, 555)) , m_controlGuide(ui::ControlGuide::create(strings::get_by_name(strings::names::CONTROL_GUIDES, 3))) , m_renderTarget(sdl::TextureManager::load(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_TARGET)) { @@ -179,7 +179,7 @@ void SettingsState::change_working_directory() } const std::string newPathString = newPath.string(); - const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, newPathString.c_str()); + std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, newPathString.c_str()); ui::PopMessageManager::push_message(popTicks, popMessage); } @@ -211,7 +211,7 @@ void SettingsState::toggle_options() case CYCLE_SCALING: SettingsState::cycle_anim_scaling(); break; default: config::toggle_by_key(CONFIG_KEY_ARRAY[selected]); break; } - config::save(); + SettingsState::update_menu_options(); } @@ -227,6 +227,7 @@ void SettingsState::cycle_zip_level() { uint8_t zipLevel = config::get_by_key(config::keys::ZIP_COMPRESSION_LEVEL); if (++zipLevel % 10 == 0) { zipLevel = 0; } + config::set_by_key(config::keys::ZIP_COMPRESSION_LEVEL, zipLevel); } @@ -239,12 +240,14 @@ void SettingsState::cycle_sort_type() data::UserList users{}; data::get_users(users); for (data::User *user : users) { user->sort_data(); } + MainMenuState::refresh_view_states(); } void SettingsState::toggle_jksm_mode() { config::toggle_by_key(config::keys::JKSM_TEXT_MODE); + MainMenuState::initialize_view_states(); } @@ -262,17 +265,20 @@ void SettingsState::cycle_anim_scaling() { double scaling = config::get_animation_scaling(); if ((scaling += 0.25f) > 4.0f) { scaling = 1.0f; } + config::set_animation_scaling(scaling); } const char *SettingsState::get_status_text(uint8_t value) { if (value > 1) { return nullptr; } + return m_onOff[value]; } const char *SettingsState::get_sort_type_text(uint8_t value) { if (value > 2) { return nullptr; } + return m_sortTypes[value]; } diff --git a/source/appstates/TaskState.cpp b/source/appstates/TaskState.cpp index 93c9e42..9eb16ab 100644 --- a/source/appstates/TaskState.cpp +++ b/source/appstates/TaskState.cpp @@ -7,10 +7,15 @@ #include "strings/strings.hpp" #include "ui/PopMessageManager.hpp" +TaskState::TaskState(sys::threadpool::JobFunction function, sys::Task::TaskData taskData) +{ + m_task = std::make_unique(function, taskData); +} + void TaskState::update() { - BaseTask::update_loading_glyph(); BaseTask::pop_on_plus(); + BaseTask::update_loading_glyph(); if (!m_task->is_running()) { TaskState::deactivate_state(); } } diff --git a/source/appstates/TextTitleSelectState.cpp b/source/appstates/TextTitleSelectState.cpp index 7e79066..08eb52b 100644 --- a/source/appstates/TextTitleSelectState.cpp +++ b/source/appstates/TextTitleSelectState.cpp @@ -23,7 +23,7 @@ namespace TextTitleSelectState::TextTitleSelectState(data::User *user) : TitleSelectCommon() , m_user(user) - , m_titleSelectMenu(ui::Menu::create(32, 8, 1000, 22, 555)) + , m_titleSelectMenu(ui::Menu::create(32, 10, 1000, 23, 555)) , m_renderTarget(sdl::TextureManager::load(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_TARGET)) { TextTitleSelectState::refresh(); @@ -61,7 +61,7 @@ void TextTitleSelectState::refresh() { static constexpr const char *STRING_HEART = "^\uE017^ "; - m_titleSelectMenu->reset(); + m_titleSelectMenu->reset(false); const size_t totalEntries = m_user->get_total_data_entries(); for (size_t i = 0; i < totalEntries; i++) @@ -118,7 +118,7 @@ void TextTitleSelectState::add_remove_favorite() const uint64_t appIDAt = m_user->get_application_id_at(i); if (appIDAt == applicationID) { break; } } - m_titleSelectMenu->set_selected(i); MainMenuState::refresh_view_states(); + m_titleSelectMenu->set_selected(i); } diff --git a/source/appstates/TitleOptionState.cpp b/source/appstates/TitleOptionState.cpp index d9d0285..1978aa1 100644 --- a/source/appstates/TitleOptionState.cpp +++ b/source/appstates/TitleOptionState.cpp @@ -38,9 +38,6 @@ namespace EXTEND_CONTAINER, EXPORT_SVI }; - - using TaskConfirm = ConfirmState; - using ProgressConfirm = ConfirmState; } // namespace TitleOptionState::TitleOptionState(data::User *user, data::TitleInfo *titleInfo, TitleSelectCommon *titleSelect) @@ -144,7 +141,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); - TaskConfirm::create_and_push(query, false, tasks::titleoptions::blacklist_title, m_dataStruct); + ConfirmTask::create_push_fade(query, false, tasks::titleoptions::blacklist_title, m_dataStruct); } void TitleOptionState::change_output_directory() @@ -193,7 +190,7 @@ void TitleOptionState::change_output_directory() config::add_custom_path(applicationID, pathBuffer.data()); const char *popSuccessFormat = strings::get_by_name(strings::names::TITLEOPTION_POPS, 8); - const std::string popSuccess = stringutil::get_formatted_string(popSuccessFormat, pathBuffer.data()); + std::string popSuccess = stringutil::get_formatted_string(popSuccessFormat, pathBuffer.data()); ui::PopMessageManager::push_message(popTicks, popSuccess); } @@ -224,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); - TaskConfirm::create_and_push(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, m_dataStruct); } void TitleOptionState::delete_all_remote_backups() @@ -233,7 +230,7 @@ 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); - TaskConfirm::create_and_push(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, m_dataStruct); } void TitleOptionState::reset_save_data() @@ -255,7 +252,7 @@ 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); - TaskConfirm::create_and_push(query, true, tasks::titleoptions::reset_save_data, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::titleoptions::reset_save_data, m_dataStruct); } void TitleOptionState::delete_save_from_system() @@ -278,7 +275,7 @@ 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); - TaskConfirm::create_and_push(query, true, tasks::titleoptions::delete_save_data_from_system, m_dataStruct); + ConfirmTask::create_push_fade(query, true, tasks::titleoptions::delete_save_data_from_system, m_dataStruct); } void TitleOptionState::extend_save_container() diff --git a/source/appstates/UserOptionState.cpp b/source/appstates/UserOptionState.cpp index 27287ea..ed2c536 100644 --- a/source/appstates/UserOptionState.cpp +++ b/source/appstates/UserOptionState.cpp @@ -30,10 +30,6 @@ namespace CREATE_ALL_SAVE, DELETE_ALL_SAVE }; - - // These make things easier to type later. - using TaskConfirm = ConfirmState; - using ProgressConfirm = ConfirmState; } // namespace UserOptionState::UserOptionState(data::User *user, TitleSelectCommon *titleSelect) @@ -128,9 +124,9 @@ void UserOptionState::backup_all() const std::string query = stringutil::get_formatted_string(confirmFormat, nickname); if (remote && autoUpload) { - ProgressConfirm::create_and_push(query, true, tasks::useroptions::backup_all_for_user_remote, m_dataStruct); + ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_remote, m_dataStruct); } - else { ProgressConfirm::create_and_push(query, true, tasks::useroptions::backup_all_for_user_local, m_dataStruct); } + else { ConfirmProgress::create_push_fade(query, true, tasks::useroptions::backup_all_for_user_local, m_dataStruct); } } void UserOptionState::create_save_create() @@ -149,7 +145,7 @@ void UserOptionState::create_all_save_data() const char *nickname = m_user->get_nickname(); const std::string query = stringutil::get_formatted_string(confirmFormat, nickname); - TaskConfirm::create_and_push(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, m_dataStruct); } void UserOptionState::delete_all_save_data() @@ -160,7 +156,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); - TaskConfirm::create_and_push(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, m_dataStruct); } void UserOptionState::deactivate_state() diff --git a/source/config/ConfigContext.cpp b/source/config/ConfigContext.cpp index 2ba541b..710b0ee 100644 --- a/source/config/ConfigContext.cpp +++ b/source/config/ConfigContext.cpp @@ -55,8 +55,6 @@ void config::ConfigContext::reset() m_configMap[config::keys::SHOW_SYSTEM_USER.data()] = 0; m_configMap[config::keys::ENABLE_TRASH_BIN.data()] = 0; m_animationScaling = DEFAULT_SCALING; - - ConfigContext::save(); } bool config::ConfigContext::load() @@ -110,7 +108,6 @@ void config::ConfigContext::add_favorite(uint64_t applicationID) const auto findFav = ConfigContext::find_application_id(m_favorites, applicationID); if (findFav != m_favorites.end()) { return; } m_favorites.push_back(applicationID); - ConfigContext::save_config_file(); } void config::ConfigContext::remove_favorite(uint64_t applicationID) noexcept @@ -118,7 +115,6 @@ void config::ConfigContext::remove_favorite(uint64_t applicationID) noexcept const auto findFav = ConfigContext::find_application_id(m_favorites, applicationID); if (findFav == m_favorites.end()) { return; } m_favorites.erase(findFav); - ConfigContext::save_config_file(); } bool config::ConfigContext::is_favorite(uint64_t applicationID) const noexcept diff --git a/source/config/config.cpp b/source/config/config.cpp index 3118586..064dfc8 100644 --- a/source/config/config.cpp +++ b/source/config/config.cpp @@ -33,7 +33,6 @@ bool config::set_working_directory(const fslib::Path &path) noexcept const bool pathSet = s_context.set_working_directory(path); if (!pathSet) { return false; } - s_context.save(); return true; } @@ -46,7 +45,6 @@ void config::add_remove_favorite(uint64_t applicationID) const bool favorite = s_context.is_favorite(applicationID); if (favorite) { s_context.remove_favorite(applicationID); } else { s_context.add_favorite(applicationID); } - s_context.save(); } bool config::is_favorite(uint64_t applicationID) noexcept { return s_context.is_favorite(applicationID); } @@ -56,7 +54,6 @@ void config::add_remove_blacklist(uint64_t applicationID) const bool blacklisted = s_context.is_blacklisted(applicationID); if (blacklisted) { s_context.remove_from_blacklist(applicationID); } else { s_context.add_to_blacklist(applicationID); } - s_context.save(); } void config::get_blacklisted_titles(std::vector &listOut) { s_context.get_blacklist(listOut); } diff --git a/source/curl/curl.cpp b/source/curl/curl.cpp index 9424002..ad75103 100644 --- a/source/curl/curl.cpp +++ b/source/curl/curl.cpp @@ -67,13 +67,14 @@ size_t curl::write_data_to_file(const char *buffer, size_t size, size_t count, f size_t curl::download_file_threaded(const char *buffer, size_t size, size_t count, curl::DownloadStruct *download) { - std::mutex &lock = download->lock; - std::condition_variable &condition = download->condition; - std::vector &sharedBuffer = download->sharedBuffer; - bool &bufferReady = download->bufferReady; - sys::ProgressTask *task = download->task; - size_t &offset = download->offset; - int64_t &fileSize = download->fileSize; + std::mutex &lock = download->lock; + std::condition_variable &condition = download->condition; + auto &sharedBuffer = download->sharedBuffer; + size_t &sharedOffset = download->sharedOffset; + bool &bufferReady = download->bufferReady; + sys::ProgressTask *task = download->task; + size_t &offset = download->offset; + int64_t &fileSize = download->fileSize; const size_t downloadSize = size * count; const std::span bufferSpan{reinterpret_cast(buffer), downloadSize}; @@ -81,11 +82,12 @@ size_t curl::download_file_threaded(const char *buffer, size_t size, size_t coun { std::unique_lock bufferLock(lock); condition.wait(bufferLock, [&]() { return bufferReady == false; }); - sharedBuffer.append_range(bufferSpan); - const size_t sharedSize = sharedBuffer.size(); + std::copy(bufferSpan.begin(), bufferSpan.end(), &sharedBuffer[sharedOffset]); + sharedOffset += downloadSize; + const int64_t nextOffset = offset + downloadSize; - if (sharedSize >= SIZE_DOWNLOAD_THRESHOLD || nextOffset >= fileSize) + if (sharedOffset >= SIZE_DOWNLOAD_THRESHOLD || nextOffset >= fileSize) { bufferReady = true; condition.notify_one(); @@ -99,14 +101,17 @@ size_t curl::download_file_threaded(const char *buffer, size_t size, size_t coun return downloadSize; } -void curl::download_write_thread_function(curl::DownloadStruct &download) +void curl::download_write_thread_function(sys::threadpool::JobData jobData) { - std::mutex &lock = download.lock; - std::condition_variable &condition = download.condition; - std::vector &sharedBuffer = download.sharedBuffer; - bool &bufferReady = download.bufferReady; - fslib::File *dest = download.dest; - size_t fileSize = download.fileSize; + auto castData = std::static_pointer_cast(jobData); + + std::mutex &lock = castData->lock; + std::condition_variable &condition = castData->condition; + auto &sharedBuffer = castData->sharedBuffer; + size_t &sharedOffset = castData->sharedOffset; + bool &bufferReady = castData->bufferReady; + fslib::File &dest = *castData->dest; + size_t fileSize = castData->fileSize; auto localBuffer = std::make_unique(SIZE_DOWNLOAD_THRESHOLD + 0x100000); // Gonna give this some room. @@ -117,14 +122,15 @@ void curl::download_write_thread_function(curl::DownloadStruct &download) std::unique_lock bufferLock(lock); condition.wait(bufferLock, [&]() { return bufferReady == true; }); - bufferSize = sharedBuffer.size(); - std::memcpy(localBuffer.get(), sharedBuffer.data(), bufferSize); + // Copy and reset the offset. + bufferSize = sharedOffset; + std::copy(sharedBuffer.begin(), sharedBuffer.begin() + sharedOffset, localBuffer.get()); + sharedOffset = 0; - sharedBuffer.clear(); bufferReady = false; condition.notify_one(); } - dest->write(localBuffer.get(), bufferSize); + dest.write(localBuffer.get(), bufferSize); i += bufferSize; } } diff --git a/source/data/DataContext.cpp b/source/data/DataContext.cpp index 3cf1923..8cdd1d7 100644 --- a/source/data/DataContext.cpp +++ b/source/data/DataContext.cpp @@ -78,8 +78,8 @@ void data::DataContext::load_user_save_info(sys::Task *task) { std::lock_guard userGuard{m_userMutex}; { - const char *nickname = user.get_nickname(); - const std::string status = stringutil::get_formatted_string(statusLoadingUserInfo, nickname); + const char *nickname = user.get_nickname(); + std::string status = stringutil::get_formatted_string(statusLoadingUserInfo, nickname); task->set_status(status); } user.load_user_data(); @@ -108,7 +108,7 @@ void data::DataContext::load_application_records(sys::Task *task) if (DataContext::title_is_loaded(record.application_id)) { continue; } { - const std::string status = stringutil::get_formatted_string(statusLoadingRecords, record.application_id); + std::string status = stringutil::get_formatted_string(statusLoadingRecords, record.application_id); task->set_status(status); } DataContext::load_title(record.application_id); @@ -171,7 +171,8 @@ void data::DataContext::import_svi_files(sys::Task *task) task->set_status(statusLoadingSvi); - auto controlData = std::make_unique(); + // auto controlData = std::make_unique(); + NsApplicationControlData controlData{}; for (const fslib::DirectoryEntry &entry : sviDir) { const fslib::Path target{sviPath / entry}; @@ -186,11 +187,11 @@ void data::DataContext::import_svi_files(sys::Task *task) const bool exists = DataContext::title_is_loaded(applicationID); if (!magicRead || magic != fs::SAVE_META_MAGIC || !idRead || exists) { continue; } - const bool dataRead = sviFile.read(controlData.get(), SIZE_CTRL_DATA) == SIZE_CTRL_DATA; + const bool dataRead = sviFile.read(&controlData, SIZE_CTRL_DATA) == SIZE_CTRL_DATA; if (!dataRead) { continue; } std::scoped_lock multiGuard{m_iconQueueMutex, m_titleMutex}; - m_titleInfo.try_emplace(applicationID, applicationID, *controlData); + m_titleInfo.try_emplace(applicationID, applicationID, controlData); m_iconQueue.push_back(&m_titleInfo.at(applicationID)); } } @@ -213,9 +214,9 @@ bool data::DataContext::read_cache(sys::Task *task) const char *statusLoadingCache = strings::get_by_name(strings::names::DATA_LOADING_STATUS, 4); task->set_status(statusLoadingCache); - auto controlData = std::make_unique(); + NsApplicationControlData controlData{}; do { - const bool dataRead = cacheZip.read(controlData.get(), SIZE_CTRL_DATA) == SIZE_CTRL_DATA; + const bool dataRead = cacheZip.read(&controlData, SIZE_CTRL_DATA) == SIZE_CTRL_DATA; if (!dataRead) { continue; } std::string_view filename{cacheZip.get_filename()}; @@ -227,7 +228,7 @@ bool data::DataContext::read_cache(sys::Task *task) std::scoped_lock multiGuard{m_iconQueueMutex, m_titleMutex}; - m_titleInfo.try_emplace(applicationID, applicationID, *controlData); + m_titleInfo.try_emplace(applicationID, applicationID, controlData); m_iconQueue.push_back(&m_titleInfo.at(applicationID)); } while (cacheZip.next_file()); m_cacheIsValid = true; diff --git a/source/data/data.cpp b/source/data/data.cpp index 06966f2..4467337 100644 --- a/source/data/data.cpp +++ b/source/data/data.cpp @@ -10,15 +10,26 @@ namespace { + // clang-format off + // This seems stupid, but it's the only way, really. + struct StateDataStruct : sys::Task::DataStruct + { + bool clearCache{}; + }; + // clang-format on + data::DataContext s_context{}; } // namespace /// @brief The main routine for the task to load data. -static void data_initialize_task(sys::Task *task, bool clearCache); +static void data_initialize_task(sys::threadpool::JobData taskData); void data::launch_initialization(bool clearCache, std::function onDestruction) { - auto loadingState = DataLoadingState::create(s_context, onDestruction, data_initialize_task, clearCache); + auto taskData = std::make_shared(); + taskData->clearCache = clearCache; + + auto loadingState = DataLoadingState::create(s_context, onDestruction, data_initialize_task, taskData); StateManager::push_state(loadingState); } @@ -40,8 +51,12 @@ void data::get_title_info_by_type(FsSaveDataType saveType, data::TitleInfoList & s_context.get_title_info_list_by_type(saveType, listOut); } -static void data_initialize_task(sys::Task *task, bool clearCache) +static void data_initialize_task(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + sys::Task *task = castData->task; + const bool clearCache = castData->clearCache; + if (error::is_null(task)) { return; } const char *statusFinalizing = strings::get_by_name(strings::names::DATA_LOADING_STATUS, 6); diff --git a/source/fs/io.cpp b/source/fs/io.cpp index cae416e..b79b495 100644 --- a/source/fs/io.cpp +++ b/source/fs/io.cpp @@ -3,6 +3,7 @@ #include "error.hpp" #include "fs/SaveMetaData.hpp" #include "fslib.hpp" +#include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" #include "sys/sys.hpp" @@ -16,9 +17,9 @@ namespace { // Size of buffer shared between threads. - // constexpr size_t FILE_BUFFER_SIZE = 0x600000; + constexpr size_t SIZE_FILE_BUFFER = 0x600000; // This one is just for testing something. - constexpr size_t SIZE_FILE_BUFFER = 0x200000; + // constexpr size_t SIZE_FILE_BUFFER = 0x200000; } // namespace // clang-format off @@ -75,7 +76,7 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy if (task) { const std::string sourceString = source.string(); - const std::string status = stringutil::get_formatted_string(statusTemplate, sourceString.c_str()); + std::string status = stringutil::get_formatted_string(statusTemplate, sourceString.c_str()); task->set_status(status); task->reset(static_cast(sourceSize)); } @@ -110,6 +111,7 @@ void fs::copy_file(const fslib::Path &source, const fslib::Path &destination, sy } // This should be checked. Not sure how yet... destFile.write(localBuffer.get(), localRead); + i += localRead; if (task) { task->update_current(static_cast(i)); } } @@ -132,7 +134,7 @@ void fs::copy_file_commit(const fslib::Path &source, if (task) { const std::string sourceString = source.string(); - const std::string status = stringutil::get_formatted_string(copyingStatus, sourceString.c_str()); + std::string status = stringutil::get_formatted_string(copyingStatus, sourceString.c_str()); task->set_status(status); task->reset(static_cast(sourceSize)); } diff --git a/source/fs/zip.cpp b/source/fs/zip.cpp index f2aafbf..9ae30e5 100644 --- a/source/fs/zip.cpp +++ b/source/fs/zip.cpp @@ -139,7 +139,7 @@ void fs::copy_directory_to_zip(const fslib::Path &source, fs::MiniZip &dest, sys if (task) { - const std::string status = stringutil::get_formatted_string(ioStatus, sourceString.c_str()); + std::string status = stringutil::get_formatted_string(ioStatus, sourceString.c_str()); task->set_status(status); task->reset(static_cast(fileSize)); } @@ -216,7 +216,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, in if (task) { - const std::string status = stringutil::get_formatted_string(statusTemplate, fullDest.get_filename()); + std::string status = stringutil::get_formatted_string(statusTemplate, fullDest.get_filename()); task->set_status(status); task->reset(static_cast(fileSize)); } diff --git a/source/logging/logger.cpp b/source/logging/logger.cpp index b35806b..6b2f35e 100644 --- a/source/logging/logger.cpp +++ b/source/logging/logger.cpp @@ -34,7 +34,7 @@ void logger::log(const char *format, ...) noexcept { static std::mutex logLock{}; - std::array vaBuffer{}; + std::array vaBuffer = {0}; std::va_list vaList{}; va_start(vaList, format); vsnprintf(vaBuffer.data(), VA_BUFFER_SIZE, format, vaList); diff --git a/source/remote/GoogleDrive.cpp b/source/remote/GoogleDrive.cpp index 71df6d9..1771afc 100644 --- a/source/remote/GoogleDrive.cpp +++ b/source/remote/GoogleDrive.cpp @@ -292,7 +292,7 @@ bool remote::GoogleDrive::download_file(const remote::Item *file, const fslib::P if (!GoogleDrive::token_is_valid() && !GoogleDrive::refresh_token()) { return false; } const int64_t itemSize = file->get_size(); - fslib::File destFile{destination, FsOpenMode_Create | FsOpenMode_Write, itemSize}; + fslib::File destFile{destination, FsOpenMode_Create | FsOpenMode_Write}; if (!destFile) { logger::log("Error downloading file: local file could not be opened for writing!"); @@ -307,16 +307,19 @@ bool remote::GoogleDrive::download_file(const remote::Item *file, const fslib::P remote::URL url{URL_DRIVE_FILE_API}; url.append_path(file->get_id()).append_parameter("alt", "media"); - curl::DownloadStruct download{.dest = &destFile, .task = task, .fileSize = itemSize}; + auto download = std::make_shared(); + download->dest = &destFile; + download->task = task; + download->fileSize = itemSize; + curl::prepare_get(m_curl); curl::set_option(m_curl, CURLOPT_HTTPHEADER, header.get()); curl::set_option(m_curl, CURLOPT_URL, url.get()); curl::set_option(m_curl, CURLOPT_WRITEFUNCTION, curl::download_file_threaded); - curl::set_option(m_curl, CURLOPT_WRITEDATA, &download); + curl::set_option(m_curl, CURLOPT_WRITEDATA, download.get()); - std::thread writeThread(curl::download_write_thread_function, std::ref(download)); + sys::threadpool::push_job(curl::download_write_thread_function, download); if (!curl::perform(m_curl)) { return false; } - writeThread.join(); return true; } diff --git a/source/remote/WebDav.cpp b/source/remote/WebDav.cpp index 0922d0e..2420d73 100644 --- a/source/remote/WebDav.cpp +++ b/source/remote/WebDav.cpp @@ -202,21 +202,23 @@ bool remote::WebDav::download_file(const remote::Item *item, const fslib::Path & remote::URL url{m_origin}; url.append_path(item->get_id()); - curl::DownloadStruct download{.dest = &destFile, .task = task, .fileSize = itemSize}; + auto download = std::make_shared(); + download->dest = &destFile; + download->task = task; + download->fileSize = itemSize; + curl::reset_handle(m_curl); WebDav::append_credentials(); curl::set_option(m_curl, CURLOPT_HTTPGET, 1L); curl::set_option(m_curl, CURLOPT_URL, url.get()); curl::set_option(m_curl, CURLOPT_WRITEFUNCTION, curl::download_file_threaded); - curl::set_option(m_curl, CURLOPT_WRITEDATA, &download); - - std::thread writeThread{curl::download_write_thread_function, std::ref(download)}; - if (!curl::perform(m_curl)) { return false; } + curl::set_option(m_curl, CURLOPT_WRITEDATA, download.get()); // Copied from gd.cpp implementation. // TODO: Not sure how a thread helps if this parent waits here. // TODO: Read and understand what's actually happening before making comments on other's choices. - writeThread.join(); + sys::threadpool::push_job(curl::download_write_thread_function, download); + if (!curl::perform(m_curl)) { return false; } return true; } diff --git a/source/remote/remote.cpp b/source/remote/remote.cpp index 58d7a0e..131c04d 100644 --- a/source/remote/remote.cpp +++ b/source/remote/remote.cpp @@ -21,11 +21,19 @@ namespace /// @brief This is the single (for now) instance of a storage class. std::unique_ptr s_storage{}; + + // clang-format off + struct DriveStruct : sys::Task::DataStruct + { + remote::GoogleDrive *drive{}; + }; + // clang-format on + } // namespace // Declarations here. Definitions at bottom. /// @brief This is the thread function that handles logging into Google. -static void drive_sign_in(sys::Task *task, remote::GoogleDrive *drive); +static void drive_sign_in(sys::threadpool::JobData taskData); /// @brief This creates (if needed) the JKSV folder for Google Drive and sets it as the root. /// @param drive Pointer to the drive instance.. @@ -56,7 +64,10 @@ void remote::initialize_google_drive() remote::GoogleDrive *drive = static_cast(s_storage.get()); if (drive->sign_in_required()) { - TaskState::create_and_push(drive_sign_in, drive); + auto driveStruct = std::make_shared(); + driveStruct->drive = drive; + + TaskState::create_and_push(drive_sign_in, driveStruct); return; } @@ -92,10 +103,15 @@ remote::Storage *remote::get_remote_storage() noexcept return s_storage.get(); } -static void drive_sign_in(sys::Task *task, remote::GoogleDrive *drive) +static void drive_sign_in(sys::threadpool::JobData taskData) { static constexpr const char *STRING_ERROR_SIGNING_IN = "Error signing into Google Drive: %s"; + auto castData = std::static_pointer_cast(taskData); + + sys::Task *task = castData->task; + remote::GoogleDrive *drive = castData->drive; + const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; std::string message{}, deviceCode{}; std::time_t expiration{}; @@ -106,7 +122,7 @@ static void drive_sign_in(sys::Task *task, remote::GoogleDrive *drive) TASK_FINISH_RETURN(task); } - task->set_status(message.c_str()); + task->set_status(message); while (std::time(NULL) < expiration && !drive->poll_sign_in(deviceCode)) { diff --git a/source/stringutil.cpp b/source/stringutil.cpp index ef51e11..4b45971 100644 --- a/source/stringutil.cpp +++ b/source/stringutil.cpp @@ -66,7 +66,7 @@ bool stringutil::sanitize_string_for_path(const char *stringIn, char *stringOut, continue; } - const bool asciiCheck = codepoint < 0x0 || codepoint >= 0x7E; + const bool asciiCheck = codepoint < 0x1E || codepoint >= 0x7E; if (asciiCheck) { return false; } const bool isForbidden = std::find(FORBIDDEN_PATH_CHARACTERS.begin(), FORBIDDEN_PATH_CHARACTERS.end(), codepoint) != diff --git a/source/sys/ProgressTask.cpp b/source/sys/ProgressTask.cpp index f03c25e..00a9d33 100644 --- a/source/sys/ProgressTask.cpp +++ b/source/sys/ProgressTask.cpp @@ -1,5 +1,14 @@ #include "sys/ProgressTask.hpp" +#include "logging/logger.hpp" + +sys::ProgressTask::ProgressTask(sys::threadpool::JobFunction function, sys::ProgressTask::TaskData taskData) + : Task() +{ + taskData->task = this; + threadpool::push_job(function, taskData); +} + void sys::ProgressTask::reset(double goal) noexcept { m_current = 0; diff --git a/source/sys/Task.cpp b/source/sys/Task.cpp index 46180e5..f90ca3f 100644 --- a/source/sys/Task.cpp +++ b/source/sys/Task.cpp @@ -2,7 +2,15 @@ #include "logging/logger.hpp" -sys::Task::~Task() { m_thread.join(); } +sys::Task::Task() + : m_isRunning(true) {}; + +sys::Task::Task(sys::threadpool::JobFunction function, sys::Task::TaskData taskData) + : Task() +{ + taskData->task = this; + sys::threadpool::push_job(function, taskData); +} bool sys::Task::is_running() const noexcept { return m_isRunning; } @@ -14,6 +22,12 @@ void sys::Task::set_status(std::string_view status) m_status = status; } +void sys::Task::set_status(std::string &status) +{ + std::lock_guard statusGuard{m_statusLock}; + m_status = std::move(status); +} + std::string sys::Task::get_status() noexcept { std::lock_guard statusGuard{m_statusLock}; diff --git a/source/sys/threadpool.cpp b/source/sys/threadpool.cpp index 3ca1ac0..a0b6d41 100644 --- a/source/sys/threadpool.cpp +++ b/source/sys/threadpool.cpp @@ -44,7 +44,7 @@ void sys::threadpool::initialize() for (size_t i = 0; i < COUNT_THREADS; i++) { // NOTE: If pool size increases, i + 1 isn't going to work anymore. - error::libnx(threadCreate(&s_threads[i], thread_pool_function, nullptr, nullptr, SIZE_THREAD_STACK, 0x2B, i + 1)); + error::libnx(threadCreate(&s_threads[i], thread_pool_function, nullptr, nullptr, SIZE_THREAD_STACK, 0x2C, i + 1)); error::libnx(threadStart(&s_threads[i])); } } @@ -64,7 +64,7 @@ void sys::threadpool::push_job(sys::threadpool::JobFunction function, sys::threa { std::lock_guard jobGuard{s_jobMutex}; s_jobQueue.push(std::make_pair(function, data)); - s_jobCondition.notify_all(); + s_jobCondition.notify_one(); } static void thread_pool_function(void *) diff --git a/source/tasks/backup.cpp b/source/tasks/backup.cpp index d3a0e8a..0107983 100644 --- a/source/tasks/backup.cpp +++ b/source/tasks/backup.cpp @@ -26,13 +26,30 @@ static void write_meta_file(const fslib::Path &target, const FsSaveDataInfo *sav static void write_meta_zip(fs::MiniZip &zip, const FsSaveDataInfo *saveInfo); static fs::ScopedSaveMount create_scoped_mount(const FsSaveDataInfo *saveInfo); -void tasks::backup::create_new_backup_local(sys::ProgressTask *task, - data::User *user, - data::TitleInfo *titleInfo, - fslib::Path target, - BackupMenuState *spawningState, - bool killTask) +void tasks::backup::create_new_backup_local(sys::threadpool::JobData taskData) { + logger::log("create_new_backup_local"); + auto castData = std::static_pointer_cast(taskData); + logger::log("static_pointer_cast"); + + sys::ProgressTask *task = static_cast(castData->task); + logger::log("task"); + + data::User *user = castData->user; + logger::log("user"); + + data::TitleInfo *titleInfo = castData->titleInfo; + logger::log("titleInfo"); + + const fslib::Path &target = castData->path; + logger::log("path"); + + BackupMenuState *spawningState = castData->spawningState; + logger::log("spawningState"); + + const bool killTask = castData->killTask; + logger::log("casts & references"); + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } @@ -67,13 +84,17 @@ void tasks::backup::create_new_backup_local(sys::ProgressTask *task, if (killTask) { task->complete(); } } -void tasks::backup::create_new_backup_remote(sys::ProgressTask *task, - data::User *user, - data::TitleInfo *titleInfo, - std::string remoteName, - BackupMenuState *spawningState, - bool killTask) +void tasks::backup::create_new_backup_remote(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + const std::string &remoteName = castData->remoteName; + BackupMenuState *spawningState = castData->spawningState; + const bool &killTask = castData->killTask; + if (error::is_null(task)) { return; } remote::Storage *remote = remote::get_remote_storage(); @@ -103,7 +124,7 @@ void tasks::backup::create_new_backup_remote(sys::ProgressTask *task, { const char *uploadFormat = strings::get_by_name(strings::names::IO_STATUSES, 5); - const std::string status = stringutil::get_formatted_string(uploadFormat, remoteName.data()); + std::string status = stringutil::get_formatted_string(uploadFormat, remoteName.data()); task->set_status(status); } const bool uploaded = remote->upload_file(tempPath, remoteName, task); @@ -118,14 +139,17 @@ void tasks::backup::create_new_backup_remote(sys::ProgressTask *task, if (killTask) { task->complete(); } } -void tasks::backup::overwrite_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData) +void tasks::backup::overwrite_backup_local(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; - const fslib::Path &target = taskData->path; - BackupMenuState *spawningState = taskData->spawningState; + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + const fslib::Path &target = castData->path; + BackupMenuState *spawningState = castData->spawningState; + + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; @@ -138,17 +162,23 @@ void tasks::backup::overwrite_backup_local(sys::ProgressTask *task, BackupMenuSt ui::PopMessageManager::push_message(popTicks, popErrorDeleting); TASK_FINISH_RETURN(task); } - tasks::backup::create_new_backup_local(task, user, titleInfo, target, spawningState); + + castData->killTask = true; + tasks::backup::create_new_backup_local(castData); } -void tasks::backup::overwrite_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData) +void tasks::backup::overwrite_backup_remote(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + if (error::is_null(task)) { return; } - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; - remote::Item *target = taskData->remoteItem; - remote::Storage *remote = remote::get_remote_storage(); + remote::Item *target = castData->remoteItem; + remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(remote) || error::is_null(target)) { TASK_FINISH_RETURN(task); } const uint64_t applicationID = titleInfo->get_application_id(); @@ -171,7 +201,7 @@ void tasks::backup::overwrite_backup_remote(sys::ProgressTask *task, BackupMenuS { const char *targetName = target->get_name().data(); const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 5); - const std::string status = stringutil::get_formatted_string(statusFormat, targetName); + std::string status = stringutil::get_formatted_string(statusFormat, targetName); task->set_status(status); } remote->patch_file(target, tempPath, task); @@ -186,14 +216,17 @@ void tasks::backup::overwrite_backup_remote(sys::ProgressTask *task, BackupMenuS task->complete(); } -void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuState::TaskData taskData) +void tasks::backup::restore_backup_local(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; - const fslib::Path &target = taskData->path; - BackupMenuState *spawningState = taskData->spawningState; + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + const fslib::Path &target = castData->path; + BackupMenuState *spawningState = castData->spawningState; + + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } const uint64_t applicationID = titleInfo->get_application_id(); @@ -211,7 +244,7 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat const bool hasZipExt = std::strstr(targetString.c_str(), STRING_ZIP_EXT); const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - if (autoBackup) { auto_backup(task, taskData); } + if (autoBackup) { auto_backup(task, castData); } { auto scopedMount = create_scoped_mount(saveInfo); @@ -229,13 +262,13 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat TASK_FINISH_RETURN(task); } - read_and_process_meta(unzip, taskData, task); + read_and_process_meta(unzip, castData, task); auto scopedMount = create_scoped_mount(saveInfo); fs::copy_zip_to_directory(unzip, fs::DEFAULT_SAVE_ROOT, journalSize, task); } else if (isDir) { - read_and_process_meta(target, taskData, task); + read_and_process_meta(target, castData, task); auto scopedMount = create_scoped_mount(saveInfo); fs::copy_directory_commit(target, fs::DEFAULT_SAVE_ROOT, journalSize, task); } @@ -250,14 +283,18 @@ void tasks::backup::restore_backup_local(sys::ProgressTask *task, BackupMenuStat task->complete(); } -void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuState::TaskData taskData) +void tasks::backup::restore_backup_remote(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + BackupMenuState *spawningState = castData->spawningState; + remote::Storage *remote = remote::get_remote_storage(); + if (error::is_null(task)) { return; } - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; - remote::Storage *remote = remote::get_remote_storage(); - BackupMenuState *spawningState = taskData->spawningState; if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } const bool autoBackup = config::get_by_key(config::keys::AUTO_BACKUP_ON_RESTORE); @@ -265,7 +302,7 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta const FsSaveDataInfo *saveInfo = user->get_save_info_by_id(applicationID); if (error::is_null(saveInfo)) { TASK_FINISH_RETURN(task); } - if (autoBackup) { auto_backup(task, taskData); } + if (autoBackup) { auto_backup(task, castData); } { auto scopedMount = create_scoped_mount(saveInfo); @@ -274,12 +311,12 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - remote::Item *target = taskData->remoteItem; + remote::Item *target = castData->remoteItem; const fslib::Path tempPath{PATH_JKSV_TEMP}; { const char *name = target->get_name().data(); const char *downloadingFormat = strings::get_by_name(strings::names::IO_STATUSES, 4); - const std::string status = stringutil::get_formatted_string(downloadingFormat, name); + std::string status = stringutil::get_formatted_string(downloadingFormat, name); task->set_status(status); } @@ -311,7 +348,7 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta } } - read_and_process_meta(backup, taskData, task); + read_and_process_meta(backup, castData, task); { FsSaveDataExtraData extraData{}; const bool readExtra = fs::read_save_extra_data(saveInfo, extraData); @@ -333,19 +370,23 @@ void tasks::backup::restore_backup_remote(sys::ProgressTask *task, BackupMenuSta task->complete(); } -void tasks::backup::delete_backup_local(sys::Task *task, BackupMenuState::TaskData taskData) +void tasks::backup::delete_backup_local(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::Task *task = castData->task; + const fslib::Path &path = castData->path; + BackupMenuState *spawningState = castData->spawningState; + if (error::is_null(task)) { return; } - const fslib::Path &path = taskData->path; - BackupMenuState *spawningState = taskData->spawningState; if (error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; { const std::string pathString = path.string(); const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 3); - const std::string status = stringutil::get_formatted_string(statusFormat, pathString.c_str()); + std::string status = stringutil::get_formatted_string(statusFormat, pathString.c_str()); task->set_status(status); } @@ -374,13 +415,17 @@ void tasks::backup::delete_backup_local(sys::Task *task, BackupMenuState::TaskDa task->complete(); } -void tasks::backup::delete_backup_remote(sys::Task *task, BackupMenuState::TaskData taskData) +void tasks::backup::delete_backup_remote(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::Task *task = castData->task; + remote::Item *target = castData->remoteItem; + BackupMenuState *spawningState = castData->spawningState; + remote::Storage *remote = remote::get_remote_storage(); + if (error::is_null(task)) { return; } - remote::Item *target = taskData->remoteItem; - BackupMenuState *spawningState = taskData->spawningState; - remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(target) || error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; @@ -402,19 +447,23 @@ void tasks::backup::delete_backup_remote(sys::Task *task, BackupMenuState::TaskD task->complete(); } -void tasks::backup::upload_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData) +void tasks::backup::upload_backup(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::ProgressTask *task = static_cast(castData->task); + const fslib::Path &path = castData->path; + BackupMenuState *spawningState = castData->spawningState; + remote::Storage *remote = remote::get_remote_storage(); + if (error::is_null(task)) { return; } - const fslib::Path &path = taskData->path; - BackupMenuState *spawningState = taskData->spawningState; - remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } { const char *filename = path.get_filename(); const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 5); - const std::string status = stringutil::get_formatted_string(statusFormat, filename); + std::string status = stringutil::get_formatted_string(statusFormat, filename); task->set_status(status); } @@ -424,20 +473,23 @@ void tasks::backup::upload_backup(sys::ProgressTask *task, BackupMenuState::Task task->complete(); } -void tasks::backup::patch_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskData) +void tasks::backup::patch_backup(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::ProgressTask *task = static_cast(castData->task); + const fslib::Path &path = castData->path; + remote::Item *remoteItem = castData->remoteItem; + BackupMenuState *spawningState = castData->spawningState; + remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(task)) { return; } - const fslib::Path &path = taskData->path; - remote::Item *remoteItem = taskData->remoteItem; - BackupMenuState *spawningState = taskData->spawningState; - remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(spawningState) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } { const char *filename = path.get_filename(); const char *statusFormat = strings::get_by_name(strings::names::IO_STATUSES, 5); - const std::string status = stringutil::get_formatted_string(statusFormat, filename); + std::string status = stringutil::get_formatted_string(statusFormat, filename); task->set_status(status); } @@ -474,10 +526,8 @@ static void auto_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskD std::string backupName = stringutil::get_formatted_string("AUTO - %s - %s", safeNickname, dateString.c_str()); if (zip) { backupName += STRING_ZIP_EXT; } - if (autoUpload && remote) - { - tasks::backup::create_new_backup_remote(task, user, titleInfo, backupName, spawningState, false); - } + taskData->killTask = false; + if (autoUpload && remote) { tasks::backup::create_new_backup_remote(taskData); } else { // We're going to get the target dir from the path passed. @@ -485,7 +535,7 @@ static void auto_backup(sys::ProgressTask *task, BackupMenuState::TaskData taskD if (lastSlash == target.NOT_FOUND) { return; } fslib::Path autoTarget{target.sub_path(lastSlash) / backupName}; - tasks::backup::create_new_backup_local(task, user, titleInfo, autoTarget, spawningState, false); + tasks::backup::create_new_backup_local(taskData); } } diff --git a/source/tasks/fileoptions.cpp b/source/tasks/fileoptions.cpp index 9400b72..76fb34c 100644 --- a/source/tasks/fileoptions.cpp +++ b/source/tasks/fileoptions.cpp @@ -4,18 +4,23 @@ #include "error.hpp" #include "fs/fs.hpp" #include "fslib.hpp" +#include "logging/logger.hpp" #include "strings/strings.hpp" #include "stringutil.hpp" -void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, FileOptionState::TaskData taskData) +void tasks::fileoptions::copy_source_to_destination(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + + auto castData = std::static_pointer_cast(taskData); const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; - const fslib::Path &source = taskData->sourcePath; - const fslib::Path &dest = taskData->destPath; - const int64_t journalSpace = taskData->journalSize; - FileOptionState *spawningState = taskData->spawningState; + sys::ProgressTask *task = static_cast(castData->task); + const fslib::Path &source = castData->sourcePath; + const fslib::Path &dest = castData->destPath; + const int64_t journalSpace = castData->journalSize; + FileOptionState *spawningState = castData->spawningState; + + if (error::is_null(task)) { return; } const bool sourceIsDir = fslib::directory_exists(source); bool destError = false; @@ -33,7 +38,7 @@ void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, Fil if (destError) { const char *errorFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 0); - const std::string pop = stringutil::get_formatted_string(errorFormat, source.get_filename()); + std::string pop = stringutil::get_formatted_string(errorFormat, source.get_filename()); ui::PopMessageManager::push_message(popTicks, pop); TASK_FINISH_RETURN(task); } @@ -49,8 +54,15 @@ void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, Fil task->complete(); } -void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskData taskData) +void tasks::fileoptions::delete_target(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::Task *task = castData->task; + const fslib::Path &target = castData->sourcePath; + const int64_t journalSpace = castData->journalSize; + FileOptionState *spawningState = castData->spawningState; + if (error::is_null(task)) { return; } // Gonna borrow this. No point in duplicating it. @@ -58,13 +70,9 @@ void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskDat const char *deletingFormat = strings::get_by_name(strings::names::IO_STATUSES, 3); const char *errorFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 1); - const fslib::Path &target = taskData->sourcePath; - const int64_t journalSpace = taskData->journalSize; - FileOptionState *spawningState = taskData->spawningState; - { - const char *filename = target.get_filename(); - const std::string status = stringutil::get_formatted_string(deletingFormat, filename); + const char *filename = target.get_filename(); + std::string status = stringutil::get_formatted_string(deletingFormat, filename); task->set_status(status); } @@ -77,16 +85,16 @@ void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskDat if (deleteError) { - const char *filename = target.get_filename(); - const std::string pop = stringutil::get_formatted_string(errorFormat, filename); + const char *filename = target.get_filename(); + std::string pop = stringutil::get_formatted_string(errorFormat, filename); ui::PopMessageManager::push_message(popTicks, pop); } const bool commitError = needsCommit && error::fslib(fslib::commit_data_to_file_system(target.get_device_name())); if (commitError) { - const char *filename = target.get_filename(); - const std::string pop = stringutil::get_formatted_string(errorFormat, filename); + const char *filename = target.get_filename(); + std::string pop = stringutil::get_formatted_string(errorFormat, filename); ui::PopMessageManager::push_message(popTicks, pop); } diff --git a/source/tasks/mainmenu.cpp b/source/tasks/mainmenu.cpp index b53c636..c9d5b17 100644 --- a/source/tasks/mainmenu.cpp +++ b/source/tasks/mainmenu.cpp @@ -8,15 +8,24 @@ #include "stringutil.hpp" #include "tasks/backup.hpp" -void tasks::mainmenu::backup_all_for_all_local(sys::ProgressTask *task, MainMenuState::TaskData taskData) +void tasks::mainmenu::backup_all_for_all_local(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); + sys::ProgressTask *task = static_cast(castData->task); + data::UserList &userList = castData->userList; const bool exportZip = config::get_by_key(config::keys::EXPORT_TO_ZIP); - data::UserList &userList = taskData->userList; + // This is to pass and use the already written backup function. + auto backupStruct = std::make_shared(); + backupStruct->task = castData->task; + backupStruct->killTask = false; // Just to be sure. + + if (error::is_null(task)) { return; } for (data::User *user : userList) { + backupStruct->user = user; + const int64_t titleCount = user->get_total_data_entries(); for (int64_t i = 0; i < titleCount; i++) { @@ -34,6 +43,7 @@ void tasks::mainmenu::backup_all_for_all_local(sys::ProgressTask *task, MainMenu data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID); if (error::is_null(titleInfo)) { continue; } + backupStruct->titleInfo = titleInfo; const fslib::Path workDir{config::get_working_directory()}; const fslib::Path targetDir{workDir / titleInfo->get_path_safe_title()}; const bool exists = fslib::directory_exists(targetDir); @@ -42,7 +52,7 @@ void tasks::mainmenu::backup_all_for_all_local(sys::ProgressTask *task, MainMenu const char *pathSafe = user->get_path_safe_nickname(); const std::string dateString = stringutil::get_date_string(); - std::string name = stringutil::get_formatted_string("%s - %s", pathSafe, dateString.c_str()); + const std::string name = stringutil::get_formatted_string("%s - %s", pathSafe, dateString.c_str()); fslib::Path finalTarget{targetDir / name}; if (exportZip) { finalTarget += ".zip"; } else @@ -51,23 +61,32 @@ void tasks::mainmenu::backup_all_for_all_local(sys::ProgressTask *task, MainMenu if (createError) { continue; } } - tasks::backup::create_new_backup_local(task, user, titleInfo, finalTarget, nullptr, false); + backupStruct->path = std::move(finalTarget); + tasks::backup::create_new_backup_local(backupStruct); } } task->complete(); } -void tasks::mainmenu::backup_all_for_all_remote(sys::ProgressTask *task, MainMenuState::TaskData taskData) +void tasks::mainmenu::backup_all_for_all_remote(sys::threadpool::JobData taskData) { + auto castData = std::static_pointer_cast(taskData); + + sys::ProgressTask *task = static_cast(castData->task); if (error::is_null(task)) { return; } remote::Storage *remote = remote::get_remote_storage(); if (error::is_null(remote)) { TASK_FINISH_RETURN(task); } - const data::UserList &userList = taskData->userList; + auto backupStruct = std::make_shared(); + backupStruct->task = task; + backupStruct->killTask = false; + + const data::UserList &userList = castData->userList; for (data::User *user : userList) { if (user->get_account_save_type() == FsSaveDataType_System) { continue; } + backupStruct->user = user; const int64_t titleCount = user->get_total_data_entries(); for (int64_t i = 0; i < titleCount; i++) @@ -84,6 +103,7 @@ void tasks::mainmenu::backup_all_for_all_remote(sys::ProgressTask *task, MainMen data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID); if (error::is_null(titleInfo)) { continue; } + backupStruct->titleInfo = titleInfo; const std::string_view remoteTitle = remote->supports_utf8() ? titleInfo->get_title() : titleInfo->get_path_safe_title(); const bool exists = remote->directory_exists(remoteTitle); @@ -95,9 +115,10 @@ void tasks::mainmenu::backup_all_for_all_remote(sys::ProgressTask *task, MainMen const char *pathSafe = user->get_path_safe_nickname(); const std::string dateString = stringutil::get_date_string(); - const std::string remoteName = stringutil::get_formatted_string("%s - %s.zip", pathSafe, dateString.c_str()); + std::string remoteName = stringutil::get_formatted_string("%s - %s.zip", pathSafe, dateString.c_str()); + backupStruct->remoteName = std::move(remoteName); - tasks::backup::create_new_backup_remote(task, user, titleInfo, remoteName, nullptr, false); + tasks::backup::create_new_backup_remote(backupStruct); remote->return_to_root(); } } diff --git a/source/tasks/savecreate.cpp b/source/tasks/savecreate.cpp index 876549e..65bc345 100644 --- a/source/tasks/savecreate.cpp +++ b/source/tasks/savecreate.cpp @@ -6,11 +6,15 @@ #include "stringutil.hpp" #include "ui/PopMessageManager.hpp" -void tasks::savecreate::create_save_data_for(sys::Task *task, - data::User *user, - data::TitleInfo *titleInfo, - SaveCreateState *spawningState) +void tasks::savecreate::create_save_data_for(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; + if (error::is_null(task) || error::is_null(user) || error::is_null(titleInfo) || error::is_null(spawningState)) { return; } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; @@ -20,7 +24,7 @@ void tasks::savecreate::create_save_data_for(sys::Task *task, const char *title = titleInfo->get_title(); { - const std::string status = stringutil::get_formatted_string(statusFormat, title); + std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } @@ -28,7 +32,7 @@ void tasks::savecreate::create_save_data_for(sys::Task *task, if (!saveCreated) { ui::PopMessageManager::push_message(popTicks, popFailed); } else { - const std::string popMessage = stringutil::get_formatted_string(popSuccess, title); + std::string popMessage = stringutil::get_formatted_string(popSuccess, title); ui::PopMessageManager::push_message(popTicks, popMessage); spawningState->refresh_required(); } diff --git a/source/tasks/titleoptions.cpp b/source/tasks/titleoptions.cpp index 263564a..b678e64 100644 --- a/source/tasks/titleoptions.cpp +++ b/source/tasks/titleoptions.cpp @@ -13,12 +13,15 @@ #include -void tasks::titleoptions::blacklist_title(sys::Task *task, TitleOptionState::TaskData taskData) +void tasks::titleoptions::blacklist_title(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::TitleInfo *titleInfo = taskData->titleInfo; - TitleOptionState *spawningState = taskData->spawningState; + sys::Task *task = castData->task; + data::TitleInfo *titleInfo = castData->titleInfo; + TitleOptionState *spawningState = castData->spawningState; + + if (error::is_null(task)) { return; } if (error::is_null(titleInfo) || error::is_null(spawningState)) { task->complete(); @@ -39,11 +42,14 @@ void tasks::titleoptions::blacklist_title(sys::Task *task, TitleOptionState::Tas task->complete(); } -void tasks::titleoptions::delete_all_local_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData) +void tasks::titleoptions::delete_all_local_backups_for_title(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::TitleInfo *titleInfo = taskData->titleInfo; + sys::Task *task = castData->task; + data::TitleInfo *titleInfo = castData->titleInfo; + + if (error::is_null(task)) { return; } if (error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; @@ -53,7 +59,7 @@ void tasks::titleoptions::delete_all_local_backups_for_title(sys::Task *task, Ti { const char *title = titleInfo->get_title(); const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 0); - const std::string status = stringutil::get_formatted_string(statusFormat, title); + std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } @@ -66,20 +72,23 @@ void tasks::titleoptions::delete_all_local_backups_for_title(sys::Task *task, Ti if (deleteFailed) { ui::PopMessageManager::push_message(popTicks, popFailure); } else { - const char *title = titleInfo->get_title(); - const std::string popMessage = stringutil::get_formatted_string(popSuccess, title); + const char *title = titleInfo->get_title(); + std::string popMessage = stringutil::get_formatted_string(popSuccess, title); ui::PopMessageManager::push_message(popTicks, popMessage); } task->complete(); } -void tasks::titleoptions::delete_all_remote_backups_for_title(sys::Task *task, TitleOptionState::TaskData taskData) +void tasks::titleoptions::delete_all_remote_backups_for_title(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::TitleInfo *titleInfo = taskData->titleInfo; + sys::Task *task = castData->task; + data::TitleInfo *titleInfo = castData->titleInfo; remote::Storage *remote = remote::get_remote_storage(); + + if (error::is_null(task)) { return; } if (error::is_null(titleInfo) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } const char *title = titleInfo->get_title(); @@ -95,7 +104,7 @@ void tasks::titleoptions::delete_all_remote_backups_for_title(sys::Task *task, T { const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 0); - const std::string status = stringutil::get_formatted_string(statusFormat, title); + std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } @@ -110,17 +119,19 @@ void tasks::titleoptions::delete_all_remote_backups_for_title(sys::Task *task, T remote->return_to_root(); - const std::string popMessage = stringutil::get_formatted_string(popSuccess, title); + std::string popMessage = stringutil::get_formatted_string(popSuccess, title); ui::PopMessageManager::push_message(popTicks, popMessage); task->complete(); } -void tasks::titleoptions::reset_save_data(sys::Task *task, TitleOptionState::TaskData taskData) +void tasks::titleoptions::reset_save_data(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; + sys::Task *task = castData->task; + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } const uint64_t applicationID = titleInfo->get_application_id(); @@ -134,7 +145,7 @@ void tasks::titleoptions::reset_save_data(sys::Task *task, TitleOptionState::Tas { const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 1); const char *title = titleInfo->get_title(); - const std::string status = stringutil::get_formatted_string(statusFormat, title); + std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } @@ -149,14 +160,16 @@ void tasks::titleoptions::reset_save_data(sys::Task *task, TitleOptionState::Tas task->complete(); } -void tasks::titleoptions::delete_save_data_from_system(sys::Task *task, TitleOptionState::TaskData taskData) +void tasks::titleoptions::delete_save_data_from_system(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; - TitleSelectCommon *titleSelect = taskData->titleSelect; - TitleOptionState *spawningState = taskData->spawningState; + sys::Task *task = castData->task; + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + TitleSelectCommon *titleSelect = castData->titleSelect; + TitleOptionState *spawningState = castData->spawningState; + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo) || error::is_null(titleSelect) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); @@ -171,7 +184,7 @@ void tasks::titleoptions::delete_save_data_from_system(sys::Task *task, TitleOpt const char *statusFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 2); const char *nickname = user->get_nickname(); const char *title = titleInfo->get_title(); - const std::string status = stringutil::get_formatted_string(statusFormat, nickname, title); + std::string status = stringutil::get_formatted_string(statusFormat, nickname, title); task->set_status(status); } @@ -180,12 +193,7 @@ void tasks::titleoptions::delete_save_data_from_system(sys::Task *task, TitleOpt { const char *popError = strings::get_by_name(strings::names::SAVECREATE_POPS, 2); ui::PopMessageManager::push_message(popTicks, popError); - } - else - { - const char *title = titleInfo->get_title(); - const char *popSuccessFormat = strings::get_by_name(strings::names::SAVECREATE_POPS, 0); - const std::string popMessage = stringutil::get_formatted_string(popSuccessFormat, title); + return; } user->erase_save_info_by_id(applicationID); @@ -194,14 +202,16 @@ void tasks::titleoptions::delete_save_data_from_system(sys::Task *task, TitleOpt task->complete(); } -void tasks::titleoptions::extend_save_data(sys::Task *task, TitleOptionState::TaskData taskData) +void tasks::titleoptions::extend_save_data(sys::threadpool::JobData taskData) { static constexpr int SIZE_MB = 0x100000; - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - data::TitleInfo *titleInfo = taskData->titleInfo; + sys::Task *task = castData->task; + data::User *user = castData->user; + data::TitleInfo *titleInfo = castData->titleInfo; + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(titleInfo)) { TASK_FINISH_RETURN(task); } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; @@ -224,7 +234,7 @@ void tasks::titleoptions::extend_save_data(sys::Task *task, TitleOptionState::Ta const char *nickname = user->get_nickname(); const char *title = titleInfo->get_title(); const char *extendingFormat = strings::get_by_name(strings::names::TITLEOPTION_STATUS, 3); - const std::string status = stringutil::get_formatted_string(extendingFormat, nickname, title); + std::string status = stringutil::get_formatted_string(extendingFormat, nickname, title); task->set_status(status); } diff --git a/source/tasks/useroptions.cpp b/source/tasks/useroptions.cpp index 1e3fb8e..de2be8e 100644 --- a/source/tasks/useroptions.cpp +++ b/source/tasks/useroptions.cpp @@ -9,13 +9,21 @@ #include "tasks/backup.hpp" #include "ui/ui.hpp" -void tasks::useroptions::backup_all_for_user_local(sys::ProgressTask *task, UserOptionState::TaskData taskData) +void tasks::useroptions::backup_all_for_user_local(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; + + if (error::is_null(task)) { return; } if (error::is_null(user)) { TASK_FINISH_RETURN(task); } + auto backupStruct = std::make_shared(); + backupStruct->task = task; + backupStruct->user = user; + backupStruct->killTask = false; + const fslib::Path workDir{config::get_working_directory()}; const bool exportToZip = config::get_by_key(config::keys::EXPORT_TO_ZIP); const int titleCount = user->get_total_data_entries(); @@ -31,6 +39,7 @@ void tasks::useroptions::backup_all_for_user_local(sys::ProgressTask *task, User data::TitleInfo *titleInfo = data::get_title_info_by_id(saveInfo->application_id); if (error::is_null(titleInfo)) { continue; } + backupStruct->titleInfo = titleInfo; const fslib::Path targetDir{workDir / titleInfo->get_path_safe_title()}; const bool targetExists = fslib::directory_exists(targetDir); @@ -48,19 +57,27 @@ void tasks::useroptions::backup_all_for_user_local(sys::ProgressTask *task, User if (createError) { continue; } } - tasks::backup::create_new_backup_local(task, user, titleInfo, finalTarget, nullptr, false); + backupStruct->path = std::move(finalTarget); + tasks::backup::create_new_backup_local(backupStruct); } task->complete(); } -void tasks::useroptions::backup_all_for_user_remote(sys::ProgressTask *task, UserOptionState::TaskData taskData) +void tasks::useroptions::backup_all_for_user_remote(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; + sys::ProgressTask *task = static_cast(castData->task); + data::User *user = castData->user; remote::Storage *remote = remote::get_remote_storage(); + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(remote)) { TASK_FINISH_RETURN(task); } + auto backupStruct = std::make_shared(); + backupStruct->task = task; + backupStruct->user = user; + backupStruct->killTask = false; + const int titleCount = user->get_total_data_entries(); for (int i = 0; i < titleCount; i++) { @@ -75,6 +92,7 @@ void tasks::useroptions::backup_all_for_user_remote(sys::ProgressTask *task, Use data::TitleInfo *titleInfo = data::get_title_info_by_id(saveInfo->application_id); if (error::is_null(saveInfo)) { continue; } + backupStruct->titleInfo = titleInfo; const std::string_view remoteTitle = remote->supports_utf8() ? titleInfo->get_title() : titleInfo->get_path_safe_title(); const bool dirExists = remote->directory_exists(remoteTitle); @@ -85,21 +103,23 @@ void tasks::useroptions::backup_all_for_user_remote(sys::ProgressTask *task, Use remote->change_directory(target); const std::string dateString = stringutil::get_date_string(); - const std::string remoteName = - stringutil::get_formatted_string("%s - %s.zip", user->get_nickname(), dateString.c_str()); - tasks::backup::create_new_backup_remote(task, user, titleInfo, remoteName, nullptr, false); + + backupStruct->remoteName = stringutil::get_formatted_string("%s - %s.zip", user->get_nickname(), dateString.c_str()); + tasks::backup::create_new_backup_remote(backupStruct); remote->return_to_root(); } task->complete(); } -void tasks::useroptions::create_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData) +void tasks::useroptions::create_all_save_data_for_user(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - UserOptionState *spawningState = taskData->spawningState; + sys::Task *task = castData->task; + data::User *user = castData->user; + UserOptionState *spawningState = castData->spawningState; + if (error::is_null(task)) { return; } if (error::is_null(user) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } data::TitleInfoList infoList{}; @@ -116,14 +136,14 @@ void tasks::useroptions::create_all_save_data_for_user(sys::Task *task, UserOpti if (!hasSaveType) { continue; } { - const std::string status = stringutil::get_formatted_string(statusFormat, title); + std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } const bool saveCreated = fs::create_save_data_for(user, titleInfo); if (!saveCreated) { - const std::string popMessage = stringutil::get_formatted_string(popFailure, title); + std::string popMessage = stringutil::get_formatted_string(popFailure, title); ui::PopMessageManager::push_message(popTicks, popMessage); } } @@ -132,14 +152,18 @@ void tasks::useroptions::create_all_save_data_for_user(sys::Task *task, UserOpti task->complete(); } -void tasks::useroptions::delete_all_save_data_for_user(sys::Task *task, UserOptionState::TaskData taskData) +void tasks::useroptions::delete_all_save_data_for_user(sys::threadpool::JobData taskData) { - if (error::is_null(task)) { return; } + auto castData = std::static_pointer_cast(taskData); - data::User *user = taskData->user; - UserOptionState *spawningState = taskData->spawningState; - if (error::is_null(user) || error::is_null(spawningState)) { TASK_FINISH_RETURN(task); } - if (user->get_account_save_type() == FsSaveDataType_System) { TASK_FINISH_RETURN(task); } + sys::Task *task = castData->task; + data::User *user = castData->user; + UserOptionState *spawningState = castData->spawningState; + if (error::is_null(task)) { return; } + if (error::is_null(user) || error::is_null(spawningState) || user->get_account_save_type() == FsSaveDataType_System) + { + TASK_FINISH_RETURN(task); + } const int popTicks = ui::PopMessageManager::DEFAULT_TICKS; const char *statusFormat = strings::get_by_name(strings::names::USEROPTION_STATUS, 1); @@ -156,7 +180,7 @@ void tasks::useroptions::delete_all_save_data_for_user(sys::Task *task, UserOpti { data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID); const char *title = titleInfo->get_title(); - const std::string status = stringutil::get_formatted_string(statusFormat, title); + std::string status = stringutil::get_formatted_string(statusFormat, title); task->set_status(status); } diff --git a/source/ui/Menu.cpp b/source/ui/Menu.cpp index e845031..26d48f6 100644 --- a/source/ui/Menu.cpp +++ b/source/ui/Menu.cpp @@ -11,7 +11,7 @@ ui::Menu::Menu(int x, int y, int width, int fontSize, int renderTargetHeight) : m_x(x) , m_y(y) - , m_optionHeight(std::round(static_cast(fontSize) * 1.8f)) + , m_optionHeight(std::floor(static_cast(fontSize) * 1.8f)) , m_optionTarget( sdl::TextureManager::load("MENU_" + std::to_string(sm_menuID++), width, m_optionHeight, SDL_TEXTUREACCESS_TARGET)) , m_boundingBox(ui::BoundingBox::create(0, 0, width + 12, m_optionHeight + 12)) @@ -75,6 +75,12 @@ void ui::Menu::add_option(std::string_view newOption) m_options.push_back(newOption.data()); } +void ui::Menu::add_option(std::string &newOption) +{ + if (m_options.empty()) { m_optionScroll->set_text(newOption, false); } + m_options.push_back(std::move(newOption)); +} + void ui::Menu::edit_option(int index, std::string_view newOption) { const int optionSize = m_options.size(); @@ -95,10 +101,14 @@ void ui::Menu::set_y(int y) noexcept { m_y = y; } void ui::Menu::set_width(int width) noexcept { m_width = width; } -void ui::Menu::reset() +void ui::Menu::reset(bool full) { - m_selected = 0; - m_y = m_originalY; + if (full) + { + m_selected = 0; + m_y = m_originalY; + } + m_options.clear(); } diff --git a/source/ui/PopMessage.cpp b/source/ui/PopMessage.cpp index 816a59b..01ae179 100644 --- a/source/ui/PopMessage.cpp +++ b/source/ui/PopMessage.cpp @@ -16,6 +16,17 @@ ui::PopMessage::PopMessage(int ticks, std::string_view message) PopMessage::PERMA_HEIGHT, ui::DialogBox::Type::Light)) {}; +ui::PopMessage::PopMessage(int ticks, std::string &message) + : m_ticks(ticks) + , m_message(std::move(message)) + , m_y(PopMessage::START_Y) + , m_width(PopMessage::START_WIDTH) + , m_dialog(ui::DialogBox::create(PopMessage::START_X, + m_y - 6, + PopMessage::START_WIDTH, + PopMessage::PERMA_HEIGHT, + ui::DialogBox::Type::Light)) {}; + void ui::PopMessage::update(double targetY) { update_y(targetY); diff --git a/source/ui/PopMessageManager.cpp b/source/ui/PopMessageManager.cpp index c2001eb..2238457 100644 --- a/source/ui/PopMessageManager.cpp +++ b/source/ui/PopMessageManager.cpp @@ -86,3 +86,26 @@ void ui::PopMessageManager::push_message(int displayTicks, std::string_view mess auto queuePair = std::make_pair(displayTicks, std::string{message}); messageQueue.push_back(std::move(queuePair)); } + +void ui::PopMessageManager::push_message(int displayTicks, std::string &message) +{ + PopMessageManager &manager = PopMessageManager::get_instance(); + std::mutex &queueMutex = manager.m_queueMutex; + std::mutex &messageMutex = manager.m_messageMutex; + auto &messageQueue = manager.m_messageQueue; + auto &messages = manager.m_messages; + + { + std::lock_guard messageGuard{messageMutex}; + if (!messages.empty()) + { + ui::PopMessage &back = messages.back(); + const std::string_view lastMessage = back.get_message(); + if (lastMessage == message) { return; } + } + } + + std::lock_guard queueGuard(queueMutex); + auto queuePair = std::make_pair(displayTicks, std::move(message)); + messageQueue.push_back(std::move(queuePair)); +}