mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2026-11-13 10:27:37 +00:00
When file_browser could not open the directory it was pointed at, it said `<Empty>`, three of its four keys stopped working for ever, and nothing was logged. Two bool returns were discarded in the worker: browser_folder_init failed at storage_dir_open but folder_cb ran anyway, so the view set list_loading and asked for a load; browser_folder_load_full then failed the same way and sent neither list_load_cb nor the is_last item callback, so list_loading was never cleared and file_browser_view_input_callback returned false for Up, Down and OK on every press. Back was not consumed, so the screen could at least be left. The user was told the folder was empty when the truth was that the card was gone. Every load now ends with a last item, on every early exit of both load paths, so the view always stops waiting. That also fixes the identical freeze in the Archive app, which gates input on the same flag and clears it only on is_last, with no change in Archive and no new ABI - it goes through callbacks Archive already implements. The chunked path had a third dead exit nobody had noticed: the items_cnt != offset break when a folder loses entries mid-load. A new optional callback, file_browser_worker_set_folder_error_callback, lets the view draw "Cannot read folder" instead of lying with `<Empty>`, and discard a row count that a failed listing can never fill - without it the message was unreachable from the load paths, where item_cnt came from a count that had succeeded, leaving rows of `---` that OK did nothing on. The existing callback signatures are untouched, so third-party .faps are unaffected. API 88.25 -> 88.26 for the new export. Three more things in the same code: - A read that died part way through a folder was indistinguishable from the end of one: storage_dir_read stops the same way for both, so a truncated listing was reported as a complete folder with nothing logged at any level. A 30-file folder failing at file 12 looked like a clean 12-file folder, and the user would conclude files had been deleted. FSE_NOT_EXIST is the end of a folder; any other error after the loop means the rest was never seen. - The failures are logged now, with the path and the FS error, at a level a release build shows, and the count pass is distinguished from the load pass. browser_folder_check_and_switch still falls back to the nearest readable ancestor for a missing folder, but it no longer does it silently. - `<Empty>` was also drawn before the first scan landed, and input was live against that zero-item model, where an Up press left item_idx at -1 and fired a redundant re-read. file_browser_start raises the loading flag before the worker exists, since the worker queues its own first scan. An unopenable folder no longer costs two storage_dir_open round trips either; the second attempt was guaranteed to fail. Not verified on hardware. Host build, lint and format are clean, SDKCHK reports API 88.26 up to date, a FAP builds against it, and the storage semantics the fix relies on were traced through storage_ext.c, but none of the failure paths have been exercised on a device. To check: open Apps, pull the SD card, navigate - expect "Cannot read folder" with Up, Down and OK still alive, and `Cannot open <path>` in the log. Left for a follow-up: the in-loop storage_file_get_error checks in the enumeration loops are dead code, browser_folder_load_chunked and _full have return values no caller reads, and the new FSE_NOT_EXIST predicate is the third hand-rolled copy in the tree (desktop_settings_app.c has it character-for-character, plugin_manager.c a looser version), so it probably belongs in storage.h. Closes #1197 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>