[FL-2633] Move files from /int to /ext on SD mount #1384
Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									fd498bdfcf
								
							
						
					
					
						commit
						2caa5c3064
					
				| @ -190,6 +190,14 @@ FS_Error storage_common_rename(Storage* storage, const char* old_path, const cha | |||||||
|  */ |  */ | ||||||
| FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path); | FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* new_path); | ||||||
| 
 | 
 | ||||||
|  | /** Copy one folder contents into another with rename of all conflicting files
 | ||||||
|  |  * @param app pointer to the api | ||||||
|  |  * @param old_path old path | ||||||
|  |  * @param new_path new path | ||||||
|  |  * @return FS_Error operation result | ||||||
|  |  */ | ||||||
|  | FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path); | ||||||
|  | 
 | ||||||
| /** Creates a directory
 | /** Creates a directory
 | ||||||
|  * @param app pointer to the api |  * @param app pointer to the api | ||||||
|  * @param path directory path |  * @param path directory path | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | #include "furi/log.h" | ||||||
| #include <furi/record.h> | #include <furi/record.h> | ||||||
| #include <m-string.h> | #include <m-string.h> | ||||||
| #include "storage.h" | #include "storage.h" | ||||||
| @ -5,8 +6,10 @@ | |||||||
| #include "storage_message.h" | #include "storage_message.h" | ||||||
| #include <toolbox/stream/file_stream.h> | #include <toolbox/stream/file_stream.h> | ||||||
| #include <toolbox/dir_walk.h> | #include <toolbox/dir_walk.h> | ||||||
|  | #include "toolbox/path.h" | ||||||
| 
 | 
 | ||||||
| #define MAX_NAME_LENGTH 256 | #define MAX_NAME_LENGTH 256 | ||||||
|  | #define MAX_EXT_LEN 16 | ||||||
| 
 | 
 | ||||||
| #define TAG "StorageAPI" | #define TAG "StorageAPI" | ||||||
| 
 | 
 | ||||||
| @ -436,6 +439,131 @@ FS_Error storage_common_copy(Storage* storage, const char* old_path, const char* | |||||||
|     return error; |     return error; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static FS_Error | ||||||
|  |     storage_merge_recursive(Storage* storage, const char* old_path, const char* new_path) { | ||||||
|  |     FS_Error error = storage_common_mkdir(storage, new_path); | ||||||
|  |     DirWalk* dir_walk = dir_walk_alloc(storage); | ||||||
|  |     string_t path; | ||||||
|  |     string_t tmp_new_path; | ||||||
|  |     string_t tmp_old_path; | ||||||
|  |     FileInfo fileinfo; | ||||||
|  |     string_init(path); | ||||||
|  |     string_init(tmp_new_path); | ||||||
|  |     string_init(tmp_old_path); | ||||||
|  | 
 | ||||||
|  |     do { | ||||||
|  |         if((error != FSE_OK) && (error != FSE_EXIST)) break; | ||||||
|  | 
 | ||||||
|  |         if(!dir_walk_open(dir_walk, old_path)) { | ||||||
|  |             error = dir_walk_get_error(dir_walk); | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         while(1) { | ||||||
|  |             DirWalkResult res = dir_walk_read(dir_walk, path, &fileinfo); | ||||||
|  | 
 | ||||||
|  |             if(res == DirWalkError) { | ||||||
|  |                 error = dir_walk_get_error(dir_walk); | ||||||
|  |                 break; | ||||||
|  |             } else if(res == DirWalkLast) { | ||||||
|  |                 break; | ||||||
|  |             } else { | ||||||
|  |                 string_set(tmp_old_path, path); | ||||||
|  |                 string_right(path, strlen(old_path)); | ||||||
|  |                 string_printf(tmp_new_path, "%s%s", new_path, string_get_cstr(path)); | ||||||
|  | 
 | ||||||
|  |                 if(fileinfo.flags & FSF_DIRECTORY) { | ||||||
|  |                     if(storage_common_stat(storage, string_get_cstr(tmp_new_path), &fileinfo) == | ||||||
|  |                        FSE_OK) { | ||||||
|  |                         if(fileinfo.flags & FSF_DIRECTORY) { | ||||||
|  |                             error = storage_common_mkdir(storage, string_get_cstr(tmp_new_path)); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     error = storage_common_merge( | ||||||
|  |                         storage, string_get_cstr(tmp_old_path), string_get_cstr(tmp_new_path)); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 if(error != FSE_OK) break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } while(false); | ||||||
|  | 
 | ||||||
|  |     string_clear(tmp_new_path); | ||||||
|  |     string_clear(tmp_old_path); | ||||||
|  |     string_clear(path); | ||||||
|  |     dir_walk_free(dir_walk); | ||||||
|  |     return error; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FS_Error storage_common_merge(Storage* storage, const char* old_path, const char* new_path) { | ||||||
|  |     FS_Error error; | ||||||
|  |     const char* new_path_tmp; | ||||||
|  |     string_t new_path_next; | ||||||
|  |     string_init(new_path_next); | ||||||
|  | 
 | ||||||
|  |     FileInfo fileinfo; | ||||||
|  |     error = storage_common_stat(storage, old_path, &fileinfo); | ||||||
|  | 
 | ||||||
|  |     if(error == FSE_OK) { | ||||||
|  |         if(fileinfo.flags & FSF_DIRECTORY) { | ||||||
|  |             error = storage_merge_recursive(storage, old_path, new_path); | ||||||
|  |         } else { | ||||||
|  |             error = storage_common_stat(storage, new_path, &fileinfo); | ||||||
|  |             if(error == FSE_OK) { | ||||||
|  |                 string_set_str(new_path_next, new_path); | ||||||
|  |                 string_t dir_path; | ||||||
|  |                 string_t filename; | ||||||
|  |                 char extension[MAX_EXT_LEN]; | ||||||
|  | 
 | ||||||
|  |                 string_init(dir_path); | ||||||
|  |                 string_init(filename); | ||||||
|  | 
 | ||||||
|  |                 path_extract_filename(new_path_next, filename, true); | ||||||
|  |                 path_extract_dirname(new_path, dir_path); | ||||||
|  |                 path_extract_extension(new_path_next, extension, MAX_EXT_LEN); | ||||||
|  | 
 | ||||||
|  |                 storage_get_next_filename( | ||||||
|  |                     storage, | ||||||
|  |                     string_get_cstr(dir_path), | ||||||
|  |                     string_get_cstr(filename), | ||||||
|  |                     extension, | ||||||
|  |                     new_path_next, | ||||||
|  |                     255); | ||||||
|  |                 string_cat_printf(dir_path, "/%s%s", string_get_cstr(new_path_next), extension); | ||||||
|  |                 string_set(new_path_next, dir_path); | ||||||
|  | 
 | ||||||
|  |                 string_clear(dir_path); | ||||||
|  |                 string_clear(filename); | ||||||
|  |                 new_path_tmp = string_get_cstr(new_path_next); | ||||||
|  |             } else { | ||||||
|  |                 new_path_tmp = new_path; | ||||||
|  |             } | ||||||
|  |             Stream* stream_from = file_stream_alloc(storage); | ||||||
|  |             Stream* stream_to = file_stream_alloc(storage); | ||||||
|  | 
 | ||||||
|  |             do { | ||||||
|  |                 if(!file_stream_open(stream_from, old_path, FSAM_READ, FSOM_OPEN_EXISTING)) break; | ||||||
|  |                 if(!file_stream_open(stream_to, new_path_tmp, FSAM_WRITE, FSOM_CREATE_NEW)) break; | ||||||
|  |                 stream_copy_full(stream_from, stream_to); | ||||||
|  |             } while(false); | ||||||
|  | 
 | ||||||
|  |             error = file_stream_get_error(stream_from); | ||||||
|  |             if(error == FSE_OK) { | ||||||
|  |                 error = file_stream_get_error(stream_to); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             stream_free(stream_from); | ||||||
|  |             stream_free(stream_to); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(new_path_next); | ||||||
|  | 
 | ||||||
|  |     return error; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| FS_Error storage_common_mkdir(Storage* storage, const char* path) { | FS_Error storage_common_mkdir(Storage* storage, const char* path) { | ||||||
|     S_API_PROLOGUE; |     S_API_PROLOGUE; | ||||||
|     S_API_DATA_PATH; |     S_API_DATA_PATH; | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								applications/storage_move_to_sd/application.fam
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								applications/storage_move_to_sd/application.fam
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | App( | ||||||
|  |     appid="storage_move_to_sd", | ||||||
|  |     name="StorageMoveToSd", | ||||||
|  |     apptype=FlipperAppType.SYSTEM, | ||||||
|  |     entry_point="storage_move_to_sd_app", | ||||||
|  |     requires=["gui","storage"], | ||||||
|  |     provides=["storage_move_to_sd_start"], | ||||||
|  |     stack_size=2 * 1024, | ||||||
|  |     order=30, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | App( | ||||||
|  |     appid="storage_move_to_sd_start", | ||||||
|  |     apptype=FlipperAppType.STARTUP, | ||||||
|  |     entry_point="storage_move_to_sd_start", | ||||||
|  |     requires=["storage"], | ||||||
|  |     order=120, | ||||||
|  | ) | ||||||
|  | 
 | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | #include "storage_move_to_sd_scene.h" | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||||||
|  | void (*const storage_move_to_sd_on_enter_handlers[])(void*) = { | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||||||
|  | bool (*const storage_move_to_sd_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||||||
|  | void (*const storage_move_to_sd_on_exit_handlers[])(void* context) = { | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Initialize scene handlers configuration structure
 | ||||||
|  | const SceneManagerHandlers storage_move_to_sd_scene_handlers = { | ||||||
|  |     .on_enter_handlers = storage_move_to_sd_on_enter_handlers, | ||||||
|  |     .on_event_handlers = storage_move_to_sd_on_event_handlers, | ||||||
|  |     .on_exit_handlers = storage_move_to_sd_on_exit_handlers, | ||||||
|  |     .scene_num = StorageMoveToSdSceneNum, | ||||||
|  | }; | ||||||
| @ -0,0 +1,29 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | 
 | ||||||
|  | // Generate scene id and total number
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) StorageMoveToSd##id, | ||||||
|  | typedef enum { | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  |     StorageMoveToSdSceneNum, | ||||||
|  | } StorageMoveToSdScene; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | extern const SceneManagerHandlers storage_move_to_sd_scene_handlers; | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) \ | ||||||
|  |     bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); | ||||||
|  | #include "storage_move_to_sd_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
| @ -0,0 +1,2 @@ | |||||||
|  | ADD_SCENE(storage_move_to_sd, confirm, Confirm) | ||||||
|  | ADD_SCENE(storage_move_to_sd, progress, Progress) | ||||||
| @ -0,0 +1,70 @@ | |||||||
|  | #include "../storage_move_to_sd.h" | ||||||
|  | #include "gui/canvas.h" | ||||||
|  | #include "gui/modules/widget_elements/widget_element_i.h" | ||||||
|  | #include "storage/storage.h" | ||||||
|  | 
 | ||||||
|  | static void storage_move_to_sd_scene_confirm_widget_callback( | ||||||
|  |     GuiButtonType result, | ||||||
|  |     InputType type, | ||||||
|  |     void* context) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     furi_assert(app); | ||||||
|  |     if(type == InputTypeShort) { | ||||||
|  |         if(result == GuiButtonTypeRight) { | ||||||
|  |             view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventConfirm); | ||||||
|  |         } else if(result == GuiButtonTypeLeft) { | ||||||
|  |             view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void storage_move_to_sd_scene_confirm_on_enter(void* context) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  | 
 | ||||||
|  |     widget_add_button_element( | ||||||
|  |         app->widget, | ||||||
|  |         GuiButtonTypeLeft, | ||||||
|  |         "Cancel", | ||||||
|  |         storage_move_to_sd_scene_confirm_widget_callback, | ||||||
|  |         app); | ||||||
|  |     widget_add_button_element( | ||||||
|  |         app->widget, | ||||||
|  |         GuiButtonTypeRight, | ||||||
|  |         "Confirm", | ||||||
|  |         storage_move_to_sd_scene_confirm_widget_callback, | ||||||
|  |         app); | ||||||
|  | 
 | ||||||
|  |     widget_add_string_element( | ||||||
|  |         app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "SD card inserted"); | ||||||
|  |     widget_add_string_multiline_element( | ||||||
|  |         app->widget, | ||||||
|  |         64, | ||||||
|  |         32, | ||||||
|  |         AlignCenter, | ||||||
|  |         AlignCenter, | ||||||
|  |         FontSecondary, | ||||||
|  |         "Move data from\ninternal storage to SD card?"); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool storage_move_to_sd_scene_confirm_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         if(event.event == MoveToSdCustomEventConfirm) { | ||||||
|  |             scene_manager_next_scene(app->scene_manager, StorageMoveToSdProgress); | ||||||
|  |             consumed = true; | ||||||
|  |         } else if(event.event == MoveToSdCustomEventExit) { | ||||||
|  |             view_dispatcher_stop(app->view_dispatcher); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void storage_move_to_sd_scene_confirm_on_exit(void* context) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     widget_reset(app->widget); | ||||||
|  | } | ||||||
| @ -0,0 +1,32 @@ | |||||||
|  | #include "../storage_move_to_sd.h" | ||||||
|  | #include "cmsis_os2.h" | ||||||
|  | 
 | ||||||
|  | void storage_move_to_sd_scene_progress_on_enter(void* context) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  | 
 | ||||||
|  |     widget_add_string_element( | ||||||
|  |         app->widget, 64, 10, AlignCenter, AlignCenter, FontPrimary, "Moving..."); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(app->view_dispatcher, StorageMoveToSdViewWidget); | ||||||
|  | 
 | ||||||
|  |     storage_move_to_sd_perform(); | ||||||
|  |     view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool storage_move_to_sd_scene_progress_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         view_dispatcher_stop(app->view_dispatcher); | ||||||
|  |     } else if(event.type == SceneManagerEventTypeBack) { | ||||||
|  |         consumed = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void storage_move_to_sd_scene_progress_on_exit(void* context) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     widget_reset(app->widget); | ||||||
|  | } | ||||||
							
								
								
									
										177
									
								
								applications/storage_move_to_sd/storage_move_to_sd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								applications/storage_move_to_sd/storage_move_to_sd.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,177 @@ | |||||||
|  | #include "storage_move_to_sd.h" | ||||||
|  | #include "cmsis_os2.h" | ||||||
|  | #include "furi/common_defines.h" | ||||||
|  | #include "furi/log.h" | ||||||
|  | #include "loader/loader.h" | ||||||
|  | #include "m-string.h" | ||||||
|  | #include <stdint.h> | ||||||
|  | 
 | ||||||
|  | #define TAG "MoveToSd" | ||||||
|  | 
 | ||||||
|  | #define MOVE_SRC "/int" | ||||||
|  | #define MOVE_DST "/ext" | ||||||
|  | 
 | ||||||
|  | static const char* app_dirs[] = { | ||||||
|  |     "subghz", | ||||||
|  |     "lfrfid", | ||||||
|  |     "nfc", | ||||||
|  |     "infrared", | ||||||
|  |     "ibutton", | ||||||
|  |     "badusb", | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | bool storage_move_to_sd_perform(void) { | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     string_t path_src; | ||||||
|  |     string_t path_dst; | ||||||
|  |     string_init(path_src); | ||||||
|  |     string_init(path_dst); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < COUNT_OF(app_dirs); i++) { | ||||||
|  |         string_printf(path_src, "%s/%s", MOVE_SRC, app_dirs[i]); | ||||||
|  |         string_printf(path_dst, "%s/%s", MOVE_DST, app_dirs[i]); | ||||||
|  |         storage_common_merge(storage, string_get_cstr(path_src), string_get_cstr(path_dst)); | ||||||
|  |         storage_simply_remove_recursive(storage, string_get_cstr(path_src)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(path_src); | ||||||
|  |     string_clear(path_dst); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
|  | 
 | ||||||
|  |     return false; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool storage_move_to_sd_check(void) { | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  | 
 | ||||||
|  |     FileInfo file_info; | ||||||
|  |     bool state = false; | ||||||
|  |     string_t path; | ||||||
|  |     string_init(path); | ||||||
|  | 
 | ||||||
|  |     for(uint32_t i = 0; i < COUNT_OF(app_dirs); i++) { | ||||||
|  |         string_printf(path, "%s/%s", MOVE_SRC, app_dirs[i]); | ||||||
|  |         if(storage_common_stat(storage, string_get_cstr(path), &file_info) == FSE_OK) { | ||||||
|  |             if((file_info.flags & FSF_DIRECTORY) != 0) { | ||||||
|  |                 state = true; | ||||||
|  |                 break; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     string_clear(path); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
|  | 
 | ||||||
|  |     return state; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool storage_move_to_sd_custom_event_callback(void* context, uint32_t event) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     return scene_manager_handle_custom_event(app->scene_manager, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool storage_move_to_sd_back_event_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     return scene_manager_handle_back_event(app->scene_manager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void storage_move_to_sd_unmount_callback(const void* message, void* context) { | ||||||
|  |     StorageMoveToSd* app = context; | ||||||
|  |     furi_assert(app); | ||||||
|  |     const StorageEvent* storage_event = message; | ||||||
|  | 
 | ||||||
|  |     if((storage_event->type == StorageEventTypeCardUnmount) || | ||||||
|  |        (storage_event->type == StorageEventTypeCardMountError)) { | ||||||
|  |         view_dispatcher_send_custom_event(app->view_dispatcher, MoveToSdCustomEventExit); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static StorageMoveToSd* storage_move_to_sd_alloc() { | ||||||
|  |     StorageMoveToSd* app = malloc(sizeof(StorageMoveToSd)); | ||||||
|  | 
 | ||||||
|  |     app->gui = furi_record_open("gui"); | ||||||
|  |     app->notifications = furi_record_open("notification"); | ||||||
|  | 
 | ||||||
|  |     app->view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |     app->scene_manager = scene_manager_alloc(&storage_move_to_sd_scene_handlers, app); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_enable_queue(app->view_dispatcher); | ||||||
|  |     view_dispatcher_set_event_callback_context(app->view_dispatcher, app); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_set_custom_event_callback( | ||||||
|  |         app->view_dispatcher, storage_move_to_sd_custom_event_callback); | ||||||
|  |     view_dispatcher_set_navigation_event_callback( | ||||||
|  |         app->view_dispatcher, storage_move_to_sd_back_event_callback); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||||
|  | 
 | ||||||
|  |     app->widget = widget_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         app->view_dispatcher, StorageMoveToSdViewWidget, widget_get_view(app->widget)); | ||||||
|  | 
 | ||||||
|  |     scene_manager_next_scene(app->scene_manager, StorageMoveToSdConfirm); | ||||||
|  | 
 | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     app->sub = furi_pubsub_subscribe( | ||||||
|  |         storage_get_pubsub(storage), storage_move_to_sd_unmount_callback, app); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  | 
 | ||||||
|  |     return app; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void storage_move_to_sd_free(StorageMoveToSd* app) { | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  |     furi_pubsub_unsubscribe(storage_get_pubsub(storage), app->sub); | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     furi_record_close("notification"); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_remove_view(app->view_dispatcher, StorageMoveToSdViewWidget); | ||||||
|  |     widget_free(app->widget); | ||||||
|  |     view_dispatcher_free(app->view_dispatcher); | ||||||
|  |     scene_manager_free(app->scene_manager); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("gui"); | ||||||
|  | 
 | ||||||
|  |     free(app); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t storage_move_to_sd_app(void* p) { | ||||||
|  |     UNUSED(p); | ||||||
|  | 
 | ||||||
|  |     if(storage_move_to_sd_check()) { | ||||||
|  |         StorageMoveToSd* app = storage_move_to_sd_alloc(); | ||||||
|  |         notification_message(app->notifications, &sequence_display_backlight_on); | ||||||
|  |         view_dispatcher_run(app->view_dispatcher); | ||||||
|  |         storage_move_to_sd_free(app); | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_I(TAG, "Nothing to move"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void storage_move_to_sd_mount_callback(const void* message, void* context) { | ||||||
|  |     UNUSED(context); | ||||||
|  | 
 | ||||||
|  |     const StorageEvent* storage_event = message; | ||||||
|  | 
 | ||||||
|  |     if(storage_event->type == StorageEventTypeCardMount) { | ||||||
|  |         Loader* loader = furi_record_open("loader"); | ||||||
|  |         loader_start(loader, "StorageMoveToSd", NULL); | ||||||
|  |         furi_record_close("loader"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t storage_move_to_sd_start(void* p) { | ||||||
|  |     UNUSED(p); | ||||||
|  |     Storage* storage = furi_record_open("storage"); | ||||||
|  | 
 | ||||||
|  |     furi_pubsub_subscribe(storage_get_pubsub(storage), storage_move_to_sd_mount_callback, NULL); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("storage"); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								applications/storage_move_to_sd/storage_move_to_sd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								applications/storage_move_to_sd/storage_move_to_sd.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | #pragma once | ||||||
|  | #include "gui/modules/widget_elements/widget_element_i.h" | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | #include <notification/notification_messages.h> | ||||||
|  | 
 | ||||||
|  | #include <gui/modules/widget.h> | ||||||
|  | #include <gui/modules/popup.h> | ||||||
|  | 
 | ||||||
|  | #include <storage/storage.h> | ||||||
|  | #include <storage/storage_sd_api.h> | ||||||
|  | 
 | ||||||
|  | #include "scenes/storage_move_to_sd_scene.h" | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     MoveToSdCustomEventExit, | ||||||
|  |     MoveToSdCustomEventConfirm, | ||||||
|  | } MoveToSdCustomEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     // records
 | ||||||
|  |     Gui* gui; | ||||||
|  |     Widget* widget; | ||||||
|  |     NotificationApp* notifications; | ||||||
|  | 
 | ||||||
|  |     // view managment
 | ||||||
|  |     SceneManager* scene_manager; | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  | 
 | ||||||
|  |     FuriPubSubSubscription* sub; | ||||||
|  | 
 | ||||||
|  | } StorageMoveToSd; | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     StorageMoveToSdViewWidget, | ||||||
|  | } StorageMoveToSdView; | ||||||
|  | 
 | ||||||
|  | bool storage_move_to_sd_perform(void); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -67,6 +67,7 @@ FIRMWARE_APPS = { | |||||||
|         # Apps |         # Apps | ||||||
|         "basic_apps", |         "basic_apps", | ||||||
|         "updater_app", |         "updater_app", | ||||||
|  |         "storage_move_to_sd", | ||||||
|         "archive", |         "archive", | ||||||
|         # Settings |         # Settings | ||||||
|         "passport", |         "passport", | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Nikolay Minaylov
						Nikolay Minaylov