Merge pull request #549 from DarkFlippers/archive

Archive Cut/Copy/Past & NewDir
This commit is contained in:
MMX 2023-07-19 03:54:29 +03:00 committed by GitHub
commit 80df63ce29
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 477 additions and 128 deletions

View file

@ -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;

View file

@ -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];
};

View file

@ -419,10 +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->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 =
@ -430,7 +432,10 @@ void archive_show_file_menu(ArchiveBrowserView* browser, bool show) {
}
} else {
model->menu = false;
model->menu_file_manage = false;
model->menu_idx = 0;
model->menu_can_switch = false;
menu_array_reset(model->context_menu);
}
},
true);

View file

@ -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;
}

View file

@ -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);

View file

@ -43,7 +43,7 @@ ARRAY_DEF(
#pragma GCC diagnostic ignored "-Wunused-function"
// Using in applications/archive/views/archive_browser_view.c
static void
archive_menu_add_item(ArchiveContextMenuItem_t* obj, FuriString* text, uint32_t event) {
archive_menu_add_item(ArchiveContextMenuItem_t* obj, const char* text, uint32_t event) {
obj->text = furi_string_alloc_set(text);
obj->event = event;
}

View file

@ -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 ArchiveBrowserEventFileMenuPaste_Cut:
case ArchiveBrowserEventFileMenuPaste_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 == ArchiveBrowserEventFileMenuPaste_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);

View file

@ -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)

View file

@ -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 <dialogs/dialogs.h>
#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);
}

View file

@ -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);

View file

@ -50,64 +50,100 @@ 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),
"Paste",
ArchiveBrowserEventFileMenuPaste_Cut);
} else if(model->clipboard_mode == CLIPBOARD_MODE_COPY) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
"Paste",
ArchiveBrowserEventFileMenuPaste_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),
"Paste",
ArchiveBrowserEventFileMenuPaste_Cut);
} else if(model->clipboard_mode == CLIPBOARD_MODE_COPY) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
"Paste",
ArchiveBrowserEventFileMenuPaste_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
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");
const char* item_pin = "Pin";
// Need init context menu
ArchiveFile_t* selected =
files_array_get(model->files, model->item_idx - model->array_offset);
if((selected->fav) || (model->tab_idx == ArchiveTabFavorites)) {
furi_string_set(item_pin, "Unpin");
item_pin = "Unpin";
}
if(selected->type == ArchiveFileTypeFolder) {
// Folder
//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);
if(selected->is_text_file) {
// { Copy/Cut, Paste } 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");
model->menu_can_switch = true;
if(model->menu_file_manage) {
// { Copy/Cut, Paste } NewDir, Rename, Delete
contex_menu_filemanager_init(model);
} else {
// Info, [Show],
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_show,
ArchiveBrowserEventFileMenuShow);
"Info",
ArchiveBrowserEventFileMenuInfo);
if(selected->is_text_file) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
"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(model->tab_idx == ArchiveTabFavorites) {
// Favorites tab
// Run, Unpin, [Show], Move
//FURI_LOG_D(TAG, "ArchiveTabFavorites");
furi_string_set(item_rename, "Move");
model->menu_can_switch = false;
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_run,
ArchiveBrowserEventFileMenuRun);
menu_array_push_raw(model->context_menu), "Run", ArchiveBrowserEventFileMenuRun);
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_pin,
@ -115,98 +151,109 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
if(selected->type <= ArchiveFileTypeBadUsb) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_show,
"Show",
ArchiveBrowserEventFileMenuShow);
}
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_rename,
ArchiveBrowserEventFileMenuRename);
menu_array_push_raw(model->context_menu), "Move", ArchiveBrowserEventEnterFavMove);
} else if(selected->is_app) {
// Only U2F?
// Run, Info, [Show], Pin, Delete
model->menu_file_manage = false;
//FURI_LOG_D(TAG, "3 types");
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_run,
ArchiveBrowserEventFileMenuRun);
menu_array_push_raw(model->context_menu), "Run", ArchiveBrowserEventFileMenuRun);
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_info,
ArchiveBrowserEventFileMenuInfo);
menu_array_push_raw(model->context_menu), "Info", ArchiveBrowserEventFileMenuInfo);
if(selected->type <= ArchiveFileTypeBadUsb) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_show,
"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,
"Delete",
ArchiveBrowserEventFileMenuDelete);
} else {
// Other
//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 <= ArchiveFileTypeBadUsb) {
model->menu_can_switch = true;
if(model->menu_file_manage) {
// { Copy/Cut, Paste } NewDir, Rename, Delete
contex_menu_filemanager_init(model);
} else {
// Run, Pin, Info, [Show]
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
item_show,
ArchiveBrowserEventFileMenuShow);
"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),
"Info",
ArchiveBrowserEventFileMenuInfo);
if(selected->type <= ArchiveFileTypeBadUsb) {
archive_menu_add_item(
menu_array_push_raw(model->context_menu),
"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));
}*/
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) * line_height);
canvas_draw_box(canvas, 71, 1, 57, calc_height + 4);
uint8_t calc_height = menu_height - ((MENU_ITEMS - size_menu - 1) * line_height);
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);
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->menu_file_manage) {
canvas_draw_str(canvas, 82, menu_y + line_height - 1, "Manage");
} else {
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 + i * line_height, furi_string_get_cstr(current->text));
canvas_draw_str(
canvas,
82,
menu_y + 1 + line_height + (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, 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) {
@ -320,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);
@ -349,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);
}
@ -364,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);
}
}
}
@ -392,6 +463,57 @@ static bool is_file_list_load_required(ArchiveBrowserViewModel* model) {
return false;
}
static inline void
archive_view_menu_input_processing(ArchiveBrowserView* browser, InputEvent* event) {
// only InputShort type
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;
}
},
true);
} else if(event->key == InputKeyLeft || event->key == InputKeyRight) {
with_view_model(
browser->view,
ArchiveBrowserViewModel * model,
{
ArchiveFile_t* selected =
files_array_get(model->files, model->item_idx - model->array_offset);
if(selected->type != ArchiveFileTypeFolder &&
model->tab_idx != ArchiveTabFavorites) {
model->menu_file_manage = !model->menu_file_manage;
model->menu_idx = 0;
menu_array_reset(model->context_menu);
selected->fav =
archive_is_favorite("%s", furi_string_get_cstr(selected->path));
}
},
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;
},
false);
browser->callback(idx, browser->context);
} else if(event->key == InputKeyBack) {
browser->callback(ArchiveBrowserEventFileMenuClose, browser->context);
}
}
static bool archive_view_input(InputEvent* event, void* context) {
furi_assert(event);
furi_assert(context);
@ -418,39 +540,18 @@ static bool archive_view_input(InputEvent* event, void* 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;
}
},
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;
},
false);
browser->callback(idx, browser->context);
} else if(event->key == InputKeyBack) {
browser->callback(ArchiveBrowserEventFileMenuClose, browser->context);
}
archive_view_menu_input_processing(browser, event);
} else {
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);
@ -542,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);
}
}
}
@ -599,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);
@ -627,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);
}

View file

@ -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,
ArchiveBrowserEventFileMenuPaste_Cut,
ArchiveBrowserEventFileMenuPaste_Copy,
ArchiveBrowserEventFileMenuDelete,
ArchiveBrowserEventFileMenuInfo,
ArchiveBrowserEventFileMenuShow,
@ -93,6 +102,9 @@ 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;
@ -117,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);