mirror of
https://github.com/J-D-K/JKSV.git
synced 2026-09-11 12:05:19 -05:00
remote::Storage just barely working.
This commit is contained in:
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user