Attempted #323 fix, revisions.

This commit is contained in:
J-D-K
2025-12-01 20:32:22 -05:00
parent 0fce729cb6
commit 47c0b1b13e
5 changed files with 411 additions and 166 deletions

View File

@@ -136,21 +136,27 @@ void BackupMenuState::render()
void BackupMenuState::refresh()
{
const bool autoUpload = config::get_by_key(config::keys::AUTO_UPLOAD);
// Grab pointer to remote service.
remote::Storage *remote = remote::get_remote_storage();
// Re-open and refresh directory.
m_directoryListing.open(m_directoryPath);
if (!autoUpload && !m_directoryListing.is_open()) { return; }
// If neither are valid, return.
if (!remote && !m_directoryListing.is_open()) { return; }
// Lock the menu.
std::lock_guard menuGuard{sm_menuMutex};
// Clear the menu and the entry array.
sm_backupMenu->reset();
m_menuEntries.clear();
// Grab the "New" string and add it & it's NULL entry in the vector.
const char *optionNew = strings::get_by_name(strings::names::BACKUPMENU_MENU, 0);
sm_backupMenu->add_option(optionNew);
m_menuEntries.push_back({MenuEntryType::Null, 0});
// Remote->Local.
if (remote)
{
const std::string_view prefix = remote->get_prefix();
@@ -218,6 +224,7 @@ void BackupMenuState::initialize_task_data()
m_dataStruct->user = m_user;
m_dataStruct->titleInfo = m_titleInfo;
m_dataStruct->saveInfo = m_saveInfo;
m_dataStruct->basePath = &m_directoryPath;
m_dataStruct->spawningState = this;
}
@@ -257,16 +264,27 @@ void BackupMenuState::initialize_remote_storage()
void BackupMenuState::name_and_create_backup()
{
static constexpr size_t SIZE_NAME_LENGTH = 0x80;
// Size of the buffer for naming backups.
static constexpr size_t SIZE_NAME_LENGTH = 0x80;
// Zip extension because it's used in multiple spots.
static constexpr const char *STRING_ZIP_EXT = ".zip";
// Remote storage pointer. This is only used for testing if it's valid at this point.
remote::Storage *remote = remote::get_remote_storage();
const bool autoName = config::get_by_key(config::keys::AUTO_NAME_BACKUPS);
const bool autoUpload = config::get_by_key(config::keys::AUTO_UPLOAD);
const bool exportZip = autoUpload || config::get_by_key(config::keys::EXPORT_TO_ZIP);
const bool zrHeld = input::button_held(HidNpadButton_ZR);
const bool autoNamed = (autoName || zrHeld); // This can be eval'd here.
// Config needed.
const bool autoName = config::get_by_key(config::keys::AUTO_NAME_BACKUPS);
const bool autoUpload = config::get_by_key(config::keys::AUTO_UPLOAD);
const bool exportZip = autoUpload || config::get_by_key(config::keys::EXPORT_TO_ZIP);
// Input.
const bool zrHeld = input::button_held(HidNpadButton_ZR);
// Whether or not we should skip the keyboard.
const bool autoNamed = (autoName || zrHeld); // This can be eval'd here.
// This is the buffer for naming. It's auto filled as [User] - [Date].
char name[SIZE_NAME_LENGTH + 1] = {0};
{
const char *nickname = m_user->get_path_safe_nickname();
@@ -274,7 +292,7 @@ void BackupMenuState::name_and_create_backup()
std::snprintf(name, SIZE_NAME_LENGTH, "%s - %s", nickname, date.c_str());
}
// Doing this like this so the strings don't linger.
// Doing this like this so the strings don't linger. Dictionary entries for the keyboard.
keyboard::Dictionary dictionary{};
{
// Array of dictionary strings.
@@ -291,37 +309,49 @@ void BackupMenuState::name_and_create_backup()
for (const std::string_view word : dictionaryStrings) { dictionary.add_word_to_list(word); }
}
// Header string for the keyboard.
const char *keyboardHeader = strings::get_by_name(strings::names::KEYBOARD, 0);
// Stores whether or not the input was successful.
const bool named =
autoNamed || keyboard::get_input(SwkbdType_QWERTY, name, keyboardHeader, name, SIZE_NAME_LENGTH, dictionary);
if (!named) { return; }
m_dataStruct->killTask = true; // Need to make sure these kill the task.
const bool hasZipExt = std::strstr(name, STRING_ZIP_EXT); // This might not be the best check.
if (autoUpload && remote)
// Send the signal that the backup task should signal completion.
m_dataStruct->killTask = true;
// Check for and append zip extension if needed.
const bool hasZipExt = std::strstr(name, STRING_ZIP_EXT); // This might not be the best check.
const bool needsZip = !hasZipExt && (autoUpload || exportZip);
if (needsZip) { std::strncat(name, STRING_ZIP_EXT, SIZE_NAME_LENGTH); }
// This is used by both if the keep local is enabled anyway.
m_dataStruct->path = m_directoryPath / name;
if (autoUpload && remote) // If both autoUpload and remote is valid.
{
const bool keepLocal = config::get_by_key(config::keys::KEEP_LOCAL_BACKUPS);
if (!hasZipExt) { std::strncat(name, STRING_ZIP_EXT, SIZE_NAME_LENGTH); }
if (keepLocal) { m_dataStruct->path = m_directoryPath / name; }
// Set the name.
m_dataStruct->remoteName = name;
// Start the process.
ProgressState::create_push_fade(tasks::backup::create_new_backup_remote, m_dataStruct);
}
else
{
fslib::Path target{m_directoryPath / name};
if (!hasZipExt && (autoUpload || exportZip)) { target += STRING_ZIP_EXT; } // We're going to append zip either way.
m_dataStruct->path = std::move(target);
// Start the process.
ProgressState::create_push_fade(tasks::backup::create_new_backup_local, m_dataStruct);
}
}
void BackupMenuState::confirm_overwrite()
{
const int selected = sm_backupMenu->get_selected();
const MenuEntry &entry = m_menuEntries.at(selected);
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE);
// Grab selected index and entry.
const int selected = sm_backupMenu->get_selected();
const MenuEntry &entry = m_menuEntries.at(selected);
// Whether or not holding is required.
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE);
// Template/format for the confirmation.
const char *confirmTemplate = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 0);
if (entry.type == MenuEntryType::Remote)
@@ -344,63 +374,95 @@ void BackupMenuState::confirm_overwrite()
void BackupMenuState::confirm_restore()
{
const int selected = sm_backupMenu->get_selected();
// Tired of typing it out.
static constexpr int POP_TICKS = ui::PopMessageManager::DEFAULT_TICKS;
// Grab selected.
const int selected = sm_backupMenu->get_selected();
// Entry reference.
const MenuEntry &entry = m_menuEntries.at(selected);
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_RESTORATION);
// Config needed.
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_RESTORATION);
const bool allowSystem = config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM);
// Template for confirmation string.
const char *confirmTemplate = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 1);
const bool isSystem = BackupMenuState::user_is_system();
const bool allowSystem = config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM);
// Whether or not we're working with a system type.
const bool isSystem = BackupMenuState::user_is_system();
// Whether or not the restoration is valid under the current conditions.
const bool isValidRestore = !isSystem || allowSystem;
if (!isValidRestore)
{
const char *popSysNotAllowed = strings::get_by_name(strings::names::BACKUPMENU_POPS, 6);
ui::PopMessageManager::push_message(popTicks, popSysNotAllowed);
// Pop and return on trying to restore system when not enabled.
const char *popInvalid = strings::get_by_name(strings::names::BACKUPMENU_POPS, 6);
ui::PopMessageManager::push_message(POP_TICKS, popInvalid);
return;
}
if (entry.type == MenuEntryType::Local)
{
const char *popBackupEmpty = strings::get_by_name(strings::names::BACKUPMENU_POPS, 1);
// Target path we're working with.
const fslib::Path target{m_directoryPath / m_directoryListing[entry.index]};
// Check if it's a directory. Ensure it has contents either way.
const bool targetIsDirectory = fslib::directory_exists(target);
const bool backupIsGood = targetIsDirectory ? fs::directory_has_contents(target) : fs::zip_has_contents(target);
if (!backupIsGood)
{
ui::PopMessageManager::push_message(popTicks, popBackupEmpty);
const char *popEmpty = strings::get_by_name(strings::names::BACKUPMENU_POPS, 1);
ui::PopMessageManager::push_message(POP_TICKS, popEmpty);
return;
}
m_dataStruct->path = target;
// Move the target to the struct path to pass it.
m_dataStruct->path = std::move(target);
// Construct our confirmation string.
const char *targetName = m_directoryListing[entry.index].get_filename();
std::string query = stringutil::get_formatted_string(confirmTemplate, targetName);
// Begin process.
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_local, nullptr, m_dataStruct);
}
else if (entry.type == MenuEntryType::Remote)
{
remote::Item *target = m_remoteListing[entry.index];
std::string query = stringutil::get_formatted_string(confirmTemplate, target->get_name().data());
m_dataStruct->remoteItem = target;
m_dataStruct->path = m_directoryPath + "//"; // To-do: This is a workaround.
// Pointer to target we're working with.
remote::Item *target = m_remoteListing[entry.index];
// String for the confirmation
std::string query = stringutil::get_formatted_string(confirmTemplate, target->get_name().data());
// Set data needed.
m_dataStruct->remoteItem = target;
m_dataStruct->path = m_directoryPath;
// Pass go and collect $200.
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::restore_backup_remote, nullptr, m_dataStruct);
}
}
void BackupMenuState::confirm_delete()
{
const int selected = sm_backupMenu->get_selected();
const MenuEntry &entry = m_menuEntries.at(selected);
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_DELETION);
// Grab the selected index and entry.
const int selected = sm_backupMenu->get_selected();
const MenuEntry &entry = m_menuEntries.at(selected);
// Whether or not the use desires to be forced to hold the button.
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_DELETION);
// Template for the confirmation string.
const char *confirmTemplate = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 2);
if (entry.type == MenuEntryType::Local)
{
m_dataStruct->path = m_directoryPath / m_directoryListing[entry.index];
// Target path to delete.
m_dataStruct->path = m_directoryPath / m_directoryListing[entry.index];
// This is just the name for the confirmation.
const char *targetName = m_directoryListing[entry.index].get_filename();
std::string query = stringutil::get_formatted_string(confirmTemplate, targetName);
@@ -418,34 +480,49 @@ void BackupMenuState::confirm_delete()
void BackupMenuState::upload_backup()
{
static constexpr int POP_TICKS = ui::PopMessageManager::DEFAULT_TICKS;
// Grab pointer to remote. Don't continue if it's not valid.
remote::Storage *remote = remote::get_remote_storage();
if (error::is_null(remote)) { return; }
// Grab index, entry. If isn't local, it can't be uploaded.
const int selected = sm_backupMenu->get_selected();
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const MenuEntry &entry = m_menuEntries[selected];
if (entry.type != BackupMenuState::MenuEntryType::Local) { return; }
// Our final target.
fslib::Path target{m_directoryPath / m_directoryListing[entry.index]};
// If it's a directory, pop and bail. Only zip can be uploaded because it's simpler that way.
const bool isDir = fslib::directory_exists(target);
if (isDir)
{
const char *popNotZip = strings::get_by_name(strings::names::BACKUPMENU_POPS, 13);
ui::PopMessageManager::push_message(popTicks, popNotZip);
ui::PopMessageManager::push_message(POP_TICKS, popNotZip);
return;
}
m_dataStruct->path = std::move(target);
// Move our final path to our data struct.
m_dataStruct->path = std::move(target);
// Grab the name of the target. If it already exists, patch. If not, new upload.
const std::string_view itemName = m_dataStruct->path.get_filename();
const bool exists = remote->file_exists(itemName);
if (exists)
{
// This is needed, since we're patching and overwriting something.
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE);
// Get the target.
remote::Item *remoteItem = remote->get_file_by_name(itemName);
const char *queryFormat = strings::get_by_name(strings::names::BACKUPMENU_CONFS, 0);
std::string query = stringutil::get_formatted_string(queryFormat, itemName.data());
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_OVERWRITE);
m_dataStruct->remoteItem = remoteItem;
const char *itemName = remoteItem->get_name().data();
// Confirmation string.
std::string query = stringutil::get_formatted_string(queryFormat, itemName);
// Push the confirmation.
ConfirmProgress::create_push_fade(query, holdRequired, tasks::backup::patch_backup, nullptr, m_dataStruct);
}
else { ProgressState::create_push_fade(tasks::backup::upload_backup, m_dataStruct); }