From e1d592ee9c02e26bf0a6f08144bd53cbe2b90f8b Mon Sep 17 00:00:00 2001 From: J-D-K Date: Sat, 6 Sep 2025 19:21:35 -0400 Subject: [PATCH] FileMode/FileOption debugging, fixes, and added safety. --- include/StateManager.hpp | 4 +- include/appstates/BackupMenuState.hpp | 3 - include/appstates/BaseTask.hpp | 3 - include/appstates/BlacklistEditState.hpp | 3 - include/appstates/ConfirmState.hpp | 5 +- include/appstates/DataLoadingState.hpp | 3 - include/appstates/ExtrasMenuState.hpp | 5 +- include/appstates/FadeState.hpp | 3 - include/appstates/FileModeState.hpp | 29 +++++---- include/appstates/FileOptionState.hpp | 25 +++++++- include/appstates/MainMenuState.hpp | 3 - include/appstates/MessageState.hpp | 3 - include/appstates/ProgressState.hpp | 6 +- include/appstates/SaveCreateState.hpp | 3 - include/appstates/SettingsState.hpp | 3 - include/appstates/TaskState.hpp | 3 - include/appstates/TextTitleSelectState.hpp | 3 - include/appstates/TitleInfoState.hpp | 3 - include/appstates/TitleOptionState.hpp | 3 - include/appstates/TitleSelectState.hpp | 3 - include/appstates/UserOptionState.hpp | 3 - include/data/DataContext.hpp | 2 +- include/remote/URL.hpp | 2 +- include/strings/names.hpp | 2 +- include/ui/ColorMod.hpp | 2 +- include/ui/Menu.hpp | 3 + include/ui/TextScroll.hpp | 1 + include/ui/TitleTile.hpp | 4 +- include/ui/TitleView.hpp | 2 +- romfs/Text/ENUS.json | 21 +++---- romfs/Textures/BarEdges.png | Bin 0 -> 434 bytes source/JKSV.cpp | 4 +- source/StateManager.cpp | 4 +- source/appstates/ExtrasMenuState.cpp | 21 ++++--- source/appstates/FileModeState.cpp | 4 +- source/appstates/FileOptionState.cpp | 69 +++++++++++++++------ source/appstates/ProgressState.cpp | 16 +++-- source/appstates/TitleOptionState.cpp | 14 ++++- source/data/DataContext.cpp | 4 +- source/data/TitleInfo.cpp | 17 ++--- source/data/User.cpp | 6 +- source/fs/io.cpp | 4 +- source/fs/zip.cpp | 7 ++- source/tasks/fileoptions.cpp | 31 +++++++-- 44 files changed, 208 insertions(+), 151 deletions(-) create mode 100644 romfs/Textures/BarEdges.png diff --git a/include/StateManager.hpp b/include/StateManager.hpp index 40efc6d..539022a 100644 --- a/include/StateManager.hpp +++ b/include/StateManager.hpp @@ -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. diff --git a/include/appstates/BackupMenuState.hpp b/include/appstates/BackupMenuState.hpp index e0ded66..ab1eae6 100644 --- a/include/appstates/BackupMenuState.hpp +++ b/include/appstates/BackupMenuState.hpp @@ -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 create(data::User *user, data::TitleInfo *titleInfo) { diff --git a/include/appstates/BaseTask.hpp b/include/appstates/BaseTask.hpp index ea76377..242f009 100644 --- a/include/appstates/BaseTask.hpp +++ b/include/appstates/BaseTask.hpp @@ -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; diff --git a/include/appstates/BlacklistEditState.hpp b/include/appstates/BlacklistEditState.hpp index 9d78b42..0c472be 100644 --- a/include/appstates/BlacklistEditState.hpp +++ b/include/appstates/BlacklistEditState.hpp @@ -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 create() { return std::make_shared(); } diff --git a/include/appstates/ConfirmState.hpp b/include/appstates/ConfirmState.hpp index 9155067..7b90bf8 100644 --- a/include/appstates/ConfirmState.hpp +++ b/include/appstates/ConfirmState.hpp @@ -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 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{}; diff --git a/include/appstates/DataLoadingState.hpp b/include/appstates/DataLoadingState.hpp index f41c894..ecf3673 100644 --- a/include/appstates/DataLoadingState.hpp +++ b/include/appstates/DataLoadingState.hpp @@ -26,9 +26,6 @@ class DataLoadingState final : public BaseTask m_task = std::make_unique(function, std::forward(args)...); } - /// @brief Destructor. Runs all DestructFunctions in the vector. - ~DataLoadingState() {}; - template static inline std::shared_ptr create(data::DataContext &context, DestructFunction destructFunction, diff --git a/include/appstates/ExtrasMenuState.hpp b/include/appstates/ExtrasMenuState.hpp index 5746ef1..0236cbd 100644 --- a/include/appstates/ExtrasMenuState.hpp +++ b/include/appstates/ExtrasMenuState.hpp @@ -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 create() { return std::make_shared(); } @@ -24,7 +21,7 @@ class ExtrasMenuState final : public BaseState private: /// @brief Menu - ui::Menu m_extrasMenu; + std::shared_ptr m_extrasMenu{}; /// @brief Render target for menu. sdl::SharedTexture m_renderTarget{}; diff --git a/include/appstates/FadeState.hpp b/include/appstates/FadeState.hpp index cf6e52e..60108d3 100644 --- a/include/appstates/FadeState.hpp +++ b/include/appstates/FadeState.hpp @@ -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 nextState); - /// @brief Required destructor. - ~FadeState() {}; - /// @brief Returns a new fade in state. See constructor. static inline std::shared_ptr create(sdl::Color baseColor, uint8_t startAlpha, diff --git a/include/appstates/FileModeState.hpp b/include/appstates/FileModeState.hpp index a801291..8dc51dd 100644 --- a/include/appstates/FileModeState.hpp +++ b/include/appstates/FileModeState.hpp @@ -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 create(std::string_view mountA, std::string_view mountB, - int64_t journalSize = 0) + int64_t journalSize = 0, + bool isSystem = false) { - return std::make_shared(mountA, mountB, journalSize); + return std::make_shared(mountA, mountB, journalSize, isSystem); } static inline std::shared_ptr 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(mountA, mountB, journalSize); + auto newState = std::make_shared(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 sm_frame{}; diff --git a/include/appstates/FileOptionState.hpp b/include/appstates/FileOptionState.hpp index 9a3a22a..7016019 100644 --- a/include/appstates/FileOptionState.hpp +++ b/include/appstates/FileOptionState.hpp @@ -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 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; + } }; \ No newline at end of file diff --git a/include/appstates/MainMenuState.hpp b/include/appstates/MainMenuState.hpp index e97255b..afb5153 100644 --- a/include/appstates/MainMenuState.hpp +++ b/include/appstates/MainMenuState.hpp @@ -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 create() { return std::make_shared(); } diff --git a/include/appstates/MessageState.hpp b/include/appstates/MessageState.hpp index 990a920..25b3fdb 100644 --- a/include/appstates/MessageState.hpp +++ b/include/appstates/MessageState.hpp @@ -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 create(std::string_view message) { diff --git a/include/appstates/ProgressState.hpp b/include/appstates/ProgressState.hpp index f8f0077..9b922fa 100644 --- a/include/appstates/ProgressState.hpp +++ b/include/appstates/ProgressState.hpp @@ -25,9 +25,6 @@ class ProgressState final : public BaseTask m_task = std::make_unique(function, std::forward(args)...); } - /// @brief Required destructor. - ~ProgressState() {}; - /// @brief Creates and returns a new progress state. template static inline std::shared_ptr 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 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(); diff --git a/include/appstates/SaveCreateState.hpp b/include/appstates/SaveCreateState.hpp index 6021e47..c40c744 100644 --- a/include/appstates/SaveCreateState.hpp +++ b/include/appstates/SaveCreateState.hpp @@ -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 create(data::User *user, TitleSelectCommon *titleSelect) { diff --git a/include/appstates/SettingsState.hpp b/include/appstates/SettingsState.hpp index 3249a65..0918797 100644 --- a/include/appstates/SettingsState.hpp +++ b/include/appstates/SettingsState.hpp @@ -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 create() { return std::make_shared(); } diff --git a/include/appstates/TaskState.hpp b/include/appstates/TaskState.hpp index 12377b6..f796e93 100644 --- a/include/appstates/TaskState.hpp +++ b/include/appstates/TaskState.hpp @@ -20,9 +20,6 @@ class TaskState final : public BaseTask m_task = std::make_unique(function, std::forward(args)...); } - /// @brief Required destructor. - ~TaskState() {}; - /// @brief Creates and returns a new TaskState. template static inline std::shared_ptr create(void (*function)(sys::Task *, Args...), Args... args) diff --git a/include/appstates/TextTitleSelectState.hpp b/include/appstates/TextTitleSelectState.hpp index 4e0c36a..e32de3f 100644 --- a/include/appstates/TextTitleSelectState.hpp +++ b/include/appstates/TextTitleSelectState.hpp @@ -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 create(data::User *user) { diff --git a/include/appstates/TitleInfoState.hpp b/include/appstates/TitleInfoState.hpp index d509bd2..b167143 100644 --- a/include/appstates/TitleInfoState.hpp +++ b/include/appstates/TitleInfoState.hpp @@ -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 create(data::User *user, data::TitleInfo *titleInfo) { diff --git a/include/appstates/TitleOptionState.hpp b/include/appstates/TitleOptionState.hpp index f987cda..afa0dc0 100644 --- a/include/appstates/TitleOptionState.hpp +++ b/include/appstates/TitleOptionState.hpp @@ -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 create(data::User *user, data::TitleInfo *titleInfo, diff --git a/include/appstates/TitleSelectState.hpp b/include/appstates/TitleSelectState.hpp index 2a9a8b7..35b1e12 100644 --- a/include/appstates/TitleSelectState.hpp +++ b/include/appstates/TitleSelectState.hpp @@ -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 create(data::User *user) { diff --git a/include/appstates/UserOptionState.hpp b/include/appstates/UserOptionState.hpp index c5dd62c..b71a7bf 100644 --- a/include/appstates/UserOptionState.hpp +++ b/include/appstates/UserOptionState.hpp @@ -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 create(data::User *user, TitleSelectCommon *titleSelect) { diff --git a/include/data/DataContext.hpp b/include/data/DataContext.hpp index 16ce0d7..2f2d2d1 100644 --- a/include/data/DataContext.hpp +++ b/include/data/DataContext.hpp @@ -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); diff --git a/include/remote/URL.hpp b/include/remote/URL.hpp index bc661c2..3c8c634 100644 --- a/include/remote/URL.hpp +++ b/include/remote/URL.hpp @@ -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(); diff --git a/include/strings/names.hpp b/include/strings/names.hpp index 062bc50..7dd3628 100644 --- a/include/strings/names.hpp +++ b/include/strings/names.hpp @@ -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"; diff --git a/include/ui/ColorMod.hpp b/include/ui/ColorMod.hpp index 5883a99..e76f92a 100644 --- a/include/ui/ColorMod.hpp +++ b/include/ui/ColorMod.hpp @@ -24,6 +24,6 @@ namespace ui bool m_direction = true; /// @brief Color value. - uint8_t m_colorMod = 0; + uint8_t m_colorMod{}; }; } // namespace ui diff --git a/include/ui/Menu.hpp b/include/ui/Menu.hpp index e2bf6f9..9bd0bbc 100644 --- a/include/ui/Menu.hpp +++ b/include/ui/Menu.hpp @@ -123,10 +123,13 @@ namespace ui /// @brief Text scroll for when the current option is too long to on screen. std::shared_ptr 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 diff --git a/include/ui/TextScroll.hpp b/include/ui/TextScroll.hpp index 9512f9a..ba9130b 100644 --- a/include/ui/TextScroll.hpp +++ b/include/ui/TextScroll.hpp @@ -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. diff --git a/include/ui/TitleTile.hpp b/include/ui/TitleTile.hpp index 8db9f29..7ddbe31 100644 --- a/include/ui/TitleTile.hpp +++ b/include/ui/TitleTile.hpp @@ -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{}; diff --git a/include/ui/TitleView.hpp b/include/ui/TitleView.hpp index 0c33d88..b22c6ff 100644 --- a/include/ui/TitleView.hpp +++ b/include/ui/TitleView.hpp @@ -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{}; diff --git a/romfs/Text/ENUS.json b/romfs/Text/ENUS.json index 2c4ad0c..011b069 100644 --- a/romfs/Text/ENUS.json +++ b/romfs/Text/ENUS.json @@ -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" diff --git a/romfs/Textures/BarEdges.png b/romfs/Textures/BarEdges.png new file mode 100644 index 0000000000000000000000000000000000000000..3b1523d4b960d8ba20f8b476524104a7278ae509 GIT binary patch literal 434 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%C&rs6b?Si}mUKs7M+SzC z{oH>NSwSk3J%W507^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+10g0sLQ zvY3HEPZ@+6E0)@q0S%Y-ba4!cIQ(|HZr`B*kyiV>H0C8-VU4beyBf21bwtT9wH~-y zCTN<^EUKZiTBBhm6QnIzrc zDZciG|FQ1L4C(I7^KK~v!TTmw5A)oOUtS&c(Xp!DC~*31+!H2|X}5#z|7!+xm`=Nt z_)BQU_mvg7OBJtv*|~LzyUzKBwX5`mJM`Derk+2W!TKgS@6fq>^=s4e!~G^-|Lnix XL;B8n;umv(VaMR<>gTe~DWM4fab2RB literal 0 HcmV?d00001 diff --git a/source/JKSV.cpp b/source/JKSV.cpp index 176c459..4455e5c 100644 --- a/source/JKSV.cpp +++ b/source/JKSV.cpp @@ -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; diff --git a/source/StateManager.cpp b/source/StateManager.cpp index 0d74e3b..911b2bf 100644 --- a/source/StateManager.cpp +++ b/source/StateManager.cpp @@ -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 &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; diff --git a/source/appstates/ExtrasMenuState.cpp b/source/appstates/ExtrasMenuState.cpp index c0c970a..f59cbc5 100644 --- a/source/appstates/ExtrasMenuState.cpp +++ b/source/appstates/ExtrasMenuState.cpp @@ -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() {} diff --git a/source/appstates/FileModeState.cpp b/source/appstates/FileModeState.cpp index 5545b22..f039f66 100644 --- a/source/appstates/FileModeState.cpp +++ b/source/appstates/FileModeState.cpp @@ -11,13 +11,15 @@ #include -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(); diff --git a/source/appstates/FileOptionState.cpp b/source/appstates/FileOptionState.cpp index 5f419b6..174315a 100644 --- a/source/appstates/FileOptionState.cpp +++ b/source/appstates/FileOptionState.cpp @@ -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; diff --git a/source/appstates/ProgressState.cpp b/source/appstates/ProgressState.cpp index 6e0a92e..3728be7 100644 --- a/source/appstates/ProgressState.cpp +++ b/source/appstates/ProgressState.cpp @@ -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(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() diff --git a/source/appstates/TitleOptionState.cpp b/source/appstates/TitleOptionState.cpp index 1234d3f..fc3027b 100644 --- a/source/appstates/TitleOptionState.cpp +++ b/source/appstates/TitleOptionState.cpp @@ -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() diff --git a/source/data/DataContext.cpp b/source/data/DataContext.cpp index 9662376..3cf1923 100644 --- a/source/data/DataContext.cpp +++ b/source/data/DataContext.cpp @@ -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; diff --git a/source/data/TitleInfo.cpp b/source/data/TitleInfo.cpp index 27ec299..95d266b 100644 --- a/source/data/TitleInfo.cpp +++ b/source/data/TitleInfo.cpp @@ -4,7 +4,6 @@ #include "error.hpp" #include "graphics/colors.hpp" #include "graphics/gfxutil.hpp" -#include "logging/logger.hpp" #include "stringutil.hpp" #include @@ -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; } diff --git a/source/data/User.cpp b/source/data/User.cpp index 7b96745..3e888b2 100644 --- a/source/data/User.cpp +++ b/source/data/User.cpp @@ -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); diff --git a/source/fs/io.cpp b/source/fs/io.cpp index 40a77c5..3e50d00 100644 --- a/source/fs/io.cpp +++ b/source/fs/io.cpp @@ -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); } diff --git a/source/fs/zip.cpp b/source/fs/zip.cpp index 980778a..3281c76 100644 --- a/source/fs/zip.cpp +++ b/source/fs/zip.cpp @@ -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()); } diff --git a/source/tasks/fileoptions.cpp b/source/tasks/fileoptions.cpp index 259d8c2..9400b72 100644 --- a/source/tasks/fileoptions.cpp +++ b/source/tasks/fileoptions.cpp @@ -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();