diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index 45c4a414e..97c68545e 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -8,6 +8,7 @@ #include #include #include +#include static void archive_folder_open_cb(void* context, uint32_t item_cnt, int32_t file_idx, bool is_root) { @@ -65,7 +66,13 @@ static void archive_add_file_item(browser, is_folder, furi_string_get_cstr(item_path)); } else { with_view_model( - browser->view, ArchiveBrowserViewModel * model, { model->list_loading = false; }, true); + browser->view, + ArchiveBrowserViewModel * model, + { + files_array_sort(model->files); + model->list_loading = false; + }, + true); } } @@ -140,7 +147,7 @@ void archive_update_focus(ArchiveBrowserView* browser, const char* target) { archive_get_items(browser, furi_string_get_cstr(browser->path)); if(!archive_file_get_array_size(browser) && archive_is_home(browser)) { - archive_switch_tab(browser, TAB_RIGHT); + archive_switch_tab(browser, TAB_LEFT); } else { with_view_model( browser->view, @@ -207,7 +214,7 @@ void archive_file_array_rm_selected(ArchiveBrowserView* browser) { false); if((items_cnt == 0) && (archive_is_home(browser))) { - archive_switch_tab(browser, TAB_RIGHT); + archive_switch_tab(browser, TAB_LEFT); } archive_update_offset(browser); @@ -456,6 +463,13 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) { } else { tab = (tab + 1) % ArchiveTabTotal; } + if(tab == ArchiveTabInternal && !furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { + if(key == InputKeyLeft) { + tab = ((tab - 1) + ArchiveTabTotal) % ArchiveTabTotal; + } else { + tab = (tab + 1) % ArchiveTabTotal; + } + } browser->is_root = true; archive_set_tab(browser, tab); diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index 09ffea1f9..43a9a651a 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -3,7 +3,7 @@ #include "../archive_i.h" #include -#define TAB_RIGHT InputKeyRight // Default tab switch direction +#define TAB_LEFT InputKeyLeft // Default tab switch direction #define TAB_DEFAULT ArchiveTabFavorites // Start tab #define FILE_LIST_BUF_LEN 50 @@ -17,6 +17,7 @@ static const char* tab_default_paths[] = { [ArchiveTabBadUsb] = ANY_PATH("badusb"), [ArchiveTabU2f] = "/app:u2f", [ArchiveTabApplications] = ANY_PATH("apps"), + [ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX, [ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX, }; @@ -44,6 +45,7 @@ static const ArchiveFileTypeEnum known_type[] = { [ArchiveTabBadUsb] = ArchiveFileTypeBadUsb, [ArchiveTabU2f] = ArchiveFileTypeU2f, [ArchiveTabApplications] = ArchiveFileTypeApplication, + [ArchiveTabInternal] = ArchiveFileTypeUnknown, [ArchiveTabBrowser] = ArchiveFileTypeUnknown, }; diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index d2cd93a66..6acdb2213 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -2,6 +2,7 @@ #include #include +#include #include #include "toolbox/path.h" @@ -81,13 +82,29 @@ static void ArchiveFile_t_clear(ArchiveFile_t* obj) { furi_string_free(obj->custom_name); } -ARRAY_DEF( - files_array, - ArchiveFile_t, - (INIT(API_2(ArchiveFile_t_init)), - SET(API_6(ArchiveFile_t_set)), - INIT_SET(API_6(ArchiveFile_t_init_set)), - CLEAR(API_2(ArchiveFile_t_clear)))) +static int ArchiveFile_t_cmp(const ArchiveFile_t* a, const ArchiveFile_t* b) { + if(a->type == ArchiveFileTypeFolder && b->type != ArchiveFileTypeFolder) { + return -1; + } + if(a->type != ArchiveFileTypeFolder && b->type == ArchiveFileTypeFolder) { + return 1; + } + + return furi_string_cmpi(a->path, b->path); +} + +#define M_OPL_ArchiveFile_t() \ + (INIT(API_2(ArchiveFile_t_init)), \ + SET(API_6(ArchiveFile_t_set)), \ + INIT_SET(API_6(ArchiveFile_t_init_set)), \ + CLEAR(API_2(ArchiveFile_t_clear)), \ + CMP(API_6(ArchiveFile_t_cmp)), \ + SWAP(M_SWAP_DEFAULT), \ + EQUAL(API_6(M_EQUAL_DEFAULT))) + +ARRAY_DEF(files_array, ArchiveFile_t) + +ALGO_DEF(files_array, ARRAY_OPLIST(files_array, M_OPL_ArchiveFile_t())) void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder, bool is_app); bool archive_get_items(void* context, const char* path); diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index dce753fde..26ed17d75 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -19,6 +19,7 @@ static const char* ArchiveTabNames[] = { [ArchiveTabBadUsb] = "Bad USB", [ArchiveTabU2f] = "U2F", [ArchiveTabApplications] = "Apps", + [ArchiveTabInternal] = "Internal", [ArchiveTabBrowser] = "Browser", }; diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 482a675e3..6e6582405 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -2,7 +2,6 @@ #include "../helpers/archive_files.h" #include "../helpers/archive_favorites.h" -#include "../helpers/archive_menu.h" #include #include @@ -10,7 +9,10 @@ #include #include #include -#include +#include "../helpers/archive_files.h" +#include "../helpers/archive_menu.h" +#include "../helpers/archive_favorites.h" +#include "gui/modules/file_browser_worker.h" #define MAX_LEN_PX 110 #define MAX_NAME_LEN 255 @@ -29,6 +31,7 @@ typedef enum { ArchiveTabBadUsb, ArchiveTabU2f, ArchiveTabApplications, + ArchiveTabInternal, ArchiveTabBrowser, ArchiveTabTotal, } ArchiveTabEnum; diff --git a/applications/services/gui/modules/file_browser.c b/applications/services/gui/modules/file_browser.c index d12a00ba5..dc3c65eed 100644 --- a/applications/services/gui/modules/file_browser.c +++ b/applications/services/gui/modules/file_browser.c @@ -11,6 +11,7 @@ #include #include #include +#include "m-algo.h" #include #define LIST_ITEMS 5u @@ -77,13 +78,36 @@ static void BrowserItem_t_clear(BrowserItem_t* obj) { } } -ARRAY_DEF( - items_array, - BrowserItem_t, - (INIT(API_2(BrowserItem_t_init)), - SET(API_6(BrowserItem_t_set)), - INIT_SET(API_6(BrowserItem_t_init_set)), - CLEAR(API_2(BrowserItem_t_clear)))) +static int BrowserItem_t_cmp(const BrowserItem_t* a, const BrowserItem_t* b) { + // Back indicator comes before everything, then folders, then all other files. + if(a->type == BrowserItemTypeBack) { + return -1; + } + if(b->type == BrowserItemTypeBack) { + return 1; + } + if(a->type == BrowserItemTypeFolder && b->type != BrowserItemTypeFolder) { + return -1; + } + if(a->type != BrowserItemTypeFolder && b->type == BrowserItemTypeFolder) { + return 1; + } + + return furi_string_cmpi(a->path, b->path); +} + +#define M_OPL_BrowserItem_t() \ + (INIT(API_2(BrowserItem_t_init)), \ + SET(API_6(BrowserItem_t_set)), \ + INIT_SET(API_6(BrowserItem_t_init_set)), \ + CLEAR(API_2(BrowserItem_t_clear)), \ + CMP(API_6(BrowserItem_t_cmp)), \ + SWAP(M_SWAP_DEFAULT), \ + EQUAL(API_6(M_EQUAL_DEFAULT))) + +ARRAY_DEF(items_array, BrowserItem_t) + +ALGO_DEF(items_array, ARRAY_OPLIST(items_array, M_OPL_BrowserItem_t())) struct FileBrowser { View* view; @@ -438,7 +462,13 @@ static void } } else { with_view_model( - browser->view, FileBrowserModel * model, { model->list_loading = false; }, true); + browser->view, + FileBrowserModel * model, + { + items_array_sort(model->items); + model->list_loading = false; + }, + true); } } @@ -485,19 +515,25 @@ static void browser_draw_list(Canvas* canvas, FileBrowserModel* model) { for(uint32_t i = 0; i < MIN(model->item_cnt, LIST_ITEMS); i++) { int32_t idx = CLAMP((uint32_t)(i + model->list_offset), model->item_cnt, 0u); - BrowserItemType item_type = BrowserItemTypeLoading; + BrowserItemType item_type; uint8_t* custom_icon_data = NULL; if(browser_is_item_in_array(model, idx)) { BrowserItem_t* item = items_array_get( model->items, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0)); item_type = item->type; - furi_string_set(filename, item->display_name); - if(item_type == BrowserItemTypeFile) { - custom_icon_data = item->custom_icon_data; + if(model->list_loading && item_type != BrowserItemTypeBack) { + furi_string_set(filename, "---"); + item_type = BrowserItemTypeLoading; + } else { + furi_string_set(filename, item->display_name); + if(item_type == BrowserItemTypeFile) { + custom_icon_data = item->custom_icon_data; + } } } else { furi_string_set(filename, "---"); + item_type = BrowserItemTypeLoading; } if(item_type == BrowserItemTypeBack) { diff --git a/applications/services/gui/modules/file_browser_worker.c b/applications/services/gui/modules/file_browser_worker.c index 80c4f4c43..4b7be70a1 100644 --- a/applications/services/gui/modules/file_browser_worker.c +++ b/applications/services/gui/modules/file_browser_worker.c @@ -202,55 +202,58 @@ static bool uint32_t items_cnt = 0; + bool ret = false; do { if(!storage_dir_open(directory, furi_string_get_cstr(path))) { break; } - items_cnt = 0; - while(items_cnt < offset) { - if(!storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX)) { - break; - } - if(storage_file_get_error(directory) == FSE_OK) { - furi_string_set(name_str, name_temp); - if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { - items_cnt++; - } - } else { - break; - } - } - if(items_cnt != offset) { - break; - } + // items_cnt = 0; + // while(items_cnt < offset) { + // if(!storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX)) { + // break; + // } + // if(storage_file_get_error(directory) == FSE_OK) { + // furi_string_set(name_str, name_temp); + // if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { + // items_cnt++; + // } + // } else { + // break; + // } + // } + // if(items_cnt != offset) { + // break; + // } + // FLIPPER DEVS MOMENT + // this used to load the file list in chunks, and then sort it... + // so while scrolling, it loads more files and sorts them... + // chances are, the new files are higher in the sorted list... + // so the files keep shifting around while scrolling... + // now this does something intelligent and loads all in one go. + // might take a few milliseconds longer, but atleast it works :kekw: + UNUSED(offset); + UNUSED(count); if(browser->list_load_cb) { - browser->list_load_cb(browser->cb_ctx, offset); + browser->list_load_cb(browser->cb_ctx, 0); } - - items_cnt = 0; - while(items_cnt < count) { - if(!storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX)) { - break; - } - if(storage_file_get_error(directory) == FSE_OK) { - furi_string_set(name_str, name_temp); - if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { - furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp); - if(browser->list_item_cb) { - browser->list_item_cb( - browser->cb_ctx, name_str, (file_info.flags & FSF_DIRECTORY), false); - } - items_cnt++; + while(storage_dir_read(directory, &file_info, name_temp, FILE_NAME_LEN_MAX) && + storage_file_get_error(directory) == FSE_OK) { + furi_string_set(name_str, name_temp); + if(browser_filter_by_name(browser, name_str, (file_info.flags & FSF_DIRECTORY))) { + furi_string_printf(name_str, "%s/%s", furi_string_get_cstr(path), name_temp); + if(browser->list_item_cb) { + browser->list_item_cb( + browser->cb_ctx, name_str, (file_info.flags & FSF_DIRECTORY), false); } - } else { - break; + items_cnt++; } } if(browser->list_item_cb) { browser->list_item_cb(browser->cb_ctx, NULL, false, true); } + ret = true; } while(0); furi_string_free(name_str); @@ -260,7 +263,7 @@ static bool furi_record_close(RECORD_STORAGE); - return (items_cnt == count); + return ret; } static int32_t browser_worker(void* context) {