Merge pull request #68 from derskythe/fixed-archive-app

Fixed archive app
This commit is contained in:
MX 2022-09-16 02:53:15 +03:00 committed by GitHub
commit 3a1705bcf9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 494 additions and 129 deletions

View file

@ -1,66 +1,90 @@
#include "archive_i.h"
#include "m-string.h"
bool archive_custom_event_callback(void* context, uint32_t event) {
static bool archive_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
ArchiveApp* archive = (ArchiveApp*)context;
ArchiveApp* archive = context;
return scene_manager_handle_custom_event(archive->scene_manager, event);
}
bool archive_back_event_callback(void* context) {
static bool archive_back_event_callback(void* context) {
furi_assert(context);
ArchiveApp* archive = (ArchiveApp*)context;
ArchiveApp* archive = context;
return scene_manager_handle_back_event(archive->scene_manager);
}
ArchiveApp* archive_alloc() {
static void archive_tick_event_callback(void* context) {
furi_assert(context);
ArchiveApp* archive = context;
scene_manager_handle_tick_event(archive->scene_manager);
}
static ArchiveApp* archive_alloc() {
ArchiveApp* archive = malloc(sizeof(ArchiveApp));
archive->gui = furi_record_open(RECORD_GUI);
archive->text_input = text_input_alloc();
string_init(archive->fav_move_str);
archive->view_dispatcher = view_dispatcher_alloc();
archive->scene_manager = scene_manager_alloc(&archive_scene_handlers, archive);
archive->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(archive->view_dispatcher);
view_dispatcher_attach_to_gui(
archive->view_dispatcher, archive->gui, ViewDispatcherTypeFullscreen);
archive->gui = furi_record_open(RECORD_GUI);
view_dispatcher_set_event_callback_context(archive->view_dispatcher, archive);
view_dispatcher_set_custom_event_callback(
archive->view_dispatcher, archive_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
archive->view_dispatcher, archive_back_event_callback);
ViewDispatcher* view_dispatcher = archive->view_dispatcher;
view_dispatcher_enable_queue(view_dispatcher);
view_dispatcher_set_event_callback_context(view_dispatcher, archive);
view_dispatcher_set_custom_event_callback(view_dispatcher, archive_custom_event_callback);
view_dispatcher_set_navigation_event_callback(view_dispatcher, archive_back_event_callback);
view_dispatcher_set_tick_event_callback(view_dispatcher, archive_tick_event_callback, 100);
archive->browser = browser_alloc();
archive->dialogs = furi_record_open(RECORD_DIALOGS);
archive->text_input = text_input_alloc();
view_dispatcher_add_view(
archive->view_dispatcher, ArchiveViewBrowser, archive_browser_get_view(archive->browser));
view_dispatcher_add_view(
archive->view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input));
view_dispatcher, ArchiveViewTextInput, text_input_get_view(archive->text_input));
archive->widget = widget_alloc();
view_dispatcher_add_view(
archive->view_dispatcher, ArchiveViewWidget, widget_get_view(archive->widget));
archive->view_stack = view_stack_alloc();
view_dispatcher_add_view(
view_dispatcher, ArchiveViewStack, view_stack_get_view(archive->view_stack));
archive->browser = browser_alloc();
view_dispatcher_add_view(
archive->view_dispatcher, ArchiveViewBrowser, archive_browser_get_view(archive->browser));
// Loading
archive->loading = loading_alloc();
return archive;
}
void archive_free(ArchiveApp* archive) {
furi_assert(archive);
ViewDispatcher* view_dispatcher = archive->view_dispatcher;
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewBrowser);
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewTextInput);
view_dispatcher_remove_view(archive->view_dispatcher, ArchiveViewWidget);
// Loading
loading_free(archive->loading);
view_dispatcher_remove_view(view_dispatcher, ArchiveViewTextInput);
text_input_free(archive->text_input);
view_dispatcher_remove_view(view_dispatcher, ArchiveViewWidget);
widget_free(archive->widget);
view_dispatcher_remove_view(view_dispatcher, ArchiveViewStack);
view_stack_free(archive->view_stack);
view_dispatcher_remove_view(view_dispatcher, ArchiveViewBrowser);
view_dispatcher_free(archive->view_dispatcher);
scene_manager_free(archive->scene_manager);
browser_free(archive->browser);
string_clear(archive->fav_move_str);
text_input_free(archive->text_input);
furi_record_close(RECORD_DIALOGS);
archive->dialogs = NULL;
furi_record_close(RECORD_GUI);
archive->gui = NULL;
@ -68,12 +92,31 @@ void archive_free(ArchiveApp* archive) {
free(archive);
}
void archive_show_loading_popup(ArchiveApp* context, bool show) {
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
ViewStack* view_stack = context->view_stack;
Loading* loading = context->loading;
if(show) {
// Raise timer priority so that animations can play
vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
view_stack_add_view(view_stack, loading_get_view(loading));
} else {
view_stack_remove_view(view_stack, loading_get_view(loading));
// Restore default timer priority
vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
}
}
int32_t archive_app(void* p) {
UNUSED(p);
ArchiveApp* archive = archive_alloc();
view_dispatcher_attach_to_gui(
archive->view_dispatcher, archive->gui, ViewDispatcherTypeFullscreen);
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser);
view_dispatcher_run(archive->view_dispatcher);
archive_free(archive);
archive_free(archive);
return 0;
}

View file

@ -8,6 +8,9 @@
#include <gui/scene_manager.h>
#include <gui/modules/text_input.h>
#include <gui/modules/widget.h>
#include <gui/view_stack.h>
#include <dialogs/dialogs.h>
#include <gui/modules/loading.h>
#include <loader/loader.h>
#include "views/archive_browser_view.h"
@ -18,17 +21,24 @@ typedef enum {
ArchiveViewTextInput,
ArchiveViewWidget,
ArchiveViewTotal,
ArchiveViewStack,
} ArchiveViewEnum;
struct ArchiveApp {
Gui* gui;
ViewDispatcher* view_dispatcher;
ViewStack* view_stack;
SceneManager* scene_manager;
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(ArchiveApp* context, bool show);

View file

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

View file

@ -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 || error == FSE_EXIST) {
FURI_LOG_I(TAG, "Rename from %s to %s is DONE", 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);
}
return error;
}

View file

@ -3,6 +3,7 @@
#include <m-array.h>
#include <m-string.h>
#include <storage/storage.h>
#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);

View file

@ -0,0 +1,52 @@
#pragma once
#include <m-array.h>
#include <m-string.h>
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

View file

@ -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,13 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
}
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 ArchiveBrowserEventFileMenuDelete:
if(archive_get_tab(browser) != ArchiveTabFavorites) {
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneDelete);

View file

@ -1,3 +1,4 @@
ADD_SCENE(archive, browser, Browser)
ADD_SCENE(archive, rename, Rename)
ADD_SCENE(archive, delete, Delete)
ADD_SCENE(archive, info, Info)

View file

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

View file

@ -0,0 +1,92 @@
#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* instance = context;
widget_add_button_element(
instance->widget, GuiButtonTypeLeft, "Back", archive_scene_info_widget_callback, instance);
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(instance->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(
instance->widget, 0, 0, 128, 25, 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, "");
// File size
FileInfo fileinfo;
storage_common_stat(fs_api, string_get_cstr(current->path), &fileinfo);
if(fileinfo.size <= 1024) {
string_printf(str_size, "%d", fileinfo.size);
snprintf(
file_info_message,
sizeof(file_info_message),
"Size: \e#%s\e# bytes\n%s",
string_get_cstr(str_size),
string_get_cstr(dirname));
} else {
string_printf(str_size, "%d", fileinfo.size / 1024);
snprintf(
file_info_message,
sizeof(file_info_message),
"Size: \e#%s\e# Kb.\n%s",
string_get_cstr(str_size),
string_get_cstr(dirname));
}
widget_add_text_box_element(
instance->widget, 0, 25, 128, 25, AlignLeft, AlignCenter, file_info_message, false);
// This one to return and cursor select this file
path_extract_filename_no_ext(string_get_cstr(current->path), filename);
strlcpy(instance->text_store, string_get_cstr(filename), MAX_NAME_LEN);
string_clear(filename);
string_clear(dirname);
string_clear(str_size);
view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget);
}
bool archive_scene_info_on_event(void* context, SceneManagerEvent event) {
furi_assert(context);
ArchiveApp* app = (ArchiveApp*)context;
if(event.type == SceneManagerEventTypeCustom) {
scene_manager_next_scene(app->scene_manager, ArchiveAppSceneBrowser);
return true;
}
return false;
}
void archive_scene_info_on_exit(void* context) {
furi_assert(context);
ArchiveApp* app = (ArchiveApp*)context;
widget_reset(app->widget);
}

View file

@ -4,6 +4,9 @@
#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_RENAME_CUSTOM_EVENT (0UL)
#define MAX_TEXT_INPUT_LEN 22
@ -14,63 +17,87 @@ void archive_scene_rename_text_input_callback(void* context) {
}
void archive_scene_rename_on_enter(void* context) {
ArchiveApp* archive = (ArchiveApp*)context;
ArchiveApp* archive = 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,
archive_scene_rename_text_input_callback,
archive,
context,
archive->text_store,
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);
}
bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
ArchiveApp* archive = (ArchiveApp*)context;
ArchiveApp* archive = context;
bool consumed = false;
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
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, 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 || error == FSE_EXIST) {
scene_manager_next_scene(archive->scene_manager, ArchiveAppSceneBrowser);
} else {
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);
}
consumed = true;
}
}
@ -78,12 +105,6 @@ bool archive_scene_rename_on_event(void* context, SceneManagerEvent event) {
}
void archive_scene_rename_on_exit(void* context) {
ArchiveApp* archive = (ArchiveApp*)context;
// Clear view
void* validator_context = text_input_get_validator_callback_context(archive->text_input);
text_input_set_validator(archive->text_input, NULL, NULL);
validator_is_file_free(validator_context);
ArchiveApp* archive = context;
text_input_reset(archive->text_input);
}

View file

@ -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,142 @@ 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_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);
}
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 = 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, 11, 57, calc_height + 4);
canvas_set_color(canvas, ColorBlack);
elements_slightly_rounded_frame(canvas, 70, 12, 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, 21 + 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, 14 + model->menu_idx * line_height, &I_ButtonRight_4x7);
}
static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, bool moving) {
@ -250,32 +351,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 +468,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 +486,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 +494,4 @@ void browser_free(ArchiveBrowserView* browser) {
view_free(browser->view);
free(browser);
}
}

View file

@ -7,6 +7,7 @@
#include <furi.h>
#include <storage/storage.h>
#include "../helpers/archive_files.h"
#include "../helpers/archive_menu.h"
#include "../helpers/archive_favorites.h"
#include "gui/modules/file_browser_worker.h"
@ -14,7 +15,7 @@
#define MAX_NAME_LEN 255
#define MAX_EXT_LEN 6
#define FRAME_HEIGHT 12
#define MENU_ITEMS 4u
#define MENU_ITEMS 5u
#define MOVE_OFFSET 5u
typedef enum {
@ -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);