mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-07-14 23:21:17 -05:00
remote::Storage just barely working.
This commit is contained in:
parent
e29db89706
commit
e27e0c8e51
|
|
@ -1 +1 @@
|
|||
Subproject commit bc0bf99b32ef89a7892093737407977b3e649e79
|
||||
Subproject commit 403a0993d5ed2bffcf0ac9b298be95279d0d3749
|
||||
2
Makefile
2
Makefile
|
|
@ -32,7 +32,7 @@ include $(DEVKITPRO)/libnx/switch_rules
|
|||
#---------------------------------------------------------------------------------
|
||||
TARGET := JKSV
|
||||
BUILD := build
|
||||
SOURCES := source source/appstates source/ui source/data source/system source/fs source/curl
|
||||
SOURCES := source source/appstates source/ui source/data source/system source/fs source/curl source/remote
|
||||
DATA := data
|
||||
INCLUDES := include ./Libraries/FsLib/Switch/FsLib/include ./Libraries/SDLLib/SDL/include
|
||||
EXEFS_SRC := exefs_src
|
||||
|
|
|
|||
|
|
@ -9,20 +9,20 @@ class JKSV
|
|||
{
|
||||
public:
|
||||
/// @brief Initializes JKSV. Initializes services.
|
||||
JKSV(void);
|
||||
JKSV();
|
||||
|
||||
/// @brief Exits services.
|
||||
~JKSV();
|
||||
|
||||
/// @brief Returns if initializing was successful and JKSV is running.
|
||||
/// @return True or false.
|
||||
bool is_running(void) const;
|
||||
bool is_running() const;
|
||||
|
||||
/// @brief Runs JKSV's update routine.
|
||||
void update(void);
|
||||
void update();
|
||||
|
||||
/// @brief Runs JKSV's render routine.
|
||||
void render(void);
|
||||
void render();
|
||||
|
||||
private:
|
||||
/// @brief Whether or not initialization was successful and JKSV is still running.
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@ class StateManager
|
|||
StateManager &operator=(StateManager &&) = delete;
|
||||
|
||||
/// @brief Runs the state update routine.
|
||||
static void update(void);
|
||||
static void update();
|
||||
|
||||
/// @brief Runs the state rendering routine(s);
|
||||
static void render(void);
|
||||
static void render();
|
||||
|
||||
/// @brief Returns whether the back of the vector is a closable state.
|
||||
static bool back_is_closable(void);
|
||||
static bool back_is_closable();
|
||||
|
||||
/// @brief Pushes a new state to the state vector.
|
||||
/// @param newState Shared_ptr to state to push.
|
||||
|
|
@ -27,11 +27,11 @@ class StateManager
|
|||
|
||||
private:
|
||||
/// @brief Private constructor so no constructing.
|
||||
StateManager(void) = default;
|
||||
StateManager() = default;
|
||||
|
||||
/// @brief Returns a reference to the instance of StateManger.
|
||||
/// @return Reference to state manager.
|
||||
static StateManager &get_instance(void);
|
||||
static StateManager &get_instance();
|
||||
|
||||
/// @brief This is the vector that holds the pointers to the states.
|
||||
static inline std::vector<std::shared_ptr<AppState>> sm_stateVector;
|
||||
|
|
|
|||
|
|
@ -13,34 +13,34 @@ class AppState
|
|||
virtual ~AppState();
|
||||
|
||||
/// @brief Every derived class is required to have this function.
|
||||
virtual void update(void) = 0;
|
||||
virtual void update() = 0;
|
||||
|
||||
/// @brief Every derived class is required to have this function.
|
||||
virtual void render(void) = 0;
|
||||
virtual void render() = 0;
|
||||
|
||||
/// @brief Deactivates state and allows JKSV to purge it from the vector.
|
||||
void deactivate(void);
|
||||
void deactivate();
|
||||
|
||||
/// @brief Allows a state to be reactivated and pushed to the vector.
|
||||
void reactivate(void);
|
||||
void reactivate();
|
||||
|
||||
/// @brief Returns if the state is still active.
|
||||
/// @return Whether state is still active or can be purged.
|
||||
bool is_active(void) const;
|
||||
bool is_active() const;
|
||||
|
||||
/// @brief Tells the state it's at the back of the vector and has focus.
|
||||
void give_focus(void);
|
||||
void give_focus();
|
||||
|
||||
/// @brief Takes the focus away and tells the state it's no long back();
|
||||
void take_focus(void);
|
||||
void take_focus();
|
||||
|
||||
/// @brief Allows the state to know whether it has focus.
|
||||
/// @return Whether state has focus or not.
|
||||
bool has_focus(void) const;
|
||||
bool has_focus() const;
|
||||
|
||||
/// @brief Returns whether or not JKSV should allow closing while state is active.
|
||||
/// @return True if closable. False if not.
|
||||
bool is_closable(void) const;
|
||||
bool is_closable() const;
|
||||
|
||||
private:
|
||||
/// @brief Stores whether or not the state is currently active.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <memory>
|
||||
|
||||
/// @brief This is the state where the user can backup and restore saves.
|
||||
class BackupMenuState : public AppState
|
||||
class BackupMenuState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Creates a new backup selection state.
|
||||
|
|
@ -23,34 +23,34 @@ class BackupMenuState : public AppState
|
|||
~BackupMenuState();
|
||||
|
||||
/// @brief Required. Inherited virtual function from AppState.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Required. Inherited virtual function from AppState.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief Refreshes the directory listing and menu.
|
||||
void refresh(void);
|
||||
void refresh();
|
||||
|
||||
/// @brief Allows a spawned task to tell this class that it wrote save data to the system.
|
||||
void save_data_written(void);
|
||||
void save_data_written();
|
||||
|
||||
/// @brief Struct used for passing data to functions.
|
||||
typedef struct
|
||||
{
|
||||
/// @brief Pointer to the target user.
|
||||
data::User *m_user;
|
||||
data::User *user;
|
||||
|
||||
/// @brief Data for the target title.
|
||||
data::TitleInfo *m_titleInfo;
|
||||
data::TitleInfo *titleInfo;
|
||||
|
||||
/// @brief Path of the target.
|
||||
fslib::Path m_targetPath;
|
||||
fslib::Path targetPath;
|
||||
|
||||
/// @brief Journal size for when a commit is needed.
|
||||
uint64_t m_journalSize;
|
||||
uint64_t journalSize;
|
||||
|
||||
/// @brief Pointer to >this spawning state.
|
||||
BackupMenuState *m_spawningState;
|
||||
BackupMenuState *spawningState;
|
||||
} DataStruct;
|
||||
|
||||
private:
|
||||
|
|
@ -92,4 +92,16 @@ class BackupMenuState : public AppState
|
|||
|
||||
/// @brief The width of the panels. This is set according to the control guide text.
|
||||
static inline int sm_panelWidth = 0;
|
||||
|
||||
/// @brief This is the function called when New Backup is selected.
|
||||
void name_and_create_backup();
|
||||
|
||||
/// @brief This is the function called when a backup is selected to be overwritten.
|
||||
void confirm_backup_overwrite();
|
||||
|
||||
/// @brief This function is called to confirm restoring a backup.
|
||||
void confirm_restore();
|
||||
|
||||
/// @brief Function called to confirm deleting a backup.
|
||||
void confirm_delete();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,21 +10,21 @@ class BaseTask : public AppState
|
|||
{
|
||||
public:
|
||||
/// @brief Constructor. Starts the glyph timer and sets AppState to not allow closing.
|
||||
BaseTask(void);
|
||||
BaseTask();
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
virtual ~BaseTask() {};
|
||||
|
||||
/// @brief Runs the update routine for rendering the loading glyph animation.
|
||||
/// @param
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Virtual render function.
|
||||
virtual void render(void) = 0;
|
||||
virtual void render() = 0;
|
||||
|
||||
/// @brief This function renders the loading glyph in the bottom left corner.
|
||||
/// @note This is mostly just so users don't think JKSV has frozen when operations take a long time.
|
||||
void render_loading_glyph(void);
|
||||
void render_loading_glyph();
|
||||
|
||||
private:
|
||||
/// @brief This is the current frame of the loading glyph animation.
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ namespace
|
|||
/// @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>
|
||||
class ConfirmState : public AppState
|
||||
class ConfirmState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief All functions passed to this state need to follow this signature: void function(<TaskType> *, std::shared_ptr<<StructType>>)
|
||||
|
|
@ -39,9 +39,8 @@ class ConfirmState : public AppState
|
|||
bool holdRequired,
|
||||
TaskFunction function,
|
||||
std::shared_ptr<StructType> dataStruct)
|
||||
: AppState(false), m_queryString(queryString.data()),
|
||||
m_yesString(strings::get_by_name(strings::names::YES_NO, 0)), m_hold(holdRequired), m_function(function),
|
||||
m_dataStruct(dataStruct)
|
||||
: AppState(false), m_queryString(queryString), m_yesString(strings::get_by_name(strings::names::YES_NO, 0)),
|
||||
m_hold(holdRequired), m_function(function), m_dataStruct(dataStruct)
|
||||
{
|
||||
// This is to make centering the Yes [A] string more accurate.
|
||||
m_yesX = YES_X_CENTER_COORDINATE - (sdl::text::get_width(22, m_yesString.c_str()) / 2);
|
||||
|
|
@ -52,7 +51,7 @@ class ConfirmState : public AppState
|
|||
~ConfirmState() {};
|
||||
|
||||
/// @brief Just updates the ConfirmState.
|
||||
void update(void) override
|
||||
void update() override
|
||||
{
|
||||
// This is to guard against the dialog being triggered right away. To do: Maybe figure out a better way to accomplish this?
|
||||
if (input::button_pressed(HidNpadButton_A) && !m_triggerGuard)
|
||||
|
|
@ -109,7 +108,7 @@ class ConfirmState : public AppState
|
|||
}
|
||||
|
||||
/// @brief Renders the state to screen.
|
||||
void render(void) override
|
||||
void render() override
|
||||
{
|
||||
// Dim background
|
||||
sdl::render_rect_fill(NULL, 0, 0, 1280, 720, colors::DIM_BACKGROUND);
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@
|
|||
#include "ui/Menu.hpp"
|
||||
|
||||
/// @brief Extras menu.
|
||||
class ExtrasMenuState : public AppState
|
||||
class ExtrasMenuState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructor.
|
||||
ExtrasMenuState(void);
|
||||
ExtrasMenuState();
|
||||
|
||||
/// @brief Required even if nothing happens.
|
||||
~ExtrasMenuState() {};
|
||||
|
||||
/// @brief Updates the menu.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Renders the menu to screen.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Menu
|
||||
|
|
|
|||
|
|
@ -6,26 +6,26 @@
|
|||
#include <memory>
|
||||
|
||||
/// @brief The main
|
||||
class MainMenuState : public AppState
|
||||
class MainMenuState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Creates and initializes the main menu.
|
||||
MainMenuState(void);
|
||||
MainMenuState();
|
||||
|
||||
/// @brief Required even if it does nothing.
|
||||
~MainMenuState() {};
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Renders menu to screen.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief Signals to
|
||||
static void initialize_view_states(void);
|
||||
static void initialize_view_states();
|
||||
|
||||
/// @brief Calls refresh on on view states in the vector.
|
||||
static void refresh_view_states(void);
|
||||
static void refresh_view_states();
|
||||
|
||||
private:
|
||||
/// @brief Render target this state renders to.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include <switch.h>
|
||||
|
||||
/// @brief State that shows progress of a task.
|
||||
class ProgressState : public BaseTask
|
||||
class ProgressState final : public BaseTask
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new ProgressState.
|
||||
|
|
@ -20,10 +20,10 @@ class ProgressState : public BaseTask
|
|||
~ProgressState() {};
|
||||
|
||||
/// @brief Checks if the thread is finished and deactivates this state.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Renders the current progress to screen.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Underlying task that has extra methods for tracking the progress of a task.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <memory>
|
||||
|
||||
/// @brief This is the state that is spawned when CreateSaveData is selected from the user menu.
|
||||
class SaveCreateState : public AppState
|
||||
class SaveCreateState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new SaveCreateState.
|
||||
|
|
@ -19,13 +19,13 @@ class SaveCreateState : public AppState
|
|||
~SaveCreateState() {};
|
||||
|
||||
/// @brief Runs the update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief This signals so data and the view can be refreshed on the next update() to avoid threading shenanigans.
|
||||
void data_and_view_refresh_required(void);
|
||||
void data_and_view_refresh_required();
|
||||
|
||||
private:
|
||||
/// @brief Pointer to target user.
|
||||
|
|
|
|||
|
|
@ -4,20 +4,20 @@
|
|||
#include "ui/Menu.hpp"
|
||||
|
||||
/// @brief The state for settings.
|
||||
class SettingsState : public AppState
|
||||
class SettingsState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new settings state.
|
||||
SettingsState(void);
|
||||
SettingsState();
|
||||
|
||||
/// @brief Required destructor.
|
||||
~SettingsState() {};
|
||||
|
||||
/// @brief Runs the update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Menu for selecting and toggling settings.
|
||||
|
|
@ -30,8 +30,8 @@ class SettingsState : public AppState
|
|||
int m_controlGuideX = 0;
|
||||
|
||||
/// @brief Runs a routine to update the menu strings for the menu.
|
||||
void update_menu_options(void);
|
||||
void update_menu_options();
|
||||
|
||||
/// @brief Toggles or executes the code to changed the selected menu option.
|
||||
void toggle_options(void);
|
||||
void toggle_options();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#include <switch.h>
|
||||
|
||||
/// @brief State that spawns a task and allows updates to be printed to screen.
|
||||
class TaskState : public BaseTask
|
||||
class TaskState final : public BaseTask
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs and spawns a new TaskState.
|
||||
|
|
@ -19,11 +19,11 @@ class TaskState : public BaseTask
|
|||
~TaskState() {};
|
||||
|
||||
/// @brief Runs update routine. Waits for thread function to signal finish and deactivates.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Run render routine. Prints m_task's status string to screen, basically.
|
||||
/// @param
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Underlying task.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "ui/Menu.hpp"
|
||||
|
||||
/// @brief Text menu title selection state.
|
||||
class TextTitleSelectState : public TitleSelectCommon
|
||||
class TextTitleSelectState final : public TitleSelectCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs new text menu title selection state.
|
||||
|
|
@ -16,13 +16,13 @@ class TextTitleSelectState : public TitleSelectCommon
|
|||
~TextTitleSelectState() {};
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief Refreshes view for changes.
|
||||
void refresh(void) override;
|
||||
void refresh() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to user view "belongs" to.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
class TitleInfoState : public AppState
|
||||
class TitleInfoState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new title info state.
|
||||
|
|
@ -19,10 +19,10 @@ class TitleInfoState : public AppState
|
|||
~TitleInfoState();
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to user.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
#include "ui/SlideOutPanel.hpp"
|
||||
#include <memory>
|
||||
|
||||
class TitleOptionState : public AppState
|
||||
class TitleOptionState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new title option state.
|
||||
|
|
@ -18,16 +18,16 @@ class TitleOptionState : public AppState
|
|||
~TitleOptionState() {};
|
||||
|
||||
/// @brief Runs update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief This function allows tasks to signal to the spawning state to close itself on the next update() call.
|
||||
void close_on_update(void);
|
||||
void close_on_update();
|
||||
|
||||
/// @brief Signals to the main thread that a view refresh is required on the next update() call.
|
||||
void refresh_required(void);
|
||||
void refresh_required();
|
||||
|
||||
/// @brief This is the struct used to pass data to the thread functions.
|
||||
typedef struct
|
||||
|
|
|
|||
|
|
@ -6,22 +6,22 @@ class TitleSelectCommon : public AppState
|
|||
{
|
||||
public:
|
||||
/// @brief Constructs a new TitleSelectCommon. Basically just calculates the X coordinate of the control if it wasn't already.
|
||||
TitleSelectCommon(void);
|
||||
TitleSelectCommon();
|
||||
|
||||
/// @brief Required destructor.
|
||||
virtual ~TitleSelectCommon() {};
|
||||
|
||||
/// @brief Required, inherited.
|
||||
virtual void update(void) = 0;
|
||||
virtual void update() = 0;
|
||||
|
||||
/// @brief Required, inherited.
|
||||
virtual void render(void) = 0;
|
||||
virtual void render() = 0;
|
||||
|
||||
/// @brief Both derived classes need this function.
|
||||
virtual void refresh(void) = 0;
|
||||
virtual void refresh() = 0;
|
||||
|
||||
/// @brief Renders the control guide string to the bottom right corner.
|
||||
void render_control_guide(void);
|
||||
void render_control_guide();
|
||||
|
||||
private:
|
||||
/// @brief X coordinate the control guide is rendered at.
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "ui/TitleView.hpp"
|
||||
|
||||
/// @brief Title select state with icon tiles.
|
||||
class TitleSelectState : public TitleSelectCommon
|
||||
class TitleSelectState final : public TitleSelectCommon
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs new title select state.
|
||||
|
|
@ -16,13 +16,13 @@ class TitleSelectState : public TitleSelectCommon
|
|||
~TitleSelectState() {};
|
||||
|
||||
/// @brief Runs the update routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief Refreshes the view.
|
||||
void refresh(void) override;
|
||||
void refresh() override;
|
||||
|
||||
private:
|
||||
/// @brief Pointer to the user the view belongs to.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#include <memory>
|
||||
|
||||
/// @brief State that allows certain actions to be taken for users.
|
||||
class UserOptionState : public AppState
|
||||
class UserOptionState final : public AppState
|
||||
{
|
||||
public:
|
||||
/// @brief Constructs a new UserOptionState.
|
||||
|
|
@ -19,14 +19,14 @@ class UserOptionState : public AppState
|
|||
~UserOptionState() {};
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void update(void) override;
|
||||
void update() override;
|
||||
|
||||
/// @brief Runs the render routine.
|
||||
void render(void) override;
|
||||
void render() override;
|
||||
|
||||
/// @brief Signals to the main update() function that a refresh is needed.
|
||||
/// @note Like this to prevent threading headaches.
|
||||
void data_and_view_refresh_required(void);
|
||||
void data_and_view_refresh_required();
|
||||
|
||||
/// @brief Struct used for passing data to functions/tasks.
|
||||
typedef struct
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@
|
|||
namespace config
|
||||
{
|
||||
/// @brief Attempts to load config from file. If it fails, loads defaults.
|
||||
void initialize(void);
|
||||
void initialize();
|
||||
|
||||
/// @brief Resets config to default values.
|
||||
void reset_to_default(void);
|
||||
void reset_to_default();
|
||||
|
||||
/// @brief Saves config to file.
|
||||
void save(void);
|
||||
void save();
|
||||
|
||||
/// @brief Retrieves the config value according to the key passed.
|
||||
/// @param key Key to retrieve. See config::keys
|
||||
|
|
@ -27,26 +27,13 @@ namespace config
|
|||
/// @param value Value to set the key to.
|
||||
void set_by_key(std::string_view key, uint8_t value);
|
||||
|
||||
/// @brief Retrieves value of config at index.
|
||||
/// @param index Index of value to retrieve.
|
||||
uint8_t get_by_index(int index);
|
||||
|
||||
/// @brief Toggles the key at index from 1 to 0 or vice-versa.
|
||||
/// @param index Index of key to toggle.
|
||||
void toggle_by_index(int index);
|
||||
|
||||
/// @brief Sets the config value at index to value.
|
||||
/// @param index Index of value to set.
|
||||
/// @param value Value to set index to.
|
||||
void set_by_index(int index, uint8_t value);
|
||||
|
||||
/// @brief Returns the working directory.
|
||||
/// @return Working directory.
|
||||
fslib::Path get_working_directory(void);
|
||||
fslib::Path get_working_directory();
|
||||
|
||||
/// @brief Returns the scaling speed of UI transitions and animations.
|
||||
/// @return Scaling variable.
|
||||
double get_animation_scaling(void);
|
||||
double get_animation_scaling();
|
||||
|
||||
/// @brief Sets the UI animation scaling.
|
||||
/// @param newScale New value to set the scaling to.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
#include "fslib.hpp"
|
||||
#include "logger.hpp"
|
||||
#include <curl/curl.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
|
@ -10,7 +9,7 @@
|
|||
namespace curl
|
||||
{
|
||||
/// @brief JKSV's user agent string.
|
||||
static constexpr std::string_view USER_AGENT_STRING = "JKSV";
|
||||
static const char *STRING_USER_AGENT = "JKSV";
|
||||
|
||||
/// @brief Self cleaning curl handle.
|
||||
using Handle = std::unique_ptr<CURL, decltype(&curl_easy_cleanup)>;
|
||||
|
|
@ -23,10 +22,10 @@ namespace curl
|
|||
|
||||
/// @brief Initializes lib curl.
|
||||
/// @return True on success. False on failure.
|
||||
bool initialize(void);
|
||||
bool initialize();
|
||||
|
||||
/// @brief Exits libcurl
|
||||
void exit(void);
|
||||
void exit();
|
||||
|
||||
/// @brief Inline templated function to wrap curl_easy_setopt and make using curl::Handle slightly easier.
|
||||
/// @tparam Option Templated type of the option. This is a headache so let the compiler figure it out.
|
||||
|
|
@ -43,14 +42,14 @@ namespace curl
|
|||
|
||||
/// @brief Inline function that returns a self cleaning curl handle.
|
||||
/// @return Curl handle.
|
||||
static inline curl::Handle new_handle(void)
|
||||
static inline curl::Handle new_handle()
|
||||
{
|
||||
return curl::Handle(curl_easy_init(), curl_easy_cleanup);
|
||||
}
|
||||
|
||||
/// @brief Inline function that returns a nullptr'd self cleaning curl_list.
|
||||
/// @return Self cleaning curl_slist.
|
||||
static inline curl::HeaderList new_header_list(void)
|
||||
static inline curl::HeaderList new_header_list()
|
||||
{
|
||||
return curl::HeaderList(nullptr, curl_slist_free_all);
|
||||
}
|
||||
|
|
@ -59,41 +58,18 @@ namespace curl
|
|||
/// @param curl curl::Handle to reset.
|
||||
static inline void reset_handle(curl::Handle &curl)
|
||||
{
|
||||
// Reset the handle.
|
||||
curl_easy_reset(curl.get());
|
||||
// Set the user agent since basically everything needs it.
|
||||
curl::set_option(curl, CURLOPT_USERAGENT, curl::USER_AGENT_STRING.data());
|
||||
curl::set_option(curl, CURLOPT_USERAGENT, curl::STRING_USER_AGENT);
|
||||
}
|
||||
|
||||
/// @brief Logged inline wrapper function for curl_easy_perform.
|
||||
/// @param curl Handle to perform.
|
||||
/// @return True on success. False on failure.
|
||||
static inline bool perform(curl::Handle &curl)
|
||||
{
|
||||
// CURLCode is just an int anyway.
|
||||
CURLcode error = curl_easy_perform(curl.get());
|
||||
if (error != CURLE_OK)
|
||||
{
|
||||
logger::log("Error performing curl: %i.", error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/// @param handle Handle to perform.
|
||||
bool perform(curl::Handle &handle);
|
||||
|
||||
/// @brief Inline wrapper function to make adding to HeaderList simpler.
|
||||
/// @param headerList Header list to append to.
|
||||
/// @param header Header to append.
|
||||
static inline void append_header(curl::HeaderList &headerList, std::string_view header)
|
||||
{
|
||||
// Release the current list and save the pointer to the head of it.
|
||||
curl_slist *list = headerList.release();
|
||||
|
||||
// Append to it.
|
||||
curl_slist_append(list, header.data());
|
||||
|
||||
// Reassign the unique_ptr to the new head.
|
||||
headerList.reset(list);
|
||||
}
|
||||
void append_header(curl::HeaderList &list, std::string_view header);
|
||||
|
||||
/// @brief Curl callback function for reading data from a file.
|
||||
/// @param buffer Incoming buffer from curl to read to.
|
||||
|
|
@ -131,9 +107,24 @@ namespace curl
|
|||
/// @param array Array of headers to search.
|
||||
/// @param header Header to search for.
|
||||
/// @param valueOut String to write the value to.
|
||||
/// @return True if the header was found and the value was successfully extracted.
|
||||
bool get_header_value(const curl::HeaderArray &array, std::string_view header, std::string &valueOut);
|
||||
|
||||
/// @brief Gets the response code from the handle passed.
|
||||
/// @param handle Handle to get the response code from.
|
||||
long get_response_code(curl::Handle &handle);
|
||||
|
||||
/// @brief Calls curl_easy_escape using the passed curl::Handle.
|
||||
/// @param handle Handle to use.
|
||||
/// @param in String to escape.
|
||||
/// @param out String to write the escaped text to.
|
||||
bool escape_string(curl::Handle &handle, std::string_view in, std::string &out);
|
||||
|
||||
/// @brief Calls curl_easy_unescape using the passed curl::Handle.
|
||||
/// @param handle Handle to use.
|
||||
/// @param in String to unescape.
|
||||
/// @param out String to write the escaped text to.
|
||||
bool unescape_string(curl::Handle &handle, std::string_view in, std::string &out);
|
||||
|
||||
/// @brief Prepares the curl handle passed for a get request.
|
||||
/// @param curl Handle to prepare for a get request.
|
||||
void prepare_get(curl::Handle &curl);
|
||||
|
|
|
|||
|
|
@ -21,31 +21,30 @@ namespace data
|
|||
|
||||
/// @brief Returns the application ID of the title.
|
||||
/// @return Title's application ID.
|
||||
uint64_t get_application_id(void) const;
|
||||
uint64_t get_application_id() const;
|
||||
|
||||
/// @brief Returns a pointer to the control data for the title.
|
||||
/// @return Pointer to control data.
|
||||
NsApplicationControlData *get_control_data(void);
|
||||
NsApplicationControlData *get_control_data();
|
||||
|
||||
/// @brief Returns whether or not the title has control data.
|
||||
/// @return Whether or not the title has control data.
|
||||
bool has_control_data(void) const;
|
||||
bool has_control_data() const;
|
||||
|
||||
/// @brief Returns the title of the title?
|
||||
/// @return Title directly from the NACP.
|
||||
const char *get_title(void);
|
||||
const char *get_title();
|
||||
|
||||
/// @brief Returns the path safe version of the title for file system usage.
|
||||
/// @return Path safe version of the title.
|
||||
const char *get_path_safe_title(void);
|
||||
const char *get_path_safe_title() const;
|
||||
|
||||
/// @brief Returns the publisher of the title.
|
||||
/// @return Publisher string from NACP.
|
||||
const char *get_publisher(void);
|
||||
const char *get_publisher();
|
||||
|
||||
/// @brief Returns the owner ID of the save data.
|
||||
/// @return Save data owner ID.
|
||||
uint64_t get_save_data_owner_id(void) const;
|
||||
uint64_t get_save_data_owner_id() const;
|
||||
|
||||
/// @brief Returns the save data container's base size.
|
||||
/// @param saveType Type of save data to return.
|
||||
|
|
@ -70,11 +69,11 @@ namespace data
|
|||
/// @brief Returns if a title uses the save type passed.
|
||||
/// @param saveType Save type to check for.
|
||||
/// @return True on success. False on failure.
|
||||
bool has_save_data_type(uint8_t saveType);
|
||||
bool has_save_data_type(uint8_t saveType) const;
|
||||
|
||||
/// @brief Returns a pointer to the icon texture.
|
||||
/// @return Icon
|
||||
sdl::SharedTexture get_icon(void) const;
|
||||
sdl::SharedTexture get_icon() const;
|
||||
|
||||
/// @brief Allows the path safe title to be set to a new path.
|
||||
/// @param newPathSafe Buffer containing the new safe path to use.
|
||||
|
|
@ -101,6 +100,6 @@ namespace data
|
|||
sdl::SharedTexture m_icon = nullptr;
|
||||
|
||||
/// @brief Private function to get/create the path safe title.
|
||||
void get_create_path_safe_title(void);
|
||||
void get_create_path_safe_title();
|
||||
};
|
||||
} // namespace data
|
||||
|
|
|
|||
|
|
@ -39,34 +39,34 @@ namespace data
|
|||
void add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistics *playStats);
|
||||
|
||||
/// @brief Clears the user save info vector.
|
||||
void clear_data_entries(void);
|
||||
void clear_data_entries();
|
||||
|
||||
/// @brief Erases data at index.
|
||||
/// @param index Index of save data info to erase.
|
||||
void erase_data(int index);
|
||||
|
||||
/// @brief Runs the sort algo on the vector.
|
||||
void sort_data(void);
|
||||
void sort_data();
|
||||
|
||||
/// @brief Returns the account ID of the user.
|
||||
/// @return AccountID
|
||||
AccountUid get_account_id(void) const;
|
||||
AccountUid get_account_id() const;
|
||||
|
||||
/// @brief Returns the save data type the account uses.
|
||||
/// @return Save data type of the account.
|
||||
FsSaveDataType get_account_save_type(void) const;
|
||||
FsSaveDataType get_account_save_type() const;
|
||||
|
||||
/// @brief Returns the account's nickname.
|
||||
/// @return Account nickname.
|
||||
const char *get_nickname(void) const;
|
||||
const char *get_nickname() const;
|
||||
|
||||
/// @brief Returns the path safe version of the nickname.
|
||||
/// @return Path safe nickname.
|
||||
const char *get_path_safe_nickname(void) const;
|
||||
const char *get_path_safe_nickname() const;
|
||||
|
||||
/// @brief Returns the total number of entries in the data vector.
|
||||
/// @return Total number of entries.
|
||||
size_t get_total_data_entries(void) const;
|
||||
size_t get_total_data_entries() const;
|
||||
|
||||
/// @brief Returns the application ID of the title at index.
|
||||
/// @param index Index of title.
|
||||
|
|
@ -90,7 +90,7 @@ namespace data
|
|||
|
||||
/// @brief Returns a reference to the user save data info vector.
|
||||
/// @return Reference to the user save info vector.
|
||||
data::UserSaveInfoList &get_user_save_info_list(void);
|
||||
data::UserSaveInfoList &get_user_save_info_list();
|
||||
|
||||
/// @brief Returns a pointer to the play statistics of applicationID
|
||||
/// @param applicationID Application ID to search and fetch.
|
||||
|
|
@ -99,18 +99,18 @@ namespace data
|
|||
|
||||
/// @brief Returns raw SDL_Texture pointer of icon.
|
||||
/// @return SDL_Texture of icon.
|
||||
SDL_Texture *get_icon(void);
|
||||
SDL_Texture *get_icon();
|
||||
|
||||
/// @brief Returns the shared texture of icon. Increasing reference count of it.
|
||||
/// @return Shared icon texture.
|
||||
sdl::SharedTexture get_shared_icon(void);
|
||||
sdl::SharedTexture get_shared_icon();
|
||||
|
||||
/// @brief Erases a UserDataEntry according to the application ID passed.
|
||||
/// @param applicationID ID of the save to erase.
|
||||
void erase_save_info_by_id(uint64_t applicationID);
|
||||
|
||||
/// @brief Loads the save data info and play statistics for the current user using the information passed to the constructor.
|
||||
void load_user_data(void);
|
||||
void load_user_data();
|
||||
|
||||
private:
|
||||
/// @brief Account's ID
|
||||
|
|
@ -137,7 +137,7 @@ namespace data
|
|||
void load_account(AccountProfile &profile, AccountProfileBase &profileBase);
|
||||
|
||||
/// @brief Creates a placeholder since something went wrong.
|
||||
void create_account(void);
|
||||
void create_account();
|
||||
|
||||
/// @brief Opens a save data info reader according to the data passed to the user.
|
||||
/// @param spaceID The FsSaveDataSpaceId to use when opening the reader.
|
||||
|
|
|
|||
|
|
@ -24,5 +24,6 @@ static inline bool operator==(AccountUid accountIDA, AccountUid accountIDB)
|
|||
/// @note I'm not 100% sure which uint64_t in the AccountUid struct comes first. I don't know if it's [0][1] or [1][0]. To do: Figure that out.
|
||||
static inline bool operator==(AccountUid accountIDA, u128 accountIDB)
|
||||
{
|
||||
return accountIDA.uid[0] == (accountIDB >> 64 & 0xFFFFFFFFFFFFFFFF) && accountIDA.uid[1] == (accountIDB & 0xFFFFFFFFFFFFFFFF);
|
||||
return accountIDA.uid[0] == (accountIDB >> 64 & 0xFFFFFFFFFFFFFFFF) &&
|
||||
accountIDA.uid[1] == (accountIDB & 0xFFFFFFFFFFFFFFFF);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace data
|
|||
|
||||
/// @brief Returns a reference to the title info map.
|
||||
/// @return Reference to TitleInfoMap.
|
||||
std::unordered_map<uint64_t, data::TitleInfo> &get_title_info_map(void);
|
||||
std::unordered_map<uint64_t, data::TitleInfo> &get_title_info_map();
|
||||
|
||||
/// @brief Uses the application ID passed to add/load a title to the map.
|
||||
/// @param applicationID Application/System save data ID to add.
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
namespace input
|
||||
{
|
||||
/// @brief Initializes PadState and input.
|
||||
void initialize(void);
|
||||
void initialize();
|
||||
|
||||
/// @brief Updates the PadState.
|
||||
void update(void);
|
||||
void update();
|
||||
|
||||
/// @brief Returns if a button was pressed the current frame, but not the previous.
|
||||
/// @param button Button to check.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
namespace logger
|
||||
{
|
||||
/// @brief Creates and empties the log file
|
||||
void initialize(void);
|
||||
void initialize();
|
||||
|
||||
/// @brief Logs a formatted string.
|
||||
/// @param format Format of string.
|
||||
|
|
|
|||
43
include/remote/Form.hpp
Normal file
43
include/remote/Form.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace remote
|
||||
{
|
||||
/// @brief This is a class to build URL encoded form bodies and be more readable than snprintfs.
|
||||
class Form
|
||||
{
|
||||
public:
|
||||
Form() = default;
|
||||
|
||||
/// @brief Copy constructor
|
||||
/// @param form Form to copy from.
|
||||
Form(const Form &form);
|
||||
|
||||
/// @brief Move constructor.
|
||||
/// @param form Form to copy from.
|
||||
Form(Form &&form);
|
||||
|
||||
/// @brief = Operator.
|
||||
/// @param form Form to copy.
|
||||
Form &operator=(const Form &form);
|
||||
|
||||
/// @brief = Move operator.
|
||||
/// @param form Form to rob of its life.
|
||||
Form &operator=(Form &&form);
|
||||
|
||||
/// @brief Appends a parameter to the form/URL encoded text.
|
||||
/// @param param Parameter to append.
|
||||
/// @param value Value to append.
|
||||
Form &append_parameter(std::string_view param, std::string_view value);
|
||||
|
||||
/// @brief Returns the C string of the form string.
|
||||
const char *get() const;
|
||||
|
||||
/// @brief Returns m_form.length()
|
||||
size_t length() const;
|
||||
|
||||
private:
|
||||
/// @brief String containing the actual data posted.
|
||||
std::string m_form{};
|
||||
};
|
||||
} // namespace remote
|
||||
|
|
@ -8,116 +8,85 @@ namespace remote
|
|||
class GoogleDrive final : public remote::Storage
|
||||
{
|
||||
public:
|
||||
/// @brief Google Drive class constructor. Unlike PC prototype, the path to the client_secret is hardcoded.
|
||||
/// @param
|
||||
GoogleDrive(void);
|
||||
/// @brief Loads the config from SD.
|
||||
GoogleDrive();
|
||||
|
||||
/// @brief Changes the current parent directory.
|
||||
/// @param id ID of the parent to target.
|
||||
void change_directory(std::string_view id) override;
|
||||
|
||||
/// @brief Creates a new directory on Google Drive.
|
||||
/// @brief Creates a directory on Google Drive.
|
||||
/// @param name Name of the directory to create.
|
||||
/// @return True on success. False on failure.
|
||||
bool create_directory(std::string_view name) override;
|
||||
|
||||
/// @brief Deletes a directory from Google Drive.
|
||||
/// @param id ID of the directory to delete.
|
||||
/// @return True on success. False on failure.
|
||||
bool delete_directory(std::string_view id) override;
|
||||
|
||||
/// @brief Uploads a file to Google Drive.
|
||||
/// @param source Source path.
|
||||
/// @return True on success. False on failure.
|
||||
/// @brief Uploads the file from source. File name is used to name the file.
|
||||
/// @param source Path to upload the file from.
|
||||
bool upload_file(const fslib::Path &source) override;
|
||||
|
||||
/// @brief Patches or updates a file on Google Drive.
|
||||
/// @param id ID of the file to patch.
|
||||
/// @param source Source path of the updated file.
|
||||
/// @return True on success. False on failure.
|
||||
bool patch_file(std::string_view id, const fslib::Path &source) override;
|
||||
|
||||
/// @brief Deletes a file from Google Drive.
|
||||
/// @param id ID of the file to delete.
|
||||
/// @return True on success. False on failure.
|
||||
bool delete_file(std::string_view id) override;
|
||||
/// @brief Patches or updates the file on Google Drive.
|
||||
/// @param file Pointer to the item containing the data needed to update the file.
|
||||
/// @param source Source path to update from.
|
||||
bool patch_file(remote::Item *file, const fslib::Path &source) override;
|
||||
|
||||
/// @brief Downloads a file from Google Drive.
|
||||
/// @param id ID of the file to download.
|
||||
/// @param destination Path with the destination to save the file to.
|
||||
/// @return True on success. False on failure.
|
||||
bool download_file(std::string_view id, const fslib::Path &destination) override;
|
||||
/// @param file Pointer to the item containing data to download the file.
|
||||
/// @param destination Location to write the downloaded file to.
|
||||
bool download_file(const remote::Item *file, const fslib::Path &destination) override;
|
||||
|
||||
// Sign in related functions.
|
||||
/// @brief Returns if a sign in is required for using Google Drive.
|
||||
/// @return True if sign in is required. False if it isn't.
|
||||
bool sign_in_required(void) const;
|
||||
/// @brief Deletes an item from Google Drive.
|
||||
/// @param item Pointer to item containing data to delete the item.
|
||||
bool delete_item(const remote::Item *item) override;
|
||||
|
||||
/// @brief Gets the data needed to display and sign into Google.
|
||||
/// @param code String to write the sign in code to.
|
||||
/// @param expires std::time_t to write the expiration time to.
|
||||
/// @param wait Time in seconds while pinging server.
|
||||
/// @return True on success. False on failure.
|
||||
bool get_sign_in_data(std::string &code, std::time_t &expires, int &wait);
|
||||
/// @brief Returns whether or not a sign in is required to use drive. AKA the refresh token is missing.
|
||||
bool sign_in_required() const;
|
||||
|
||||
/// @brief This function waits for the response from the server that the user signed in.
|
||||
/// @return True on success. False on failure.
|
||||
bool sign_in(void);
|
||||
/// @brief Requests the the necessary data from Google to login.
|
||||
/// @param message String to store the message to.
|
||||
/// @param code String to store the device code from Google.
|
||||
/// @param expiration time_t to store when the sign in window closes.
|
||||
/// @param wait Int to store the time in seconds between server pings.
|
||||
bool get_sign_in_data(std::string &message, std::string &code, std::time_t &expiration, int &wait);
|
||||
|
||||
/// @brief This is the function that pings the server to see if the user entered the code yet.
|
||||
/// @param code The code Google reponded with for verification.
|
||||
/// @return If the user signs in, true. If not, false;
|
||||
bool poll_sign_in(std::string_view code);
|
||||
|
||||
private:
|
||||
/// @brief Client ID.
|
||||
/// @brief Google client ID.
|
||||
std::string m_clientId;
|
||||
|
||||
/// @brief Client secret.
|
||||
/// @brief Google client secret.
|
||||
std::string m_clientSecret;
|
||||
|
||||
/// @brief Authorization token.
|
||||
/// @brief Authentication token.
|
||||
std::string m_token;
|
||||
|
||||
/// @brief Token refresh token.
|
||||
/// @brief Token used for refreshing token when it expires.
|
||||
std::string m_refreshToken;
|
||||
|
||||
/// @brief Authentication header string.
|
||||
/// @brief This is to save the authentication header string instead of recreating it over and over.
|
||||
std::string m_authHeader;
|
||||
|
||||
/// @brief Calculated time the token expires in.
|
||||
/// @brief This is the calculate time when the auth token expires.
|
||||
std::time_t m_tokenExpires;
|
||||
|
||||
/// @brief Gets and sets the root ID of Google Drive using V2 of the API.
|
||||
/// @return True on success. False on failure.
|
||||
bool get_set_root_id(void);
|
||||
/// @brief Uses V2 of Drive's API to get the root directory ID from Google.
|
||||
bool get_root_id();
|
||||
|
||||
/// @brief Returns whether or not the token is still valid with a grace period of 10 seconds.
|
||||
/// @return True if the token is still valid. False if it isn't.
|
||||
bool token_is_valid(void) const;
|
||||
/// @brief Returns whether or not the auth token is still valid for use or needs to be refreshed.
|
||||
bool token_is_valid() const;
|
||||
|
||||
/// @brief Forces a refresh of the access token.
|
||||
/// @return True on success. False on failure.
|
||||
bool refresh_token(void);
|
||||
/// @brief Attempts to refresh the auth token if needed.
|
||||
bool refresh_token();
|
||||
|
||||
/// @brief Requests a listing and processes it.
|
||||
/// @return True on success. False on failure.
|
||||
bool request_listing(void);
|
||||
/// @brief Requests and processes the entire listing for JKSV.
|
||||
bool request_listing();
|
||||
|
||||
/// @brief Processes a file list from Google Drive.
|
||||
/// @param json Json object to process.
|
||||
/// @return True on success. False on failure.
|
||||
/// @brief Processes and listing
|
||||
/// @param json Json object to use for parsing.
|
||||
bool process_listing(json::Object &json);
|
||||
|
||||
/// @brief Tries to locate a directory according to its ID instead of its name.
|
||||
/// @param id ID of the directory to search for.
|
||||
/// @return Iterator to directory found. m_list.end() on failure.
|
||||
remote::Storage::List::iterator find_directory_by_id(std::string_view id);
|
||||
|
||||
/// @brief Tries to locate a file according to its ID instead of its name.
|
||||
/// @param id ID of the file to locate.
|
||||
/// @return Iterator to the file on success. m_list.end() on failure.
|
||||
remote::Storage::List::iterator find_file_by_id(std::string_view id);
|
||||
|
||||
/// @brief Checks for, logs, and returns if an error is detected within the json::Object passed.
|
||||
/// @param json json::Object to check.
|
||||
/// @return True if an error was found. False if one wasn't.
|
||||
bool error_occurred(json::Object &json);
|
||||
/// @brief Performs a quick check on the json object passed for errors.
|
||||
/// @param json Json object to check.
|
||||
/// @param log Whether or not to log the error.
|
||||
/// @note This doesn't catch every error. Google's errors aren't consistent.
|
||||
bool error_occurred(json::Object &json, bool log = true);
|
||||
};
|
||||
} // namespace remote
|
||||
|
|
|
|||
|
|
@ -16,23 +16,23 @@ namespace remote
|
|||
|
||||
/// @brief Returns the name of the item.
|
||||
/// @return Name of the item.
|
||||
std::string_view get_name(void) const;
|
||||
std::string_view get_name() const;
|
||||
|
||||
/// @brief Returns the id of the item.
|
||||
/// @return ID of the item.
|
||||
std::string_view get_id(void) const;
|
||||
std::string_view get_id() const;
|
||||
|
||||
/// @brief Returns the parent id of the item.
|
||||
/// @return Parent ID of the item.
|
||||
std::string_view get_parent_id(void) const;
|
||||
std::string_view get_parent_id() const;
|
||||
|
||||
/// @brief Gets the size of the item.
|
||||
/// @return Size of the item in bytes.
|
||||
size_t get_size(void) const;
|
||||
size_t get_size() const;
|
||||
|
||||
/// @brief Returns whether or not the item is a directory.
|
||||
/// @return Whether or not the item is a directory.
|
||||
bool is_directory(void) const;
|
||||
bool is_directory() const;
|
||||
|
||||
/// @brief Sets the name of the item.
|
||||
/// @param name New name of the item.
|
||||
|
|
|
|||
|
|
@ -8,102 +8,113 @@
|
|||
|
||||
namespace remote
|
||||
{
|
||||
/// @brief This is the base storage class.
|
||||
class Storage
|
||||
{
|
||||
public:
|
||||
// Definition for remote file listing.
|
||||
/// @brief Definition to make things easier to type.
|
||||
using DirectoryListing = std::vector<remote::Item *>;
|
||||
|
||||
/// @brief This makes writing some stuff for these classes way easier.
|
||||
using List = std::vector<remote::Item>;
|
||||
|
||||
/// @brief Default storage constructor.
|
||||
Storage(void) = default;
|
||||
/// @brief This just allocates the curl::Handle.
|
||||
Storage();
|
||||
|
||||
/// @brief Returns whether or not the storage type/driver was initialized successfully.
|
||||
/// @return True if it was. False if it wasn't.
|
||||
bool is_initialized(void) const;
|
||||
/// @brief Returns whether or not the Storage type was successfully. initialized.
|
||||
bool is_initialized() const;
|
||||
|
||||
// Directory functions.
|
||||
/// @brief Returns whether or not a directory with name exists within the current parent.
|
||||
/// @param name Name of the directory.
|
||||
/// @return True if one was found. False if one wasn't.
|
||||
/// @param name Name of the directory to search for.
|
||||
bool directory_exists(std::string_view name);
|
||||
|
||||
/// @brief Tries to locate and get the ID of a directory within the current parent.
|
||||
/// @param name Name of the directory to get.
|
||||
/// @param idOut String to write the ID to if it's found.
|
||||
/// @return True on success. False on failure.
|
||||
bool get_directory_id(std::string_view name, std::string &idOut);
|
||||
/// @brief Returns the parent to the root directory.
|
||||
void return_to_root();
|
||||
|
||||
/// @brief Returns whether or not a file exists within the current parent directory.
|
||||
/// @param name Name of the file to search for.
|
||||
/// @return True if one is found. False if one isn't.
|
||||
bool file_exists(std::string_view name);
|
||||
/// @brief This allows the root to be set to something other than what it originally was at construction.
|
||||
/// @param root Item to be used as the new root.
|
||||
void set_root_directory(remote::Item *root);
|
||||
|
||||
/// @brief Tries to locate and get the ID of a file within the current parent directory.
|
||||
/// @param name Name of the file to search for
|
||||
/// @param idOut String it write the ID to.
|
||||
/// @return True on success. False when no file is found.
|
||||
bool get_file_id(std::string_view name, std::string &idOut);
|
||||
/// @brief Changes the current parent directory.
|
||||
/// @param Item Item to use as the current parent directory.
|
||||
void change_directory(remote::Item *item);
|
||||
|
||||
/// @brief Virtual function to change the current parent/working directory.
|
||||
/// @param name Name or ID of the directory to change to.
|
||||
virtual void change_directory(std::string_view name) = 0;
|
||||
|
||||
/// @brief Virtual function to create a new directory within the current parent directory.
|
||||
/// @brief Creates a directory in the current parent directory.
|
||||
/// @param name Name of the directory to create.
|
||||
/// @return True on success. False on failure.
|
||||
virtual bool create_directory(std::string_view name) = 0;
|
||||
|
||||
/// @brief Virtual function to delete a directory from within the current parent directory.
|
||||
/// @param name Name or ID of the directory to delete.
|
||||
/// @return True on success. False on failure.
|
||||
virtual bool delete_directory(std::string_view name) = 0;
|
||||
/// @brief Searches the list for a directory matching name and the current parent.
|
||||
/// @param name Name of the directory to search for.
|
||||
/// @return Pointer to the item representing the directory on success. nullptr on failure/not found.
|
||||
remote::Item *get_directory_by_name(std::string_view name);
|
||||
|
||||
/// @brief Virtual function to upload a file to remote storage.
|
||||
/// @param source fslib::Path of the source file to upload.
|
||||
/// @return True on success. False on failure.
|
||||
/// @brief Retrieves a listing of the items in the current parent directory.
|
||||
/// @param out List to fill.
|
||||
remote::Storage::DirectoryListing get_directory_listing();
|
||||
|
||||
// File functions.
|
||||
/// @brief Returns whether a file with name exists within the current directory.
|
||||
/// @param name Name of the file.
|
||||
bool file_exists(std::string_view name);
|
||||
|
||||
/// @brief Uploads a file from the SD card to the remote.
|
||||
/// @param source Path to the file to upload.
|
||||
virtual bool upload_file(const fslib::Path &source) = 0;
|
||||
|
||||
/// @brief Virtual function to patch or update a file.
|
||||
/// @param name Name or ID of the file to update.
|
||||
/// @param source Source path to upload from.
|
||||
/// @return True on success. False on failure.
|
||||
virtual bool patch_file(std::string_view name, const fslib::Path &source) = 0;
|
||||
/// @brief Patches or updates a file on the remote.
|
||||
/// @param item Item to be updated.
|
||||
/// @param source Path to the file to update with.
|
||||
virtual bool patch_file(remote::Item *file, const fslib::Path &source) = 0;
|
||||
|
||||
/// @brief Virtual function for downloading a file.
|
||||
/// @param name Name or ID of the file.
|
||||
/// @param destination fslib::Path containing the destination path.
|
||||
/// @return True on success. False on failure.
|
||||
virtual bool download_file(std::string_view name, const fslib::Path &destination) = 0;
|
||||
/// @brief Downloads a file from the remote.
|
||||
/// @param item Item to download.
|
||||
/// @param destination Path to download the file to.
|
||||
virtual bool download_file(const remote::Item *file, const fslib::Path &destination) = 0;
|
||||
|
||||
/// @brief Virtual function to delete a file from the remote storage.
|
||||
/// @param name Name or ID of the file to delete.
|
||||
/// @return True on success. False on failure.
|
||||
virtual bool delete_file(std::string_view name) = 0;
|
||||
/// @brief Searches the list for a file matching name and the current parent.
|
||||
/// @param name Name of the file to search for.
|
||||
/// @return Pointer to the item if located. nullptr if not.
|
||||
remote::Item *get_file_by_name(std::string_view name);
|
||||
|
||||
// General functions that apply to both.
|
||||
/// @brief Deletes a file or folder from the remote.
|
||||
/// @param item Item to delete.
|
||||
virtual bool delete_item(const remote::Item *item) = 0;
|
||||
|
||||
/// @brief Returns whether or not the remote storage type supports UTF-8 for names or requires path safe titles.
|
||||
bool supports_utf8() const;
|
||||
|
||||
protected:
|
||||
/// @brief Whether or not initialization of the remote storage service was successful.
|
||||
/// @brief This is the size of the buffers used for snprintf'ing URLs together.
|
||||
static constexpr size_t SIZE_URL_BUFFER = 0x401;
|
||||
|
||||
/// @brief This is the size used for uploads.
|
||||
static constexpr size_t SIZE_UPLOAD_BUFFER = 0x10000;
|
||||
|
||||
/// @brief This allows JKSV to know whether or not the storage type supports UTF-8.
|
||||
bool m_utf8Paths = false;
|
||||
|
||||
/// @brief This stores whether or not the instance was initialized successfully.
|
||||
bool m_isInitialized = false;
|
||||
|
||||
/// @brief The root directory of the remote storage.
|
||||
/// @brief This is the root directory of the remote storage.
|
||||
std::string m_root;
|
||||
|
||||
/// @brief Current parent directory.
|
||||
/// @brief This stores the current parent.
|
||||
std::string m_parent;
|
||||
|
||||
/// @brief Current storage listing.
|
||||
Storage::List m_list;
|
||||
|
||||
/// @brief CURL handle.
|
||||
/// @brief Curl handle.
|
||||
curl::Handle m_curl;
|
||||
|
||||
/// @brief Searches for a directory in the current parent directory.
|
||||
/// @param name Name of the directory to search for.
|
||||
/// @return Iterator to found directory or m_list.end() on failure.
|
||||
Storage::List::iterator find_directory(std::string_view name);
|
||||
/// @brief This is the main remote listing.
|
||||
Storage::List m_list;
|
||||
|
||||
/// @brief Searches for a file named file within the current parent directory.
|
||||
/// @brief Searches the list for a directory matching name and the current parent.
|
||||
/// @param name Name to search for.
|
||||
Storage::List::iterator find_directory_by_name(std::string_view name);
|
||||
|
||||
/// @brief Searches to find if a file with name exists within the current parent.
|
||||
/// @param name Name of the file to search for.
|
||||
/// @return Iterator to the file found. m_list.end() on failure.
|
||||
Storage::List::iterator find_file(std::string_view name);
|
||||
Storage::List::iterator find_file_by_name(std::string_view name);
|
||||
};
|
||||
} // namespace remote
|
||||
|
|
|
|||
60
include/remote/URL.hpp
Normal file
60
include/remote/URL.hpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace remote
|
||||
{
|
||||
/// @brief This is a class to make URLs easier to build for Google Drive and WebDav.
|
||||
/// @note Normally I don't go this route, but it makes things easier.
|
||||
class URL final
|
||||
{
|
||||
public:
|
||||
/// @brief Default
|
||||
URL() = default;
|
||||
|
||||
/// @brief Constructs a URL with a base URL already in place.
|
||||
/// @param base String_view containing the base URL.
|
||||
URL(std::string_view base);
|
||||
|
||||
/// @brief Copy constructor.
|
||||
/// @param url URL to copy.
|
||||
URL(const URL &url);
|
||||
|
||||
/// @brief Move constructor.
|
||||
/// @param url URL to move.
|
||||
URL(URL &&url);
|
||||
|
||||
/// @brief Makes a copy of the URL passed.
|
||||
/// @param url remote::URL instance to make a copy of.
|
||||
URL &operator=(const URL &url);
|
||||
|
||||
/// @brief Move operator.
|
||||
/// @param url URL to move.
|
||||
URL &operator=(URL &&url);
|
||||
|
||||
/// @brief Sets the base URL. Basically resets the string back to square 0.
|
||||
/// @param base Base URL to start with.
|
||||
URL &set_base(std::string_view base);
|
||||
|
||||
/// @brief Appends the string passed as a path to the URL
|
||||
/// @param path Path to append;
|
||||
URL &append_path(std::string_view path);
|
||||
|
||||
/// @brief Appends a string parameter
|
||||
/// @param param Parameter to append.
|
||||
/// @param value Value of the parameter to append.
|
||||
URL &append_parameter(std::string_view param, std::string_view value);
|
||||
|
||||
/// @brief Appends a trailing slash if needed.
|
||||
URL &append_slash();
|
||||
|
||||
/// @brief Returns the C string of the url string.
|
||||
const char *get() const;
|
||||
|
||||
private:
|
||||
/// @brief This is where the actual URL is held.
|
||||
std::string m_url;
|
||||
|
||||
/// @brief This checks and appends the necessary separator to the URL string.
|
||||
void append_separator();
|
||||
};
|
||||
} // namespace remote
|
||||
58
include/remote/WebDav.hpp
Normal file
58
include/remote/WebDav.hpp
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
#pragma once
|
||||
#include "remote/Storage.hpp"
|
||||
#include "remote/URL.hpp"
|
||||
#include <string>
|
||||
|
||||
namespace remote
|
||||
{
|
||||
class WebDav final : public remote::Storage
|
||||
{
|
||||
public:
|
||||
/// @brief Loads the WebDav config from the SD card and loads the listing.
|
||||
WebDav();
|
||||
|
||||
/// @brief Creates a new directory on the WebDav server.
|
||||
/// @param name Name of the directory to create.
|
||||
bool create_directory(std::string_view name) override;
|
||||
|
||||
/// @brief Uploads a file to the webdav server. File name is retrieved from the path.
|
||||
/// @param source Local path of the file to upload.
|
||||
bool upload_file(const fslib::Path &source) override;
|
||||
|
||||
/// @brief Patches or updates a file on the WebDav server.
|
||||
/// @param file Pointer to the file to update.
|
||||
/// @param source Path of the source file to update with.
|
||||
bool patch_file(remote::Item *file, const fslib::Path &source) override;
|
||||
|
||||
/// @brief Downloads the passed file from the WebDav server.
|
||||
/// @param file Pointer to the file to download.
|
||||
/// @param destination Path to write the downloaded data from.
|
||||
bool download_file(const remote::Item *item, const fslib::Path &destination) override;
|
||||
|
||||
/// @brief Deletes the target item from the WebDav server.
|
||||
/// @param item Item to delete.
|
||||
bool delete_item(const remote::Item *item) override;
|
||||
|
||||
private:
|
||||
/// @brief Origin or server address.
|
||||
std::string m_origin;
|
||||
|
||||
/// @brief Username for curl requests.
|
||||
std::string m_username;
|
||||
|
||||
/// @brief Password for curl requests.
|
||||
std::string m_password;
|
||||
|
||||
/// @brief Appends the username and password to a WebDav curl request.
|
||||
void append_credentials();
|
||||
|
||||
/// @brief Requests PROPFIND to the url passed.
|
||||
/// @param url URL to PROPFIND with.
|
||||
/// @param xml String to record XML response to.
|
||||
bool prop_find(const remote::URL &url, std::string &xml);
|
||||
|
||||
/// @brief Processes a PROPFIND XML response.
|
||||
/// @param xml XML response.
|
||||
bool process_listing(std::string_view xml);
|
||||
};
|
||||
} // namespace remote
|
||||
19
include/remote/remote.hpp
Normal file
19
include/remote/remote.hpp
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include "remote/Storage.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace remote
|
||||
{
|
||||
// Both of these are needed in two different places.
|
||||
static constexpr std::string_view PATH_GOOGLE_DRIVE_CONFIG = "sdmc:/config/JKSV/client_secret.json";
|
||||
static constexpr std::string_view PATH_WEBDAV_CONFIG = "sdmc:/config/JKSV/WebDav.json";
|
||||
|
||||
/// @brief Initializes the Storage instance to Google Drive.
|
||||
void initialize_google_drive();
|
||||
|
||||
/// @brief Initializes the Storage instance to WebDav
|
||||
void initialize_webdav();
|
||||
|
||||
/// @brief Returns the pointer to the Storage instance.
|
||||
remote::Storage *get_remote_storage();
|
||||
} // namespace remote
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
namespace strings
|
||||
{
|
||||
// Attempts to load strings from file in RomFS.
|
||||
bool initialize(void);
|
||||
bool initialize();
|
||||
|
||||
// Returns string with name and index. Returns nullptr if string doesn't exist.
|
||||
const char *get_by_name(std::string_view name, int index);
|
||||
|
|
@ -41,5 +41,6 @@ namespace strings
|
|||
static constexpr std::string_view POP_MESSAGES_SAVE_CREATE = "PopMessagesSaveCreate";
|
||||
static constexpr std::string_view POP_MESSAGES_TITLE_OPTIONS = "PopMessagesTitleOptions";
|
||||
static constexpr std::string_view GOOGLE_DRIVE_STRINGS = "GoogleDriveStrings";
|
||||
static constexpr std::string_view WEBDAV_STRINGS = "WebDavStrings";
|
||||
} // namespace names
|
||||
} // namespace strings
|
||||
|
|
|
|||
|
|
@ -25,11 +25,11 @@ namespace sys
|
|||
|
||||
/// @brief Returns the goal value.
|
||||
/// @return Goal
|
||||
double get_goal(void) const;
|
||||
double get_goal() const;
|
||||
|
||||
/// @brief Returns the current progress.
|
||||
/// @return Current progress.
|
||||
double get_current(void) const;
|
||||
double get_current() const;
|
||||
|
||||
private:
|
||||
// Current value and goal
|
||||
|
|
|
|||
|
|
@ -35,11 +35,11 @@ namespace sys
|
|||
|
||||
/// @brief Returns if the thread has signaled it's finished running.
|
||||
/// @return True if the thread is still running. False if it isn't.
|
||||
bool is_running(void) const;
|
||||
bool is_running() const;
|
||||
|
||||
/// @brief Allows thread to signal it's finished.
|
||||
/// @note Spawned task threads must call this when their work is finished.
|
||||
void finished(void);
|
||||
void finished();
|
||||
|
||||
/// @brief Sets the task/threads current status string. Thread safe.
|
||||
/// @param format Format of string.
|
||||
|
|
@ -48,7 +48,7 @@ namespace sys
|
|||
|
||||
/// @brief Returns the status string. Thread safe.
|
||||
/// @return Copy of the status string.
|
||||
std::string get_status(void);
|
||||
std::string get_status();
|
||||
|
||||
private:
|
||||
// Whether task is still running.
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ namespace sys
|
|||
{
|
||||
public:
|
||||
/// @brief Default constructor.
|
||||
Timer(void) = default;
|
||||
Timer() = default;
|
||||
|
||||
/// @brief Constructs a new timer.
|
||||
/// @param triggerTicks Number of ticks the timer is triggered at.
|
||||
|
|
@ -21,15 +21,16 @@ namespace sys
|
|||
|
||||
/// @brief Updates and returns if the timer was triggered.
|
||||
/// @return True if timer is triggered. False if it isn't.
|
||||
bool is_triggered(void);
|
||||
bool is_triggered();
|
||||
|
||||
/// @brief Forces the timer to restart.
|
||||
void restart(void);
|
||||
void restart();
|
||||
|
||||
private:
|
||||
// Beginning ticks.
|
||||
/// @brief Tick count when the timer starts.
|
||||
uint64_t m_startingTicks;
|
||||
// How many ticks to trigger the timer.
|
||||
|
||||
/// @brief Number of ticks to trigger on.
|
||||
uint64_t m_triggerTicks;
|
||||
};
|
||||
} // namespace sys
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ namespace ui
|
|||
{
|
||||
public:
|
||||
/// @brief Default constructor.
|
||||
ColorMod(void) = default;
|
||||
ColorMod() = default;
|
||||
|
||||
/// @brief Updates the color modification variable.
|
||||
void update(void);
|
||||
void update();
|
||||
|
||||
/// @brief Operator that allows using this as an sdl::Color directly.
|
||||
/// @note Since all of these pulse the same color, no sense in not doing this.
|
||||
operator sdl::Color(void) const;
|
||||
operator sdl::Color() const;
|
||||
|
||||
private:
|
||||
/// @brief Whether we're adding or subtracting from the color value.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace ui
|
|||
{
|
||||
public:
|
||||
/// @brief Default constructor.
|
||||
Element(void) = default;
|
||||
Element() = default;
|
||||
|
||||
/// @brief Virtual destructor.
|
||||
virtual ~Element() {};
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ namespace ui
|
|||
{
|
||||
public:
|
||||
/// @brief Default constructor.
|
||||
IconMenu(void) = default;
|
||||
IconMenu() = default;
|
||||
|
||||
/// @brief This constructor calls initialize.
|
||||
/// @param x X coordinate to render the menu to.
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ namespace ui
|
|||
|
||||
/// @brief Returns the index of the currently selected menu option.
|
||||
/// @return Index of currently selected option.
|
||||
int get_selected(void) const;
|
||||
int get_selected() const;
|
||||
|
||||
/// @brief Sets the selected item.
|
||||
/// @param selected Value to set selected to.
|
||||
|
|
@ -52,7 +52,7 @@ namespace ui
|
|||
void set_width(int width);
|
||||
|
||||
/// @brief Resets the menu and returns it to an empty, default state.
|
||||
void reset(void);
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
/// @brief X coordinate menu is rendered to.
|
||||
|
|
|
|||
|
|
@ -31,10 +31,10 @@ namespace ui
|
|||
PopMessageManager &operator=(PopMessageManager &&) = delete;
|
||||
|
||||
/// @brief Updates and processes message queue.
|
||||
static void update(void);
|
||||
static void update();
|
||||
|
||||
/// @brief Renders messages to screen.
|
||||
static void render(void);
|
||||
static void render();
|
||||
|
||||
/// @brief Pushes a new message to the queue for processing.
|
||||
/// @param displayTicks Number of ticks for the message to be displayed until it is purged.
|
||||
|
|
@ -47,9 +47,9 @@ namespace ui
|
|||
|
||||
private:
|
||||
// Only one instance allowed.
|
||||
PopMessageManager(void) = default;
|
||||
PopMessageManager() = default;
|
||||
// Returns the only instance.
|
||||
static PopMessageManager &get_instance(void)
|
||||
static PopMessageManager &get_instance()
|
||||
{
|
||||
static PopMessageManager manager;
|
||||
return manager;
|
||||
|
|
|
|||
|
|
@ -33,32 +33,32 @@ namespace ui
|
|||
void render(SDL_Texture *target, bool hasFocus);
|
||||
|
||||
/// @brief Clears the target to a semi-transparent black. To do: Maybe not hard coded color.
|
||||
void clear_target(void);
|
||||
void clear_target();
|
||||
|
||||
/// @brief Resets the panel back to its default state.
|
||||
void reset(void);
|
||||
void reset();
|
||||
|
||||
/// @brief Closes the panel.
|
||||
void close(void);
|
||||
void close();
|
||||
|
||||
/// @brief Returns if the panel is fully open.
|
||||
/// @return If the panel is fully open.
|
||||
bool is_open(void) const;
|
||||
bool is_open() const;
|
||||
|
||||
/// @brief Returns if the panel is fully closed.
|
||||
/// @return If the panel is fully closed.
|
||||
bool is_closed(void) const;
|
||||
bool is_closed() const;
|
||||
|
||||
/// @brief Pushes a new element to the element vector.
|
||||
/// @param newElement New element to push.
|
||||
void push_new_element(std::shared_ptr<ui::Element> newElement);
|
||||
|
||||
/// @brief Clears the element vector, freeing them in the process.
|
||||
void clear_elements(void);
|
||||
void clear_elements();
|
||||
|
||||
/// @brief Returns a pointer to the render target of the panel.
|
||||
/// @return Raw SDL_Texture pointer to target.
|
||||
SDL_Texture *get_target(void);
|
||||
SDL_Texture *get_target();
|
||||
|
||||
private:
|
||||
/// @brief Bool for whether panel is fully open or not.
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace ui
|
|||
{
|
||||
public:
|
||||
/// @brief This is only here so I can get around the backup menu having static members.
|
||||
TextScroll(void) = default;
|
||||
TextScroll() = default;
|
||||
|
||||
/// @brief Constructor for TextScroll.
|
||||
/// @param text Text to create the textscroll with.
|
||||
|
|
|
|||
|
|
@ -23,15 +23,15 @@ namespace ui
|
|||
void render(SDL_Texture *target, int x, int y);
|
||||
|
||||
/// @brief Resets the width and height of the tile.
|
||||
void reset(void);
|
||||
void reset();
|
||||
|
||||
/// @brief Returns the render width in pixels.
|
||||
/// @return Render width.
|
||||
int get_width(void) const;
|
||||
int get_width() const;
|
||||
|
||||
/// @brief Returns the render height in pixels.
|
||||
/// @return Render height.
|
||||
int get_height(void) const;
|
||||
int get_height() const;
|
||||
|
||||
private:
|
||||
/// @brief Width in pixels to render icon at.
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ namespace ui
|
|||
|
||||
/// @brief Returns index of the currently selected tile.
|
||||
/// @return Index of currently selected tile.
|
||||
int get_selected(void) const;
|
||||
int get_selected() const;
|
||||
|
||||
/// @brief Forces a refresh of the view.
|
||||
void refresh(void);
|
||||
void refresh();
|
||||
|
||||
/// @brief Resets the view to its default, empty state.
|
||||
void reset(void);
|
||||
void reset();
|
||||
|
||||
private:
|
||||
/// @brief Pointer to user passed.
|
||||
|
|
|
|||
|
|
@ -98,10 +98,11 @@
|
|||
"Are you sure you really want to delete #%s#?"
|
||||
],
|
||||
"BackupMenuStatus": [
|
||||
"Processing save data meta file..."
|
||||
"Processing save data meta file...",
|
||||
"Uploading #%s# to remote storage..."
|
||||
],
|
||||
"BackupMenuPops": [
|
||||
"System save data cannot be restored to the system!"
|
||||
"Writing to system data is disabled!"
|
||||
],
|
||||
"DeletingFiles": [
|
||||
"Deleting #%s#..."
|
||||
|
|
@ -195,8 +196,12 @@
|
|||
"Error setting new output path!"
|
||||
],
|
||||
"GoogleDriveStrings": [
|
||||
"In order to use Google Drive, please go to #%s# on your phone or PC and type in the code >%s>.",
|
||||
"To continue, go to #%s# and enter >%s>!",
|
||||
"Successfully signed in to Google Drive!",
|
||||
"Google Drive sign in failed!"
|
||||
],
|
||||
"WebDavStrings": [
|
||||
"WebDav successfully started!",
|
||||
"WebDav failed!"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "fslib.hpp"
|
||||
#include "input.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "ui/PopMessageManager.hpp"
|
||||
|
|
@ -42,7 +43,7 @@ static bool initialize_service(Result (*function)(Args...), const char *serviceN
|
|||
return true;
|
||||
}
|
||||
|
||||
JKSV::JKSV(void)
|
||||
JKSV::JKSV()
|
||||
{
|
||||
// Start with this.
|
||||
appletSetCpuBoostMode(ApmCpuBoostMode_FastLoad);
|
||||
|
|
@ -122,6 +123,14 @@ JKSV::JKSV(void)
|
|||
|
||||
// Push initial main menu state.
|
||||
StateManager::push_state(std::make_shared<MainMenuState>());
|
||||
if (fslib::file_exists(remote::PATH_GOOGLE_DRIVE_CONFIG))
|
||||
{
|
||||
remote::initialize_google_drive();
|
||||
}
|
||||
else if (fslib::file_exists(remote::PATH_WEBDAV_CONFIG))
|
||||
{
|
||||
remote::initialize_webdav();
|
||||
}
|
||||
|
||||
m_isRunning = true;
|
||||
}
|
||||
|
|
@ -146,12 +155,12 @@ JKSV::~JKSV()
|
|||
appletSetCpuBoostMode(ApmCpuBoostMode_Normal);
|
||||
}
|
||||
|
||||
bool JKSV::is_running(void) const
|
||||
bool JKSV::is_running() const
|
||||
{
|
||||
return m_isRunning;
|
||||
}
|
||||
|
||||
void JKSV::update(void)
|
||||
void JKSV::update()
|
||||
{
|
||||
input::update();
|
||||
|
||||
|
|
@ -167,7 +176,7 @@ void JKSV::update(void)
|
|||
ui::PopMessageManager::update();
|
||||
}
|
||||
|
||||
void JKSV::render(void)
|
||||
void JKSV::render()
|
||||
{
|
||||
sdl::frame_begin(colors::CLEAR_COLOR);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "StateManager.hpp"
|
||||
|
||||
void StateManager::update(void)
|
||||
void StateManager::update()
|
||||
{
|
||||
// Grab the instance.
|
||||
StateManager &instance = StateManager::get_instance();
|
||||
|
|
@ -35,7 +35,7 @@ void StateManager::update(void)
|
|||
instance.sm_stateVector.back()->update();
|
||||
}
|
||||
|
||||
void StateManager::render(void)
|
||||
void StateManager::render()
|
||||
{
|
||||
// Instance.
|
||||
StateManager &instance = StateManager::get_instance();
|
||||
|
|
@ -47,7 +47,7 @@ void StateManager::render(void)
|
|||
}
|
||||
}
|
||||
|
||||
bool StateManager::back_is_closable(void)
|
||||
bool StateManager::back_is_closable()
|
||||
{
|
||||
// Instance.
|
||||
StateManager &instance = StateManager::get_instance();
|
||||
|
|
@ -78,7 +78,7 @@ void StateManager::push_state(std::shared_ptr<AppState> newState)
|
|||
instance.sm_stateVector.push_back(newState);
|
||||
}
|
||||
|
||||
StateManager &StateManager::get_instance(void)
|
||||
StateManager &StateManager::get_instance()
|
||||
{
|
||||
static StateManager instance;
|
||||
return instance;
|
||||
|
|
|
|||
|
|
@ -17,22 +17,22 @@ AppState::~AppState()
|
|||
}
|
||||
}
|
||||
|
||||
void AppState::deactivate(void)
|
||||
void AppState::deactivate()
|
||||
{
|
||||
m_isActive = false;
|
||||
}
|
||||
|
||||
void AppState::reactivate(void)
|
||||
void AppState::reactivate()
|
||||
{
|
||||
m_isActive = true;
|
||||
}
|
||||
|
||||
bool AppState::is_active(void) const
|
||||
bool AppState::is_active() const
|
||||
{
|
||||
return m_isActive;
|
||||
}
|
||||
|
||||
void AppState::give_focus(void)
|
||||
void AppState::give_focus()
|
||||
{
|
||||
m_hasFocus = true;
|
||||
}
|
||||
|
|
@ -42,12 +42,12 @@ void AppState::take_focus()
|
|||
m_hasFocus = false;
|
||||
}
|
||||
|
||||
bool AppState::has_focus(void) const
|
||||
bool AppState::has_focus() const
|
||||
{
|
||||
return m_hasFocus;
|
||||
}
|
||||
|
||||
bool AppState::is_closable(void) const
|
||||
bool AppState::is_closable() const
|
||||
{
|
||||
return m_isClosable;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "input.hpp"
|
||||
#include "keyboard.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include "sdl.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
|
@ -23,7 +24,7 @@ namespace
|
|||
constexpr size_t SIZE_BACKUP_NAME_LENGTH = 0x80;
|
||||
|
||||
/// @brief This is just so there isn't random .zip comparisons everywhere.
|
||||
constexpr std::string_view STRING_ZIP_EXTENSION = ".zip";
|
||||
const char *STRING_ZIP_EXTENSION = ".zip";
|
||||
} // namespace
|
||||
|
||||
// Declarations here. Definitions after class.
|
||||
|
|
@ -39,12 +40,16 @@ static void overwrite_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenu
|
|||
static void restore_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuState::DataStruct> dataStruct);
|
||||
// Deletes a backup and requires confirmation to do so. Takes a shared_ptr to a TargetStruct.
|
||||
static void delete_backup(sys::Task *task, std::shared_ptr<BackupMenuState::DataStruct> dataStruct);
|
||||
// Uploads a backup to the remote server.
|
||||
static void upload_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuState::DataStruct> dataStruct);
|
||||
|
||||
BackupMenuState::BackupMenuState(data::User *user, data::TitleInfo *titleInfo, FsSaveDataType saveType)
|
||||
: m_user(user), m_titleInfo(titleInfo), m_saveType(saveType),
|
||||
m_directoryPath(config::get_working_directory() / m_titleInfo->get_path_safe_title()),
|
||||
m_dataStruct(std::make_shared<BackupMenuState::DataStruct>())
|
||||
{
|
||||
static const char *STRING_ERROR_CONSTRUCTING = "Error constructing BackupMenuState: %s";
|
||||
|
||||
if (!sm_isInitialized)
|
||||
{
|
||||
sm_panelWidth = sdl::text::get_width(22, strings::get_by_name(strings::names::CONTROL_GUIDES, 2)) + 64;
|
||||
|
|
@ -59,11 +64,20 @@ BackupMenuState::BackupMenuState(data::User *user, data::TitleInfo *titleInfo, F
|
|||
sm_isInitialized = true;
|
||||
}
|
||||
|
||||
// Check to make sure the directory exists.
|
||||
fslib::Path targetPath = config::get_working_directory() / titleInfo->get_path_safe_title();
|
||||
// This failing will immediately deactivate the state. The user *probably* won't even notice it!
|
||||
if (!fslib::directory_exists(targetPath) && !fslib::create_directory(targetPath))
|
||||
{
|
||||
logger::log(STRING_ERROR_CONSTRUCTING, "Error creating target directory on SD!");
|
||||
AppState::deactivate();
|
||||
}
|
||||
|
||||
// Fill this out. Target path is not set here.
|
||||
m_dataStruct->m_user = m_user;
|
||||
m_dataStruct->m_titleInfo = m_titleInfo;
|
||||
m_dataStruct->m_journalSize = m_titleInfo->get_journal_size(m_saveType);
|
||||
m_dataStruct->m_spawningState = this;
|
||||
m_dataStruct->user = m_user;
|
||||
m_dataStruct->titleInfo = m_titleInfo;
|
||||
m_dataStruct->journalSize = m_titleInfo->get_journal_size(m_saveType);
|
||||
m_dataStruct->spawningState = this;
|
||||
|
||||
// String for the top of the panel.
|
||||
std::string panelString =
|
||||
|
|
@ -78,6 +92,30 @@ BackupMenuState::BackupMenuState(data::User *user, data::TitleInfo *titleInfo, F
|
|||
|
||||
// This just fills out the menu.
|
||||
BackupMenuState::refresh();
|
||||
|
||||
// This is here so I can bail if the remote isn't setup without causing anymore problems.
|
||||
remote::Storage *remote = remote::get_remote_storage();
|
||||
if (!remote || !remote->is_initialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// First make sure the directory exists.
|
||||
std::string_view remoteTitle = remote->supports_utf8() ? titleInfo->get_title() : titleInfo->get_path_safe_title();
|
||||
if (!remote->directory_exists(remoteTitle) && !remote->create_directory(remoteTitle))
|
||||
{
|
||||
logger::log(STRING_ERROR_CONSTRUCTING, "Error creating directory for remote storage!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Now set it as the parent.
|
||||
remote::Item *parent = remote->get_directory_by_name(remoteTitle);
|
||||
if (!parent)
|
||||
{
|
||||
logger::log(STRING_ERROR_CONSTRUCTING, "Error getting parent for remote! This shouldn't be able to happen...");
|
||||
return;
|
||||
}
|
||||
remote->change_directory(parent);
|
||||
}
|
||||
|
||||
BackupMenuState::~BackupMenuState()
|
||||
|
|
@ -86,54 +124,22 @@ BackupMenuState::~BackupMenuState()
|
|||
fslib::close_file_system(fs::DEFAULT_SAVE_MOUNT);
|
||||
// Close the panel.
|
||||
sm_slidePanel->clear_elements();
|
||||
|
||||
// Return the remote to root.
|
||||
remote::Storage *remote = remote::get_remote_storage();
|
||||
if (remote && remote->is_initialized())
|
||||
{
|
||||
remote->return_to_root();
|
||||
}
|
||||
}
|
||||
|
||||
void BackupMenuState::update(void)
|
||||
void BackupMenuState::update()
|
||||
{
|
||||
bool hasFocus = AppState::has_focus();
|
||||
|
||||
if (input::button_pressed(HidNpadButton_A) && sm_backupMenu->get_selected() == 0 && m_saveHasData)
|
||||
{
|
||||
// get name for backup.
|
||||
char backupName[SIZE_BACKUP_NAME_LENGTH + 1] = {0};
|
||||
|
||||
// Set backup to default.
|
||||
std::snprintf(backupName,
|
||||
SIZE_BACKUP_NAME_LENGTH,
|
||||
"%s - %s",
|
||||
m_user->get_path_safe_nickname(),
|
||||
stringutil::get_date_string().c_str());
|
||||
|
||||
if (!input::button_held(HidNpadButton_ZR) &&
|
||||
!keyboard::get_input(SwkbdType_QWERTY,
|
||||
backupName,
|
||||
strings::get_by_name(strings::names::KEYBOARD_STRINGS, 0),
|
||||
backupName,
|
||||
SIZE_BACKUP_NAME_LENGTH))
|
||||
{
|
||||
return;
|
||||
}
|
||||
// To do: This isn't a good way to check for this... Check to make sure zip has zip extension.
|
||||
if (config::get_by_key(config::keys::EXPORT_TO_ZIP) && std::strstr(backupName, ".zip") == NULL)
|
||||
{
|
||||
// I guess this is a safer way to accomplish this?
|
||||
std::strncat(backupName, ".zip", SIZE_BACKUP_NAME_LENGTH);
|
||||
}
|
||||
else if (!config::get_by_key(config::keys::EXPORT_TO_ZIP) && !std::strstr(backupName, ".zip") &&
|
||||
!fslib::directory_exists(m_directoryPath / backupName) &&
|
||||
!fslib::create_directory(m_directoryPath / backupName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
fslib::Path targetPath = m_directoryPath / backupName;
|
||||
|
||||
// Create the state.
|
||||
auto createNewBackup =
|
||||
std::make_shared<ProgressState>(create_new_backup, m_user, m_titleInfo, targetPath, this);
|
||||
|
||||
// Push the task.
|
||||
StateManager::push_state(createNewBackup);
|
||||
BackupMenuState::name_and_create_backup();
|
||||
}
|
||||
else if (input::button_pressed(HidNpadButton_A) && sm_backupMenu->get_selected() == 0 && !m_saveHasData)
|
||||
{
|
||||
|
|
@ -143,89 +149,29 @@ void BackupMenuState::update(void)
|
|||
}
|
||||
else if (input::button_pressed(HidNpadButton_A) && m_saveHasData && sm_backupMenu->get_selected() > 0)
|
||||
{
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
|
||||
std::string queryString =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::BACKUPMENU_CONFIRMATIONS, 0),
|
||||
m_directoryListing[selected]);
|
||||
|
||||
// Set the target path quick.
|
||||
m_dataStruct->m_targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
auto confirm = std::make_shared<ConfirmState<sys::ProgressTask, ProgressState, BackupMenuState::DataStruct>>(
|
||||
queryString,
|
||||
config::get_by_key(config::keys::HOLD_FOR_OVERWRITE),
|
||||
overwrite_backup,
|
||||
m_dataStruct);
|
||||
|
||||
StateManager::push_state(confirm);
|
||||
BackupMenuState::confirm_backup_overwrite();
|
||||
}
|
||||
else if (input::button_pressed(HidNpadButton_A) && !m_saveHasData && sm_backupMenu->get_selected() > 0)
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 0));
|
||||
}
|
||||
else if (input::button_pressed(HidNpadButton_Y) && sm_backupMenu->get_selected() > 0 &&
|
||||
(m_saveType != FsSaveDataType_System || config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM)))
|
||||
else if (input::button_pressed(HidNpadButton_Y) && sm_backupMenu->get_selected() > 0)
|
||||
{
|
||||
// Need to account for new at the top.
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
|
||||
// Gonna need to test this quick.
|
||||
fslib::Path targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
// This is a quick check to avoid restoring blanks.
|
||||
if (fslib::directory_exists(targetPath) && !fs::directory_has_contents(targetPath))
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 1));
|
||||
return;
|
||||
}
|
||||
else if (fslib::file_exists(targetPath) && std::strcmp("zip", targetPath.get_extension()) == 0 &&
|
||||
!fs::zip_has_contents(targetPath))
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
// Set target path
|
||||
m_dataStruct->m_targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
std::string queryString =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::BACKUPMENU_CONFIRMATIONS, 1),
|
||||
m_directoryListing[selected]);
|
||||
|
||||
auto confirm = std::make_shared<ConfirmState<sys::ProgressTask, ProgressState, BackupMenuState::DataStruct>>(
|
||||
queryString,
|
||||
config::get_by_key(config::keys::HOLD_FOR_RESTORATION),
|
||||
restore_backup,
|
||||
m_dataStruct);
|
||||
|
||||
StateManager::push_state(confirm);
|
||||
BackupMenuState::confirm_restore();
|
||||
}
|
||||
else if (input::button_pressed(HidNpadButton_X) && sm_backupMenu->get_selected() > 0)
|
||||
{
|
||||
// Selected needs to be offset by one to account for New
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
|
||||
// Set path quick.
|
||||
m_dataStruct->m_targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
// get the string.
|
||||
std::string queryString =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::BACKUPMENU_CONFIRMATIONS, 2),
|
||||
m_directoryListing[selected]);
|
||||
|
||||
auto confirm = std::make_shared<ConfirmState<sys::Task, TaskState, BackupMenuState::DataStruct>>(
|
||||
queryString,
|
||||
config::get_by_key(config::keys::HOLD_FOR_DELETION),
|
||||
delete_backup,
|
||||
m_dataStruct);
|
||||
|
||||
// Create/push new state.
|
||||
StateManager::push_state(confirm);
|
||||
BackupMenuState::confirm_delete();
|
||||
}
|
||||
else if (input::button_pressed(HidNpadButton_ZR) && sm_backupMenu->get_selected() > 0)
|
||||
{
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
m_dataStruct->targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
auto upload = std::make_shared<ProgressState>(upload_backup, m_dataStruct);
|
||||
StateManager::push_state(upload);
|
||||
}
|
||||
|
||||
else if (input::button_pressed(HidNpadButton_B))
|
||||
{
|
||||
sm_slidePanel->close();
|
||||
|
|
@ -244,7 +190,7 @@ void BackupMenuState::update(void)
|
|||
sm_backupMenu->update(hasFocus);
|
||||
}
|
||||
|
||||
void BackupMenuState::render(void)
|
||||
void BackupMenuState::render()
|
||||
{
|
||||
// Save this locally.
|
||||
bool hasFocus = AppState::has_focus();
|
||||
|
|
@ -278,7 +224,7 @@ void BackupMenuState::render(void)
|
|||
sm_slidePanel->render(NULL, hasFocus);
|
||||
}
|
||||
|
||||
void BackupMenuState::refresh(void)
|
||||
void BackupMenuState::refresh()
|
||||
{
|
||||
m_directoryListing.open(m_directoryPath);
|
||||
if (!m_directoryListing)
|
||||
|
|
@ -294,7 +240,7 @@ void BackupMenuState::refresh(void)
|
|||
}
|
||||
}
|
||||
|
||||
void BackupMenuState::save_data_written(void)
|
||||
void BackupMenuState::save_data_written()
|
||||
{
|
||||
if (!m_saveHasData)
|
||||
{
|
||||
|
|
@ -302,6 +248,133 @@ void BackupMenuState::save_data_written(void)
|
|||
}
|
||||
}
|
||||
|
||||
void BackupMenuState::name_and_create_backup()
|
||||
{
|
||||
static const char *STRING_ERROR_CREATE_NEW = "Error creating new backup: %s";
|
||||
|
||||
bool zip = config::get_by_key(config::keys::EXPORT_TO_ZIP);
|
||||
char backupName[SIZE_BACKUP_NAME_LENGTH + 1] = {0};
|
||||
|
||||
std::snprintf(backupName,
|
||||
SIZE_BACKUP_NAME_LENGTH,
|
||||
"%s - %s",
|
||||
m_user->get_path_safe_nickname(),
|
||||
stringutil::get_date_string().c_str());
|
||||
|
||||
// ZR is a shortcut to skip the keyboard popping up.
|
||||
if (!input::button_held(HidNpadButton_ZR) &&
|
||||
!keyboard::get_input(SwkbdType_QWERTY,
|
||||
backupName,
|
||||
strings::get_by_name(strings::names::KEYBOARD_STRINGS, 0),
|
||||
backupName,
|
||||
SIZE_BACKUP_NAME_LENGTH))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (zip && !std::strstr(backupName, STRING_ZIP_EXTENSION))
|
||||
{
|
||||
// This could have potential consequences...
|
||||
std::strncat(backupName, STRING_ZIP_EXTENSION, SIZE_BACKUP_NAME_LENGTH);
|
||||
}
|
||||
else if (!zip && !std::strstr(backupName, STRING_ZIP_EXTENSION) &&
|
||||
!fslib::directory_exists(m_directoryPath / backupName) &&
|
||||
!fslib::create_directory(m_directoryPath / backupName))
|
||||
{
|
||||
logger::log(STRING_ERROR_CREATE_NEW, "Error creating export directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
// We should now be able to create the final target path.
|
||||
fslib::Path targetPath = m_directoryPath / backupName;
|
||||
|
||||
auto newBackupTask = std::make_shared<ProgressState>(create_new_backup, m_user, m_titleInfo, targetPath, this);
|
||||
StateManager::push_state(newBackupTask);
|
||||
}
|
||||
|
||||
void BackupMenuState::confirm_backup_overwrite()
|
||||
{
|
||||
// This has one subtracted to account for New Backup.
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
|
||||
std::string confirmationString =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::BACKUPMENU_CONFIRMATIONS, 0),
|
||||
m_directoryListing[selected]);
|
||||
|
||||
// This needs a new target path to pass.
|
||||
m_dataStruct->targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
auto confirm = std::make_shared<ConfirmState<sys::ProgressTask, ProgressState, BackupMenuState::DataStruct>>(
|
||||
confirmationString,
|
||||
config::get_by_key(config::keys::HOLD_FOR_OVERWRITE),
|
||||
overwrite_backup,
|
||||
m_dataStruct);
|
||||
|
||||
StateManager::push_state(confirm);
|
||||
}
|
||||
|
||||
void BackupMenuState::confirm_restore()
|
||||
{
|
||||
if ((m_saveType == FsSaveDataType_System || m_saveType == FsSaveDataType_SystemBcat) &&
|
||||
!config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM))
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::BACKUPMENU_POPS, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
|
||||
fslib::Path target = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
if (fslib::directory_exists(target) && !fs::directory_has_contents(target))
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 1));
|
||||
return;
|
||||
}
|
||||
else if (fslib::file_exists(target) && std::strcmp("zip", target.get_extension()) == 0 &&
|
||||
!fs::zip_has_contents(target))
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 1));
|
||||
return;
|
||||
}
|
||||
|
||||
m_dataStruct->targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
std::string confirmationString =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::BACKUPMENU_CONFIRMATIONS, 1),
|
||||
m_directoryListing[selected]);
|
||||
|
||||
auto confirm = std::make_shared<ConfirmState<sys::ProgressTask, ProgressState, BackupMenuState::DataStruct>>(
|
||||
confirmationString,
|
||||
config::get_by_key(config::keys::HOLD_FOR_RESTORATION),
|
||||
restore_backup,
|
||||
m_dataStruct);
|
||||
|
||||
StateManager::push_state(confirm);
|
||||
}
|
||||
|
||||
void BackupMenuState::confirm_delete()
|
||||
{
|
||||
int selected = sm_backupMenu->get_selected() - 1;
|
||||
|
||||
m_dataStruct->targetPath = m_directoryPath / m_directoryListing[selected];
|
||||
|
||||
std::string confirmationString =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::BACKUPMENU_CONFIRMATIONS, 2),
|
||||
m_directoryListing[selected]);
|
||||
|
||||
auto confirm = std::make_shared<ConfirmState<sys::Task, TaskState, BackupMenuState::DataStruct>>(
|
||||
confirmationString,
|
||||
config::get_by_key(config::keys::HOLD_FOR_DELETION),
|
||||
delete_backup,
|
||||
m_dataStruct);
|
||||
|
||||
StateManager::push_state(confirm);
|
||||
}
|
||||
|
||||
// This is the function to create new backups.
|
||||
static void create_new_backup(sys::ProgressTask *task,
|
||||
data::User *user,
|
||||
|
|
@ -386,12 +459,12 @@ static void overwrite_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenu
|
|||
static const char *STRING_ERROR_PREFIX = "Error overwriting backup: %s";
|
||||
|
||||
// Might need this later.
|
||||
FsSaveDataInfo *saveInfo = dataStruct->m_user->get_save_info_by_id(dataStruct->m_titleInfo->get_application_id());
|
||||
FsSaveDataInfo *saveInfo = dataStruct->user->get_save_info_by_id(dataStruct->titleInfo->get_application_id());
|
||||
|
||||
// Wew this is a fun one to read, but it takes care of everything in one go.
|
||||
if ((fslib::directory_exists(dataStruct->m_targetPath) &&
|
||||
!fslib::delete_directory_recursively(dataStruct->m_targetPath)) ||
|
||||
(fslib::file_exists(dataStruct->m_targetPath) && !fslib::delete_file(dataStruct->m_targetPath)))
|
||||
if ((fslib::directory_exists(dataStruct->targetPath) &&
|
||||
!fslib::delete_directory_recursively(dataStruct->targetPath)) ||
|
||||
(fslib::file_exists(dataStruct->targetPath) && !fslib::delete_file(dataStruct->targetPath)))
|
||||
{
|
||||
logger::log(STRING_ERROR_PREFIX, fslib::get_error_string());
|
||||
task->finished();
|
||||
|
|
@ -403,9 +476,9 @@ static void overwrite_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenu
|
|||
bool hasMeta = fs::fill_save_meta_data(saveInfo, meta);
|
||||
|
||||
|
||||
if (std::strstr(STRING_ZIP_EXTENSION.data(), dataStruct->m_targetPath.c_string()))
|
||||
if (std::strstr(STRING_ZIP_EXTENSION, dataStruct->targetPath.c_string()))
|
||||
{
|
||||
zipFile backupZip = zipOpen64(dataStruct->m_targetPath.c_string(), APPEND_STATUS_CREATE);
|
||||
zipFile backupZip = zipOpen64(dataStruct->targetPath.c_string(), APPEND_STATUS_CREATE);
|
||||
if (!backupZip)
|
||||
{
|
||||
logger::log("Error overwriting backup: Couldn't create new zip!");
|
||||
|
|
@ -441,11 +514,11 @@ static void overwrite_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenu
|
|||
fs::copy_directory_to_zip(fs::DEFAULT_SAVE_ROOT, backupZip, task);
|
||||
zipClose(backupZip, NULL);
|
||||
} // I hope this check works for making sure this is a folder
|
||||
else if (dataStruct->m_targetPath.get_extension() == nullptr && fslib::create_directory(dataStruct->m_targetPath))
|
||||
else if (dataStruct->targetPath.get_extension() == nullptr && fslib::create_directory(dataStruct->targetPath))
|
||||
{
|
||||
// Write this quick.
|
||||
{
|
||||
fslib::Path metaPath = dataStruct->m_targetPath / fs::NAME_SAVE_META;
|
||||
fslib::Path metaPath = dataStruct->targetPath / fs::NAME_SAVE_META;
|
||||
fslib::File metaFile(metaPath, FsOpenMode_Create | FsOpenMode_Write, sizeof(fs::SaveMetaData));
|
||||
if (metaFile && hasMeta)
|
||||
{
|
||||
|
|
@ -453,7 +526,7 @@ static void overwrite_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenu
|
|||
}
|
||||
}
|
||||
|
||||
fs::copy_directory(fs::DEFAULT_SAVE_ROOT, dataStruct->m_targetPath, 0, {}, task);
|
||||
fs::copy_directory(fs::DEFAULT_SAVE_ROOT, dataStruct->targetPath, 0, {}, task);
|
||||
}
|
||||
task->finished();
|
||||
}
|
||||
|
|
@ -461,7 +534,7 @@ static void overwrite_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenu
|
|||
static void restore_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuState::DataStruct> dataStruct)
|
||||
{
|
||||
// Going to need this later.
|
||||
FsSaveDataInfo *saveInfo = dataStruct->m_user->get_save_info_by_id(dataStruct->m_titleInfo->get_application_id());
|
||||
FsSaveDataInfo *saveInfo = dataStruct->user->get_save_info_by_id(dataStruct->titleInfo->get_application_id());
|
||||
if (!saveInfo)
|
||||
{
|
||||
// To do: Log this.
|
||||
|
|
@ -480,12 +553,12 @@ static void restore_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuSt
|
|||
return;
|
||||
}
|
||||
|
||||
if (fslib::directory_exists(dataStruct->m_targetPath))
|
||||
if (fslib::directory_exists(dataStruct->targetPath))
|
||||
{
|
||||
{
|
||||
// Process the save meta if it's there.
|
||||
fs::SaveMetaData meta = {0};
|
||||
fslib::Path saveMetaPath = dataStruct->m_targetPath / fs::NAME_SAVE_META;
|
||||
fslib::Path saveMetaPath = dataStruct->targetPath / fs::NAME_SAVE_META;
|
||||
fslib::File saveMetaFile(saveMetaPath, FsOpenMode_Read);
|
||||
if (saveMetaFile && saveMetaFile.read(&meta, sizeof(fs::SaveMetaData)) == sizeof(fs::SaveMetaData))
|
||||
{
|
||||
|
|
@ -495,15 +568,15 @@ static void restore_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuSt
|
|||
}
|
||||
}
|
||||
|
||||
fs::copy_directory(dataStruct->m_targetPath,
|
||||
fs::copy_directory(dataStruct->targetPath,
|
||||
fs::DEFAULT_SAVE_ROOT,
|
||||
dataStruct->m_journalSize,
|
||||
dataStruct->journalSize,
|
||||
fs::DEFAULT_SAVE_MOUNT,
|
||||
task);
|
||||
}
|
||||
else if (std::strstr(dataStruct->m_targetPath.c_string(), ".zip") != NULL)
|
||||
else if (std::strstr(dataStruct->targetPath.c_string(), ".zip") != NULL)
|
||||
{
|
||||
unzFile targetZip = unzOpen64(dataStruct->m_targetPath.c_string());
|
||||
unzFile targetZip = unzOpen64(dataStruct->targetPath.c_string());
|
||||
if (!targetZip)
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
|
|
@ -527,22 +600,22 @@ static void restore_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuSt
|
|||
|
||||
fs::copy_zip_to_directory(targetZip,
|
||||
fs::DEFAULT_SAVE_ROOT,
|
||||
dataStruct->m_journalSize,
|
||||
dataStruct->journalSize,
|
||||
fs::DEFAULT_SAVE_MOUNT,
|
||||
task);
|
||||
unzClose(targetZip);
|
||||
}
|
||||
else
|
||||
{
|
||||
fs::copy_file(dataStruct->m_targetPath,
|
||||
fs::copy_file(dataStruct->targetPath,
|
||||
fs::DEFAULT_SAVE_ROOT,
|
||||
dataStruct->m_journalSize,
|
||||
dataStruct->journalSize,
|
||||
fs::DEFAULT_SAVE_MOUNT,
|
||||
task);
|
||||
}
|
||||
|
||||
// Update this just in case.
|
||||
dataStruct->m_spawningState->save_data_written();
|
||||
dataStruct->spawningState->save_data_written();
|
||||
|
||||
task->finished();
|
||||
}
|
||||
|
|
@ -551,22 +624,37 @@ static void delete_backup(sys::Task *task, std::shared_ptr<BackupMenuState::Data
|
|||
{
|
||||
if (task)
|
||||
{
|
||||
task->set_status(strings::get_by_name(strings::names::DELETING_FILES, 0), dataStruct->m_targetPath.c_string());
|
||||
task->set_status(strings::get_by_name(strings::names::DELETING_FILES, 0), dataStruct->targetPath.c_string());
|
||||
}
|
||||
|
||||
if (fslib::directory_exists(dataStruct->m_targetPath) &&
|
||||
!fslib::delete_directory_recursively(dataStruct->m_targetPath))
|
||||
if (fslib::directory_exists(dataStruct->targetPath) && !fslib::delete_directory_recursively(dataStruct->targetPath))
|
||||
{
|
||||
logger::log("Error deleting folder backup: %s", fslib::get_error_string());
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 4));
|
||||
}
|
||||
else if (fslib::file_exists(dataStruct->m_targetPath) && !fslib::delete_file(dataStruct->m_targetPath))
|
||||
else if (fslib::file_exists(dataStruct->targetPath) && !fslib::delete_file(dataStruct->targetPath))
|
||||
{
|
||||
logger::log("Error deleting backup: %s", fslib::get_error_string());
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::POP_MESSAGES_BACKUP_MENU, 4));
|
||||
}
|
||||
dataStruct->m_spawningState->refresh();
|
||||
dataStruct->spawningState->refresh();
|
||||
task->finished();
|
||||
}
|
||||
|
||||
static void upload_backup(sys::ProgressTask *task, std::shared_ptr<BackupMenuState::DataStruct> dataStruct)
|
||||
{
|
||||
if (task)
|
||||
{
|
||||
task->set_status(strings::get_by_name(strings::names::BACKUPMENU_STATUS, 1),
|
||||
dataStruct->targetPath.get_filename().data());
|
||||
}
|
||||
|
||||
// To do: This but flashier.
|
||||
remote::Storage *remote = remote::get_remote_storage();
|
||||
|
||||
remote->upload_file(dataStruct->targetPath);
|
||||
|
||||
task->finished();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ namespace
|
|||
constexpr uint64_t TICKS_GLYPH_TRIGGER = 50;
|
||||
} // namespace
|
||||
|
||||
BaseTask::BaseTask(void) : AppState(false)
|
||||
BaseTask::BaseTask() : AppState(false)
|
||||
{
|
||||
m_frameTimer.start(TICKS_GLYPH_TRIGGER);
|
||||
}
|
||||
|
||||
void BaseTask::update(void)
|
||||
void BaseTask::update()
|
||||
{
|
||||
// Just bail if the timer wasn't triggered yet.
|
||||
if (!m_frameTimer.is_triggered())
|
||||
|
|
@ -30,7 +30,7 @@ void BaseTask::update(void)
|
|||
m_colorMod.update();
|
||||
}
|
||||
|
||||
void BaseTask::render_loading_glyph(void)
|
||||
void BaseTask::render_loading_glyph()
|
||||
{
|
||||
// This assumes it's being called after the background was dimmed.
|
||||
sdl::text::render(NULL, 56, 673, 32, sdl::text::NO_TEXT_WRAP, m_colorMod, sm_glyphArray.at(m_currentFrame).data());
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ namespace
|
|||
};
|
||||
} // namespace
|
||||
|
||||
ExtrasMenuState::ExtrasMenuState(void)
|
||||
ExtrasMenuState::ExtrasMenuState()
|
||||
: m_extrasMenu(32, 8, 1000, 24, 555),
|
||||
m_renderTarget(sdl::TextureManager::create_load_texture(SECONDARY_TARGET,
|
||||
1080,
|
||||
|
|
@ -41,7 +41,7 @@ ExtrasMenuState::ExtrasMenuState(void)
|
|||
}
|
||||
}
|
||||
|
||||
void ExtrasMenuState::update(void)
|
||||
void ExtrasMenuState::update()
|
||||
{
|
||||
m_extrasMenu.update(AppState::has_focus());
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ void ExtrasMenuState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void ExtrasMenuState::render(void)
|
||||
void ExtrasMenuState::render()
|
||||
{
|
||||
m_renderTarget->clear(colors::TRANSPARENT);
|
||||
m_extrasMenu.render(m_renderTarget->get(), AppState::has_focus());
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#include "sdl.hpp"
|
||||
#include "strings.hpp"
|
||||
|
||||
MainMenuState::MainMenuState(void)
|
||||
MainMenuState::MainMenuState()
|
||||
: m_renderTarget(sdl::TextureManager::create_load_texture("mainMenuTarget",
|
||||
200,
|
||||
555,
|
||||
|
|
@ -46,7 +46,7 @@ MainMenuState::MainMenuState(void)
|
|||
MainMenuState::initialize_view_states();
|
||||
}
|
||||
|
||||
void MainMenuState::update(void)
|
||||
void MainMenuState::update()
|
||||
{
|
||||
// Update the main menu.
|
||||
m_mainMenu.update(AppState::has_focus());
|
||||
|
|
@ -69,13 +69,13 @@ void MainMenuState::update(void)
|
|||
{
|
||||
// Get pointers to data the user option state needs.
|
||||
data::User *targetUser = sm_users.at(selected);
|
||||
TitleSelectCommon *targetTitleSelect = reinterpret_cast<TitleSelectCommon *>(sm_states.at(selected).get());
|
||||
TitleSelectCommon *targetTitleSelect = static_cast<TitleSelectCommon *>(sm_states.at(selected).get());
|
||||
|
||||
StateManager::push_state(std::make_shared<UserOptionState>(targetUser, targetTitleSelect));
|
||||
}
|
||||
}
|
||||
|
||||
void MainMenuState::render(void)
|
||||
void MainMenuState::render()
|
||||
{
|
||||
// Clear render target by rendering background to it.
|
||||
m_background->render(m_renderTarget->get(), 0, 0);
|
||||
|
|
@ -84,7 +84,7 @@ void MainMenuState::render(void)
|
|||
// render target to screen.
|
||||
m_renderTarget->render(NULL, 0, 91);
|
||||
|
||||
// render next state for current user and control guide if this state has focus.
|
||||
// render next state for current user and control guide if this state has focus. To do: Maybe this different?
|
||||
if (AppState::has_focus())
|
||||
{
|
||||
sm_states.at(m_mainMenu.get_selected())->render();
|
||||
|
|
@ -92,7 +92,7 @@ void MainMenuState::render(void)
|
|||
}
|
||||
}
|
||||
|
||||
void MainMenuState::initialize_view_states(void)
|
||||
void MainMenuState::initialize_view_states()
|
||||
{
|
||||
// Constructor should have taken care of the menu and user list.
|
||||
// Start by clearing the vector.
|
||||
|
|
@ -117,12 +117,12 @@ void MainMenuState::initialize_view_states(void)
|
|||
sm_states.push_back(sm_extrasState);
|
||||
}
|
||||
|
||||
void MainMenuState::refresh_view_states(void)
|
||||
void MainMenuState::refresh_view_states()
|
||||
{
|
||||
// For this, we're only looping through the user states to be extra careful because the last two don't have the refresh() function.
|
||||
int userCount = sm_users.size();
|
||||
for (int i = 0; i < userCount; i++)
|
||||
{
|
||||
std::static_pointer_cast<TitleSelectCommon>(sm_states.at(i))->refresh();
|
||||
static_cast<TitleSelectCommon *>(sm_states.at(i).get())->refresh();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#include "ui/render_functions.hpp"
|
||||
#include <cmath>
|
||||
|
||||
void ProgressState::update(void)
|
||||
void ProgressState::update()
|
||||
{
|
||||
// Base routine.
|
||||
BaseTask::update();
|
||||
|
|
@ -29,7 +29,7 @@ void ProgressState::update(void)
|
|||
m_percentageX = 640 - (sdl::text::get_width(18, m_percentageString.c_str()));
|
||||
}
|
||||
|
||||
void ProgressState::render(void)
|
||||
void ProgressState::render()
|
||||
{
|
||||
// This will dim the background.
|
||||
sdl::render_rect_fill(NULL, 0, 0, 1280, 720, colors::DIM_BACKGROUND);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ SaveCreateState::SaveCreateState(data::User *user, TitleSelectCommon *titleSelec
|
|||
}
|
||||
}
|
||||
|
||||
void SaveCreateState::update(void)
|
||||
void SaveCreateState::update()
|
||||
{
|
||||
if (m_refreshRequired)
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@ void SaveCreateState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void SaveCreateState::render(void)
|
||||
void SaveCreateState::render()
|
||||
{
|
||||
// Clear slide target, render menu, render slide to frame buffer.
|
||||
sm_slidePanel->clear_target();
|
||||
|
|
@ -83,7 +83,7 @@ void SaveCreateState::render(void)
|
|||
sm_slidePanel->render(NULL, AppState::has_focus());
|
||||
}
|
||||
|
||||
void SaveCreateState::data_and_view_refresh_required(void)
|
||||
void SaveCreateState::data_and_view_refresh_required()
|
||||
{
|
||||
m_refreshRequired = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,18 +9,40 @@
|
|||
#include "logger.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "stringutil.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace
|
||||
{
|
||||
// All of these states share the same render target.
|
||||
constexpr std::string_view SECONDARY_TARGET = "SecondaryTarget";
|
||||
|
||||
// This is needed to be able to get and set keys by index. Anything "NULL" isn't a key that can be easily toggled.
|
||||
constexpr std::array<std::string_view, 19> CONFIG_KEY_ARRAY = {"NULL",
|
||||
"NULL",
|
||||
config::keys::INCLUDE_DEVICE_SAVES,
|
||||
config::keys::AUTO_BACKUP_ON_RESTORE,
|
||||
config::keys::AUTO_NAME_BACKUPS,
|
||||
config::keys::AUTO_UPLOAD,
|
||||
config::keys::HOLD_FOR_DELETION,
|
||||
config::keys::HOLD_FOR_RESTORATION,
|
||||
config::keys::HOLD_FOR_OVERWRITE,
|
||||
config::keys::ONLY_LIST_MOUNTABLE,
|
||||
config::keys::LIST_ACCOUNT_SYS_SAVES,
|
||||
config::keys::ALLOW_WRITING_TO_SYSTEM,
|
||||
config::keys::EXPORT_TO_ZIP,
|
||||
config::keys::ZIP_COMPRESSION_LEVEL,
|
||||
config::keys::TITLE_SORT_TYPE,
|
||||
config::keys::JKSM_TEXT_MODE,
|
||||
config::keys::FORCE_ENGLISH,
|
||||
config::keys::ENABLE_TRASH_BIN,
|
||||
"NULL"};
|
||||
} // namespace
|
||||
|
||||
// Declarations. Definitions after class members.
|
||||
static const char *get_value_text(uint8_t value);
|
||||
static const char *get_sort_type_text(uint8_t value);
|
||||
|
||||
SettingsState::SettingsState(void)
|
||||
SettingsState::SettingsState()
|
||||
: m_settingsMenu(32, 8, 1000, 24, 555),
|
||||
m_renderTarget(sdl::TextureManager::create_load_texture(SECONDARY_TARGET,
|
||||
1080,
|
||||
|
|
@ -40,7 +62,7 @@ SettingsState::SettingsState(void)
|
|||
SettingsState::update_menu_options();
|
||||
}
|
||||
|
||||
void SettingsState::update(void)
|
||||
void SettingsState::update()
|
||||
{
|
||||
m_settingsMenu.update(AppState::has_focus());
|
||||
|
||||
|
|
@ -54,7 +76,7 @@ void SettingsState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void SettingsState::render(void)
|
||||
void SettingsState::render()
|
||||
{
|
||||
m_renderTarget->clear(colors::TRANSPARENT);
|
||||
m_settingsMenu.render(m_renderTarget->get(), AppState::has_focus());
|
||||
|
|
@ -72,33 +94,34 @@ void SettingsState::render(void)
|
|||
}
|
||||
}
|
||||
|
||||
void SettingsState::update_menu_options(void)
|
||||
void SettingsState::update_menu_options()
|
||||
{
|
||||
// These can be looped, so screw it.
|
||||
for (int i = 2; i < 13; i++)
|
||||
{
|
||||
std::string updatedOption =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::SETTINGS_MENU, i),
|
||||
get_value_text(config::get_by_index(i - 2)));
|
||||
get_value_text(config::get_by_key(CONFIG_KEY_ARRAY[i])));
|
||||
m_settingsMenu.edit_option(i, updatedOption);
|
||||
}
|
||||
|
||||
// This just displays the value. The config value is offset to account for the first two settings options.
|
||||
m_settingsMenu.edit_option(13,
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::SETTINGS_MENU, 13),
|
||||
config::get_by_index(11)));
|
||||
config::get_by_key(CONFIG_KEY_ARRAY[13])));
|
||||
|
||||
// This gets the type according to the value.
|
||||
m_settingsMenu.edit_option(14,
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::SETTINGS_MENU, 14),
|
||||
get_sort_type_text(config::get_by_index(12))));
|
||||
m_settingsMenu.edit_option(
|
||||
14,
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::SETTINGS_MENU, 14),
|
||||
get_sort_type_text(config::get_by_key(CONFIG_KEY_ARRAY[14]))));
|
||||
|
||||
// Loop again.
|
||||
for (int i = 15; i < 18; i++)
|
||||
{
|
||||
std::string updatedOption =
|
||||
stringutil::get_formatted_string(strings::get_by_name(strings::names::SETTINGS_MENU, i),
|
||||
get_value_text(config::get_by_index(i - 2)));
|
||||
get_value_text(config::get_by_key(CONFIG_KEY_ARRAY[i])));
|
||||
m_settingsMenu.edit_option(i, updatedOption);
|
||||
}
|
||||
|
||||
|
|
@ -108,11 +131,10 @@ void SettingsState::update_menu_options(void)
|
|||
config::get_animation_scaling()));
|
||||
}
|
||||
|
||||
void SettingsState::toggle_options(void)
|
||||
void SettingsState::toggle_options()
|
||||
{
|
||||
int selected = m_settingsMenu.get_selected();
|
||||
|
||||
|
||||
switch (selected)
|
||||
{
|
||||
// Zip level.
|
||||
|
|
@ -154,10 +176,9 @@ void SettingsState::toggle_options(void)
|
|||
// Text mode. This is handled beyond a toggle.
|
||||
case 15:
|
||||
{
|
||||
// We're gonna use this to toggle first.
|
||||
config::toggle_by_index(selected - 2);
|
||||
config::toggle_by_key(CONFIG_KEY_ARRAY[selected]);
|
||||
|
||||
// Need the main state to reinit all the views.
|
||||
// This will reinit all the views according the key toggled.
|
||||
MainMenuState::initialize_view_states();
|
||||
}
|
||||
break;
|
||||
|
|
@ -176,7 +197,7 @@ void SettingsState::toggle_options(void)
|
|||
|
||||
default:
|
||||
{
|
||||
config::toggle_by_index(selected - 2);
|
||||
config::toggle_by_key(CONFIG_KEY_ARRAY[selected]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
#include "strings.hpp"
|
||||
#include "ui/PopMessageManager.hpp"
|
||||
|
||||
void TaskState::update(void)
|
||||
void TaskState::update()
|
||||
{
|
||||
// Run the base update routine.
|
||||
BaseTask::update();
|
||||
|
|
@ -22,7 +22,7 @@ void TaskState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void TaskState::render(void)
|
||||
void TaskState::render()
|
||||
{
|
||||
// Grab task string.
|
||||
std::string status = m_task.get_status();
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ TextTitleSelectState::TextTitleSelectState(data::User *user)
|
|||
TextTitleSelectState::refresh();
|
||||
}
|
||||
|
||||
void TextTitleSelectState::update(void)
|
||||
void TextTitleSelectState::update()
|
||||
{
|
||||
m_titleSelectMenu.update(AppState::has_focus());
|
||||
|
||||
|
|
@ -96,7 +96,7 @@ void TextTitleSelectState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void TextTitleSelectState::render(void)
|
||||
void TextTitleSelectState::render()
|
||||
{
|
||||
m_renderTarget->clear(colors::TRANSPARENT);
|
||||
m_titleSelectMenu.render(m_renderTarget->get(), AppState::has_focus());
|
||||
|
|
@ -104,7 +104,7 @@ void TextTitleSelectState::render(void)
|
|||
m_renderTarget->render(NULL, 201, 91);
|
||||
}
|
||||
|
||||
void TextTitleSelectState::refresh(void)
|
||||
void TextTitleSelectState::refresh()
|
||||
{
|
||||
m_titleSelectMenu.reset();
|
||||
for (size_t i = 0; i < m_user->get_total_data_entries(); i++)
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ TitleInfoState::~TitleInfoState()
|
|||
sm_slidePanel->clear_elements();
|
||||
}
|
||||
|
||||
void TitleInfoState::update(void)
|
||||
void TitleInfoState::update()
|
||||
{
|
||||
// Grab this instead of calling the function over and over.
|
||||
bool hasFocus = AppState::has_focus();
|
||||
|
|
@ -123,7 +123,7 @@ void TitleInfoState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void TitleInfoState::render(void)
|
||||
void TitleInfoState::render()
|
||||
{
|
||||
// This is the vertical gap for rendering text.
|
||||
static constexpr int SIZE_VERT_GAP = SIZE_TEXT_TARGET_HEIGHT + 4;
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ TitleOptionState::TitleOptionState(data::User *user, data::TitleInfo *titleInfo,
|
|||
m_dataStruct->m_titleSelect = m_titleSelect;
|
||||
}
|
||||
|
||||
void TitleOptionState::update(void)
|
||||
void TitleOptionState::update()
|
||||
{
|
||||
// This is kind of tricky to handle, because the blacklist function uses both.
|
||||
if (m_refreshRequired)
|
||||
|
|
@ -251,19 +251,19 @@ void TitleOptionState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void TitleOptionState::render(void)
|
||||
void TitleOptionState::render()
|
||||
{
|
||||
sm_slidePanel->clear_target();
|
||||
sm_titleOptionMenu->render(sm_slidePanel->get_target(), AppState::has_focus());
|
||||
sm_slidePanel->render(NULL, AppState::has_focus());
|
||||
}
|
||||
|
||||
void TitleOptionState::close_on_update(void)
|
||||
void TitleOptionState::close_on_update()
|
||||
{
|
||||
m_exitRequired = true;
|
||||
}
|
||||
|
||||
void TitleOptionState::refresh_required(void)
|
||||
void TitleOptionState::refresh_required()
|
||||
{
|
||||
m_refreshRequired = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
#include "sdl.hpp"
|
||||
#include "strings.hpp"
|
||||
|
||||
TitleSelectCommon::TitleSelectCommon(void)
|
||||
TitleSelectCommon::TitleSelectCommon()
|
||||
{
|
||||
if (m_titleControlsX == 0)
|
||||
{
|
||||
|
|
@ -11,7 +11,7 @@ TitleSelectCommon::TitleSelectCommon(void)
|
|||
}
|
||||
}
|
||||
|
||||
void TitleSelectCommon::render_control_guide(void)
|
||||
void TitleSelectCommon::render_control_guide()
|
||||
{
|
||||
if (AppState::has_focus())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ TitleSelectState::TitleSelectState(data::User *user)
|
|||
SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET)),
|
||||
m_titleView(m_user) {};
|
||||
|
||||
void TitleSelectState::update(void)
|
||||
void TitleSelectState::update()
|
||||
{
|
||||
if (m_user->get_total_data_entries() <= 0)
|
||||
{
|
||||
|
|
@ -44,11 +44,8 @@ void TitleSelectState::update(void)
|
|||
FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
|
||||
data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
|
||||
|
||||
// Path to output to.
|
||||
fslib::Path targetPath = config::get_working_directory() / titleInfo->get_path_safe_title();
|
||||
|
||||
if ((fslib::directory_exists(targetPath) || fslib::create_directory(targetPath)) &&
|
||||
fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo))
|
||||
// To do: Figure out how to handle this differently. Meta files need this closed.
|
||||
if (fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo))
|
||||
{
|
||||
auto backupMenuState =
|
||||
std::make_shared<BackupMenuState>(m_user,
|
||||
|
|
@ -94,7 +91,7 @@ void TitleSelectState::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void TitleSelectState::render(void)
|
||||
void TitleSelectState::render()
|
||||
{
|
||||
m_renderTarget->clear(colors::TRANSPARENT);
|
||||
m_titleView.render(m_renderTarget->get(), AppState::has_focus());
|
||||
|
|
@ -102,7 +99,7 @@ void TitleSelectState::render(void)
|
|||
m_renderTarget->render(NULL, 201, 91);
|
||||
}
|
||||
|
||||
void TitleSelectState::refresh(void)
|
||||
void TitleSelectState::refresh()
|
||||
{
|
||||
m_titleView.refresh();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ UserOptionState::UserOptionState(data::User *user, TitleSelectCommon *titleSelec
|
|||
m_dataStruct->m_spawningState = this;
|
||||
}
|
||||
|
||||
void UserOptionState::update(void)
|
||||
void UserOptionState::update()
|
||||
{
|
||||
// Update the main panel.
|
||||
m_menuPanel->update(AppState::has_focus());
|
||||
|
|
@ -152,7 +152,7 @@ void UserOptionState::update(void)
|
|||
m_userOptionMenu.update(AppState::has_focus());
|
||||
}
|
||||
|
||||
void UserOptionState::render(void)
|
||||
void UserOptionState::render()
|
||||
{
|
||||
// Render target user's title selection screen.
|
||||
m_titleSelect->render();
|
||||
|
|
@ -163,7 +163,7 @@ void UserOptionState::render(void)
|
|||
m_menuPanel->render(NULL, AppState::has_focus());
|
||||
}
|
||||
|
||||
void UserOptionState::data_and_view_refresh_required(void)
|
||||
void UserOptionState::data_and_view_refresh_required()
|
||||
{
|
||||
m_refreshRequired = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,26 +5,23 @@
|
|||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Makes stuff slightly easier to read.
|
||||
using ConfigPair = std::pair<std::string, uint8_t>;
|
||||
|
||||
/// @brief This is the default working directory path.
|
||||
constexpr std::string_view PATH_DEFAULT_WORK_DIR = "sdmc:/JKSV";
|
||||
// Folder path.
|
||||
constexpr std::string_view PATH_CONFIG_FOLDER = "sdmc:/config/JKSV";
|
||||
// Actual config path.
|
||||
constexpr std::string_view PATH_CONFIG_FILE = "sdmc:/config/JKSV/JKSV.json";
|
||||
// Paths file. Funny name too.
|
||||
constexpr std::string_view PATH_PATHS_PATH = "sdmc:/config/JKSV/Paths.json";
|
||||
// Actual config path.
|
||||
const char *PATH_CONFIG_FILE = "sdmc:/config/JKSV/JKSV.json";
|
||||
|
||||
// Vector to preserve order now.
|
||||
std::vector<ConfigPair> s_configVector;
|
||||
/// @brief This map holds the majority of config values.
|
||||
std::map<std::string, uint8_t> s_configMap;
|
||||
|
||||
// Working directory
|
||||
fslib::Path s_workingDirectory;
|
||||
|
|
@ -36,7 +33,7 @@ namespace
|
|||
std::vector<uint64_t> s_blacklist;
|
||||
|
||||
// Map of paths.
|
||||
std::unordered_map<uint64_t, std::string> s_pathMap;
|
||||
std::map<uint64_t, std::string> s_pathMap;
|
||||
} // namespace
|
||||
|
||||
static void read_array_to_vector(std::vector<uint64_t> &vector, json_object *array)
|
||||
|
|
@ -56,7 +53,7 @@ static void read_array_to_vector(std::vector<uint64_t> &vector, json_object *arr
|
|||
}
|
||||
}
|
||||
|
||||
void config::initialize(void)
|
||||
void config::initialize()
|
||||
{
|
||||
if (!fslib::directory_exists(PATH_CONFIG_FOLDER) && !fslib::create_directories_recursively(PATH_CONFIG_FOLDER))
|
||||
{
|
||||
|
|
@ -65,7 +62,7 @@ void config::initialize(void)
|
|||
return;
|
||||
}
|
||||
|
||||
json::Object configJSON = json::new_object(json_object_from_file, PATH_CONFIG_FILE.data());
|
||||
json::Object configJSON = json::new_object(json_object_from_file, PATH_CONFIG_FILE);
|
||||
if (!configJSON)
|
||||
{
|
||||
logger::log("Error opening config for reading: %s", fslib::get_error_string());
|
||||
|
|
@ -99,7 +96,7 @@ void config::initialize(void)
|
|||
}
|
||||
else
|
||||
{
|
||||
s_configVector.push_back(std::make_pair(keyName, json_object_get_uint64(configValue)));
|
||||
s_configMap[keyName] = json_object_get_uint64(configValue);
|
||||
}
|
||||
json_object_iter_next(&configIterator);
|
||||
}
|
||||
|
|
@ -132,29 +129,29 @@ void config::initialize(void)
|
|||
}
|
||||
}
|
||||
|
||||
void config::reset_to_default(void)
|
||||
void config::reset_to_default()
|
||||
{
|
||||
s_workingDirectory = PATH_DEFAULT_WORK_DIR;
|
||||
s_configVector.push_back(std::make_pair(config::keys::INCLUDE_DEVICE_SAVES.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::AUTO_BACKUP_ON_RESTORE.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::AUTO_NAME_BACKUPS.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::AUTO_UPLOAD.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::HOLD_FOR_DELETION.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::HOLD_FOR_RESTORATION.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::HOLD_FOR_OVERWRITE.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::ONLY_LIST_MOUNTABLE.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::LIST_ACCOUNT_SYS_SAVES.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::ALLOW_WRITING_TO_SYSTEM.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::EXPORT_TO_ZIP.data(), 1));
|
||||
s_configVector.push_back(std::make_pair(config::keys::ZIP_COMPRESSION_LEVEL.data(), 6));
|
||||
s_configVector.push_back(std::make_pair(config::keys::TITLE_SORT_TYPE.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::JKSM_TEXT_MODE.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::FORCE_ENGLISH.data(), 0));
|
||||
s_configVector.push_back(std::make_pair(config::keys::ENABLE_TRASH_BIN.data(), 0));
|
||||
s_configMap[config::keys::INCLUDE_DEVICE_SAVES.data()] = 0;
|
||||
s_configMap[config::keys::AUTO_BACKUP_ON_RESTORE.data()] = 1;
|
||||
s_configMap[config::keys::AUTO_NAME_BACKUPS.data()] = 0;
|
||||
s_configMap[config::keys::AUTO_UPLOAD.data()] = 0;
|
||||
s_configMap[config::keys::HOLD_FOR_DELETION.data()] = 1;
|
||||
s_configMap[config::keys::HOLD_FOR_RESTORATION.data()] = 1;
|
||||
s_configMap[config::keys::HOLD_FOR_OVERWRITE.data()] = 1;
|
||||
s_configMap[config::keys::ONLY_LIST_MOUNTABLE.data()] = 1;
|
||||
s_configMap[config::keys::LIST_ACCOUNT_SYS_SAVES.data()] = 0;
|
||||
s_configMap[config::keys::ALLOW_WRITING_TO_SYSTEM.data()] = 0;
|
||||
s_configMap[config::keys::EXPORT_TO_ZIP.data()] = 1;
|
||||
s_configMap[config::keys::ZIP_COMPRESSION_LEVEL.data()] = 6;
|
||||
s_configMap[config::keys::TITLE_SORT_TYPE.data()] = 0;
|
||||
s_configMap[config::keys::JKSM_TEXT_MODE.data()] = 0;
|
||||
s_configMap[config::keys::FORCE_ENGLISH.data()] = 0;
|
||||
s_configMap[config::keys::ENABLE_TRASH_BIN.data()] = 0;
|
||||
s_uiAnimationScaling = 2.5f;
|
||||
}
|
||||
|
||||
void config::save(void)
|
||||
void config::save()
|
||||
{
|
||||
{
|
||||
json::Object configJSON = json::new_object(json_object_new_object);
|
||||
|
|
@ -164,7 +161,7 @@ void config::save(void)
|
|||
json::add_object(configJSON, config::keys::WORKING_DIRECTORY.data(), workingDirectory);
|
||||
|
||||
// Loop through map and add it.
|
||||
for (auto &[key, value] : s_configVector)
|
||||
for (auto &[key, value] : s_configMap)
|
||||
{
|
||||
json_object *jsonValue = json_object_new_uint64(value);
|
||||
json::add_object(configJSON, key.c_str(), jsonValue);
|
||||
|
|
@ -234,83 +231,40 @@ void config::save(void)
|
|||
uint8_t config::get_by_key(std::string_view key)
|
||||
{
|
||||
// See if the key can be found.
|
||||
auto findKey = std::find_if(s_configVector.begin(), s_configVector.end(), [key](const auto &configPair) {
|
||||
return key == configPair.first;
|
||||
});
|
||||
|
||||
// Bail.
|
||||
if (findKey == s_configVector.end())
|
||||
auto findKey = s_configMap.find(key.data());
|
||||
if (findKey == s_configMap.end())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return the value.
|
||||
return findKey->second;
|
||||
}
|
||||
|
||||
void config::toggle_by_key(std::string_view key)
|
||||
{
|
||||
// Make sure the key exists first.
|
||||
auto findKey = std::find_if(s_configVector.begin(), s_configVector.end(), [key](const auto &configPair) {
|
||||
return key == configPair.first;
|
||||
});
|
||||
|
||||
if (findKey == s_configVector.end())
|
||||
auto findKey = s_configMap.find(key.data());
|
||||
if (findKey == s_configMap.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
findKey->second = findKey->second ? 0 : 1;
|
||||
}
|
||||
|
||||
void config::set_by_key(std::string_view key, uint8_t value)
|
||||
{
|
||||
auto findKey = std::find_if(s_configVector.begin(), s_configVector.end(), [key](const auto &configPair) {
|
||||
return key == configPair.first;
|
||||
});
|
||||
if (findKey == s_configVector.end())
|
||||
auto findKey = s_configMap.find(key.data());
|
||||
if (findKey == s_configMap.end())
|
||||
{
|
||||
return;
|
||||
}
|
||||
findKey->second = value;
|
||||
}
|
||||
|
||||
|
||||
uint8_t config::get_by_index(int index)
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(s_configVector.size()))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return s_configVector.at(index).second;
|
||||
}
|
||||
|
||||
void config::toggle_by_index(int index)
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(s_configVector.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
s_configVector[index].second = s_configVector[index].second ? 0 : 1;
|
||||
}
|
||||
|
||||
void config::set_by_index(int index, uint8_t value)
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int>(s_configVector.size()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_configVector[index].second = value;
|
||||
}
|
||||
|
||||
fslib::Path config::get_working_directory(void)
|
||||
fslib::Path config::get_working_directory()
|
||||
{
|
||||
return s_workingDirectory;
|
||||
}
|
||||
|
||||
double config::get_animation_scaling(void)
|
||||
double config::get_animation_scaling()
|
||||
{
|
||||
return s_uiAnimationScaling;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
#include "curl/curl.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "stringutil.hpp"
|
||||
|
||||
namespace
|
||||
|
|
@ -7,16 +8,35 @@ namespace
|
|||
constexpr size_t SIZE_UPLOAD_BUFFER = 0x10000;
|
||||
} // namespace
|
||||
|
||||
bool curl::initialize(void)
|
||||
bool curl::initialize()
|
||||
{
|
||||
return curl_global_init(CURL_GLOBAL_ALL) == CURLE_OK;
|
||||
}
|
||||
|
||||
void curl::exit(void)
|
||||
void curl::exit()
|
||||
{
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
bool curl::perform(curl::Handle &handle)
|
||||
{
|
||||
CURLcode error = curl_easy_perform(handle.get());
|
||||
if (error != CURLE_OK)
|
||||
{
|
||||
logger::log("Error performing curl: %i.", error);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void curl::append_header(curl::HeaderList &list, std::string_view header)
|
||||
{
|
||||
// This is the only real way to accomplish this since slist is a linked list.
|
||||
curl_slist *head = list.release();
|
||||
head = curl_slist_append(head, header.data());
|
||||
list.reset(head);
|
||||
}
|
||||
|
||||
size_t curl::read_data_from_file(char *buffer, size_t size, size_t count, fslib::File *target)
|
||||
{
|
||||
// This should be good enough.
|
||||
|
|
@ -31,7 +51,7 @@ size_t curl::write_header_array(const char *buffer, size_t size, size_t count, c
|
|||
|
||||
size_t curl::write_response_string(const char *buffer, size_t size, size_t count, std::string *string)
|
||||
{
|
||||
string->append(buffer, buffer + (size * count));
|
||||
string->append(buffer, size * count);
|
||||
return size * count;
|
||||
}
|
||||
|
||||
|
|
@ -75,6 +95,43 @@ bool curl::get_header_value(const curl::HeaderArray &array, std::string_view hea
|
|||
return false;
|
||||
}
|
||||
|
||||
long curl::get_response_code(curl::Handle &handle)
|
||||
{
|
||||
long code = 0;
|
||||
curl_easy_getinfo(handle.get(), CURLINFO_RESPONSE_CODE, &code);
|
||||
return code;
|
||||
}
|
||||
|
||||
bool curl::escape_string(curl::Handle &handle, std::string_view in, std::string &out)
|
||||
{
|
||||
char *escaped = curl_easy_escape(handle.get(), in.data(), in.length());
|
||||
if (!escaped)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
out.assign(escaped);
|
||||
|
||||
// I'm assuming this just calls free itself?
|
||||
curl_free(escaped);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool curl::unescape_string(curl::Handle &handle, std::string_view in, std::string &out)
|
||||
{
|
||||
int lengthOut{};
|
||||
char *unescaped = curl_easy_unescape(handle.get(), in.data(), in.length(), &lengthOut);
|
||||
if (!unescaped)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
out.assign(unescaped);
|
||||
|
||||
curl_free(unescaped);
|
||||
return true;
|
||||
}
|
||||
|
||||
void curl::prepare_get(curl::Handle &curl)
|
||||
{
|
||||
// Reset handle. This is faster than making duplicates over and over.
|
||||
|
|
@ -98,6 +155,5 @@ void curl::prepare_upload(curl::Handle &curl)
|
|||
curl::reset_handle(curl);
|
||||
|
||||
curl::set_option(curl, CURLOPT_UPLOAD, 1L);
|
||||
curl::set_option(curl, CURLOPT_UPLOAD_BUFFERSIZE, SIZE_UPLOAD_BUFFER);
|
||||
curl::set_option(curl, CURLOPT_ACCEPT_ENCODING, ""); // Not really sure this will have any affect here...
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,22 +73,22 @@ data::TitleInfo::TitleInfo(uint64_t applicationID, NsApplicationControlData &con
|
|||
m_icon = sdl::TextureManager::create_load_texture(entry->name, m_data.icon, sizeof(m_data.icon));
|
||||
}
|
||||
|
||||
uint64_t data::TitleInfo::get_application_id(void) const
|
||||
uint64_t data::TitleInfo::get_application_id() const
|
||||
{
|
||||
return m_applicationID;
|
||||
}
|
||||
|
||||
NsApplicationControlData *data::TitleInfo::get_control_data(void)
|
||||
NsApplicationControlData *data::TitleInfo::get_control_data()
|
||||
{
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
bool data::TitleInfo::has_control_data(void) const
|
||||
bool data::TitleInfo::has_control_data() const
|
||||
{
|
||||
return m_hasData;
|
||||
}
|
||||
|
||||
const char *data::TitleInfo::get_title(void)
|
||||
const char *data::TitleInfo::get_title()
|
||||
{
|
||||
NacpLanguageEntry *entry = nullptr;
|
||||
if (R_FAILED(nacpGetLanguageEntry(&m_data.nacp, &entry)))
|
||||
|
|
@ -98,12 +98,12 @@ const char *data::TitleInfo::get_title(void)
|
|||
return entry->name;
|
||||
}
|
||||
|
||||
const char *data::TitleInfo::get_path_safe_title(void)
|
||||
const char *data::TitleInfo::get_path_safe_title() const
|
||||
{
|
||||
return m_pathSafeTitle;
|
||||
}
|
||||
|
||||
const char *data::TitleInfo::get_publisher(void)
|
||||
const char *data::TitleInfo::get_publisher()
|
||||
{
|
||||
NacpLanguageEntry *Entry = nullptr;
|
||||
if (R_FAILED(nacpGetLanguageEntry(&m_data.nacp, &Entry)))
|
||||
|
|
@ -113,7 +113,7 @@ const char *data::TitleInfo::get_publisher(void)
|
|||
return Entry->author;
|
||||
}
|
||||
|
||||
uint64_t data::TitleInfo::get_save_data_owner_id(void) const
|
||||
uint64_t data::TitleInfo::get_save_data_owner_id() const
|
||||
{
|
||||
return m_data.nacp.save_data_owner_id;
|
||||
}
|
||||
|
|
@ -312,9 +312,9 @@ int64_t data::TitleInfo::get_journal_size_max(uint8_t saveType) const
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool data::TitleInfo::has_save_data_type(uint8_t saveType)
|
||||
bool data::TitleInfo::has_save_data_type(uint8_t saveType) const
|
||||
{
|
||||
NacpStruct *nacp = &m_data.nacp;
|
||||
const NacpStruct *nacp = &m_data.nacp;
|
||||
|
||||
// I'm not 100% sure this is the best way to test for this.
|
||||
switch (saveType)
|
||||
|
|
@ -352,7 +352,7 @@ bool data::TitleInfo::has_save_data_type(uint8_t saveType)
|
|||
return false;
|
||||
}
|
||||
|
||||
sdl::SharedTexture data::TitleInfo::get_icon(void) const
|
||||
sdl::SharedTexture data::TitleInfo::get_icon() const
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
|
@ -369,7 +369,7 @@ void data::TitleInfo::set_path_safe_title(const char *newPathSafe, size_t newPat
|
|||
std::memcpy(m_pathSafeTitle, newPathSafe, newPathLength);
|
||||
}
|
||||
|
||||
void data::TitleInfo::get_create_path_safe_title(void)
|
||||
void data::TitleInfo::get_create_path_safe_title()
|
||||
{
|
||||
// Avoid calling this function over and over.
|
||||
uint64_t applicationID = TitleInfo::get_application_id();
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ void data::User::add_data(const FsSaveDataInfo *saveInfo, const PdmPlayStatistic
|
|||
m_userData.push_back(std::make_pair(applicationID, std::make_pair(*saveInfo, *playStats)));
|
||||
}
|
||||
|
||||
void data::User::clear_data_entries(void)
|
||||
void data::User::clear_data_entries()
|
||||
{
|
||||
m_userData.clear();
|
||||
}
|
||||
|
|
@ -80,32 +80,32 @@ void data::User::erase_data(int index)
|
|||
m_userData.erase(m_userData.begin() + index);
|
||||
}
|
||||
|
||||
void data::User::sort_data(void)
|
||||
void data::User::sort_data()
|
||||
{
|
||||
std::sort(m_userData.begin(), m_userData.end(), sort_user_data);
|
||||
}
|
||||
|
||||
AccountUid data::User::get_account_id(void) const
|
||||
AccountUid data::User::get_account_id() const
|
||||
{
|
||||
return m_accountID;
|
||||
}
|
||||
|
||||
FsSaveDataType data::User::get_account_save_type(void) const
|
||||
FsSaveDataType data::User::get_account_save_type() const
|
||||
{
|
||||
return m_saveType;
|
||||
}
|
||||
|
||||
const char *data::User::get_nickname(void) const
|
||||
const char *data::User::get_nickname() const
|
||||
{
|
||||
return m_nickname;
|
||||
}
|
||||
|
||||
const char *data::User::get_path_safe_nickname(void) const
|
||||
const char *data::User::get_path_safe_nickname() const
|
||||
{
|
||||
return m_pathSafeNickname;
|
||||
}
|
||||
|
||||
size_t data::User::get_total_data_entries(void) const
|
||||
size_t data::User::get_total_data_entries() const
|
||||
{
|
||||
return m_userData.size();
|
||||
}
|
||||
|
|
@ -150,7 +150,7 @@ FsSaveDataInfo *data::User::get_save_info_by_id(uint64_t applicationID)
|
|||
return &findTitle->second.first;
|
||||
}
|
||||
|
||||
data::UserSaveInfoList &data::User::get_user_save_info_list(void)
|
||||
data::UserSaveInfoList &data::User::get_user_save_info_list()
|
||||
{
|
||||
return m_userData;
|
||||
}
|
||||
|
|
@ -168,12 +168,12 @@ PdmPlayStatistics *data::User::get_play_stats_by_id(uint64_t applicationID)
|
|||
return &findTitle->second.second;
|
||||
}
|
||||
|
||||
SDL_Texture *data::User::get_icon(void)
|
||||
SDL_Texture *data::User::get_icon()
|
||||
{
|
||||
return m_icon->get();
|
||||
}
|
||||
|
||||
sdl::SharedTexture data::User::get_shared_icon(void)
|
||||
sdl::SharedTexture data::User::get_shared_icon()
|
||||
{
|
||||
return m_icon;
|
||||
}
|
||||
|
|
@ -194,7 +194,7 @@ void data::User::erase_save_info_by_id(uint64_t applicationID)
|
|||
m_userData.erase(targetEntry);
|
||||
}
|
||||
|
||||
void data::User::load_user_data(void)
|
||||
void data::User::load_user_data()
|
||||
{
|
||||
// Pull these from config quick.
|
||||
bool accountSystemSaves = config::get_by_key(config::keys::LIST_ACCOUNT_SYS_SAVES);
|
||||
|
|
@ -297,7 +297,7 @@ void data::User::load_account(AccountProfile &profile, AccountProfileBase &profi
|
|||
}
|
||||
}
|
||||
|
||||
void data::User::create_account(void)
|
||||
void data::User::create_account()
|
||||
{
|
||||
// This is needed a lot here.
|
||||
std::string accountIDString = stringutil::get_formatted_string("Acc_%08X", m_accountID.uid[0] & 0xFFFFFFFF);
|
||||
|
|
|
|||
|
|
@ -41,20 +41,20 @@ namespace
|
|||
|
||||
// Declarations here. Definitions at bottom. These should appear in the order called.
|
||||
/// @brief Loads users from the system and creates the system users.
|
||||
static bool load_create_user_accounts(void);
|
||||
static bool load_create_user_accounts();
|
||||
|
||||
/// @brief Loads the application records from NS.
|
||||
static void load_application_records(void);
|
||||
static void load_application_records();
|
||||
|
||||
/// @brief Imports external SVI(Control Data) files.
|
||||
static void import_svi_files(void);
|
||||
static void import_svi_files();
|
||||
|
||||
/// @brief Attempts to read the cache file from the SD.
|
||||
/// @return True on success. False on failure.
|
||||
static bool read_cache_file(void);
|
||||
static bool read_cache_file();
|
||||
|
||||
/// @brief Creates the cache file on the SD card.
|
||||
static void create_cache_file(void);
|
||||
static void create_cache_file();
|
||||
|
||||
bool data::initialize(bool clearCache)
|
||||
{
|
||||
|
|
@ -137,7 +137,7 @@ bool data::title_exists_in_map(uint64_t applicationID)
|
|||
return s_titleInfoMap.find(applicationID) != s_titleInfoMap.end();
|
||||
}
|
||||
|
||||
std::unordered_map<uint64_t, data::TitleInfo> &data::get_title_info_map(void)
|
||||
std::unordered_map<uint64_t, data::TitleInfo> &data::get_title_info_map()
|
||||
{
|
||||
return s_titleInfoMap;
|
||||
}
|
||||
|
|
@ -157,7 +157,7 @@ void data::get_title_info_by_type(FsSaveDataType saveType, std::vector<data::Tit
|
|||
}
|
||||
}
|
||||
|
||||
static bool load_create_user_accounts(void)
|
||||
static bool load_create_user_accounts()
|
||||
{
|
||||
// For saving total accounts found.
|
||||
int total = 0;
|
||||
|
|
@ -206,7 +206,7 @@ static bool load_create_user_accounts(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void load_application_records(void)
|
||||
static void load_application_records()
|
||||
{
|
||||
// Record struct/buffer.
|
||||
NsApplicationRecord record = {0};
|
||||
|
|
@ -223,7 +223,7 @@ static void load_application_records(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void import_svi_files(void)
|
||||
static void import_svi_files()
|
||||
{
|
||||
// Path.
|
||||
fslib::Path sviPath = config::get_working_directory() / "svi";
|
||||
|
|
@ -271,7 +271,7 @@ static void import_svi_files(void)
|
|||
}
|
||||
}
|
||||
|
||||
static bool read_cache_file(void)
|
||||
static bool read_cache_file()
|
||||
{
|
||||
// Try opening the cache file.
|
||||
fslib::File cache(PATH_CACHE_PATH, FsOpenMode_Read);
|
||||
|
|
@ -311,7 +311,7 @@ static bool read_cache_file(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
static void create_cache_file(void)
|
||||
static void create_cache_file()
|
||||
{
|
||||
// First try creating and opening the file.
|
||||
fslib::File cache(PATH_CACHE_PATH, FsOpenMode_Create | FsOpenMode_Write);
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ namespace
|
|||
PadState s_gamepad;
|
||||
}
|
||||
|
||||
void input::initialize(void)
|
||||
void input::initialize()
|
||||
{
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
padInitializeDefault(&s_gamepad);
|
||||
}
|
||||
|
||||
void input::update(void)
|
||||
void input::update()
|
||||
{
|
||||
padUpdate(&s_gamepad);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ namespace
|
|||
constexpr size_t VA_BUFFER_SIZE = 0x1000;
|
||||
} // namespace
|
||||
|
||||
void logger::initialize(void)
|
||||
void logger::initialize()
|
||||
{
|
||||
// Create log path and empty the log for this run.
|
||||
s_logFilePath = "sdmc:/config/JKSV/JKSV.log";
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#include "config.hpp"
|
||||
#include <switch.h>
|
||||
|
||||
int main(void)
|
||||
int main()
|
||||
{
|
||||
JKSV jksv{};
|
||||
while (appletMainLoop() && jksv.is_running())
|
||||
|
|
|
|||
45
source/remote/Form.cpp
Normal file
45
source/remote/Form.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "remote/Form.hpp"
|
||||
|
||||
remote::Form::Form(const remote::Form &form)
|
||||
{
|
||||
m_form = form.m_form;
|
||||
}
|
||||
|
||||
remote::Form::Form(remote::Form &&form)
|
||||
{
|
||||
m_form = form.m_form;
|
||||
form.m_form.clear();
|
||||
}
|
||||
|
||||
remote::Form &remote::Form::operator=(const remote::Form &form)
|
||||
{
|
||||
m_form = form.m_form;
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::Form &remote::Form::operator=(remote::Form &&form)
|
||||
{
|
||||
m_form = form.m_form;
|
||||
form.m_form.clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::Form &remote::Form::append_parameter(std::string_view param, std::string_view value)
|
||||
{
|
||||
if (!m_form.empty() && m_form.back() != '&')
|
||||
{
|
||||
m_form.append("&");
|
||||
}
|
||||
m_form.append(param).append("=").append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char *remote::Form::get() const
|
||||
{
|
||||
return m_form.c_str();
|
||||
}
|
||||
|
||||
size_t remote::Form::length() const
|
||||
{
|
||||
return m_form.length();
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,29 +1,29 @@
|
|||
#include "remote/Item.hpp"
|
||||
|
||||
remote::Item::Item(std::string_view name, std::string_view id, std::string_view parent, bool directory)
|
||||
: m_name(name), m_id(id), m_parent(parent), m_isDirectory(directory) {};
|
||||
remote::Item::Item(std::string_view name, std::string_view id, std::string_view parent, size_t size, bool directory)
|
||||
: m_name(name), m_id(id), m_parent(parent), m_size(size), m_isDirectory(directory) {};
|
||||
|
||||
std::string_view remote::Item::get_name(void) const
|
||||
std::string_view remote::Item::get_name() const
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
std::string_view remote::Item::get_id(void) const
|
||||
std::string_view remote::Item::get_id() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
std::string_view remote::Item::get_parent_id(void) const
|
||||
std::string_view remote::Item::get_parent_id() const
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
size_t remote::Item::get_size(void) const
|
||||
size_t remote::Item::get_size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
bool remote::Item::is_directory(void) const
|
||||
bool remote::Item::is_directory() const
|
||||
{
|
||||
return m_isDirectory;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,51 +1,87 @@
|
|||
#include "remote/Storage.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
bool remote::Storage::is_initialized(void) const
|
||||
// Declarations here. Defined at bottom.
|
||||
remote::Storage::Storage() : m_curl(curl::new_handle()) {};
|
||||
|
||||
bool remote::Storage::is_initialized() const
|
||||
{
|
||||
return m_isInitialized;
|
||||
}
|
||||
|
||||
bool remote::Storage::directory_exists(std::string_view name)
|
||||
{
|
||||
return Storage::find_directory(name) != m_list.end();
|
||||
return Storage::find_directory_by_name(name) != m_list.end();
|
||||
}
|
||||
|
||||
bool remote::Storage::get_directory_id(std::string_view name, std::string &idOut)
|
||||
void remote::Storage::return_to_root()
|
||||
{
|
||||
remote::Storage::List::iterator findDir = Storage::find_directory(name);
|
||||
if (findDir == m_list.end())
|
||||
m_parent = m_root;
|
||||
}
|
||||
|
||||
void remote::Storage::set_root_directory(remote::Item *root)
|
||||
{
|
||||
m_root = root->get_id();
|
||||
}
|
||||
|
||||
void remote::Storage::change_directory(remote::Item *item)
|
||||
{
|
||||
m_parent = item->get_id();
|
||||
}
|
||||
|
||||
remote::Item *remote::Storage::get_directory_by_name(std::string_view name)
|
||||
{
|
||||
auto findDirectory = Storage::find_directory_by_name(name);
|
||||
if (findDirectory == m_list.end())
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
idOut = findDir->get_id();
|
||||
return true;
|
||||
return &(*findDirectory);
|
||||
}
|
||||
|
||||
remote::Storage::DirectoryListing remote::Storage::get_directory_listing()
|
||||
{
|
||||
remote::Storage::DirectoryListing listing;
|
||||
|
||||
Storage::List::iterator current = m_list.begin();
|
||||
while ((current = std::find_if(current, m_list.end(), [this](const Item &item) {
|
||||
return item.get_parent_id() == this->m_parent;
|
||||
})) != m_list.end())
|
||||
{
|
||||
listing.push_back(&(*current));
|
||||
}
|
||||
|
||||
return listing;
|
||||
}
|
||||
|
||||
bool remote::Storage::file_exists(std::string_view name)
|
||||
{
|
||||
return Storage::find_file(name) != m_list.end();
|
||||
return Storage::find_file_by_name(name) != m_list.end();
|
||||
}
|
||||
|
||||
bool remote::Storage::get_file_id(std::string_view name, std::string &idOut)
|
||||
remote::Item *remote::Storage::get_file_by_name(std::string_view name)
|
||||
{
|
||||
remote::Storage::List::iterator findFile = Storage::find_file(name);
|
||||
auto findFile = Storage::find_file_by_name(name);
|
||||
if (findFile == m_list.end())
|
||||
{
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
idOut = findFile->get_id();
|
||||
return true;
|
||||
return &(*findFile);
|
||||
}
|
||||
|
||||
remote::Storage::List::iterator remote::Storage::find_directory(std::string_view name)
|
||||
bool remote::Storage::supports_utf8() const
|
||||
{
|
||||
return m_utf8Paths;
|
||||
}
|
||||
|
||||
remote::Storage::List::iterator remote::Storage::find_directory_by_name(std::string_view name)
|
||||
{
|
||||
return std::find_if(m_list.begin(), m_list.end(), [name, this](const Item &item) {
|
||||
return item.is_directory() && item.get_parent_id() == this->m_parent && item.get_name() == name;
|
||||
});
|
||||
}
|
||||
|
||||
remote::Storage::List::iterator remote::Storage::find_file(std::string_view name)
|
||||
remote::Storage::List::iterator remote::Storage::find_file_by_name(std::string_view name)
|
||||
{
|
||||
return std::find_if(m_list.begin(), m_list.end(), [name, this](const Item &item) {
|
||||
return !item.is_directory() && item.get_parent_id() == this->m_parent && item.get_name() == name;
|
||||
|
|
|
|||
90
source/remote/URL.cpp
Normal file
90
source/remote/URL.cpp
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
#include "remote/URL.hpp"
|
||||
|
||||
remote::URL::URL(std::string_view base) : m_url(base) {};
|
||||
|
||||
remote::URL::URL(const URL &url)
|
||||
{
|
||||
m_url = url.m_url;
|
||||
}
|
||||
|
||||
remote::URL::URL(URL &&url)
|
||||
{
|
||||
m_url = url.m_url;
|
||||
// This seems odd, but w/e
|
||||
url.m_url.clear();
|
||||
}
|
||||
|
||||
remote::URL &remote::URL::operator=(const remote::URL &url)
|
||||
{
|
||||
m_url = url.m_url;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::URL &remote::URL::operator=(remote::URL &&url)
|
||||
{
|
||||
m_url = url.m_url;
|
||||
url.m_url.clear();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::URL &remote::URL::set_base(std::string_view base)
|
||||
{
|
||||
// This will just assign and clear out the old one, I hope.
|
||||
m_url = base;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::URL &remote::URL::append_path(std::string_view path)
|
||||
{
|
||||
// Check both just to be sure because this makes WebDav easier to tackle.
|
||||
if (m_url.back() != '/' && path.front() != '/')
|
||||
{
|
||||
m_url.append("/");
|
||||
}
|
||||
|
||||
// This is here to make WebDav easier to read and deal with in case of blank basepaths.
|
||||
if (path.empty())
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
m_url.append(path);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::URL &remote::URL::append_parameter(std::string_view param, std::string_view value)
|
||||
{
|
||||
URL::append_separator();
|
||||
m_url.append(param).append("=").append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
remote::URL &remote::URL::append_slash()
|
||||
{
|
||||
if (m_url.back() != '/')
|
||||
{
|
||||
m_url.append("/");
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const char *remote::URL::get() const
|
||||
{
|
||||
return m_url.c_str();
|
||||
}
|
||||
|
||||
void remote::URL::append_separator()
|
||||
{
|
||||
if (m_url.find('?') == m_url.npos)
|
||||
{
|
||||
m_url.append("?");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_url.append("&");
|
||||
}
|
||||
}
|
||||
390
source/remote/WebDav.cpp
Normal file
390
source/remote/WebDav.cpp
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
#include "remote/WebDav.hpp"
|
||||
#include "JSON.hpp"
|
||||
#include "curl/curl.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "remote/remote.hpp"
|
||||
#include <tinyxml2.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
const char *TAG_XML_HREF = "href";
|
||||
}
|
||||
|
||||
// Declarations here. Definitions at bottom.
|
||||
/// @brief Gets a XML element by name. This is namespace agnostic.
|
||||
/// @param parent Parent XML element.
|
||||
/// @param name Name of the element to get. No namespace needed.
|
||||
static tinyxml2::XMLElement *get_element_by_name(tinyxml2::XMLElement *parent, std::string_view name);
|
||||
|
||||
/// @brief Returns the starting point of the tag name without the namespace.
|
||||
/// @param tag Tag to get the name of.
|
||||
static std::string_view get_tag_begin(std::string_view tag);
|
||||
|
||||
remote::WebDav::WebDav() : Storage()
|
||||
{
|
||||
static const char *STRING_CONFIG_READ_ERROR = "Error initializing WebDav: %s";
|
||||
|
||||
// WebDav has problems with these.
|
||||
m_utf8Paths = false;
|
||||
|
||||
json::Object config = json::new_object(json_object_from_file, remote::PATH_WEBDAV_CONFIG.data());
|
||||
if (!config)
|
||||
{
|
||||
logger::log(STRING_CONFIG_READ_ERROR, "Error reading configuration file!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's just get this all out of the way at once.
|
||||
json_object *origin = json::get_object(config, "origin");
|
||||
json_object *basepath = json::get_object(config, "basepath");
|
||||
json_object *username = json::get_object(config, "username");
|
||||
json_object *password = json::get_object(config, "password");
|
||||
|
||||
// This is the bare minimum required to continue.
|
||||
if (!origin)
|
||||
{
|
||||
logger::log(STRING_CONFIG_READ_ERROR, "Config is missing origin!");
|
||||
return;
|
||||
}
|
||||
m_origin = json_object_get_string(origin);
|
||||
|
||||
if (basepath)
|
||||
{
|
||||
// The root is both in the beginning. I want this to work as closely as the original just not as poorly written
|
||||
// or thought out as the original JKSV dav code.
|
||||
m_root = json_object_get_string(basepath);
|
||||
m_parent = m_root;
|
||||
}
|
||||
|
||||
if (username)
|
||||
{
|
||||
m_username = json_object_get_string(username);
|
||||
}
|
||||
|
||||
if (password)
|
||||
{
|
||||
m_password = json_object_get_string(password);
|
||||
}
|
||||
|
||||
// This is the starting point. This will read the entire basepath listing in one go.
|
||||
remote::URL url{m_origin};
|
||||
url.append_path(m_root).append_slash();
|
||||
|
||||
// This'll recursively get the full listing of the basepath for the WebDav server.
|
||||
std::string xml{};
|
||||
if (!WebDav::prop_find(url, xml) || !WebDav::process_listing(xml))
|
||||
{
|
||||
logger::log(STRING_CONFIG_READ_ERROR, "Error retrieving listing from WebDav server!");
|
||||
return;
|
||||
}
|
||||
|
||||
m_isInitialized = true;
|
||||
}
|
||||
|
||||
bool remote::WebDav::create_directory(std::string_view name)
|
||||
{
|
||||
static const char *STRING_CREATE_DIR_ERROR = "Error creating WebDav directory: %s";
|
||||
|
||||
std::string escapedName;
|
||||
if (!curl::escape_string(m_curl, name, escapedName))
|
||||
{
|
||||
logger::log(STRING_CREATE_DIR_ERROR, "Error escaping directory name!");
|
||||
return false;
|
||||
}
|
||||
|
||||
remote::URL url{m_origin};
|
||||
url.append_path(m_parent).append_path(escapedName).append_slash();
|
||||
|
||||
curl::reset_handle(m_curl);
|
||||
WebDav::append_credentials();
|
||||
curl::set_option(m_curl, CURLOPT_URL, url.get());
|
||||
curl::set_option(m_curl, CURLOPT_CUSTOMREQUEST, "MKCOL");
|
||||
|
||||
if (!curl::perform(m_curl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (curl::get_response_code(m_curl) != 201)
|
||||
{
|
||||
logger::log(STRING_CREATE_DIR_ERROR, name.data());
|
||||
return false;
|
||||
}
|
||||
|
||||
// This is the ID string so we can make WebDav work within the same framework as Google Drive.
|
||||
std::string id = m_parent + "/" + escapedName + "/";
|
||||
m_list.emplace_back(name, id, m_parent, 0, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remote::WebDav::upload_file(const fslib::Path &source)
|
||||
{
|
||||
static const char *STRING_ERROR_UPLOADING = "Error uploading file: %s";
|
||||
|
||||
fslib::File file(source, FsOpenMode_Read);
|
||||
if (!file)
|
||||
{
|
||||
logger::log(STRING_ERROR_UPLOADING, fslib::get_error_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string escapedName;
|
||||
if (!curl::escape_string(m_curl, source.get_filename(), escapedName))
|
||||
{
|
||||
logger::log(STRING_ERROR_UPLOADING, "Failed to escape filename!");
|
||||
return false;
|
||||
}
|
||||
|
||||
remote::URL url{m_origin};
|
||||
url.append_path(m_parent).append_path(escapedName);
|
||||
|
||||
curl::reset_handle(m_curl);
|
||||
WebDav::append_credentials();
|
||||
curl::set_option(m_curl, CURLOPT_URL, url.get());
|
||||
curl::set_option(m_curl, CURLOPT_UPLOAD, 1L);
|
||||
curl::set_option(m_curl, CURLOPT_UPLOAD_BUFFERSIZE, Storage::SIZE_UPLOAD_BUFFER);
|
||||
curl::set_option(m_curl, CURLOPT_READFUNCTION, curl::read_data_from_file);
|
||||
curl::set_option(m_curl, CURLOPT_READDATA, &file);
|
||||
|
||||
if (!curl::perform(m_curl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_list.emplace_back(source.get_filename(), escapedName, m_parent, file.get_size(), false);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remote::WebDav::patch_file(remote::Item *item, const fslib::Path &source)
|
||||
{
|
||||
static const char *STRING_ERROR_PATCHING = "Error patching file: %s";
|
||||
|
||||
fslib::File file(source, FsOpenMode_Read);
|
||||
if (!file)
|
||||
{
|
||||
logger::log(STRING_ERROR_PATCHING, fslib::get_error_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
remote::URL url{m_origin};
|
||||
url.append_path(m_parent).append_path(item->get_id());
|
||||
|
||||
curl::reset_handle(m_curl);
|
||||
WebDav::append_credentials();
|
||||
curl::set_option(m_curl, CURLOPT_URL, url.get());
|
||||
curl::set_option(m_curl, CURLOPT_UPLOAD, 1L);
|
||||
curl::set_option(m_curl, CURLOPT_UPLOAD_BUFFERSIZE, Storage::SIZE_UPLOAD_BUFFER);
|
||||
curl::set_option(m_curl, CURLOPT_READFUNCTION, curl::read_data_from_file);
|
||||
curl::set_option(m_curl, CURLOPT_READDATA, &file);
|
||||
|
||||
if (!curl::perform(m_curl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Just update the size this time.
|
||||
item->set_size(file.get_size());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remote::WebDav::download_file(const remote::Item *item, const fslib::Path &destination)
|
||||
{
|
||||
static const char *STRING_ERROR_DOWNLOADING = "Error downloading file: %s";
|
||||
|
||||
fslib::File file(destination, FsOpenMode_Create | FsOpenMode_Write);
|
||||
if (!file)
|
||||
{
|
||||
logger::log(STRING_ERROR_DOWNLOADING, fslib::get_error_string());
|
||||
return false;
|
||||
}
|
||||
|
||||
remote::URL url{m_origin};
|
||||
url.append_path(m_parent).append_path(item->get_id());
|
||||
|
||||
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::write_data_to_file);
|
||||
curl::set_option(m_curl, CURLOPT_WRITEDATA, &file);
|
||||
|
||||
if (!curl::perform(m_curl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool remote::WebDav::delete_item(const remote::Item *item)
|
||||
{
|
||||
static const char *STRING_ERROR_DELETING = "Error deleting item: %s";
|
||||
|
||||
remote::URL url{m_origin};
|
||||
url.append_path(m_parent).append_path(item->get_id());
|
||||
if (item->is_directory())
|
||||
{
|
||||
url.append_slash();
|
||||
}
|
||||
|
||||
curl::reset_handle(m_curl);
|
||||
WebDav::append_credentials();
|
||||
curl::set_option(m_curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
curl::set_option(m_curl, CURLOPT_URL, url.get());
|
||||
|
||||
if (!curl::perform(m_curl))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (curl::get_response_code(m_curl) != 204)
|
||||
{
|
||||
logger::log(STRING_ERROR_DELETING, "Deletion failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void remote::WebDav::append_credentials()
|
||||
{
|
||||
if (!m_username.empty())
|
||||
{
|
||||
curl::set_option(m_curl, CURLOPT_USERNAME, m_username.c_str());
|
||||
}
|
||||
|
||||
if (!m_password.empty())
|
||||
{
|
||||
curl::set_option(m_curl, CURLOPT_PASSWORD, m_password.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool remote::WebDav::prop_find(const remote::URL &url, std::string &xml)
|
||||
{
|
||||
// Some servers block Depth: Infinity.
|
||||
curl::HeaderList header = curl::new_header_list();
|
||||
curl::append_header(header, "Depth: 1");
|
||||
|
||||
curl::reset_handle(m_curl);
|
||||
WebDav::append_credentials();
|
||||
curl::set_option(m_curl, CURLOPT_CUSTOMREQUEST, "PROPFIND");
|
||||
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::write_response_string);
|
||||
curl::set_option(m_curl, CURLOPT_WRITEDATA, &xml);
|
||||
|
||||
return curl::perform(m_curl);
|
||||
}
|
||||
|
||||
bool remote::WebDav::process_listing(std::string_view xml)
|
||||
{
|
||||
static const char *STRING_ERROR_PROCESSING_XML = "Error processing XML: %s";
|
||||
|
||||
tinyxml2::XMLDocument listing{};
|
||||
if (listing.Parse(xml.data(), xml.length()))
|
||||
{
|
||||
logger::log(STRING_ERROR_PROCESSING_XML, "Couldn't parse XML!");
|
||||
return false;
|
||||
}
|
||||
|
||||
tinyxml2::XMLElement *root = listing.RootElement();
|
||||
|
||||
// The first element is what we're using as the parent.
|
||||
tinyxml2::XMLElement *parent = root->FirstChildElement();
|
||||
|
||||
tinyxml2::XMLElement *parentLocation = get_element_by_name(parent, TAG_XML_HREF);
|
||||
if (!parentLocation)
|
||||
{
|
||||
logger::log(STRING_ERROR_PROCESSING_XML, "Error finding list parent location!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// There's no point in continuing if this fails. Just return true.
|
||||
tinyxml2::XMLElement *current = parent->NextSiblingElement();
|
||||
if (!current)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
// Parsing XML is actually annoying. Even with tinyxml2.
|
||||
tinyxml2::XMLElement *href = get_element_by_name(current, TAG_XML_HREF);
|
||||
tinyxml2::XMLElement *propstat = get_element_by_name(current, "propstat");
|
||||
tinyxml2::XMLElement *prop = get_element_by_name(propstat, "prop");
|
||||
tinyxml2::XMLElement *resourceType = get_element_by_name(prop, "resourcetype");
|
||||
if (!href || !propstat || !prop || !resourceType)
|
||||
{
|
||||
logger::log(STRING_ERROR_PROCESSING_XML, "Element is missing data!");
|
||||
continue;
|
||||
}
|
||||
|
||||
// This is the best way to detect a directory.
|
||||
tinyxml2::XMLElement *collection = get_element_by_name(resourceType, "collection");
|
||||
if (collection)
|
||||
{
|
||||
// JKSV doesn't expose folder names to the end user, so they are emplaced as-is.
|
||||
m_list.emplace_back(href->GetText(), href->GetText(), parentLocation->GetText(), 0, true);
|
||||
|
||||
remote::URL nextUrl{m_origin};
|
||||
nextUrl.append_path(href->GetText());
|
||||
|
||||
std::string xml{};
|
||||
if (!WebDav::prop_find(nextUrl, xml) || !WebDav::process_listing(xml))
|
||||
{
|
||||
logger::log(STRING_ERROR_PROCESSING_XML, href->GetText());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tinyxml2::XMLElement *displayName = get_element_by_name(prop, "displayname");
|
||||
tinyxml2::XMLElement *getContentLength = get_element_by_name(prop, "getcontentlength");
|
||||
if (!displayName || !getContentLength)
|
||||
{
|
||||
logger::log(STRING_ERROR_PROCESSING_XML, "Missing needed tags for file!");
|
||||
continue;
|
||||
}
|
||||
|
||||
m_list.emplace_back(displayName->GetText(),
|
||||
href->GetText(),
|
||||
parentLocation->GetText(),
|
||||
std::strtoll(getContentLength->GetText(), NULL, 10),
|
||||
false);
|
||||
}
|
||||
} while ((current = current->NextSiblingElement()));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static tinyxml2::XMLElement *get_element_by_name(tinyxml2::XMLElement *parent, std::string_view name)
|
||||
{
|
||||
tinyxml2::XMLElement *current = parent->FirstChildElement();
|
||||
if (!current)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
if (get_tag_begin(current->Name()) == name)
|
||||
{
|
||||
return current;
|
||||
}
|
||||
} while ((current = current->NextSiblingElement()));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static std::string_view get_tag_begin(std::string_view tag)
|
||||
{
|
||||
size_t colon = tag.find_first_of(':');
|
||||
if (colon == tag.npos)
|
||||
{
|
||||
return tag;
|
||||
}
|
||||
return tag.substr(colon + 1);
|
||||
}
|
||||
140
source/remote/remote.cpp
Normal file
140
source/remote/remote.cpp
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
#include "remote/remote.hpp"
|
||||
#include "StateManager.hpp"
|
||||
#include "appStates/TaskState.hpp"
|
||||
#include "logger.hpp"
|
||||
#include "remote/GoogleDrive.hpp"
|
||||
#include "remote/WebDav.hpp"
|
||||
#include "strings.hpp"
|
||||
#include "ui/PopMessageManager.hpp"
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
namespace
|
||||
{
|
||||
/// @brief This is just the string for finding and creating the JKSV dir.
|
||||
const char *STRING_JKSV_DIR = "JKSV";
|
||||
|
||||
/// @brief This is the single (for now) instance of a storage class.
|
||||
std::unique_ptr<remote::Storage> s_storage = nullptr;
|
||||
} // 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);
|
||||
|
||||
/// @brief This creates (if needed) the JKSV folder for Google Drive and sets it as the root.
|
||||
/// @param drive Pointer to the drive instance..
|
||||
static void drive_set_jksv_root(remote::GoogleDrive *drive);
|
||||
|
||||
void remote::initialize_google_drive()
|
||||
{
|
||||
// Create drive instance.
|
||||
s_storage = std::make_unique<remote::GoogleDrive>();
|
||||
|
||||
// Need to cast this for it to work right.
|
||||
remote::GoogleDrive *drive = static_cast<remote::GoogleDrive *>(s_storage.get());
|
||||
|
||||
if (drive->sign_in_required())
|
||||
{
|
||||
auto signIn = std::make_shared<TaskState>(drive_sign_in, drive);
|
||||
StateManager::push_state(signIn);
|
||||
// We can return here because the task should handle the rest of the setup for us.
|
||||
return;
|
||||
}
|
||||
|
||||
// To do: Handle this better. Maybe retry somehow?
|
||||
if (!drive->is_initialized())
|
||||
{
|
||||
return;
|
||||
}
|
||||
// Can't forget this.
|
||||
drive_set_jksv_root(drive);
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::GOOGLE_DRIVE_STRINGS, 1));
|
||||
}
|
||||
|
||||
void remote::initialize_webdav()
|
||||
{
|
||||
s_storage = std::make_unique<remote::WebDav>();
|
||||
|
||||
if (s_storage->is_initialized())
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::WEBDAV_STRINGS, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::WEBDAV_STRINGS, 1));
|
||||
}
|
||||
}
|
||||
|
||||
remote::Storage *remote::get_remote_storage()
|
||||
{
|
||||
if (!s_storage || !s_storage->is_initialized())
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
return s_storage.get();
|
||||
}
|
||||
|
||||
static void drive_sign_in(sys::Task *task, remote::GoogleDrive *drive)
|
||||
{
|
||||
static const char *STRING_ERROR_SIGNING_IN = "Error signing into Google Drive: %s";
|
||||
|
||||
std::string message{}, deviceCode{};
|
||||
std::time_t expiration = 0;
|
||||
int pollingInterval = 0;
|
||||
|
||||
if (!drive->get_sign_in_data(message, deviceCode, expiration, pollingInterval))
|
||||
{
|
||||
logger::log(STRING_ERROR_SIGNING_IN, "Getting sign in data failed!");
|
||||
task->finished();
|
||||
return;
|
||||
}
|
||||
|
||||
task->set_status(message.c_str());
|
||||
|
||||
while (std::time(NULL) < expiration && !drive->poll_sign_in(deviceCode))
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(pollingInterval));
|
||||
}
|
||||
|
||||
if (drive->is_initialized())
|
||||
{
|
||||
// Run this quick so the root is set correctly.
|
||||
drive_set_jksv_root(drive);
|
||||
// Show everyone I did it!
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::GOOGLE_DRIVE_STRINGS, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
ui::PopMessageManager::push_message(ui::PopMessageManager::DEFAULT_MESSAGE_TICKS,
|
||||
strings::get_by_name(strings::names::GOOGLE_DRIVE_STRINGS, 2));
|
||||
}
|
||||
|
||||
task->finished();
|
||||
}
|
||||
|
||||
static void drive_set_jksv_root(remote::GoogleDrive *drive)
|
||||
{
|
||||
static const char *STRING_ERROR_SETTING_DIR = "Error creating/setting JKSV directory on Drive: %s";
|
||||
|
||||
if (!drive->directory_exists(STRING_JKSV_DIR) && !drive->create_directory(STRING_JKSV_DIR))
|
||||
{
|
||||
logger::log(STRING_ERROR_SETTING_DIR, "Error finding and/or creating directory!");
|
||||
return;
|
||||
}
|
||||
|
||||
remote::Item *jksvDir = drive->get_directory_by_name(STRING_JKSV_DIR);
|
||||
if (!jksvDir)
|
||||
{
|
||||
logger::log(STRING_ERROR_SETTING_DIR, "Error locating directory in list! This shouldn't be able to happen!");
|
||||
return;
|
||||
}
|
||||
drive->set_root_directory(jksvDir);
|
||||
drive->change_directory(jksvDir);
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@ namespace
|
|||
} // namespace
|
||||
|
||||
// This returns the language file to use depending on the system's language.
|
||||
static fslib::Path get_file_path(void)
|
||||
static fslib::Path get_file_path()
|
||||
{
|
||||
fslib::Path returnPath = "romfs:/Text";
|
||||
|
||||
|
|
|
|||
|
|
@ -11,12 +11,12 @@ void sys::ProgressTask::update_current(double current)
|
|||
m_current = current;
|
||||
}
|
||||
|
||||
double sys::ProgressTask::get_goal(void) const
|
||||
double sys::ProgressTask::get_goal() const
|
||||
{
|
||||
return m_goal;
|
||||
}
|
||||
|
||||
double sys::ProgressTask::get_current(void) const
|
||||
double sys::ProgressTask::get_current() const
|
||||
{
|
||||
return m_current / m_goal;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@ sys::Task::~Task()
|
|||
m_thread.join();
|
||||
}
|
||||
|
||||
bool sys::Task::is_running(void) const
|
||||
bool sys::Task::is_running() const
|
||||
{
|
||||
return m_isRunning;
|
||||
}
|
||||
|
||||
void sys::Task::finished(void)
|
||||
void sys::Task::finished()
|
||||
{
|
||||
m_isRunning = false;
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ void sys::Task::set_status(const char *format, ...)
|
|||
m_status = vaBuffer;
|
||||
}
|
||||
|
||||
std::string sys::Task::get_status(void)
|
||||
std::string sys::Task::get_status()
|
||||
{
|
||||
std::scoped_lock<std::mutex> StatusLock(m_statusLock);
|
||||
return m_status;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ void sys::Timer::start(uint64_t triggerTicks)
|
|||
m_startingTicks = SDL_GetTicks64();
|
||||
}
|
||||
|
||||
bool sys::Timer::is_triggered(void)
|
||||
bool sys::Timer::is_triggered()
|
||||
{
|
||||
uint64_t currentTicks = SDL_GetTicks64();
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ bool sys::Timer::is_triggered(void)
|
|||
return true;
|
||||
}
|
||||
|
||||
void sys::Timer::restart(void)
|
||||
void sys::Timer::restart()
|
||||
{
|
||||
m_startingTicks = SDL_GetTicks64();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "ui/ColorMod.hpp"
|
||||
|
||||
void ui::ColorMod::update(void)
|
||||
void ui::ColorMod::update()
|
||||
{
|
||||
if (m_direction && (m_colorMod += 6) >= 0x72)
|
||||
{
|
||||
|
|
@ -12,7 +12,7 @@ void ui::ColorMod::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
ui::ColorMod::operator sdl::Color(void) const
|
||||
ui::ColorMod::operator sdl::Color() const
|
||||
{
|
||||
return {static_cast<uint32_t>((0x88 + m_colorMod) << 16 | (0xC5 + (m_colorMod / 2)) << 8 | 0xFF)};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ void ui::IconMenu::render(SDL_Texture *target, bool hasFocus)
|
|||
}
|
||||
sdl::render_rect_fill(m_optionTarget->get(), 0, 0, 4, 130, {0x00FFC5FF});
|
||||
}
|
||||
//m_options.at(i)->render(m_optiontarget->Get(), 0, 0);
|
||||
m_options.at(i)->render_stretched(m_optionTarget->get(), 8, 1, 128, 128);
|
||||
m_optionTarget->render(target, m_x, tempY);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ void ui::Menu::edit_option(int index, std::string_view newOption)
|
|||
m_options[index] = newOption.data();
|
||||
}
|
||||
|
||||
int ui::Menu::get_selected(void) const
|
||||
int ui::Menu::get_selected() const
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
|
|
@ -160,7 +160,7 @@ void ui::Menu::set_width(int width)
|
|||
m_width = width;
|
||||
}
|
||||
|
||||
void ui::Menu::reset(void)
|
||||
void ui::Menu::reset()
|
||||
{
|
||||
m_selected = 0;
|
||||
m_y = m_originalY;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace
|
|||
|
||||
} // namespace
|
||||
|
||||
void ui::PopMessageManager::update(void)
|
||||
void ui::PopMessageManager::update()
|
||||
{
|
||||
// Grab instance.
|
||||
PopMessageManager &manager = PopMessageManager::get_instance();
|
||||
|
|
@ -65,7 +65,7 @@ void ui::PopMessageManager::update(void)
|
|||
}
|
||||
}
|
||||
|
||||
void ui::PopMessageManager::render(void)
|
||||
void ui::PopMessageManager::render()
|
||||
{
|
||||
// Get instance.
|
||||
PopMessageManager &manager = PopMessageManager::get_instance();
|
||||
|
|
|
|||
|
|
@ -59,29 +59,29 @@ void ui::SlideOutPanel::render(SDL_Texture *Target, bool hasFocus)
|
|||
m_renderTarget->render(NULL, m_x, 0);
|
||||
}
|
||||
|
||||
void ui::SlideOutPanel::clear_target(void)
|
||||
void ui::SlideOutPanel::clear_target()
|
||||
{
|
||||
m_renderTarget->clear(colors::SLIDE_PANEL_CLEAR);
|
||||
}
|
||||
|
||||
void ui::SlideOutPanel::reset(void)
|
||||
void ui::SlideOutPanel::reset()
|
||||
{
|
||||
m_x = m_side == Side::Left ? -(m_width) : 1280.0f;
|
||||
m_isOpen = false;
|
||||
m_closePanel = false;
|
||||
}
|
||||
|
||||
void ui::SlideOutPanel::close(void)
|
||||
void ui::SlideOutPanel::close()
|
||||
{
|
||||
m_closePanel = true;
|
||||
}
|
||||
|
||||
bool ui::SlideOutPanel::is_open(void) const
|
||||
bool ui::SlideOutPanel::is_open() const
|
||||
{
|
||||
return m_isOpen;
|
||||
}
|
||||
|
||||
bool ui::SlideOutPanel::is_closed(void) const
|
||||
bool ui::SlideOutPanel::is_closed() const
|
||||
{
|
||||
return m_closePanel && (m_side == Side::Left ? m_x > -(m_width) : m_x < 1280);
|
||||
}
|
||||
|
|
@ -91,12 +91,12 @@ void ui::SlideOutPanel::push_new_element(std::shared_ptr<ui::Element> newElement
|
|||
m_elements.push_back(newElement);
|
||||
}
|
||||
|
||||
void ui::SlideOutPanel::clear_elements(void)
|
||||
void ui::SlideOutPanel::clear_elements()
|
||||
{
|
||||
m_elements.clear();
|
||||
}
|
||||
|
||||
SDL_Texture *ui::SlideOutPanel::get_target(void)
|
||||
SDL_Texture *ui::SlideOutPanel::get_target()
|
||||
{
|
||||
return m_renderTarget->get();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,18 +30,18 @@ void ui::TitleTile::render(SDL_Texture *target, int x, int y)
|
|||
}
|
||||
}
|
||||
|
||||
void ui::TitleTile::reset(void)
|
||||
void ui::TitleTile::reset()
|
||||
{
|
||||
m_renderWidth = 128;
|
||||
m_renderHeight = 128;
|
||||
}
|
||||
|
||||
int ui::TitleTile::get_width(void) const
|
||||
int ui::TitleTile::get_width() const
|
||||
{
|
||||
return m_renderWidth;
|
||||
}
|
||||
|
||||
int ui::TitleTile::get_height(void) const
|
||||
int ui::TitleTile::get_height() const
|
||||
{
|
||||
return m_renderHeight;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,12 +111,12 @@ void ui::TitleView::render(SDL_Texture *target, bool hasFocus)
|
|||
m_titleTiles.at(m_selected).render(target, m_selectedX, m_selectedY);
|
||||
}
|
||||
|
||||
int ui::TitleView::get_selected(void) const
|
||||
int ui::TitleView::get_selected() const
|
||||
{
|
||||
return m_selected;
|
||||
}
|
||||
|
||||
void ui::TitleView::refresh(void)
|
||||
void ui::TitleView::refresh()
|
||||
{
|
||||
// Clear the current tiles.
|
||||
m_titleTiles.clear();
|
||||
|
|
@ -140,7 +140,7 @@ void ui::TitleView::refresh(void)
|
|||
}
|
||||
}
|
||||
|
||||
void ui::TitleView::reset(void)
|
||||
void ui::TitleView::reset()
|
||||
{
|
||||
for (ui::TitleTile ¤tTile : m_titleTiles)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user