mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-11-27 15:00:46 +00:00
Merge pull request #68 from derskythe/fixed-archive-app
Fixed archive app
This commit is contained in:
commit
3a1705bcf9
13 changed files with 494 additions and 129 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
|
@ -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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
52
applications/main/archive/helpers/archive_menu.h
Normal file
52
applications/main/archive/helpers/archive_menu.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
ADD_SCENE(archive, browser, Browser)
|
||||
ADD_SCENE(archive, rename, Rename)
|
||||
ADD_SCENE(archive, delete, Delete)
|
||||
ADD_SCENE(archive, info, Info)
|
||||
|
|
|
@ -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
|
||||
|
|
92
applications/main/archive/scenes/archive_scene_info.c
Normal file
92
applications/main/archive/scenes/archive_scene_info.c
Normal 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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue