FileMode/FileOption debugging, fixes, and added safety.

This commit is contained in:
J-D-K
2025-09-06 19:21:35 -04:00
parent f052d0b2a7
commit e1d592ee9c
44 changed files with 208 additions and 151 deletions

View File

@@ -17,10 +17,10 @@ class StateManager
static void update();
/// @brief Runs the state rendering routine(s);
static void render();
static void render() noexcept;
/// @brief Returns whether the back of the vector is a closable state.
static bool back_is_closable();
static bool back_is_closable() noexcept;
/// @brief Pushes a new state to the state vector.
/// @param newState Shared_ptr to state to push.

View File

@@ -20,9 +20,6 @@ class BackupMenuState final : public BaseState
/// @param saveType Save data type we're working with.
BackupMenuState(data::User *user, data::TitleInfo *titleInfo);
/// @brief Destructor. This is required even if it doesn't free or do anything.
~BackupMenuState() {};
/// @brief Creates and returns a new BackupMenuState.
static inline std::shared_ptr<BackupMenuState> create(data::User *user, data::TitleInfo *titleInfo)
{

View File

@@ -13,9 +13,6 @@ class BaseTask : public BaseState
/// @brief Constructor. Starts the glyph timer and sets AppState to not allow closing.
BaseTask();
/// @brief Virtual destructor.
virtual ~BaseTask() {};
/// @brief Runs the update routine for rendering the loading glyph animation.
/// @param
void update() override;

View File

@@ -12,9 +12,6 @@ class BlacklistEditState final : public BaseState
/// @brief Constructor. Loads the blacklist and ensures the panel is allocated.S
BlacklistEditState();
/// @brief Required destructor.
~BlacklistEditState() {};
/// @brief Creates and returns a new state.
static inline std::shared_ptr<BlacklistEditState> create() { return std::make_shared<BlacklistEditState>(); }

View File

@@ -56,9 +56,6 @@ class ConfirmState final : public BaseState
ConfirmState::load_holding_strings();
}
/// @brief Required even if it does nothing.
~ConfirmState() {};
/// @brief Returns a new ConfirmState. See constructor.
static inline std::shared_ptr<ConfirmState> create(std::string_view query,
bool holdRequired,
@@ -145,7 +142,7 @@ class ConfirmState final : public BaseState
const bool m_holdRequired{};
/// @brief These are pointers to the holding strings.
const char *m_holdText[3];
const char *m_holdText[3]{};
/// @brief Keep track of the ticks/time needed to confirm.
uint64_t m_startingTickCount{};

View File

@@ -26,9 +26,6 @@ class DataLoadingState final : public BaseTask
m_task = std::make_unique<sys::Task>(function, std::forward<Args>(args)...);
}
/// @brief Destructor. Runs all DestructFunctions in the vector.
~DataLoadingState() {};
template <typename... Args>
static inline std::shared_ptr<DataLoadingState> create(data::DataContext &context,
DestructFunction destructFunction,

View File

@@ -10,9 +10,6 @@ class ExtrasMenuState final : public BaseState
/// @brief Constructor.
ExtrasMenuState();
/// @brief Required even if nothing happens.
~ExtrasMenuState() {};
/// @brief Returns a new ExtrasMenuState
static inline std::shared_ptr<ExtrasMenuState> create() { return std::make_shared<ExtrasMenuState>(); }
@@ -24,7 +21,7 @@ class ExtrasMenuState final : public BaseState
private:
/// @brief Menu
ui::Menu m_extrasMenu;
std::shared_ptr<ui::Menu> m_extrasMenu{};
/// @brief Render target for menu.
sdl::SharedTexture m_renderTarget{};

View File

@@ -20,9 +20,6 @@ class FadeState final : public BaseState
/// @param nextState The next state to push after the the fade is finished.
FadeState(sdl::Color baseColor, uint8_t startAlpha, uint8_t endAlpha, std::shared_ptr<BaseState> nextState);
/// @brief Required destructor.
~FadeState() {};
/// @brief Returns a new fade in state. See constructor.
static inline std::shared_ptr<FadeState> create(sdl::Color baseColor,
uint8_t startAlpha,

View File

@@ -11,23 +11,22 @@ class FileModeState final : public BaseState
{
public:
/// @brief Constructs a new FileModeState.
FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize = 0);
/// @brief Destructor. Closes the filesystems passed.
~FileModeState() {};
FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize = 0, bool isSystem = false);
static inline std::shared_ptr<FileModeState> create(std::string_view mountA,
std::string_view mountB,
int64_t journalSize = 0)
int64_t journalSize = 0,
bool isSystem = false)
{
return std::make_shared<FileModeState>(mountA, mountB, journalSize);
return std::make_shared<FileModeState>(mountA, mountB, journalSize, isSystem);
}
static inline std::shared_ptr<FileModeState> create_and_push(std::string_view mountA,
std::string_view mountB,
int64_t journalSize = 0)
int64_t journalSize = 0,
bool isSystem = false)
{
auto newState = std::make_shared<FileModeState>(mountA, mountB, journalSize);
auto newState = std::make_shared<FileModeState>(mountA, mountB, journalSize, isSystem);
StateManager::push_state(newState);
return newState;
}
@@ -43,8 +42,8 @@ class FileModeState final : public BaseState
private:
/// @brief These store the mount points to close the filesystems upon construction.
std::string m_mountA;
std::string m_mountB;
std::string m_mountA{};
std::string m_mountB{};
/// @brief These are the actual target paths.
fslib::Path m_pathA{};
@@ -65,10 +64,10 @@ class FileModeState final : public BaseState
int64_t m_journalSize{};
/// @brief The beginning Y coord of the dialog.
double m_y{720.0f};
double m_y = 720.0f;
/// @brief This is the targetY. Used for the opening and hiding effect.
double m_targetY{91.0f};
double m_targetY = 91.0f;
/// @brief Config scaling for the "transition"
double m_scaling{};
@@ -76,6 +75,12 @@ class FileModeState final : public BaseState
/// @brief Stores whether or not the dialog has reached its targetted position.
bool m_inPlace{};
/// @brief Stores whether the instance is dealing with sensitive data.
bool m_isSystem{};
/// @brief Stores the config setting from config to allow writing to the sensitive parts of the system.
bool m_allowSystem{};
/// @brief Frame shared by all instances.
static inline std::shared_ptr<ui::Frame> sm_frame{};

View File

@@ -14,8 +14,6 @@ class FileOptionState final : public BaseState
/// @param spawningState Pointer to spawning state to grab its goodies.
FileOptionState(FileModeState *spawningState);
~FileOptionState() {};
/// @brief Inline creation function.
static inline std::shared_ptr<FileOptionState> create(FileModeState *spawningState)
{
@@ -124,6 +122,9 @@ class FileOptionState final : public BaseState
/// @param path
void get_show_file_properties(const fslib::Path &path);
/// @brief Pops the error writing to system message.
void pop_system_error();
/// @brief Closes and hides the state.
void close();
@@ -132,4 +133,24 @@ class FileOptionState final : public BaseState
/// @brief Sets the menu index back to 0 and deactivates the state.
void deactivate_state();
/// @brief Returns if the copy/from is allowed before continuing.
inline bool system_write_check()
{
const bool target = m_spawningState->m_target;
const bool isSystem = m_spawningState->m_isSystem;
const bool allowSystem = m_spawningState->m_allowSystem;
return target && isSystem && !allowSystem;
}
/// @brief Returns if the operation is allowed.
inline bool system_operation_check()
{
const bool target = m_spawningState->m_target;
const bool isSystem = m_spawningState->m_isSystem;
const bool allowSystem = m_spawningState->m_allowSystem;
return !target && isSystem && !allowSystem;
}
};

View File

@@ -14,9 +14,6 @@ class MainMenuState final : public BaseState
/// @brief Creates and initializes the main menu.
MainMenuState();
/// @brief Required even if it does nothing.
~MainMenuState() {};
/// @brief Returns a new MainMenuState
static inline std::shared_ptr<MainMenuState> create() { return std::make_shared<MainMenuState>(); }

View File

@@ -15,9 +15,6 @@ class MessageState final : public BaseState
/// @param message Message to display.
MessageState(std::string_view message);
/// @brief Required. Does NOTHING~
~MessageState() {};
/// @brief Creates and returns a new MessageState. See constructor.
static inline std::shared_ptr<MessageState> create(std::string_view message)
{

View File

@@ -25,9 +25,6 @@ class ProgressState final : public BaseTask
m_task = std::make_unique<sys::ProgressTask>(function, std::forward<Args>(args)...);
}
/// @brief Required destructor.
~ProgressState() {};
/// @brief Creates and returns a new progress state.
template <typename... Args>
static inline std::shared_ptr<ProgressState> create(void (*function)(sys::ProgressTask *, Args...), Args... args)
@@ -67,6 +64,9 @@ class ProgressState final : public BaseTask
/// @brief This is the dialog box everything is rendered to.
static inline std::shared_ptr<ui::DialogBox> sm_dialog{};
/// @brief This is rendered over the edges of the bar to give it a slightly rounded look.
static inline sdl::SharedTexture sm_barEdges{};
/// @brief Initializes the shared dialog box.
void initialize_static_members();

View File

@@ -17,9 +17,6 @@ class SaveCreateState final : public BaseState
/// @param titleSelect The selection view for the user for refreshing and rendering.
SaveCreateState(data::User *user, TitleSelectCommon *titleSelect);
/// @brief Required destructor.
~SaveCreateState() {};
/// @brief Returns a new SaveCreate state. See constructor for arguments.
static inline std::shared_ptr<SaveCreateState> create(data::User *user, TitleSelectCommon *titleSelect)
{

View File

@@ -10,9 +10,6 @@ class SettingsState final : public BaseState
/// @brief Constructs a new settings state.
SettingsState();
/// @brief Required destructor.
~SettingsState() {};
/// @brief Returns a new SettingsState.
static inline std::shared_ptr<SettingsState> create() { return std::make_shared<SettingsState>(); }

View File

@@ -20,9 +20,6 @@ class TaskState final : public BaseTask
m_task = std::make_unique<sys::Task>(function, std::forward<Args>(args)...);
}
/// @brief Required destructor.
~TaskState() {};
/// @brief Creates and returns a new TaskState.
template <typename... Args>
static inline std::shared_ptr<TaskState> create(void (*function)(sys::Task *, Args...), Args... args)

View File

@@ -13,9 +13,6 @@ class TextTitleSelectState final : public TitleSelectCommon
/// @param user User to construct title select for.
TextTitleSelectState(data::User *user);
/// @brief Required destructor.
~TextTitleSelectState() {};
/// @brief Creates and returns a new TextTitleSelect. See constructor.
static inline std::shared_ptr<TextTitleSelectState> create(data::User *user)
{

View File

@@ -17,9 +17,6 @@ class TitleInfoState final : public BaseState
/// @param titleInfo Title to display info for.
TitleInfoState(data::User *user, data::TitleInfo *titleInfo);
/// @brief Required destructor.
~TitleInfoState() {};
/// @brief Creates a new TitleInfoState.
static inline std::shared_ptr<TitleInfoState> create(data::User *user, data::TitleInfo *titleInfo)
{

View File

@@ -15,9 +15,6 @@ class TitleOptionState final : public BaseState
/// @param titleInfo Target title.
TitleOptionState(data::User *user, data::TitleInfo *titleInfo, TitleSelectCommon *titleSelect);
/// @brief Required destructor.
~TitleOptionState() {};
/// @brief Returns a new TitleOptionState. See constructor.
static inline std::shared_ptr<TitleOptionState> create(data::User *user,
data::TitleInfo *titleInfo,

View File

@@ -13,9 +13,6 @@ class TitleSelectState final : public TitleSelectCommon
/// @param user User the state "belongs" to.
TitleSelectState(data::User *user);
/// @brief Required destructor.
~TitleSelectState() {};
/// @brief Returns a new TitleSelect state.
static inline std::shared_ptr<TitleSelectState> create(data::User *user)
{

View File

@@ -16,9 +16,6 @@ class UserOptionState final : public BaseState
/// @param titleSelect Pointer to the selection state for refresh and rendering.
UserOptionState(data::User *user, TitleSelectCommon *titleSelect);
/// @brief Required destructor.
~UserOptionState() {};
/// @brief Returns a new UserOptionState. See constructor.
static inline std::shared_ptr<UserOptionState> create(data::User *user, TitleSelectCommon *titleSelect)
{

View File

@@ -29,7 +29,7 @@ namespace data
void load_application_records(sys::Task *task);
/// @brief Returns whether a title is loaded with the application ID passed.
bool title_is_loaded(uint64_t applicationID);
bool title_is_loaded(uint64_t applicationID) noexcept;
/// @brief Attempts to load a title with the application ID passed.
void load_title(uint64_t applicationID);

View File

@@ -52,7 +52,7 @@ namespace remote
private:
/// @brief This is where the actual URL is held.
std::string m_url;
std::string m_url{};
/// @brief This checks and appends the necessary separator to the URL string.
void append_separator();

View File

@@ -15,7 +15,7 @@ namespace strings::names
inline constexpr std::string_view FILEOPTION_CONFS = "FileOptionConfs";
inline constexpr std::string_view FILEOPTION_MESSAGES = "FileOptionMessages";
inline constexpr std::string_view FILEOPTION_STATUS = "FileOptionStatus";
inline constexpr std::string_view FILEMODE_POPS = "FileModePops";
inline constexpr std::string_view FILEOPTION_POPS = "FileOptionPops";
inline constexpr std::string_view GENERAL_POPS = "GeneralPops";
inline constexpr std::string_view GOOGLE_DRIVE = "GoogleDriveStrings";
inline constexpr std::string_view HOLDING_STRINGS = "HoldingStrings";

View File

@@ -24,6 +24,6 @@ namespace ui
bool m_direction = true;
/// @brief Color value.
uint8_t m_colorMod = 0;
uint8_t m_colorMod{};
};
} // namespace ui

View File

@@ -123,10 +123,13 @@ namespace ui
/// @brief Text scroll for when the current option is too long to on screen.
std::shared_ptr<ui::TextScroll> m_optionScroll{};
/// @brief Updates the text scroll for the currently highlighted option.
void update_scroll_text();
/// @brief Updates the menu's vertical scrolling.
void update_scrolling();
/// @brief Handles the menu's input routine.
void handle_input();
};
} // namespace ui

View File

@@ -118,6 +118,7 @@ namespace ui
/// @brief Whether or not a scroll was triggered.
bool m_textScrollTriggered{};
/// @brief Render target for the text so it can't be rendered outside of it.
sdl::SharedTexture m_renderTarget{};
/// @brief Timer for scrolling text.

View File

@@ -35,10 +35,10 @@ namespace ui
private:
/// @brief Width in pixels to render icon at.
int m_renderWidth{128};
int m_renderWidth = 128;
/// @brief Height in pixels to render icon at.
int m_renderHeight{128};
int m_renderHeight = 128;
/// @brief Whether or not the title is a favorite.
bool m_isFavorite{};

View File

@@ -50,7 +50,7 @@ namespace ui
data::User *m_user{};
/// @brief Y coordinate.
double m_y{32.0f};
double m_y = 32.0f;
/// @brief Currently highlighted/selected title.
int m_selected{};

View File

@@ -78,15 +78,14 @@
"FileOptionStatus": [
"0: Reading #%s#'s data..."
],
"FileModePops": [
"0: Copied #%s#!",
"1: Failed to copy #%s#!",
"2: Deleted #%s#!",
"3: Failed to delete #%s#!",
"4: Renamed #%s# to #%s#!",
"5: Failed to rename #%s#!",
"6: Created #%s#!",
"7: Failed to create #%s#!"
"FileOptionPops": [
"0: Failed to copy #%s%!",
"1: Failed to delete #%s#!",
"2: Failed to rename #%s#!",
"3: Failed to create #%s#!",
"4: #%s# is not a directory!",
"5: Writing to the system is disabled!",
"6: Deleting files from system partitions is disabled!"
],
"GeneralPops": [
"0: Unable to exit JKSV while tasks are running!"
@@ -217,8 +216,8 @@
"TitleInfo": [
"0: App ID: %016lX",
"1: Save ID: %016lx",
"2: First Played: %x - %X",
"3: Last Played: %x - %X",
"2: First Played: %c",
"3: Last Played: %c",
"4: Play Time: %02d:%02d:%02d",
"5: Launches: %i",
"6: Save Type: %s"

BIN
romfs/Textures/BarEdges.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

View File

@@ -29,9 +29,9 @@
namespace
{
/// @brief Build month.
constexpr uint8_t BUILD_MON = 8;
constexpr uint8_t BUILD_MON = 9;
/// @brief Build day.
constexpr uint8_t BUILD_DAY = 29;
constexpr uint8_t BUILD_DAY = 6;
/// @brief Year.
constexpr uint16_t BUILD_YEAR = 2025;

View File

@@ -32,7 +32,7 @@ void StateManager::update()
back->update();
}
void StateManager::render()
void StateManager::render() noexcept
{
StateManager &instance = StateManager::get_instance();
auto &stateVector = instance.m_stateVector;
@@ -40,7 +40,7 @@ void StateManager::render()
for (std::shared_ptr<BaseState> &state : stateVector) { state->render(); }
}
bool StateManager::back_is_closable()
bool StateManager::back_is_closable() noexcept
{
StateManager &instance = StateManager::get_instance();
auto &stateVector = instance.m_stateVector;

View File

@@ -34,8 +34,7 @@ namespace
static void finish_reinitialization();
ExtrasMenuState::ExtrasMenuState()
: m_extrasMenu(32, 8, 1000, 24, 555)
, m_renderTarget(sdl::TextureManager::load(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_TARGET))
: m_renderTarget(sdl::TextureManager::load(SECONDARY_TARGET, 1080, 555, SDL_TEXTUREACCESS_TARGET))
{
ExtrasMenuState::initialize_menu();
}
@@ -46,11 +45,11 @@ void ExtrasMenuState::update()
const bool aPressed = input::button_pressed(HidNpadButton_A);
const bool bPressed = input::button_pressed(HidNpadButton_B);
m_extrasMenu.update(hasFocus);
m_extrasMenu->update(hasFocus);
if (aPressed)
{
switch (m_extrasMenu.get_selected())
switch (m_extrasMenu->get_selected())
{
case REINIT_DATA: ExtrasMenuState::reinitialize_data(); break;
case SD_TO_SD_BROWSER: ExtrasMenuState::sd_to_sd_browser(); break;
@@ -69,15 +68,17 @@ void ExtrasMenuState::render()
const bool hasFocus = BaseState::has_focus();
m_renderTarget->clear(colors::TRANSPARENT);
m_extrasMenu.render(m_renderTarget, hasFocus);
m_extrasMenu->render(m_renderTarget, hasFocus);
m_renderTarget->render(sdl::Texture::Null, 201, 91);
}
void ExtrasMenuState::initialize_menu()
{
if (!m_extrasMenu) { m_extrasMenu = ui::Menu::create(32, 8, 1000, 24, 555); }
for (int i = 0; const char *option = strings::get_by_name(strings::names::EXTRASMENU_MENU, i); i++)
{
m_extrasMenu.add_option(option);
m_extrasMenu->add_option(option);
}
}
@@ -90,7 +91,7 @@ void ExtrasMenuState::prodinfof_to_sd()
const bool mountError = error::fslib(fslib::open_bis_filesystem("prodinfo-f", FsBisPartitionId_CalibrationFile));
if (mountError) { return; }
FileModeState::create_and_push("prodinfo-f", "sdmc", false);
FileModeState::create_and_push("prodinfo-f", "sdmc", false, true);
}
void ExtrasMenuState::safe_to_sd()
@@ -98,7 +99,7 @@ void ExtrasMenuState::safe_to_sd()
const bool mountError = error::fslib(fslib::open_bis_filesystem("safe", FsBisPartitionId_SafeMode));
if (mountError) { return; }
FileModeState::create_and_push("safe", "sdmc", false);
FileModeState::create_and_push("safe", "sdmc", false, true);
}
void ExtrasMenuState::system_to_sd()
@@ -106,7 +107,7 @@ void ExtrasMenuState::system_to_sd()
const bool mountError = error::fslib(fslib::open_bis_filesystem("system", FsBisPartitionId_System));
if (mountError) { return; }
FileModeState::create_and_push("system", "sdmc", false);
FileModeState::create_and_push("system", "sdmc", false, true);
}
void ExtrasMenuState::user_to_sd()
@@ -114,7 +115,7 @@ void ExtrasMenuState::user_to_sd()
const bool mountError = error::fslib(fslib::open_bis_filesystem("user", FsBisPartitionId_User));
if (mountError) { return; }
FileModeState::create_and_push("user", "sdmc", false);
FileModeState::create_and_push("user", "sdmc", false, true);
}
void ExtrasMenuState::terminate_process() {}

View File

@@ -11,13 +11,15 @@
#include <cmath>
FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize)
FileModeState::FileModeState(std::string_view mountA, std::string_view mountB, int64_t journalSize, bool isSystem)
: m_mountA(mountA)
, m_mountB(mountB)
, m_journalSize(journalSize)
, m_y(720.f)
, m_targetY(91.0f)
, m_scaling(config::get_animation_scaling())
, m_isSystem(isSystem)
, m_allowSystem(config::get_by_key(config::keys::ALLOW_WRITING_TO_SYSTEM))
{
FileModeState::initialize_static_members();
FileModeState::initialize_paths();

View File

@@ -165,6 +165,14 @@ void FileOptionState::update_x_coord()
void FileOptionState::copy_target()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
if (FileOptionState::system_write_check())
{
FileOptionState::pop_system_error();
return;
}
const int64_t journalSize = m_spawningState->m_journalSize;
const fslib::Path &sourcePath = m_spawningState->get_source_path();
@@ -188,7 +196,16 @@ void FileOptionState::copy_target()
if (destSelected == 0 && sourceSelected > 1) { fullDest /= sourceDir[sourceIndex]; }
if (destSelected > 1)
{
fullDest /= destDir[destIndex];
const fslib::DirectoryEntry &entry = destDir[destIndex];
if (!entry.is_directory())
{
const char *errorFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 4);
const std::string pop = stringutil::get_formatted_string(errorFormat, entry.get_filename());
ui::PopMessageManager::push_message(popTicks, pop);
return;
}
fullDest /= entry;
if (sourceSelected > 1) { fullDest /= sourceDir[sourceIndex]; }
}
@@ -207,6 +224,12 @@ void FileOptionState::copy_target()
void FileOptionState::delete_target()
{
if (FileOptionState::system_operation_check())
{
FileOptionState::pop_system_error();
return;
}
const fslib::Path &targetPath = m_spawningState->get_source_path();
const fslib::Directory &targetDir = m_spawningState->get_source_directory();
const ui::Menu &targetMenu = m_spawningState->get_source_menu();
@@ -220,18 +243,26 @@ void FileOptionState::delete_target()
fullTarget /= targetDir[dirIndex];
}
const bool holdRequired = config::get_by_key(config::keys::HOLD_FOR_DELETION);
const char *deleteFormat = strings::get_by_name(strings::names::FILEOPTION_CONFS, 1);
const std::string query = stringutil::get_formatted_string(deleteFormat, fullTarget.string().c_str());
m_dataStruct->sourcePath = std::move(fullTarget);
m_dataStruct->journalSize = m_spawningState->m_journalSize;
TaskConfirm::create_push_fade(query, true, tasks::fileoptions::delete_target, m_dataStruct);
TaskConfirm::create_push_fade(query, holdRequired, tasks::fileoptions::delete_target, m_dataStruct);
}
void FileOptionState::rename_target()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
if (FileOptionState::system_operation_check())
{
FileOptionState::pop_system_error();
return;
}
const fslib::Path &targetPath = m_spawningState->get_source_path();
fslib::Directory &targetDir = m_spawningState->get_source_directory();
ui::Menu &targetMenu = m_spawningState->get_source_menu();
@@ -263,23 +294,24 @@ void FileOptionState::rename_target()
const bool commitError = commitNeeded && error::fslib(fslib::commit_data_to_file_system(oldPath.get_device_name()));
if (dirError && fileError && commitError)
{
const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 5);
const char *popFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 2);
const std::string pop = stringutil::get_formatted_string(popFormat, filename);
ui::PopMessageManager::push_message(popTicks, pop);
}
else
{
const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 4);
const std::string pop = stringutil::get_formatted_string(popFormat, filename, nameBuffer);
ui::PopMessageManager::push_message(popTicks, pop);
}
m_spawningState->initialize_directory_menu(targetPath, targetDir, targetMenu);
}
void FileOptionState::create_directory()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
if (FileOptionState::system_operation_check())
{
FileOptionState::pop_system_error();
return;
}
const fslib::Path &targetPath = m_spawningState->get_source_path();
fslib::Directory &targetDir = m_spawningState->get_source_directory();
ui::Menu &targetMenu = m_spawningState->get_source_menu();
@@ -296,13 +328,7 @@ void FileOptionState::create_directory()
const bool commitError = !createError && error::fslib(fslib::commit_data_to_file_system(fullTarget.get_device_name()));
if (createError || (commitRequired && commitError))
{
const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 7);
const std::string pop = stringutil::get_formatted_string(popFormat, nameBuffer);
ui::PopMessageManager::push_message(popTicks, pop);
}
else
{
const char *popFormat = strings::get_by_name(strings::names::FILEMODE_POPS, 6);
const char *popFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 3);
const std::string pop = stringutil::get_formatted_string(popFormat, nameBuffer);
ui::PopMessageManager::push_message(popTicks, pop);
}
@@ -386,6 +412,13 @@ void FileOptionState::get_show_file_properties(const fslib::Path &path)
MessageState::create_and_push(message);
}
void FileOptionState::pop_system_error()
{
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const char *error = strings::get_by_name(strings::names::FILEOPTION_POPS, 5);
ui::PopMessageManager::push_message(popTicks, error);
}
void FileOptionState::close()
{
const bool target = m_spawningState->m_target;

View File

@@ -13,9 +13,9 @@
namespace
{
constexpr int COORD_BAR_X = 312;
constexpr int COORD_BAR_Y = 462;
constexpr int COORD_BAR_Y = 470;
constexpr int COORD_TEXT_Y = 467;
constexpr int COORD_TEXT_Y = 475;
constexpr int COORD_DISPLAY_CENTER = 640;
constexpr double SIZE_BAR_WIDTH = 656.0f;
@@ -38,6 +38,8 @@ void ProgressState::update()
void ProgressState::render()
{
static constexpr int RIGHT_EDGE_X = (COORD_BAR_X + SIZE_BAR_WIDTH) - 16;
const bool hasFocus = BaseState::has_focus();
const int barWidth = static_cast<int>(SIZE_BAR_WIDTH);
const std::string status = m_task->get_status();
@@ -46,8 +48,11 @@ void ProgressState::render()
sm_dialog->render(sdl::Texture::Null, hasFocus);
sdl::text::render(sdl::Texture::Null, 312, 288, BaseTask::FONT_SIZE, 656, colors::WHITE, status);
sdl::render_line(sdl::Texture::Null, 280, 454, 999, 454, colors::DIV_COLOR);
sdl::render_rect_fill(sdl::Texture::Null, COORD_BAR_X, COORD_BAR_Y, barWidth, 32, colors::BLACK);
sdl::render_rect_fill(sdl::Texture::Null, COORD_BAR_X, COORD_BAR_Y, m_progressBarWidth, 32, colors::GREEN);
sm_barEdges->render_part(sdl::Texture::Null, COORD_BAR_X, COORD_BAR_Y, 0, 0, 16, 32);
sm_barEdges->render_part(sdl::Texture::Null, RIGHT_EDGE_X, COORD_BAR_Y, 16, 0, 16, 32);
sdl::text::render(sdl::Texture::Null,
m_percentageX,
COORD_TEXT_Y,
@@ -61,9 +66,12 @@ void ProgressState::render()
void ProgressState::initialize_static_members()
{
if (sm_dialog) { return; }
static constexpr std::string_view BAR_EDGE_NAME = "BarEdges";
sm_dialog = ui::DialogBox::create(280, 262, 720, 256);
if (sm_dialog && sm_barEdges) { return; }
sm_dialog = ui::DialogBox::create(280, 262, 720, 256);
sm_barEdges = sdl::TextureManager::load(BAR_EDGE_NAME, "romfs:/Textures/BarEdges.png");
}
void ProgressState::deactivate_state()

View File

@@ -199,15 +199,23 @@ void TitleOptionState::change_output_directory()
void TitleOptionState::create_push_file_mode()
{
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
const uint64_t applicationID = m_titleInfo->get_application_id();
const FsSaveDataInfo *saveInfo = m_user->get_save_info_by_id(applicationID);
const data::TitleInfo *titleInfo = data::get_title_info_by_id(applicationID);
if (error::is_null(saveInfo)) { return; }
const bool saveOpened = fslib::open_save_data_with_save_info(fs::DEFAULT_SAVE_MOUNT, *saveInfo);
if (!saveOpened) { return; }
const FsSaveDataType saveType = m_user->get_account_save_type();
const bool isSystem = saveType == FsSaveDataType_System || saveType == FsSaveDataType_SystemBcat;
FsSaveDataExtraData extraData{};
const bool readExtra = fs::read_save_extra_data(saveInfo, extraData);
const int64_t journalSize = readExtra ? extraData.journal_size : titleInfo->get_journal_size(saveType);
sm_slidePanel->hide();
FileModeState::create_and_push(fs::DEFAULT_SAVE_MOUNT, "sdmc", true);
FileModeState::create_and_push(fs::DEFAULT_SAVE_MOUNT, "sdmc", journalSize, isSystem);
}
void TitleOptionState::delete_all_local_backups()

View File

@@ -115,7 +115,7 @@ void data::DataContext::load_application_records(sys::Task *task)
} while (!listError);
}
bool data::DataContext::title_is_loaded(uint64_t applicationID)
bool data::DataContext::title_is_loaded(uint64_t applicationID) noexcept
{
const bool isSystem = applicationID & 0x8000000000000000;
@@ -259,7 +259,7 @@ bool data::DataContext::write_cache(sys::Task *task)
if (!opened) { continue; }
const bool controlWritten = cacheZip.write(controlData, SIZE_CTRL_DATA);
if (!controlWritten) { logger::log("Error writing control data to zip!"); }
if (!controlWritten) { logger::log("Error writing control data to cache!"); }
cacheZip.close_current_file();
}
m_cacheIsValid = true;

View File

@@ -4,7 +4,6 @@
#include "error.hpp"
#include "graphics/colors.hpp"
#include "graphics/gfxutil.hpp"
#include "logging/logger.hpp"
#include "stringutil.hpp"
#include <cstring>
@@ -27,9 +26,9 @@ data::TitleInfo::TitleInfo(uint64_t applicationID) noexcept
if (isSystem || getError)
{
const std::string appIDHex = stringutil::get_formatted_string("%04X", m_applicationID & 0xFFFF);
char *name = m_data.nacp.lang[SetLanguage_ENUS].name; // I'm hoping this is enough?
m_entry = &m_data.nacp.lang[SetLanguage_ENUS]; // I'm hoping this is enough?
std::snprintf(name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID);
std::snprintf(m_entry->name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID);
TitleInfo::get_create_path_safe_title();
}
else if (!getError && !entryError)
@@ -47,7 +46,11 @@ data::TitleInfo::TitleInfo(uint64_t applicationID, NsApplicationControlData &con
m_data = controlData;
const bool entryError = error::libnx(nacpGetLanguageEntry(&m_data.nacp, &m_entry));
if (entryError) { std::snprintf(m_entry->name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID); }
if (entryError)
{
m_entry = &m_data.nacp.lang[SetLanguage_ENUS];
std::snprintf(m_entry->name, TitleInfo::SIZE_PATH_SAFE, "%016lX", m_applicationID);
}
TitleInfo::get_create_path_safe_title();
}
@@ -150,12 +153,10 @@ void data::TitleInfo::set_path_safe_title(const char *newPathSafe) noexcept
void data::TitleInfo::get_create_path_safe_title() noexcept
{
const uint64_t applicationID = TitleInfo::get_application_id();
const bool hasCustom = config::has_custom_path(applicationID);
const bool hasCustom = config::has_custom_path(m_applicationID);
if (hasCustom)
{
config::get_custom_path(applicationID, m_pathSafeTitle, TitleInfo::SIZE_PATH_SAFE);
config::get_custom_path(m_applicationID, m_pathSafeTitle, TitleInfo::SIZE_PATH_SAFE);
return;
}

View File

@@ -6,7 +6,6 @@
#include "fs/fs.hpp"
#include "graphics/colors.hpp"
#include "graphics/gfxutil.hpp"
#include "logging/logger.hpp"
#include "sdl.hpp"
#include "stringutil.hpp"
@@ -172,8 +171,9 @@ void data::User::load_user_data()
const uint64_t saveInfoAppID = saveInfo.application_id;
const uint64_t saveInfoSysID = saveInfo.system_save_data_id;
const uint64_t applicationID = saveInfoAppID != 0 ? saveInfoAppID : saveInfoSysID;
const uint8_t saveDataType = saveInfo.save_data_type;
const bool isSystemSave = saveDataType == FsSaveDataType_System || saveDataType == FsSaveDataType_SystemBcat;
const uint8_t saveDataType = saveInfo.save_data_type;
const bool isSystemSave = saveDataType == FsSaveDataType_System || saveDataType == FsSaveDataType_SystemBcat;
const bool isBlacklisted = config::is_blacklisted(applicationID);
const bool systemFilter = (!accountSys && isAccountUser && isSystemSave);

View File

@@ -228,7 +228,9 @@ void fs::copy_directory_commit(const fslib::Path &source,
{
const bool destExists = fslib::directory_exists(fullDest);
const bool createError = !destExists && error::fslib(fslib::create_directory(fullDest));
if (!destExists && createError) { continue; }
const bool commitError =
!createError && error::fslib(fslib::commit_data_to_file_system(fullDest.get_device_name()));
if (!destExists && (createError || commitError)) { continue; }
fs::copy_directory_commit(fullSource, fullDest, journalSize, task);
}

View File

@@ -178,7 +178,8 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, in
const bool isValid = dirPath.is_valid();
const bool exists = isValid && fslib::directory_exists(dirPath);
const bool createError = isValid && !exists && error::fslib(fslib::create_directories_recursively(dirPath));
if (isValid && !exists && createError) { continue; }
bool commitError = !createError && error::fslib(fslib::commit_data_to_file_system(dirPath.get_device_name()));
if (isValid && !exists && (createError || commitError)) { continue; }
const int64_t fileSize = unzip.get_uncompressed_size();
fslib::File destFile{fullDest, FsOpenMode_Create | FsOpenMode_Write, fileSize};
@@ -221,7 +222,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, in
if (commitNeeded)
{
destFile.close();
const bool commitError = error::fslib(fslib::commit_data_to_file_system(dest.get_device_name()));
commitError = error::fslib(fslib::commit_data_to_file_system(dest.get_device_name()));
if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); } // To do: How to recover?
destFile.open(fullDest, FsOpenMode_Write);
@@ -238,7 +239,7 @@ void fs::copy_zip_to_directory(fs::MiniUnzip &unzip, const fslib::Path &dest, in
readThread.join();
destFile.close();
const bool commitError = needCommits && error::fslib(fslib::commit_data_to_file_system(dest.get_device_name()));
commitError = needCommits && error::fslib(fslib::commit_data_to_file_system(dest.get_device_name()));
if (commitError) { ui::PopMessageManager::push_message(popTicks, popCommitFailed); }
} while (unzip.next_file());
}

View File

@@ -11,6 +11,7 @@ void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, Fil
{
if (error::is_null(task)) { return; }
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const fslib::Path &source = taskData->sourcePath;
const fslib::Path &dest = taskData->destPath;
const int64_t journalSpace = taskData->journalSize;
@@ -29,7 +30,13 @@ void tasks::fileoptions::copy_source_to_destination(sys::ProgressTask *task, Fil
}
}
if (destError) { TASK_FINISH_RETURN(task); }
if (destError)
{
const char *errorFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 0);
const std::string pop = stringutil::get_formatted_string(errorFormat, source.get_filename());
ui::PopMessageManager::push_message(popTicks, pop);
TASK_FINISH_RETURN(task);
}
const bool needsCommit = journalSpace > 0;
@@ -47,7 +54,9 @@ void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskDat
if (error::is_null(task)) { return; }
// Gonna borrow this. No point in duplicating it.
const int popTicks = ui::PopMessageManager::DEFAULT_TICKS;
const char *deletingFormat = strings::get_by_name(strings::names::IO_STATUSES, 3);
const char *errorFormat = strings::get_by_name(strings::names::FILEOPTION_POPS, 1);
const fslib::Path &target = taskData->sourcePath;
const int64_t journalSpace = taskData->journalSize;
@@ -62,10 +71,24 @@ void tasks::fileoptions::delete_target(sys::Task *task, FileOptionState::TaskDat
const bool isDir = fslib::directory_exists(target);
bool needsCommit = journalSpace > 0;
if (isDir) { fslib::delete_directory_recursively(target); }
else { fslib::delete_file(target); }
bool deleteError{};
if (isDir) { deleteError = error::fslib(fslib::delete_directory_recursively(target)); }
else { deleteError = error::fslib(fslib::delete_file(target)); }
if (needsCommit) { fslib::commit_data_to_file_system(target.get_device_name()); }
if (deleteError)
{
const char *filename = target.get_filename();
const std::string pop = stringutil::get_formatted_string(errorFormat, filename);
ui::PopMessageManager::push_message(popTicks, pop);
}
const bool commitError = needsCommit && error::fslib(fslib::commit_data_to_file_system(target.get_device_name()));
if (commitError)
{
const char *filename = target.get_filename();
const std::string pop = stringutil::get_formatted_string(errorFormat, filename);
ui::PopMessageManager::push_message(popTicks, pop);
}
spawningState->update_source();
task->complete();