Thread pooled & fslib update.

This commit is contained in:
J-D-K 2025-09-16 17:59:33 -04:00
parent 30a607a9e1
commit 3c54474e5b
63 changed files with 694 additions and 466 deletions

@ -1 +1 @@
Subproject commit 995054e0d28ca9d4bf5134b10493ecebb51a7ab9
Subproject commit 382c7d490a68e4897fdc7d1ba37ac6e49cd6ac0e

View File

@ -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<BackupMenuState::DataStruct>;
private:

View File

@ -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 <typename TaskType, typename StateType, typename StructType>
template <typename TaskType, typename StateType>
class ConfirmState final : public BaseState
{
public:
/// @brief All functions passed to this state need to follow this signature: void function(<TaskType> *,
/// std::shared_ptr<<StructType>>)
using TaskFunction = void (*)(TaskType *, std::shared_ptr<StructType>);
/// @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<StructType> 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<StructType> 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<ConfirmState> create(std::string_view query,
bool holdRequired,
TaskFunction function,
std::shared_ptr<StructType> dataStruct)
sys::threadpool::JobFunction function,
sys::Task::TaskData taskData)
{
return std::make_shared<ConfirmState>(query, holdRequired, function, dataStruct);
return std::make_shared<ConfirmState>(query, holdRequired, function, taskData);
}
/// @brief Creates and returns a new ConfirmState and pushes it.
static inline std::shared_ptr<ConfirmState> create_and_push(std::string_view query,
bool holdRequired,
TaskFunction function,
std::shared_ptr<StructType> 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<ConfirmState> create_push_fade(std::string_view query,
bool holdRequired,
TaskFunction function,
std::shared_ptr<StructType> 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<StructType> m_dataStruct{};
const sys::Task::TaskData m_taskData{};
static inline std::shared_ptr<ui::DialogBox> sm_dialog{};
@ -188,8 +187,8 @@ class ConfirmState final : public BaseState
void confirmed()
{
auto newState = std::make_shared<StateType>(m_function, m_dataStruct);
StateManager::push_state(newState);
// auto newState = std::make_shared<StateType>(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<sys::Task, TaskState>;
using ConfirmProgress = ConfirmState<sys::ProgressTask, ProgressState>;

View File

@ -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<void()>;
template <typename... Args>
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<sys::Task>(function, std::forward<Args>(args)...);
}
sys::threadpool::JobFunction function,
sys::Task::TaskData taskData);
template <typename... Args>
static inline std::shared_ptr<DataLoadingState> 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<DataLoadingState>(context, destructFunction, function, std::forward<Args>(args)...);
return std::make_shared<DataLoadingState>(context, destructFunction, function, taskData);
}
template <typename... Args>
static inline std::shared_ptr<DataLoadingState> 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>(args)...);
auto newState = DataLoadingState::create(context, destructFunction, function, taskData);
StateManager::push_state(newState);
return newState;
}

View File

@ -3,6 +3,7 @@
#include "appstates/BaseState.hpp"
#include "appstates/FileModeState.hpp"
#include "fslib.hpp"
#include "sys/sys.hpp"
#include "ui/ui.hpp"
#include <atomic>
@ -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<FileOptionState::DataStruct>;
private:
/// @brief Pointer to spawning FileMode state.
FileModeState *m_spawningState{};

View File

@ -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<MainMenuState::DataStruct>;
private:
/// @brief Render target this state renders to.
sdl::SharedTexture m_renderTarget{};
@ -70,7 +68,7 @@ class MainMenuState final : public BaseState
std::shared_ptr<ui::ControlGuide> m_controlGuide{};
/// @brief This is the data struct passed to tasks.
MainMenuState::TaskData m_dataStruct{};
std::shared_ptr<MainMenuState::DataStruct> m_dataStruct{};
/// @brief Records the size of the sm_users vector.
static inline int sm_userCount{};

View File

@ -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 *, <arguments>)
template <typename... Args>
ProgressState(void (*function)(sys::ProgressTask *, Args...), Args... args)
: BaseTask()
{
ProgressState::initialize_static_members();
m_task = std::make_unique<sys::ProgressTask>(function, std::forward<Args>(args)...);
}
ProgressState(sys::threadpool::JobFunction function, sys::Task::TaskData taskData);
/// @brief Creates and returns a new progress state.
template <typename... Args>
static inline std::shared_ptr<ProgressState> create(void (*function)(sys::ProgressTask *, Args...), Args... args)
/// @brief Creates and returns a new ProgressState
static inline std::shared_ptr<ProgressState> create(sys::threadpool::JobFunction function, sys::Task::TaskData taskData)
{
return std::make_shared<ProgressState>(function, std::forward<Args>(args)...);
return std::make_shared<ProgressState>(function, taskData);
}
/// @brief Creates, pushes, then returns a new ProgressState.
template <typename... Args>
static inline std::shared_ptr<ProgressState> create_and_push(void (*function)(sys::ProgressTask *, Args...),
Args... args)
static inline std::shared_ptr<ProgressState> create_and_push(sys::threadpool::JobFunction function,
sys::Task::TaskData taskData)
{
auto newState = ProgressState::create(function, std::forward<Args>(args)...);
auto newState = ProgressState::create(function, taskData);
StateManager::push_state(newState);
return newState;
}

View File

@ -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<bool> m_refreshRequired{};
/// @brief Data struct passed to the task.
std::shared_ptr<SaveCreateState::DataStruct> 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<ui::SlideOutPanel> 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();

View File

@ -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 *, <arguments>)
template <typename... Args>
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<TaskState> create(sys::threadpool::JobFunction function, sys::Task::TaskData taskData)
{
m_task = std::make_unique<sys::Task>(function, std::forward<Args>(args)...);
return std::make_shared<TaskState>(function, taskData);
}
/// @brief Creates and returns a new TaskState.
template <typename... Args>
static inline std::shared_ptr<TaskState> create(void (*function)(sys::Task *, Args...), Args... args)
/// @brief Constructs, pushes, then returns a new TaskState.
static inline std::shared_ptr<TaskState> create_and_push(sys::threadpool::JobFunction function,
sys::Task::TaskData taskData)
{
return std::make_shared<TaskState>(function, std::forward<Args>(args)...);
}
/// @brief Creates, pushes, then returns and new TaskState.
template <typename... Args>
static inline std::shared_ptr<TaskState> create_and_push(void (*function)(sys::Task *, Args...), Args... args)
{
auto newState = TaskState::create(function, std::forward<Args>(args)...);
auto newState = TaskState::create(function, taskData);
StateManager::push_state(newState);
return newState;
}

View File

@ -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<TitleOptionState::DataStruct>;
private:
/// @brief This is just in case the option should only apply to the current user.
data::User *m_user{};

View File

@ -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<UserOptionState::DataStruct>;
private:
/// @brief Pointer to the target user.
data::User *m_user{};

View File

@ -2,14 +2,17 @@
#include "fslib.hpp"
#include "sys/sys.hpp"
#include <array>
#include <condition_variable>
#include <memory>
#include <mutex>
#include <vector>
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<sys::byte> sharedBuffer{};
std::array<sys::byte, SHARED_BUFFER_SIZE> 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<curl::DownloadStruct> create_download_struct(fslib::File &dest,
sys::ProgressTask *task,
int64_t fileSize)
{
auto downloadStruct = std::make_shared<curl::DownloadStruct>();
downloadStruct->dest = &dest;
downloadStruct->task = task;
downloadStruct->offset = fileSize;
return downloadStruct;
}
}

View File

@ -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.

View File

@ -1,26 +1,16 @@
#pragma once
#include "sys/Task.hpp"
#include <functional>
#include <memory>
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 *,
//<arguments>)
template <typename... Args>
ProgressTask(void (*function)(sys::ProgressTask *, Args...), Args... args)
{
m_thread = std::thread(function, this, std::forward<Args>(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.

View File

@ -1,9 +1,10 @@
#pragma once
#include "sys/threadpool.hpp"
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
// 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 <typename... Args>
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>(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<Task::DataStruct>;
/// @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<bool> m_isRunning{};
// Thread
std::thread m_thread{};
private:
// Status string the thread can set that the main thread can display.
std::string m_status{};

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -21,13 +21,6 @@
#include <cstring>
namespace
{
// These make some things cleaner and easier to type.
using TaskConfirm = ConfirmState<sys::Task, TaskState, BackupMenuState::DataStruct>;
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, BackupMenuState::DataStruct>;
} // 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<TaskConfirm> 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); }
}

View File

@ -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(); }
}

View File

@ -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<sys::Task>(function, taskData);
}
void DataLoadingState::update()
{
BaseTask::update_loading_glyph();

View File

@ -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++)
{

View File

@ -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());

View File

@ -30,10 +30,6 @@ namespace
PROPERTIES,
CLOSE
};
// These make things easier to read and type.
using TaskConfirm = ConfirmState<sys::Task, TaskState, FileOptionState::DataStruct>;
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, FileOptionState::DataStruct>;
}
// 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);
}

View File

@ -19,11 +19,6 @@
#include "tasks/mainmenu.hpp"
#include "ui/PopMessageManager.hpp"
namespace
{
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, MainMenuState::DataStruct>;
}
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); }
}

View File

@ -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<sys::ProgressTask>(function, taskData);
}
void ProgressState::update()
{
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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,

View File

@ -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::DataStruct>())
{
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()

View File

@ -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];
}

View File

@ -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<sys::Task>(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(); }
}

View File

@ -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);
}

View File

@ -38,9 +38,6 @@ namespace
EXTEND_CONTAINER,
EXPORT_SVI
};
using TaskConfirm = ConfirmState<sys::Task, TaskState, TitleOptionState::DataStruct>;
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, TitleOptionState::DataStruct>;
} // 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()

View File

@ -30,10 +30,6 @@ namespace
CREATE_ALL_SAVE,
DELETE_ALL_SAVE
};
// These make things easier to type later.
using TaskConfirm = ConfirmState<sys::Task, TaskState, UserOptionState::DataStruct>;
using ProgressConfirm = ConfirmState<sys::ProgressTask, ProgressState, UserOptionState::DataStruct>;
} // 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()

View File

@ -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

View File

@ -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<uint64_t> &listOut) { s_context.get_blacklist(listOut); }

View File

@ -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<sys::byte> &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<const sys::byte> bufferSpan{reinterpret_cast<const sys::byte *>(buffer), downloadSize};
@ -81,11 +82,12 @@ size_t curl::download_file_threaded(const char *buffer, size_t size, size_t coun
{
std::unique_lock<std::mutex> 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<sys::byte> &sharedBuffer = download.sharedBuffer;
bool &bufferReady = download.bufferReady;
fslib::File *dest = download.dest;
size_t fileSize = download.fileSize;
auto castData = std::static_pointer_cast<curl::DownloadStruct>(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<sys::byte[]>(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<std::mutex> 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;
}
}

View File

@ -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<NsApplicationControlData>();
// auto controlData = std::make_unique<NsApplicationControlData>();
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>();
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;

View File

@ -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<void()> onDestruction)
{
auto loadingState = DataLoadingState::create(s_context, onDestruction, data_initialize_task, clearCache);
auto taskData = std::make_shared<StateDataStruct>();
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<StateDataStruct>(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);

View File

@ -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<double>(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<double>(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<double>(sourceSize));
}

View File

@ -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<double>(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<double>(fileSize));
}

View File

@ -34,7 +34,7 @@ void logger::log(const char *format, ...) noexcept
{
static std::mutex logLock{};
std::array<char, VA_BUFFER_SIZE> vaBuffer{};
std::array<char, VA_BUFFER_SIZE> vaBuffer = {0};
std::va_list vaList{};
va_start(vaList, format);
vsnprintf(vaBuffer.data(), VA_BUFFER_SIZE, format, vaList);

View File

@ -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<curl::DownloadStruct>();
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;
}

View File

@ -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<curl::DownloadStruct>();
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;
}

View File

@ -21,11 +21,19 @@ namespace
/// @brief This is the single (for now) instance of a storage class.
std::unique_ptr<remote::Storage> 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<remote::GoogleDrive *>(s_storage.get());
if (drive->sign_in_required())
{
TaskState::create_and_push(drive_sign_in, drive);
auto driveStruct = std::make_shared<DriveStruct>();
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<DriveStruct>(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))
{

View File

@ -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) !=

View File

@ -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;

View File

@ -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};

View File

@ -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 *)

View File

@ -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<BackupMenuState::DataStruct>(taskData);
logger::log("static_pointer_cast");
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(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<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(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<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(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<BackupMenuState::DataStruct>(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<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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);
}
}

View File

@ -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<FileOptionState::DataStruct>(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<sys::ProgressTask *>(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<FileOptionState::DataStruct>(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);
}

View File

@ -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<MainMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>();
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<MainMenuState::DataStruct>(taskData);
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>();
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();
}
}

View File

@ -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<SaveCreateState::DataStruct>(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();
}

View File

@ -13,12 +13,15 @@
#include <array>
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<TitleOptionState::DataStruct>(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<TitleOptionState::DataStruct>(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<TitleOptionState::DataStruct>(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<TitleOptionState::DataStruct>(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<TitleOptionState::DataStruct>(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<TitleOptionState::DataStruct>(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);
}

View File

@ -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<UserOptionState::DataStruct>(taskData);
data::User *user = taskData->user;
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>();
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<UserOptionState::DataStruct>(taskData);
data::User *user = taskData->user;
sys::ProgressTask *task = static_cast<sys::ProgressTask *>(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<BackupMenuState::DataStruct>();
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<UserOptionState::DataStruct>(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<UserOptionState::DataStruct>(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);
}

View File

@ -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<double>(fontSize) * 1.8f))
, m_optionHeight(std::floor(static_cast<double>(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();
}

View File

@ -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);

View File

@ -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));
}