diff --git a/applications/main/archive/archive.c b/applications/main/archive/archive.c index bbe532c8c..93689a345 100644 --- a/applications/main/archive/archive.c +++ b/applications/main/archive/archive.c @@ -1,5 +1,4 @@ #include "archive_i.h" -#include "m-string.h" bool archive_custom_event_callback(void* context, uint32_t event) { furi_assert(context); @@ -17,6 +16,7 @@ ArchiveApp* archive_alloc() { ArchiveApp* archive = malloc(sizeof(ArchiveApp)); archive->gui = furi_record_open(RECORD_GUI); + archive->dialogs = furi_record_open(RECORD_DIALOGS); archive->text_input = text_input_alloc(); string_init(archive->fav_move_str); @@ -45,12 +45,21 @@ ArchiveApp* archive_alloc() { view_dispatcher_add_view( archive->view_dispatcher, ArchiveViewWidget, widget_get_view(archive->widget)); + // Loading + archive->loading = loading_alloc(); + view_dispatcher_add_view( + archive->view_dispatcher, ArchiveViewLoading, loading_get_view(archive->loading)); + return archive; } void archive_free(ArchiveApp* archive) { furi_assert(archive); + // Loading + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewLoading); + loading_free(archive->loading); + view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewBrowser); view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput); view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewWidget); @@ -62,12 +71,29 @@ void archive_free(ArchiveApp* archive) { text_input_free(archive->text_input); + furi_record_close(RECORD_DIALOGS); + archive->dialogs = NULL; + furi_record_close(RECORD_GUI); archive->gui = NULL; free(archive); } +void archive_show_loading_popup(void* context, bool show) { + ArchiveApp* instance = context; + TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME); + + if(show) { + // Raise timer priority so that animations can play + vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1); + view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewLoading); + } else { + // Restore default timer priority + vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY); + } +} + int32_t archive_app(void* p) { UNUSED(p); ArchiveApp* archive = archive_alloc(); diff --git a/applications/main/archive/archive_i.h b/applications/main/archive/archive_i.h index 865e837dc..3020b1753 100644 --- a/applications/main/archive/archive_i.h +++ b/applications/main/archive/archive_i.h @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include "views/archive_browser_view.h" @@ -18,6 +20,7 @@ typedef enum { ArchiveViewTextInput, ArchiveViewWidget, ArchiveViewTotal, + ArchiveViewLoading, } ArchiveViewEnum; struct ArchiveApp { @@ -27,8 +30,12 @@ struct ArchiveApp { ArchiveBrowserView* browser; TextInput* text_input; Widget* widget; + DialogsApp* dialogs; + Loading* loading; FuriPubSubSubscription* loader_stop_subscription; string_t fav_move_str; char text_store[MAX_NAME_LEN]; char file_extension[MAX_EXT_LEN + 1]; }; + +void archive_show_loading_popup(void* context, bool show); \ No newline at end of file diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index b08e58983..01a1c888c 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -377,6 +377,7 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { if(archive_is_item_in_array(model, model->item_idx)) { model->menu = true; model->menu_idx = 0; + menu_array_reset(model->context_menu); ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); selected->fav = archive_is_favorite("%s", string_get_cstr(selected->path)); diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index 9f8b4ee1b..e67fbb74d 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -109,3 +109,38 @@ void archive_delete_file(void* context, const char* format, ...) { string_clear(filename); } + +FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path) { + furi_assert(context); + + FURI_LOG_I(TAG, "Rename from %s to %s", src_path, dst_path); + + ArchiveBrowserView* browser = context; + Storage* fs_api = furi_record_open(RECORD_STORAGE); + + FileInfo fileinfo; + storage_common_stat(fs_api, src_path, &fileinfo); + + FS_Error error = FSE_OK; + + if(!path_contains_only_ascii(dst_path)) { + error = FSE_INVALID_NAME; + } else { + error = storage_common_rename(fs_api, src_path, dst_path); + } + furi_record_close(RECORD_STORAGE); + + if(archive_is_favorite("%s", src_path)) { + archive_favorites_rename(src_path, dst_path); + } + + if(error == FSE_OK) { + FURI_LOG_I(TAG, "Rename from %s to %s is DONE", src_path, dst_path); + archive_refresh_dir(browser); + } else { + const char* error_msg = filesystem_api_error_get_desc(error); + FURI_LOG_E(TAG, "Rename failed: %s, Code: %d", error_msg, error); + } + + return error; +} diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index 84b7e24a6..d4df327a9 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -3,6 +3,7 @@ #include #include #include +#include "toolbox/path.h" typedef enum { ArchiveFileTypeIButton, @@ -62,3 +63,4 @@ void archive_set_file_type(ArchiveFile_t* file, const char* path, bool is_folder bool archive_get_items(void* context, const char* path); void archive_file_append(const char* path, const char* format, ...); void archive_delete_file(void* context, const char* format, ...); +FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path); diff --git a/applications/main/archive/helpers/archive_menu.h b/applications/main/archive/helpers/archive_menu.h new file mode 100644 index 000000000..5df6a1ca2 --- /dev/null +++ b/applications/main/archive/helpers/archive_menu.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +typedef struct { + string_t text; + uint32_t event; +} ArchiveContextMenuItem_t; + +static void ArchiveContextMenuItem_t_init(ArchiveContextMenuItem_t* obj) { + string_init(obj->text); + obj->event = 0; // ArchiveBrowserEventFileMenuNone +} + +static void ArchiveContextMenuItem_t_init_set( + ArchiveContextMenuItem_t* obj, + const ArchiveContextMenuItem_t* src) { + string_init_set(obj->text, src->text); + obj->event = src->event; +} + +static void ArchiveContextMenuItem_t_set( + ArchiveContextMenuItem_t* obj, + const ArchiveContextMenuItem_t* src) { + string_init_set(obj->text, src->text); + obj->event = src->event; +} + +static void ArchiveContextMenuItem_t_clear(ArchiveContextMenuItem_t* obj) { + string_clear(obj->text); +} + +ARRAY_DEF( + menu_array, + ArchiveContextMenuItem_t, + (INIT(API_2(ArchiveContextMenuItem_t_init)), + SET(API_6(ArchiveContextMenuItem_t_set)), + INIT_SET(API_6(ArchiveContextMenuItem_t_init_set)), + CLEAR(API_2(ArchiveContextMenuItem_t_clear)))) + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-function" +// Using in applications/archive/views/archive_browser_view.c +static void archive_menu_add_item( + ArchiveContextMenuItem_t* obj, + string_t text, + uint32_t event) { + string_init_move(obj->text, text); + obj->event = event; +} +#pragma GCC diagnostic pop \ No newline at end of file diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index e22ac792f..06e86941e 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -132,7 +132,9 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { case ArchiveBrowserEventFileMenuRename: if(favorites) { browser->callback(ArchiveBrowserEventEnterFavMove, browser->context); - } else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) { + //} else if((archive_is_known_app(selected->type)) && (selected->is_app == false)) { + } else { + // Added ability to rename files and folders archive_show_file_menu(browser, false); scene_manager_set_scene_state( archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); @@ -140,6 +142,10 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { } consumed = true; break; + case ArchiveBrowserEventFileMenuInfo: + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneInfo); + consumed = true; + break; case ArchiveBrowserEventFileMenuDelete: if(archive_get_tab(browser) != ArchiveTabFavorites) { scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete); diff --git a/applications/main/archive/scenes/archive_scene_config.h b/applications/main/archive/scenes/archive_scene_config.h index 4145f43da..6dda7a20d 100644 --- a/applications/main/archive/scenes/archive_scene_config.h +++ b/applications/main/archive/scenes/archive_scene_config.h @@ -1,3 +1,4 @@ ADD_SCENE(archive, browser, Browser) ADD_SCENE(archive, rename, Rename) ADD_SCENE(archive, delete, Delete) +ADD_SCENE(archive, info, Info) diff --git a/applications/main/archive/scenes/archive_scene_delete.c b/applications/main/archive/scenes/archive_scene_delete.c index d882fd066..cca84fea3 100644 --- a/applications/main/archive/scenes/archive_scene_delete.c +++ b/applications/main/archive/scenes/archive_scene_delete.c @@ -1,10 +1,6 @@ #include "../archive_i.h" -#include "../helpers/archive_favorites.h" -#include "../helpers/archive_files.h" #include "../helpers/archive_apps.h" #include "../helpers/archive_browser.h" -#include "toolbox/path.h" -#include "m-string.h" #define SCENE_DELETE_CUSTOM_EVENT (0UL) #define MAX_TEXT_INPUT_LEN 22 diff --git a/applications/main/archive/scenes/archive_scene_info.c b/applications/main/archive/scenes/archive_scene_info.c new file mode 100644 index 000000000..a69274802 --- /dev/null +++ b/applications/main/archive/scenes/archive_scene_info.c @@ -0,0 +1,78 @@ +#include "../archive_i.h" +#include "../helpers/archive_browser.h" + +#define TAG "Archive" + +void archive_scene_info_widget_callback(GuiButtonType result, InputType type, void* context) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + if(type == InputTypeShort) { + view_dispatcher_send_custom_event(app->view_dispatcher, result); + } +} + +void archive_scene_info_on_enter(void* context) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + + widget_add_button_element( + app->widget, GuiButtonTypeLeft, "Back", archive_scene_info_widget_callback, app); + + string_t filename; + string_t dirname; + string_t str_size; + string_init(filename); + string_init(dirname); + string_init(str_size); + + ArchiveFile_t* current = archive_get_current_file(app->browser); + char file_info_message[128]; + Storage* fs_api = furi_record_open(RECORD_STORAGE); + + // Filename + path_extract_filename(current->path, filename, false); + snprintf(file_info_message, sizeof(file_info_message), "\e#%s\e#", string_get_cstr(filename)); + widget_add_text_box_element( + app->widget, 0, 0, 128, 20, AlignLeft, AlignCenter, file_info_message, false); + + // File size + FileInfo fileinfo; + storage_common_stat(fs_api, string_get_cstr(current->path), &fileinfo); + string_printf(str_size, "%d", fileinfo.size / 1024); + snprintf( + file_info_message, + sizeof(file_info_message), + "Size: \e#%s\e# Kb.", + string_get_cstr(str_size)); + widget_add_text_box_element( + app->widget, 0, 23, 128, 20, AlignLeft, AlignCenter, file_info_message, false); + + // Directory path + path_extract_dirname(string_get_cstr(current->path), dirname); + string_replace_str(dirname, STORAGE_ANY_PATH_PREFIX, ""); + widget_add_text_box_element( + app->widget, 0, 23, 128, 20, AlignLeft, AlignCenter, string_get_cstr(dirname), false); + + string_clear(filename); + string_clear(dirname); + string_clear(str_size); + + view_dispatcher_switch_to_view(app->view_dispatcher, ArchiveViewWidget); +} + +bool archive_scene_info_on_event(void* context, SceneManagerEvent event) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + + if(event.type == SceneManagerEventTypeCustom) { + return scene_manager_previous_scene(app->scene_manager); + } + return false; +} + +void archive_scene_info_on_exit(void* context) { + furi_assert(context); + ArchiveApp* app = (ArchiveApp*)context; + + widget_reset(app->widget); +} diff --git a/applications/main/archive/scenes/archive_scene_rename.c b/applications/main/archive/scenes/archive_scene_rename.c index 293fa89af..6e4a65ec4 100644 --- a/applications/main/archive/scenes/archive_scene_rename.c +++ b/applications/main/archive/scenes/archive_scene_rename.c @@ -4,6 +4,9 @@ #include "../helpers/archive_browser.h" #include "archive/views/archive_browser_view.h" #include "toolbox/path.h" +#include + +#define TAG "Archive" #define SCENE_RENAME_CUSTOM_EVENT (0UL) #define MAX_TEXT_INPUT_LEN 22 @@ -19,14 +22,24 @@ void archive_scene_rename_on_enter(void* context) { TextInput* text_input = archive->text_input; ArchiveFile_t* current = archive_get_current_file(archive->browser); - string_t filename; - string_init(filename); - path_extract_filename(current->path, filename, true); - strlcpy(archive->text_store, string_get_cstr(filename), MAX_NAME_LEN); + string_t path_name; + string_init(path_name); - path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN); + if(current->type == ArchiveFileTypeFolder) { + path_extract_basename(string_get_cstr(current->path), path_name); + strlcpy(archive->text_store, string_get_cstr(path_name), MAX_NAME_LEN); + text_input_set_header_text(text_input, "Rename directory:"); + } else /*if(current->type != ArchiveFileTypeUnknown) */ { + path_extract_filename(current->path, path_name, true); + strlcpy(archive->text_store, string_get_cstr(path_name), MAX_NAME_LEN); - text_input_set_header_text(text_input, "Rename:"); + path_extract_extension(current->path, archive->file_extension, MAX_EXT_LEN); + text_input_set_header_text(text_input, "Rename file:"); + } /*else { + path_extract_filename(current->path, path_name, false); + strlcpy(archive->text_store, string_get_cstr(path_name), MAX_NAME_LEN); + text_input_set_header_text(text_input, "Rename unknown file:"); + }*/ text_input_set_result_callback( text_input, @@ -36,11 +49,7 @@ void archive_scene_rename_on_enter(void* context) { MAX_TEXT_INPUT_LEN, false); - ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( - string_get_cstr(archive->browser->path), archive->file_extension, ""); - text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); - - string_clear(filename); + string_clear(path_name); view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); } @@ -51,26 +60,43 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { if(event.event == SCENE_RENAME_CUSTOM_EVENT) { - Storage* fs_api = furi_record_open(RECORD_STORAGE); - const char* path_src = archive_get_name(archive->browser); ArchiveFile_t* file = archive_get_current_file(archive->browser); string_t path_dst; string_init(path_dst); - path_extract_dirname(path_src, path_dst); - string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]); - storage_common_rename(fs_api, path_src, string_get_cstr(path_dst)); - furi_record_close(RECORD_STORAGE); - - if(file->fav) { - archive_favorites_rename(path_src, string_get_cstr(path_dst)); + if(file->type == ArchiveFileTypeFolder) { + // Rename folder/dir + path_extract_dirname(path_src, path_dst); + string_cat_printf(path_dst, "/%s", archive->text_store); + } else if(file->type != ArchiveFileTypeUnknown) { + // Rename known type + path_extract_dirname(path_src, path_dst); + string_cat_printf(path_dst, "/%s%s", archive->text_store, known_ext[file->type]); + } else { + // Rename unknown type + path_extract_dirname(path_src, path_dst); + string_cat_printf(path_dst, "/%s%s", archive->text_store, archive->file_extension); } + // Long time process if this is directory + archive_show_loading_popup(archive, true); + FS_Error error = + archive_rename_file_or_dir(archive->browser, path_src, string_get_cstr(path_dst)); + archive_show_loading_popup(archive, false); + archive_show_file_menu(archive->browser, false); string_clear(path_dst); - scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser); + if(error != FSE_OK) { + string_t dialog_msg; + string_init(dialog_msg); + string_cat_printf(dialog_msg, "Cannot rename\nCode: %d", error); + dialog_message_show_storage_error(archive->dialogs, string_get_cstr(dialog_msg)); + string_clear(dialog_msg); + } else { + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser); + } consumed = true; } } diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index ddd6637db..d2720da12 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -5,6 +5,8 @@ #include "archive_browser_view.h" #include "../helpers/archive_browser.h" +#define TAG "Archive" + static const char* ArchiveTabNames[] = { [ArchiveTabFavorites] = "Favorites", [ArchiveTabIButton] = "iButton", @@ -42,43 +44,141 @@ void archive_browser_set_callback( } static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { - canvas_set_color(canvas, ColorWhite); - canvas_draw_box(canvas, 71, 17, 57, 46); - canvas_set_color(canvas, ColorBlack); - elements_slightly_rounded_frame(canvas, 70, 16, 58, 48); + if(menu_array_size(model->context_menu) == 0) { + // Context menu is empty, init array + string_t item_run; + string_t item_pin; + string_t item_info; + string_t item_rename; + string_t item_delete; - string_t menu[MENU_ITEMS]; + string_init_set_str(item_run, "Run In App"); + string_init_set_str(item_pin, "Pin"); + string_init_set_str(item_info, "Info"); + string_init_set_str(item_rename, "Rename"); + string_init_set_str(item_delete, "Delete"); - string_init_set_str(menu[0], "Run in app"); - string_init_set_str(menu[1], "Pin"); - string_init_set_str(menu[2], "Rename"); - string_init_set_str(menu[3], "Delete"); + // Need init context menu + ArchiveFile_t* selected = + files_array_get(model->files, model->item_idx - model->array_offset); - ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); - - if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) { - string_set_str(menu[1], "Unpin"); - } - - if(!archive_is_known_app(selected->type)) { - string_set_str(menu[0], "---"); - string_set_str(menu[1], "---"); - string_set_str(menu[2], "---"); - } else { - if(model->tab_idx == ArchiveTabFavorites) { - string_set_str(menu[2], "Move"); - string_set_str(menu[3], "---"); - } else if(selected->is_app) { - string_set_str(menu[2], "---"); + if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) { + string_set_str(item_pin, "Unpin"); } + + if (selected->type == ArchiveFileTypeFolder) { + FURI_LOG_D(TAG, "Directory type"); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_rename, + ArchiveBrowserEventFileMenuRename); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_delete, + ArchiveBrowserEventFileMenuDelete); + } else if(!archive_is_known_app(selected->type)) { + FURI_LOG_D(TAG, "Unknown type"); + + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_info, + ArchiveBrowserEventFileMenuInfo); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_rename, + ArchiveBrowserEventFileMenuRename); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_delete, + ArchiveBrowserEventFileMenuDelete); + } else if(model->tab_idx == ArchiveTabFavorites) { + FURI_LOG_D(TAG, "ArchiveTabFavorites"); + + string_set_str(item_rename, "Move"); + + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_run, + ArchiveBrowserEventFileMenuRun); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_pin, + ArchiveBrowserEventFileMenuPin); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_rename, + ArchiveBrowserEventFileMenuRename); + } else if(selected->is_app) { + FURI_LOG_D(TAG, "3 types"); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_run, + ArchiveBrowserEventFileMenuRun); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_info, + ArchiveBrowserEventFileMenuInfo); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_pin, + ArchiveBrowserEventFileMenuPin); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_delete, + ArchiveBrowserEventFileMenuDelete); + } else { + FURI_LOG_D(TAG, "All menu"); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_run, + ArchiveBrowserEventFileMenuRun); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_pin, + ArchiveBrowserEventFileMenuPin); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_rename, + ArchiveBrowserEventFileMenuRename); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_delete, + ArchiveBrowserEventFileMenuDelete); + } + + string_clear(item_run); + string_clear(item_pin); + string_clear(item_info); + string_clear(item_rename); + string_clear(item_delete); + } else { + FURI_LOG_D( + TAG, + "menu_array_size already set: %d", + menu_array_size(model->context_menu)); + } + size_t size_menu = menu_array_size(model->context_menu); + const uint8_t menu_height = 44; + const uint8_t line_height = 11; + + canvas_set_color(canvas, ColorWhite); + uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu) * line_height); + canvas_draw_box(canvas, 71, 17, 57, calc_height + 2); + canvas_set_color(canvas, ColorBlack); + elements_slightly_rounded_frame(canvas, 70, 16, 58, calc_height + 4); + + FURI_LOG_D( + TAG, + "size_menu: %d, calc_height: %d, menu_idx: %d", + size_menu, + calc_height, + model->menu_idx); + for(size_t i = 0; i < size_menu; i++) { + ArchiveContextMenuItem_t* current = menu_array_get(model->context_menu, i); + canvas_draw_str(canvas, 82, 27 + i * line_height, string_get_cstr(current->text)); } - for(size_t i = 0; i < MENU_ITEMS; i++) { - canvas_draw_str(canvas, 82, 27 + i * 11, string_get_cstr(menu[i])); - string_clear(menu[i]); - } - - canvas_draw_icon(canvas, 74, 20 + model->menu_idx * 11, &I_ButtonRight_4x7); + canvas_draw_icon(canvas, 74, 20 + model->menu_idx * line_height, &I_ButtonRight_4x7); } static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, bool moving) { @@ -250,32 +350,33 @@ static bool archive_view_input(InputEvent* event, void* context) { }); if(in_menu) { - if(event->type == InputTypeShort) { - if(event->key == InputKeyUp || event->key == InputKeyDown) { - with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - if(event->key == InputKeyUp) { - model->menu_idx = ((model->menu_idx - 1) + MENU_ITEMS) % MENU_ITEMS; - } else if(event->key == InputKeyDown) { - model->menu_idx = (model->menu_idx + 1) % MENU_ITEMS; - } - return true; - }); - } - - if(event->key == InputKeyOk) { - uint8_t idx; - with_view_model( - browser->view, (ArchiveBrowserViewModel * model) { - idx = model->menu_idx; - return false; - }); - browser->callback(file_menu_actions[idx], browser->context); - } else if(event->key == InputKeyBack) { - browser->callback(ArchiveBrowserEventFileMenuClose, browser->context); - } + if(event->type != InputTypeShort) { + return true; // RETURN + } + if(event->key == InputKeyUp || event->key == InputKeyDown) { + with_view_model( + browser->view, (ArchiveBrowserViewModel * model) { + size_t size_menu = menu_array_size(model->context_menu); + if(event->key == InputKeyUp) { + model->menu_idx = ((model->menu_idx - 1) + size_menu) % size_menu; + } else if(event->key == InputKeyDown) { + model->menu_idx = (model->menu_idx + 1) % size_menu; + } + return true; + }); + } else if(event->key == InputKeyOk) { + uint32_t idx; + with_view_model( + browser->view, (ArchiveBrowserViewModel * model) { + ArchiveContextMenuItem_t* current = + menu_array_get(model->context_menu, model->menu_idx); + idx = current->event; + return false; + }); + browser->callback(idx, browser->context); + } else if(event->key == InputKeyBack) { + browser->callback(ArchiveBrowserEventFileMenuClose, browser->context); } - } else { if(event->type == InputTypeShort) { if(event->key == InputKeyLeft || event->key == InputKeyRight) { @@ -366,6 +467,7 @@ ArchiveBrowserView* browser_alloc() { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_init(model->files); + menu_array_init(model->context_menu); model->tab_idx = TAB_DEFAULT; return true; }); @@ -383,6 +485,7 @@ void browser_free(ArchiveBrowserView* browser) { with_view_model( browser->view, (ArchiveBrowserViewModel * model) { files_array_clear(model->files); + menu_array_clear(model->context_menu); return false; }); @@ -390,4 +493,4 @@ void browser_free(ArchiveBrowserView* browser) { view_free(browser->view); free(browser); -} +} \ No newline at end of file diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 5c649c389..838d2505d 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -7,6 +7,7 @@ #include #include #include "../helpers/archive_files.h" +#include "../helpers/archive_menu.h" #include "../helpers/archive_favorites.h" #include "gui/modules/file_browser_worker.h" @@ -31,12 +32,14 @@ typedef enum { } ArchiveTabEnum; typedef enum { + ArchiveBrowserEventFileMenuNone, ArchiveBrowserEventFileMenuOpen, - ArchiveBrowserEventFileMenuClose, ArchiveBrowserEventFileMenuRun, ArchiveBrowserEventFileMenuPin, ArchiveBrowserEventFileMenuRename, ArchiveBrowserEventFileMenuDelete, + ArchiveBrowserEventFileMenuInfo, + ArchiveBrowserEventFileMenuClose, ArchiveBrowserEventEnterDir, @@ -54,13 +57,6 @@ typedef enum { ArchiveBrowserEventExit, } ArchiveBrowserEvent; -static const uint8_t file_menu_actions[MENU_ITEMS] = { - [0] = ArchiveBrowserEventFileMenuRun, - [1] = ArchiveBrowserEventFileMenuPin, - [2] = ArchiveBrowserEventFileMenuRename, - [3] = ArchiveBrowserEventFileMenuDelete, -}; - typedef struct ArchiveBrowserView ArchiveBrowserView; typedef void (*ArchiveBrowserViewCallback)(ArchiveBrowserEvent event, void* context); @@ -88,6 +84,8 @@ typedef struct { uint8_t menu_idx; bool menu; + menu_array_t context_menu; + bool move_fav; bool list_loading; bool folder_loading; @@ -106,4 +104,5 @@ void archive_browser_set_callback( View* archive_browser_get_view(ArchiveBrowserView* browser); ArchiveBrowserView* browser_alloc(); + void browser_free(ArchiveBrowserView* browser);