diff --git a/applications/main/archive/archive.c b/applications/main/archive/archive.c index 588087fd2..4a5a8b39e 100644 --- a/applications/main/archive/archive.c +++ b/applications/main/archive/archive.c @@ -22,6 +22,7 @@ static ArchiveApp* archive_alloc() { ArchiveApp* archive = malloc(sizeof(ArchiveApp)); archive->fav_move_str = furi_string_alloc(); + archive->dst_path = furi_string_alloc(); archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive); archive->view_dispatcher = view_dispatcher_alloc(); @@ -82,6 +83,7 @@ void archive_free(ArchiveApp* archive) { browser_free(archive->browser); furi_string_free(archive->fav_move_str); + furi_string_free(archive->dst_path); furi_record_close(RECORD_DIALOGS); archive->dialogs = NULL; diff --git a/applications/main/archive/archive_i.h b/applications/main/archive/archive_i.h index b96145827..7d612687c 100644 --- a/applications/main/archive/archive_i.h +++ b/applications/main/archive/archive_i.h @@ -37,6 +37,7 @@ struct ArchiveApp { FuriPubSubSubscription* loader_stop_subscription; FuriString* fav_move_str; + FuriString* dst_path; char text_store[MAX_NAME_LEN]; char file_extension[MAX_EXT_LEN + 1]; }; diff --git a/applications/main/archive/helpers/archive_browser.c b/applications/main/archive/helpers/archive_browser.c index e83426d53..facf00a3a 100644 --- a/applications/main/archive/helpers/archive_browser.c +++ b/applications/main/archive/helpers/archive_browser.c @@ -419,11 +419,12 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { ArchiveBrowserViewModel * model, { if(show) { + model->menu = true; + model->menu_idx = 0; + menu_array_reset(model->context_menu); if(archive_is_item_in_array(model, model->item_idx)) { - model->menu = true; - model->filemang = false; - model->menu_idx = 0; - menu_array_reset(model->context_menu); + model->menu_file_manage = false; + ArchiveFile_t* selected = files_array_get(model->files, model->item_idx - model->array_offset); selected->fav = @@ -431,8 +432,10 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) { } } else { model->menu = false; - model->filemang = false; + model->menu_file_manage = false; model->menu_idx = 0; + model->menu_can_switch = false; + menu_array_reset(model->context_menu); } }, true); diff --git a/applications/main/archive/helpers/archive_files.c b/applications/main/archive/helpers/archive_files.c index e12576cb2..6e654d5a2 100644 --- a/applications/main/archive/helpers/archive_files.c +++ b/applications/main/archive/helpers/archive_files.c @@ -121,14 +121,19 @@ 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_rename_copy_file_or_dir( + void* context, + const char* src_path, + const char* dst_path, + bool copy) { 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" : "Rename/Move", src_path, dst_path); - ArchiveBrowserView* browser = context; Storage* fs_api = furi_record_open(RECORD_STORAGE); + FuriString* temp_str = furi_string_alloc_set(dst_path); + FileInfo fileinfo; storage_common_stat(fs_api, src_path, &fileinfo); @@ -136,22 +141,60 @@ 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(storage_common_exists(fs_api, dst_path)) { + FuriString* filename = furi_string_alloc(); + char* file_ext = malloc(MAX_EXT_LEN + 1); + strncpy(file_ext, "", MAX_EXT_LEN); + + path_extract_filename(temp_str, filename, true); + path_extract_extension(temp_str, file_ext, MAX_EXT_LEN); + + path_extract_dirname(dst_path, temp_str); + + storage_get_next_filename( + fs_api, + furi_string_get_cstr(temp_str), + furi_string_get_cstr(filename), + file_ext, + filename, + 255); + + furi_string_cat_printf(temp_str, "/%s%s", furi_string_get_cstr(filename), file_ext); + + dst_path = furi_string_get_cstr(temp_str); + + furi_string_free(filename); + free(file_ext); + } + + 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 || error == FSE_EXIST) { - FURI_LOG_I(TAG, "Rename from %s to %s is DONE", src_path, dst_path); - archive_refresh_dir(browser); + if(error == FSE_OK) { + FURI_LOG_I( + TAG, "%s from %s to %s is DONE", copy ? "Copy" : "Rename/Move", src_path, dst_path); } 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" : "Rename/Move", + filesystem_api_error_get_desc(error), + error); } + furi_string_free(temp_str); + return error; } diff --git a/applications/main/archive/helpers/archive_files.h b/applications/main/archive/helpers/archive_files.h index 989198fec..43d9b27d6 100644 --- a/applications/main/archive/helpers/archive_files.h +++ b/applications/main/archive/helpers/archive_files.h @@ -113,4 +113,8 @@ 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_rename_copy_file_or_dir( + void* context, + const char* src_path, + const char* dst_path, + bool copy); diff --git a/applications/main/archive/scenes/archive_scene_browser.c b/applications/main/archive/scenes/archive_scene_browser.c index e512d31d5..0d90c33ea 100644 --- a/applications/main/archive/scenes/archive_scene_browser.c +++ b/applications/main/archive/scenes/archive_scene_browser.c @@ -156,6 +156,77 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneRename); } consumed = true; + break; + case ArchiveBrowserEventFileMenuNewDir: + archive_show_file_menu(browser, 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 ArchiveBrowserEventFileMenuCut: + case ArchiveBrowserEventFileMenuCopy: + archive_show_file_menu(browser, false); + furi_string_set(archive->fav_move_str, selected->path); + + archive_browser_clipboard_set_mode( + browser, + (event.event == ArchiveBrowserEventFileMenuCut) ? CLIPBOARD_MODE_CUT : + CLIPBOARD_MODE_COPY); + consumed = true; + break; + case ArchiveBrowserEventFileMenuPast_Cut: + case ArchiveBrowserEventFileMenuPast_Copy: + archive_show_file_menu(browser, false); + + FuriString* path_src = archive->fav_move_str; + FuriString* path_dst = furi_string_alloc(); + FuriString* base = furi_string_alloc(); + + const bool copy = (event.event == ArchiveBrowserEventFileMenuPast_Copy); + + path_extract_basename(furi_string_get_cstr(path_src), base); + path_concat(furi_string_get_cstr(browser->path), furi_string_get_cstr(base), path_dst); + + if(path_src && path_dst) { + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewStack); + archive_show_loading_popup(archive, true); + FS_Error error = archive_rename_copy_file_or_dir( + archive->browser, + furi_string_get_cstr(path_src), + furi_string_get_cstr(path_dst), + copy); + archive_show_loading_popup(archive, false); + + 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); + } else { + ArchiveFile_t* current = archive_get_current_file(archive->browser); + if(current != NULL) furi_string_set(current->path, path_dst); + view_dispatcher_send_custom_event( + archive->view_dispatcher, ArchiveBrowserEventListRefresh); + } + + view_dispatcher_switch_to_view(archive->view_dispatcher, ArchiveViewBrowser); + } + + furi_string_free(base); + furi_string_free(path_dst); + + archive_browser_clipboard_reset(browser); + furi_string_reset(path_src); + break; case ArchiveBrowserEventFileMenuInfo: archive_show_file_menu(browser, false); diff --git a/applications/main/archive/scenes/archive_scene_config.h b/applications/main/archive/scenes/archive_scene_config.h index d16c6f1a6..2f3ebe771 100644 --- a/applications/main/archive/scenes/archive_scene_config.h +++ b/applications/main/archive/scenes/archive_scene_config.h @@ -3,3 +3,4 @@ ADD_SCENE(archive, rename, Rename) ADD_SCENE(archive, delete, Delete) ADD_SCENE(archive, info, Info) ADD_SCENE(archive, show, Show) +ADD_SCENE(archive, new_dir, NewDir) \ No newline at end of file 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..6b95b30f5 --- /dev/null +++ b/applications/main/archive/scenes/archive_scene_new_dir.c @@ -0,0 +1,85 @@ +#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) + +void archive_scene_new_dir_text_input_callback(void* context) { + furi_assert(context); + ArchiveApp* archive = 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_NAME_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_show_loading_popup(archive, false); + + 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); + } else { + ArchiveFile_t* current = archive_get_current_file(archive->browser); + if(current != NULL) furi_string_set(current->path, path_dst); + } + + furi_string_free(path_dst); + 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 e6c728f03..21b4e05d8 100644 --- a/applications/main/archive/scenes/archive_scene_rename.c +++ b/applications/main/archive/scenes/archive_scene_rename.c @@ -98,8 +98,8 @@ 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_rename_copy_file_or_dir( + archive->browser, path_src, furi_string_get_cstr(path_dst), false); archive_show_loading_popup(archive, false); archive_show_file_menu(archive->browser, false); diff --git a/applications/main/archive/views/archive_browser_view.c b/applications/main/archive/views/archive_browser_view.c index 6df78fae3..d3806fc45 100644 --- a/applications/main/archive/views/archive_browser_view.c +++ b/applications/main/archive/views/archive_browser_view.c @@ -50,6 +50,48 @@ void archive_browser_set_callback( browser->context = context; } +static void contex_menu_filemanager_init(ArchiveBrowserViewModel* model) { + if(model->item_cnt > 0) { + if(model->clipboard_mode == CLIPBOARD_MODE_OFF) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), "Cut", ArchiveBrowserEventFileMenuCut); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), "Copy", ArchiveBrowserEventFileMenuCopy); + } else if(model->clipboard_mode == CLIPBOARD_MODE_CUT) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + "Past", + ArchiveBrowserEventFileMenuPast_Cut); + } else if(model->clipboard_mode == CLIPBOARD_MODE_COPY) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + "Past", + ArchiveBrowserEventFileMenuPast_Copy); + } + + archive_menu_add_item( + menu_array_push_raw(model->context_menu), "NewDir", ArchiveBrowserEventFileMenuNewDir); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), "Rename", ArchiveBrowserEventFileMenuRename); + archive_menu_add_item( + menu_array_push_raw(model->context_menu), "Delete", ArchiveBrowserEventFileMenuDelete); + } else { + if(model->clipboard_mode == CLIPBOARD_MODE_CUT) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + "Past", + ArchiveBrowserEventFileMenuPast_Cut); + } else if(model->clipboard_mode == CLIPBOARD_MODE_COPY) { + archive_menu_add_item( + menu_array_push_raw(model->context_menu), + "Past", + ArchiveBrowserEventFileMenuPast_Copy); + } + archive_menu_add_item( + menu_array_push_raw(model->context_menu), "NewDir", ArchiveBrowserEventFileMenuNewDir); + } +} + static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { if(menu_array_size(model->context_menu) == 0) { // Context menu is empty, init array @@ -65,32 +107,20 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { if(selected->type == ArchiveFileTypeFolder) { // Folder - // Rename, Delete - model->filemang = true; - //FURI_LOG_D(TAG, "Directory type"); - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - "Rename", - ArchiveBrowserEventFileMenuRename); - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - "Delete", - ArchiveBrowserEventFileMenuDelete); + + // { Copy/Cut, Past } NewDir, Rename, Delete + model->menu_file_manage = true; + model->menu_can_switch = false; + + contex_menu_filemanager_init(model); } else if(!archive_is_known_app(selected->type)) { // UnKnown app type //FURI_LOG_D(TAG, "Unknown type"); - - if(model->filemang) { - // Rename, Delete - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - "Rename", - ArchiveBrowserEventFileMenuRename); - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - "Delete", - ArchiveBrowserEventFileMenuDelete); + model->menu_can_switch = true; + if(model->menu_file_manage) { + // { Copy/Cut, Past } NewDir, Rename, Delete + contex_menu_filemanager_init(model); } else { // Info, [Show], archive_menu_add_item( @@ -110,6 +140,8 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { // Run, Unpin, [Show], Move //FURI_LOG_D(TAG, "ArchiveTabFavorites"); + + model->menu_can_switch = false; archive_menu_add_item( menu_array_push_raw(model->context_menu), "Run", ArchiveBrowserEventFileMenuRun); archive_menu_add_item( @@ -127,7 +159,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { } else if(selected->is_app) { // Only U2F? // Run, Info, [Show], Pin, Delete - model->filemang = false; + model->menu_file_manage = false; //FURI_LOG_D(TAG, "3 types"); archive_menu_add_item( @@ -153,16 +185,10 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { // Other //FURI_LOG_D(TAG, "All menu"); - if(model->filemang) { - // Rename, Delete - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - "Rename", - ArchiveBrowserEventFileMenuRename); - archive_menu_add_item( - menu_array_push_raw(model->context_menu), - "Delete", - ArchiveBrowserEventFileMenuDelete); + model->menu_can_switch = true; + if(model->menu_file_manage) { + // { Copy/Cut, Past } NewDir, Rename, Delete + contex_menu_filemanager_init(model); } else { // Run, Pin, Info, [Show] @@ -190,34 +216,44 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) { 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_y = 0; const uint8_t menu_height = 48; const uint8_t line_height = 10; canvas_set_color(canvas, ColorWhite); uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu - 1) * line_height); - canvas_draw_box(canvas, 71, 1, 57, calc_height + 4 + 2); + canvas_draw_box(canvas, 71, menu_y, 57, calc_height + 4 + 2); canvas_set_color(canvas, ColorBlack); - elements_slightly_rounded_frame(canvas, 70, 2, 58, calc_height + 4 + 2); - canvas_draw_line(canvas, 70, 13, 128, 13); + elements_slightly_rounded_frame(canvas, 70, menu_y, 58, calc_height + 5 + 1); + canvas_draw_line(canvas, 70, menu_y + 1 + line_height, 128, menu_y + 1 + line_height); /*FURI_LOG_D( TAG, "size_menu: %d, calc_height: %d, menu_idx: %d", size_menu, calc_height, model->menu_idx);*/ - if(model->filemang) { - canvas_draw_str(canvas, 82, 11, "FileMan"); // XXX + if(model->menu_file_manage) { + canvas_draw_str(canvas, 82, menu_y + line_height - 1, "Manage"); } else { - canvas_draw_str(canvas, 82, 11, "Actions"); + canvas_draw_str(canvas, 82, menu_y + line_height - 1, "Actions"); + } + if(model->menu_can_switch) { + canvas_draw_icon(canvas, 74, menu_y + 2, &I_ButtonLeft_4x7); + canvas_draw_icon(canvas, 120, menu_y + 2, &I_ButtonRight_4x7); } 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 + 2 + (i + 1) * line_height, furi_string_get_cstr(current->text)); + canvas, + 82, + menu_y + 1 + line_height + (i + 1) * line_height, + furi_string_get_cstr(current->text)); } - canvas_draw_icon(canvas, 74, 4 + 2 + (model->menu_idx + 1) * line_height, &I_ButtonRight_4x7); + canvas_draw_icon( + canvas, 74, menu_y + 4 + (model->menu_idx + 1) * line_height, &I_ButtonRight_4x7); } static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, bool moving) { @@ -331,6 +367,7 @@ 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_mode != CLIPBOARD_MODE_OFF; canvas_draw_icon(canvas, 0, 0, &I_Background_128x11); @@ -360,6 +397,26 @@ static void archive_render_status_bar(Canvas* canvas, ArchiveBrowserViewModel* m canvas_draw_dot(canvas, 50, 0); canvas_draw_dot(canvas, 127, 0); + if(clip) { + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, 69, 0, 24, 13); + + canvas_set_color(canvas, ColorBlack); + 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_mode == CLIPBOARD_MODE_COPY) ? "Copy" : "Cut"); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_dot(canvas, 93, 0); + } + canvas_set_color(canvas, ColorBlack); } @@ -375,6 +432,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); + } } } @@ -429,7 +489,7 @@ static inline void if(selected->type != ArchiveFileTypeFolder && model->tab_idx != ArchiveTabFavorites) { - model->filemang = !model->filemang; + model->menu_file_manage = !model->menu_file_manage; model->menu_idx = 0; menu_array_reset(model->context_menu); selected->fav = @@ -485,7 +545,13 @@ static bool archive_view_input(InputEvent* event, void* context) { if(event->type == InputTypeShort) { if(event->key == InputKeyLeft || event->key == InputKeyRight) { if(move_fav_mode) return false; + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { model->clipboard_mode = CLIPBOARD_MODE_OFF; }, + false); archive_switch_tab(browser, event->key); + } else if(event->key == InputKeyBack) { if(move_fav_mode) { browser->callback(ArchiveBrowserEventExitFavMove, browser->context); @@ -577,6 +643,8 @@ static bool archive_view_input(InputEvent* event, void* context) { browser->callback(ArchiveBrowserEventFileMenuOpen, browser->context); } } + } else if(event->type == InputTypeLong) { + browser->callback(ArchiveBrowserEventFileMenuOpen, browser->context); } } } @@ -634,6 +702,7 @@ ArchiveBrowserView* browser_alloc() { files_array_init(model->files); menu_array_init(model->context_menu); model->tab_idx = TAB_DEFAULT; + model->clipboard_mode = CLIPBOARD_MODE_OFF; }, true); @@ -662,4 +731,21 @@ void browser_free(ArchiveBrowserView* browser) { view_free(browser->view); free(browser); +} + +void archive_browser_clipboard_set_mode(ArchiveBrowserView* browser, uint8_t mode) { + furi_assert(browser); + + with_view_model( + browser->view, ArchiveBrowserViewModel * model, { model->clipboard_mode = mode; }, true); +} + +void archive_browser_clipboard_reset(ArchiveBrowserView* browser) { + furi_assert(browser); + + with_view_model( + browser->view, + ArchiveBrowserViewModel * model, + { model->clipboard_mode = CLIPBOARD_MODE_OFF; }, + true); } \ 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 ff0963719..ba4b5c484 100644 --- a/applications/main/archive/views/archive_browser_view.h +++ b/applications/main/archive/views/archive_browser_view.h @@ -21,6 +21,10 @@ #define MENU_ITEMS 5u #define MOVE_OFFSET 5u +#define CLIPBOARD_MODE_OFF (0U) +#define CLIPBOARD_MODE_CUT (1U) +#define CLIPBOARD_MODE_COPY (2U) + typedef enum { ArchiveTabFavorites, ArchiveTabSubGhz, @@ -43,6 +47,11 @@ typedef enum { ArchiveBrowserEventFileMenuRun, ArchiveBrowserEventFileMenuPin, ArchiveBrowserEventFileMenuRename, + ArchiveBrowserEventFileMenuNewDir, + ArchiveBrowserEventFileMenuCut, + ArchiveBrowserEventFileMenuCopy, + ArchiveBrowserEventFileMenuPast_Cut, + ArchiveBrowserEventFileMenuPast_Copy, ArchiveBrowserEventFileMenuDelete, ArchiveBrowserEventFileMenuInfo, ArchiveBrowserEventFileMenuShow, @@ -93,11 +102,13 @@ typedef struct { uint8_t menu_idx; bool menu; menu_array_t context_menu; + bool menu_file_manage; + bool menu_can_switch; + uint8_t clipboard_mode; bool move_fav; bool list_loading; bool folder_loading; - bool filemang; // XXX uint32_t item_cnt; int32_t item_idx; @@ -118,3 +129,7 @@ View* archive_browser_get_view(ArchiveBrowserView* browser); ArchiveBrowserView* browser_alloc(); void browser_free(ArchiveBrowserView* browser); + +void archive_browser_clipboard_set_mode(ArchiveBrowserView* browser, uint8_t mode); + +void archive_browser_clipboard_reset(ArchiveBrowserView* browser);