diff --git a/applications/main/archive/archive_i.h b/applications/main/archive/archive_i.h index bd683c22d..8d60d63a2 100644 --- a/applications/main/archive/archive_i.h +++ b/applications/main/archive/archive_i.h @@ -8,9 +8,11 @@ #include #include #include +#include #include #include #include +#include #include #include "views/archive_browser_view.h" @@ -39,6 +41,9 @@ struct ArchiveApp { FuriString* fav_move_str; char text_store[MAX_NAME_LEN]; FuriString* file_extension; + + WidgetElement* element; + FuriThread* thread; }; void archive_show_loading_popup(ArchiveApp* context, bool show); diff --git a/applications/main/archive/scenes/archive_scene_info.c b/applications/main/archive/scenes/archive_scene_info.c index 7af7d0db5..19bbc900e 100644 --- a/applications/main/archive/scenes/archive_scene_info.c +++ b/applications/main/archive/scenes/archive_scene_info.c @@ -3,6 +3,8 @@ #define TAG "Archive" +const char* units[] = {"Bytes", "KiB", "MiB", "GiB", "TiB"}; + void archive_scene_info_widget_callback(GuiButtonType result, InputType type, void* context) { furi_assert(context); ArchiveApp* app = (ArchiveApp*)context; @@ -11,6 +13,54 @@ void archive_scene_info_widget_callback(GuiButtonType result, InputType type, vo } } +uint32_t archive_scene_info_dirwalk(void* context) { + furi_assert(context); + ArchiveApp* instance = context; + + char buf[128]; + FileInfo fileinfo; + uint64_t total = 0; + DirWalk* dir_walk = dir_walk_alloc(furi_record_open(RECORD_STORAGE)); + ArchiveFile_t* current = archive_get_current_file(instance->browser); + if(dir_walk_open(dir_walk, furi_string_get_cstr(current->path))) { + while(scene_manager_get_scene_state(instance->scene_manager, ArchiveAppSceneInfo)) { + DirWalkResult result = dir_walk_read(dir_walk, NULL, &fileinfo); + if(result == DirWalkError) { + snprintf(buf, sizeof(buf), "Size: \e#Error\e#"); + widget_element_text_box_set_text(instance->element, buf); + break; + } + bool is_last = result == DirWalkLast; + if(!file_info_is_dir(&fileinfo) || is_last) { + if(!is_last) total += fileinfo.size; + double show = total; + size_t unit; + for(unit = 0; unit < COUNT_OF(units); unit++) { + if(show < 1024) break; + show /= 1024; + } + snprintf( + buf, + sizeof(buf), + unit ? "Size: %s\e#%.2f\e# %s" : "Size: %s\e#%.0f\e# %s", + is_last ? "" : "... ", + show, + units[unit]); + widget_element_text_box_set_text(instance->element, buf); + } + if(is_last) break; + } + } else { + snprintf(buf, sizeof(buf), "Size: \e#Error\e#"); + widget_element_text_box_set_text(instance->element, buf); + } + dir_walk_free(dir_walk); + furi_record_close(RECORD_STORAGE); + + view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget); + return 0; +} + void archive_scene_info_on_enter(void* context) { furi_assert(context); ArchiveApp* instance = context; @@ -18,55 +68,30 @@ void archive_scene_info_on_enter(void* context) { widget_add_button_element( instance->widget, GuiButtonTypeLeft, "Back", archive_scene_info_widget_callback, instance); - FuriString* filename; - FuriString* dirname; - FuriString* str_size; - filename = furi_string_alloc(); - dirname = furi_string_alloc(); - str_size = furi_string_alloc(); + FuriString* filename = furi_string_alloc(); + FuriString* dirname = furi_string_alloc(); ArchiveFile_t* current = archive_get_current_file(instance->browser); - char file_info_message[128]; - Storage* fs_api = furi_record_open(RECORD_STORAGE); + char buf[128]; // Filename path_extract_filename(current->path, filename, false); - snprintf( - file_info_message, sizeof(file_info_message), "\e#%s\e#", furi_string_get_cstr(filename)); + snprintf(buf, sizeof(buf), "\e#%s\e#", furi_string_get_cstr(filename)); widget_add_text_box_element( - instance->widget, 0, 0, 128, 25, AlignLeft, AlignCenter, file_info_message, false); + instance->widget, 0, 0, 128, 24, AlignLeft, AlignCenter, buf, false); // Directory path path_extract_dirname(furi_string_get_cstr(current->path), dirname); - - // File size - FileInfo fileinfo; - if(storage_common_stat(fs_api, furi_string_get_cstr(current->path), &fileinfo) != FSE_OK || - file_info_is_dir(&fileinfo)) { - snprintf( - file_info_message, - sizeof(file_info_message), - "Size: \e#N/A\e#\n%s", - furi_string_get_cstr(dirname)); - } else if(fileinfo.size <= 1024) { - furi_string_printf(str_size, "%lld", fileinfo.size); - snprintf( - file_info_message, - sizeof(file_info_message), - "Size: \e#%s\e# bytes\n%s", - furi_string_get_cstr(str_size), - furi_string_get_cstr(dirname)); - } else { - furi_string_printf(str_size, "%lld", fileinfo.size / 1024); - snprintf( - file_info_message, - sizeof(file_info_message), - "Size: \e#%s\e# Kb.\n%s", - furi_string_get_cstr(str_size), - furi_string_get_cstr(dirname)); - } widget_add_text_box_element( - instance->widget, 0, 25, 128, 25, AlignLeft, AlignCenter, file_info_message, true); + instance->widget, + 0, + 42, + 128, + 12, + AlignLeft, + AlignCenter, + furi_string_get_cstr(dirname), + false); // This one to return and cursor select this file path_extract_filename_no_ext(furi_string_get_cstr(current->path), filename); @@ -74,9 +99,44 @@ void archive_scene_info_on_enter(void* context) { furi_string_free(filename); furi_string_free(dirname); - furi_string_free(str_size); + + // File size + FileInfo fileinfo; + bool is_dir = false; + if(storage_common_stat( + furi_record_open(RECORD_STORAGE), furi_string_get_cstr(current->path), &fileinfo) != + FSE_OK) { + snprintf(buf, sizeof(buf), "Size: \e#Error\e#"); + } else if(file_info_is_dir(&fileinfo)) { + is_dir = true; + snprintf(buf, sizeof(buf), "Size: ... \e#0\e# %s", units[0]); + + } else { + double show = fileinfo.size; + size_t unit; + for(unit = 0; unit < COUNT_OF(units); unit++) { + if(show < 1024) break; + show /= 1024; + } + snprintf( + buf, + sizeof(buf), + unit ? "Size: \e#%.2f\e# %s" : "Size: \e#%.0f\e# %s", + show, + units[unit]); + } + instance->element = widget_add_text_box_element( + instance->widget, 0, 24, 128, 24, AlignLeft, AlignCenter, buf, true); + furi_record_close(RECORD_STORAGE); view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget); + + if(is_dir) { + scene_manager_set_scene_state(instance->scene_manager, ArchiveAppSceneInfo, true); + instance->thread = furi_thread_alloc_ex( + "ArchiveDirWalk", 1024, (FuriThreadCallback)archive_scene_info_dirwalk, instance); + furi_thread_start(instance->thread); + } } bool archive_scene_info_on_event(void* context, SceneManagerEvent event) { @@ -94,5 +154,11 @@ void archive_scene_info_on_exit(void* context) { furi_assert(context); ArchiveApp* app = (ArchiveApp*)context; + scene_manager_set_scene_state(app->scene_manager, ArchiveAppSceneInfo, false); + if(app->thread) { + furi_thread_join(app->thread); + furi_thread_free(app->thread); + app->thread = NULL; + } widget_reset(app->widget); }