From 405a6f76db56f6a785dc24152b16f8002147cea4 Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Mon, 22 May 2023 14:10:12 +0100 Subject: [PATCH] Archive go brrr --- .../main/archive/helpers/archive_browser.c | 17 +- .../main/archive/helpers/archive_browser.h | 2 +- .../main/archive/helpers/archive_files.c | 54 +++- .../main/archive/helpers/archive_files.h | 7 +- .../archive/scenes/archive_scene_browser.c | 147 +++++++-- .../archive/scenes/archive_scene_config.h | 1 + .../archive/scenes/archive_scene_delete.c | 1 - .../archive/scenes/archive_scene_new_dir.c | 83 +++++ .../archive/scenes/archive_scene_rename.c | 5 +- .../main/archive/views/archive_browser_view.c | 298 ++++++++++-------- .../main/archive/views/archive_browser_view.h | 8 + 11 files changed, 449 insertions(+), 174 deletions(-) create mode 100644 applications/main/archive/scenes/archive_scene_new_dir.c diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index bca558fde..15c9d97f4 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -353,7 +353,13 @@ void archive_set_tab(ArchiveBrowserView* browser, ArchiveTabEnum tab) { furi_assert(browser); with_view_model( - browser->view, ArchiveBrowserViewModel * model, { model->tab_idx = tab; }, false); + browser->view, + ArchiveBrowserViewModel * model, + { + model->tab_idx = tab; + model->clipboard = NULL; + }, + false); } void archive_add_app_item(ArchiveBrowserView* browser, const char* name) { @@ -410,17 +416,18 @@ void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const ch ArchiveFile_t_clear(&item); } -void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { +void archive_show_file_menu(ArchiveBrowserView* browser, bool show, bool manage) { furi_assert(browser); with_view_model( browser->view, ArchiveBrowserViewModel * model, { if(show) { + model->menu = true; + model->menu_manage = manage; + model->menu_idx = 0; + menu_array_reset(model->context_menu); 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 = diff --git a/applications/main/archive/helpers/archive_browser.h b/applications/main/archive/helpers/archive_browser.h index a96fa9679..ec3ef00ce 100644 --- a/applications/main/archive/helpers/archive_browser.h +++ b/applications/main/archive/helpers/archive_browser.h @@ -85,7 +85,7 @@ const char* archive_get_name(ArchiveBrowserView* browser); void archive_add_app_item(ArchiveBrowserView* browser, const char* name); void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const char* name); -void archive_show_file_menu(ArchiveBrowserView* browser, bool show); +void archive_show_file_menu(ArchiveBrowserView* browser, bool show, bool manage); void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active); void archive_switch_tab(ArchiveBrowserView* browser, InputKey key); diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index cf78c72ef..89abf7355 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -115,13 +115,20 @@ void archive_delete_file(void* context, const char* format, ...) { furi_string_free(filename); } -FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path) { +FS_Error archive_copy_move_file_or_dir( + void* context, + const char* src_path, + const char* dst_path, + bool copy, + bool find_name) { furi_assert(context); - FURI_LOG_I(TAG, "Rename from %s to %s", src_path, dst_path); + FURI_LOG_I(TAG, "%s from %s to %s", copy ? "Copy" : "Move", src_path, dst_path); ArchiveBrowserView* browser = context; Storage* fs_api = furi_record_open(RECORD_STORAGE); + FuriString* dst_str = furi_string_alloc_set(dst_path); + dst_path = furi_string_get_cstr(dst_str); FileInfo fileinfo; storage_common_stat(fs_api, src_path, &fileinfo); @@ -130,22 +137,57 @@ FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const c if(!path_contains_only_ascii(dst_path)) { error = FSE_INVALID_NAME; + } else if(!copy && !strcmp(src_path, dst_path)) { + error = FSE_EXIST; } else { - error = storage_common_rename(fs_api, src_path, dst_path); + if(find_name && storage_common_exists(fs_api, dst_path)) { + FuriString* dir_path = furi_string_alloc(); + FuriString* filename = furi_string_alloc(); + char extension[MAX_EXT_LEN] = {0}; + + path_extract_filename(dst_str, filename, true); + path_extract_dirname(furi_string_get_cstr(dst_str), dir_path); + path_extract_extension(dst_str, extension, MAX_EXT_LEN); + + storage_get_next_filename( + fs_api, + furi_string_get_cstr(dir_path), + furi_string_get_cstr(filename), + extension, + dst_str, + 255); + furi_string_cat_printf(dir_path, "/%s%s", furi_string_get_cstr(dst_str), extension); + furi_string_set(dst_str, dir_path); + + furi_string_free(dir_path); + furi_string_free(filename); + } + + if(copy) { + error = storage_common_copy(fs_api, src_path, dst_path); + } else { + error = storage_common_rename(fs_api, src_path, dst_path); + } } furi_record_close(RECORD_STORAGE); - if(archive_is_favorite("%s", src_path)) { + if(!copy && 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); + FURI_LOG_I(TAG, "%s from %s to %s is DONE", copy ? "Copy" : "Move", src_path, dst_path); archive_refresh_dir(browser); } else { FURI_LOG_E( - TAG, "Rename failed: %s, Code: %d", filesystem_api_error_get_desc(error), error); + TAG, + "%s failed: %s, Code: %d", + copy ? "Copy" : "Move", + filesystem_api_error_get_desc(error), + error); } + furi_string_free(dst_str); + return error; } diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index 7680bbd57..984823382 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -117,4 +117,9 @@ void archive_file_append(const char* path, const char* format, ...) _ATTRIBUTE((__format__(__printf__, 2, 3))); void archive_delete_file(void* context, const char* format, ...) _ATTRIBUTE((__format__(__printf__, 2, 3))); -FS_Error archive_rename_file_or_dir(void* context, const char* src_path, const char* dst_path); +FS_Error archive_copy_move_file_or_dir( + void* context, + const char* src_path, + const char* dst_path, + bool copy, + bool find_name); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index f0884ab73..4170c1fd8 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -107,22 +107,27 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { if(event.type == SceneManagerEventTypeCustom) { switch(event.event) { case ArchiveBrowserEventFileMenuOpen: - archive_show_file_menu(browser, true); + archive_show_file_menu(browser, true, false); + consumed = true; + break; + case ArchiveBrowserEventManageMenuOpen: + if(!favorites) { + archive_show_file_menu(browser, true, true); + } consumed = true; break; case ArchiveBrowserEventFileMenuClose: - archive_show_file_menu(browser, false); + archive_show_file_menu(browser, false, false); consumed = true; break; case ArchiveBrowserEventFileMenuRun: if(selected->type == ArchiveFileTypeFolder) { archive_switch_tab(browser, TAB_LEFT); - archive_show_file_menu(browser, false); archive_enter_dir(browser, selected->path); } else if(archive_is_known_app(selected->type)) { archive_run_in_app(browser, selected, favorites); - archive_show_file_menu(browser, false); } + archive_show_file_menu(browser, false, false); consumed = true; break; case ArchiveBrowserEventFileMenuPin: { @@ -130,47 +135,142 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { if(favorites) { archive_favorites_delete("%s", name); archive_file_array_rm_selected(browser); - archive_show_file_menu(browser, false); } else if(archive_is_known_app(selected->type)) { if(archive_is_favorite("%s", name)) { archive_favorites_delete("%s", name); } else { archive_file_append(ARCHIVE_FAV_PATH, "%s\n", name); } - archive_show_file_menu(browser, false); } + archive_show_file_menu(browser, false, false); consumed = true; } break; - + case ArchiveBrowserEventFileMenuInfo: + archive_show_file_menu(browser, false, false); + scene_manager_set_scene_state( + archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneInfo); + consumed = true; + break; + case ArchiveBrowserEventFileMenuShow: + archive_show_file_menu(browser, false, false); + scene_manager_set_scene_state( + archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneShow); + consumed = true; + break; + case ArchiveBrowserEventFileMenuCut: + archive_show_file_menu(browser, false, false); + if(!favorites) { + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { + if(model->clipboard == NULL) { + model->clipboard = strdup(furi_string_get_cstr(selected->path)); + model->clipboard_copy = false; + } + }, + false); + } + consumed = true; + break; + case ArchiveBrowserEventFileMenuCopy: + archive_show_file_menu(browser, false, false); + if(!favorites) { + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { + if(model->clipboard == NULL) { + model->clipboard = strdup(furi_string_get_cstr(selected->path)); + model->clipboard_copy = true; + } + }, + false); + } + consumed = true; + break; + case ArchiveBrowserEventFileMenuPaste: + archive_show_file_menu(browser, false, false); + if(!favorites) { + FuriString* path_src = NULL; + FuriString* path_dst = NULL; + bool copy; + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { + if(model->clipboard != NULL) { + path_src = furi_string_alloc_set(model->clipboard); + path_dst = furi_string_alloc(); + FuriString* base = furi_string_alloc(); + path_extract_basename(model->clipboard, base); + path_concat( + furi_string_get_cstr(browser->path), + furi_string_get_cstr(base), + path_dst); + furi_string_free(base); + copy = model->clipboard_copy; + free(model->clipboard); + model->clipboard = NULL; + } + }, + false); + if(path_src && path_dst) { + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewStack); + archive_show_loading_popup(archive, true); + FS_Error error = archive_copy_move_file_or_dir( + archive->browser, + furi_string_get_cstr(path_src), + furi_string_get_cstr(path_dst), + copy, + true); + archive_show_loading_popup(archive, false); + furi_string_free(path_src); + furi_string_free(path_dst); + if(error != FSE_OK) { + FuriString* dialog_msg; + dialog_msg = furi_string_alloc(); + furi_string_cat_printf( + dialog_msg, + "Cannot %s:\n%s", + copy ? "copy" : "move", + storage_error_get_desc(error)); + dialog_message_show_storage_error( + archive->dialogs, furi_string_get_cstr(dialog_msg)); + furi_string_free(dialog_msg); + } + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewBrowser); + } + } + consumed = true; + break; + case ArchiveBrowserEventFileMenuNewDir: + archive_show_file_menu(browser, false, false); + if(!favorites) { + scene_manager_set_scene_state( + archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); + scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneNewDir); + } + consumed = true; + break; case ArchiveBrowserEventFileMenuRename: + archive_show_file_menu(browser, false, false); if(favorites) { browser->callback(ArchiveBrowserEventEnterFavMove, browser->context); //} 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); scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneRename); } consumed = true; break; - case ArchiveBrowserEventFileMenuInfo: - archive_show_file_menu(browser, false); - scene_manager_set_scene_state( - archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_DEFAULT); - scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneInfo); - consumed = true; - break; - case ArchiveBrowserEventFileMenuShow: - archive_show_file_menu(browser, false); - scene_manager_set_scene_state( - archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_DEFAULT); - scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneShow); - consumed = true; - break; case ArchiveBrowserEventFileMenuDelete: - if(archive_get_tab(browser) != ArchiveTabFavorites) { + archive_show_file_menu(browser, false, false); + if(!favorites) { scene_manager_set_scene_state( archive->scene_manager, ArchiveAppSceneBrowser, SCENE_STATE_NEED_REFRESH); scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete); @@ -191,7 +291,6 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { break; case ArchiveBrowserEventEnterFavMove: furi_string_set(archive->fav_move_str, selected->path); - archive_show_file_menu(browser, false); archive_favorites_move_mode(archive->browser, true); consumed = true; break; diff --git a/applications/main/archive/scenes/archive_scene_config.h b/applications/main/archive/scenes/archive_scene_config.h index d16c6f1a6..63631c65c 100644 --- a/applications/main/archive/scenes/archive_scene_config.h +++ b/applications/main/archive/scenes/archive_scene_config.h @@ -1,4 +1,5 @@ ADD_SCENE(archive, browser, Browser) +ADD_SCENE(archive, new_dir, NewDir) 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 c2f2ddad5..4a84e1c38 100644 --- a/applications/main/archive/scenes/archive_scene_delete.c +++ b/applications/main/archive/scenes/archive_scene_delete.c @@ -58,7 +58,6 @@ bool archive_scene_delete_on_event(void* context, SceneManagerEvent event) { archive_delete_file(browser, "%s", name); } archive_show_loading_popup(app, false); - archive_show_file_menu(browser, false); return scene_manager_previous_scene(app->scene_manager); } else if(event.event == GuiButtonTypeLeft) { return scene_manager_previous_scene(app->scene_manager); diff --git a/applications/main/archive/scenes/archive_scene_new_dir.c b/applications/main/archive/scenes/archive_scene_new_dir.c new file mode 100644 index 000000000..4d64d0ee9 --- /dev/null +++ b/applications/main/archive/scenes/archive_scene_new_dir.c @@ -0,0 +1,83 @@ +#include "../archive_i.h" +#include "../helpers/archive_favorites.h" +#include "../helpers/archive_files.h" +#include "../helpers/archive_browser.h" +#include "archive/views/archive_browser_view.h" +#include "toolbox/path.h" +#include + +#define TAG "Archive" + +#define SCENE_NEW_DIR_CUSTOM_EVENT (0UL) +#define MAX_TEXT_INPUT_LEN 22 + +void archive_scene_new_dir_text_input_callback(void* context) { + ArchiveApp* archive = (ArchiveApp*)context; + view_dispatcher_send_custom_event(archive->view_dispatcher, SCENE_NEW_DIR_CUSTOM_EVENT); +} + +void archive_scene_new_dir_on_enter(void* context) { + ArchiveApp* archive = context; + + TextInput* text_input = archive->text_input; + + archive->text_store[0] = '\0'; + text_input_set_header_text(text_input, "New directory:"); + + text_input_set_result_callback( + text_input, + archive_scene_new_dir_text_input_callback, + context, + archive->text_store, + MAX_TEXT_INPUT_LEN, + false); + + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewTextInput); +} + +bool archive_scene_new_dir_on_event(void* context, SceneManagerEvent event) { + ArchiveApp* archive = context; + bool consumed = false; + + if(event.type == SceneManagerEventTypeCustom) { + if(event.event == SCENE_NEW_DIR_CUSTOM_EVENT) { + FuriString* path_dst = furi_string_alloc(); + + path_concat( + furi_string_get_cstr(archive->browser->path), archive->text_store, path_dst); + + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewStack); + archive_show_loading_popup(archive, true); + FS_Error error; + if(!path_contains_only_ascii(furi_string_get_cstr(path_dst))) { + error = FSE_INVALID_NAME; + } else { + Storage* fs_api = furi_record_open(RECORD_STORAGE); + error = storage_common_mkdir(fs_api, furi_string_get_cstr(path_dst)); + furi_record_close(RECORD_STORAGE); + } + archive_refresh_dir(archive->browser); + archive_show_loading_popup(archive, false); + + furi_string_free(path_dst); + + if(error != FSE_OK) { + FuriString* dialog_msg; + dialog_msg = furi_string_alloc(); + furi_string_cat_printf( + dialog_msg, "Cannot mkdir:\n%s", storage_error_get_desc(error)); + dialog_message_show_storage_error( + archive->dialogs, furi_string_get_cstr(dialog_msg)); + furi_string_free(dialog_msg); + } + scene_manager_previous_scene(archive->scene_manager); + consumed = true; + } + } + return consumed; +} + +void archive_scene_new_dir_on_exit(void* context) { + ArchiveApp* archive = context; + text_input_reset(archive->text_input); +} diff --git a/applications/main/archive/scenes/archive_scene_rename.c b/applications/main/archive/scenes/archive_scene_rename.c index 81e806a30..f06339263 100644 --- a/applications/main/archive/scenes/archive_scene_rename.c +++ b/applications/main/archive/scenes/archive_scene_rename.c @@ -85,10 +85,9 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) { // Long time process if this is directory view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewStack); archive_show_loading_popup(archive, true); - FS_Error error = archive_rename_file_or_dir( - archive->browser, path_src, furi_string_get_cstr(path_dst)); + FS_Error error = archive_copy_move_file_or_dir( + archive->browser, path_src, furi_string_get_cstr(path_dst), false, false); archive_show_loading_popup(archive, false); - archive_show_file_menu(archive->browser, false); furi_string_free(path_dst); diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 6e42cb40b..d4a52ba9e 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -50,140 +50,154 @@ void archive_browser_set_callback( static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { if(menu_array_size(model->context_menu) == 0) { - // Context menu is empty, init array - FuriString* item_run = furi_string_alloc_set("Run In App"); - FuriString* item_pin = furi_string_alloc_set("Pin"); - FuriString* item_info = furi_string_alloc_set("Info"); - FuriString* item_show = furi_string_alloc_set("Show"); - FuriString* item_rename = furi_string_alloc_set("Rename"); - FuriString* item_delete = furi_string_alloc_set("Delete"); - // Need init context menu ArchiveFile_t* selected = - files_array_get(model->files, model->item_idx - model->array_offset); + archive_is_item_in_array(model, model->item_idx) ? + files_array_get(model->files, model->item_idx - model->array_offset) : + NULL; + bool favorites = model->tab_idx == ArchiveTabFavorites; - if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) { - furi_string_set(item_pin, "Unpin"); + if(model->menu_manage && !favorites) { + FuriString* item_cut = furi_string_alloc_set("Cut"); + FuriString* item_copy = furi_string_alloc_set("Copy"); + FuriString* item_paste = furi_string_alloc_set("Paste"); + FuriString* item_new_dir = furi_string_alloc_set("New Dir"); + FuriString* item_rename = furi_string_alloc_set("Rename"); + FuriString* item_delete = furi_string_alloc_set("Delete"); + if(model->clipboard != NULL) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_paste, + ArchiveBrowserEventFileMenuPaste); + } else if(selected) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_cut, + ArchiveBrowserEventFileMenuCut); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_copy, + ArchiveBrowserEventFileMenuCopy); + } + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_new_dir, + ArchiveBrowserEventFileMenuNewDir); + if(selected) { + if(!selected->is_app) { + 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); + } + furi_string_free(item_cut); + furi_string_free(item_copy); + furi_string_free(item_paste); + furi_string_free(item_new_dir); + furi_string_free(item_rename); + furi_string_free(item_delete); + } else if(!model->menu_manage && selected) { + FuriString* item_run = furi_string_alloc_set("Run In App"); + FuriString* item_pin = furi_string_alloc_set("Pin"); + FuriString* item_info = furi_string_alloc_set("Info"); + FuriString* item_show = furi_string_alloc_set("Show"); + if(selected->fav || favorites) { + furi_string_set(item_pin, "Unpin"); + } + + if(favorites) { + //FURI_LOG_D(TAG, "ArchiveTabFavorites"); + 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); + if(selected->type <= ArchiveFileTypeBadKb) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_show, + ArchiveBrowserEventFileMenuShow); + } + furi_string_set(item_info, "Move"); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_info, + ArchiveBrowserEventFileMenuRename); + } else { + if(selected->type == ArchiveFileTypeFolder) { + //FURI_LOG_D(TAG, "Directory type"); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_pin, + ArchiveBrowserEventFileMenuPin); + } 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); + if(selected->is_text_file) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_show, + ArchiveBrowserEventFileMenuShow); + } + } 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); + if(selected->type <= ArchiveFileTypeBadKb) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_show, + ArchiveBrowserEventFileMenuShow); + } + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_pin, + ArchiveBrowserEventFileMenuPin); + } 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_info, + ArchiveBrowserEventFileMenuInfo); + if(selected->type <= ArchiveFileTypeBadKb) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + item_show, + ArchiveBrowserEventFileMenuShow); + } + } + } + + furi_string_free(item_run); + furi_string_free(item_pin); + furi_string_free(item_info); + furi_string_free(item_show); } - - if(model->tab_idx == ArchiveTabFavorites) { - //FURI_LOG_D(TAG, "ArchiveTabFavorites"); - - furi_string_set(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); - if(selected->type <= ArchiveFileTypeBadKb) { - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - item_show, - ArchiveBrowserEventFileMenuShow); - } - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - item_rename, - ArchiveBrowserEventFileMenuRename); - } else if(selected->type == ArchiveFileTypeFolder) { - //FURI_LOG_D(TAG, "Directory type"); - 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); - } 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); - if(selected->is_text_file) { - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - item_show, - ArchiveBrowserEventFileMenuShow); - } - 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(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); - if(selected->type <= ArchiveFileTypeBadKb) { - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - item_show, - ArchiveBrowserEventFileMenuShow); - } - 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_info, - ArchiveBrowserEventFileMenuInfo); - if(selected->type <= ArchiveFileTypeBadKb) { - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - item_show, - ArchiveBrowserEventFileMenuShow); - } - 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); - } - - furi_string_free(item_run); - furi_string_free(item_pin); - furi_string_free(item_info); - furi_string_free(item_show); - furi_string_free(item_rename); - furi_string_free(item_delete); } /*else { FURI_LOG_D(TAG, "menu_array_size already set: %d", menu_array_size(model->context_menu)); }*/ @@ -192,7 +206,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { const uint8_t line_height = 10; canvas_set_color(canvas, ColorWhite); - uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu) * line_height); + uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu - 1) * line_height); canvas_draw_box(canvas, 71, 1, 57, calc_height + 4); canvas_set_color(canvas, ColorBlack); elements_slightly_rounded_frame(canvas, 70, 2, 58, calc_height + 4); @@ -203,12 +217,14 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { size_menu, calc_height, model->menu_idx);*/ + canvas_draw_str(canvas, 74, 11, model->menu_manage ? "Manage:" : "Actions:"); for(size_t i = 0; i < size_menu; i++) { ArchiveContextMenuItem_t* current = menu_array_get(model->context_menu, i); - canvas_draw_str(canvas, 82, 11 + i * line_height, furi_string_get_cstr(current->text)); + canvas_draw_str( + canvas, 82, 11 + (i + 1) * line_height, furi_string_get_cstr(current->text)); } - canvas_draw_icon(canvas, 74, 4 + model->menu_idx * line_height, &I_ButtonRight_4x7); + canvas_draw_icon(canvas, 74, 4 + (model->menu_idx + 1) * line_height, &I_ButtonRight_4x7); } static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, bool moving) { @@ -323,11 +339,13 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m furi_assert(model); const char* tab_name = ArchiveTabNames[model->tab_idx]; + bool clip = model->clipboard != NULL; canvas_draw_icon(canvas, 0, 0, &I_Background_128x11); canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 0, 0, 50, 13); + if(clip) canvas_draw_box(canvas, 69, 0, 24, 13); canvas_draw_box(canvas, 107, 0, 20, 13); canvas_set_color(canvas, ColorBlack); @@ -336,6 +354,14 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m canvas_draw_line(canvas, 1, 11, 49, 11); // shadow bottom canvas_draw_str_aligned(canvas, 25, 9, AlignCenter, AlignBottom, tab_name); + if(clip) { + canvas_draw_rframe(canvas, 69, 0, 25, 13, 1); + canvas_draw_line(canvas, 92, 1, 92, 11); + canvas_draw_line(canvas, 70, 11, 92, 11); + canvas_draw_str_aligned( + canvas, 81, 9, AlignCenter, AlignBottom, model->clipboard_copy ? "Copy" : "Cut"); + } + canvas_draw_rframe(canvas, 107, 0, 21, 13, 1); canvas_draw_line(canvas, 126, 1, 126, 11); canvas_draw_line(canvas, 108, 11, 126, 11); @@ -350,6 +376,7 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m canvas_set_color(canvas, ColorWhite); canvas_draw_dot(canvas, 50, 0); + if(clip) canvas_draw_dot(canvas, 93, 0); canvas_draw_dot(canvas, 127, 0); canvas_set_color(canvas, ColorBlack); @@ -367,6 +394,9 @@ static void archive_view_render(Canvas* canvas, void* mdl) { } else { canvas_draw_str_aligned( canvas, GUI_DISPLAY_WIDTH / 2, 40, AlignCenter, AlignCenter, "Empty"); + if(model->menu) { + render_item_menu(canvas, model); + } } } @@ -523,6 +553,8 @@ static bool archive_view_input(InputEvent* event, void* context) { } } } + } else if(event->key == InputKeyBack && event->type == InputTypeLong) { + browser->callback(ArchiveBrowserEventManageMenuOpen, browser->context); } } diff --git a/applications/main/archive/views/archive_browser_view.h b/applications/main/archive/views/archive_browser_view.h index 1ce35cb53..1b4c0f525 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -39,8 +39,13 @@ typedef enum { typedef enum { ArchiveBrowserEventFileMenuNone, ArchiveBrowserEventFileMenuOpen, + ArchiveBrowserEventManageMenuOpen, ArchiveBrowserEventFileMenuRun, ArchiveBrowserEventFileMenuPin, + ArchiveBrowserEventFileMenuCut, + ArchiveBrowserEventFileMenuCopy, + ArchiveBrowserEventFileMenuPaste, + ArchiveBrowserEventFileMenuNewDir, ArchiveBrowserEventFileMenuRename, ArchiveBrowserEventFileMenuDelete, ArchiveBrowserEventFileMenuInfo, @@ -91,6 +96,9 @@ typedef struct { uint8_t menu_idx; bool menu; + bool menu_manage; + char* clipboard; + bool clipboard_copy; menu_array_t context_menu; bool move_fav;