mag.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. #include "mag_i.h"
  2. #define TAG "Mag"
  3. static bool mag_debug_custom_event_callback(void* context, uint32_t event) {
  4. furi_assert(context);
  5. Mag* mag = context;
  6. return scene_manager_handle_custom_event(mag->scene_manager, event);
  7. }
  8. static bool mag_debug_back_event_callback(void* context) {
  9. furi_assert(context);
  10. Mag* mag = context;
  11. return scene_manager_handle_back_event(mag->scene_manager);
  12. }
  13. static Mag* mag_alloc() {
  14. Mag* mag = malloc(sizeof(Mag));
  15. mag->storage = furi_record_open(RECORD_STORAGE);
  16. mag->dialogs = furi_record_open(RECORD_DIALOGS);
  17. mag->file_name = furi_string_alloc();
  18. mag->file_path = furi_string_alloc_set(MAG_APP_FOLDER);
  19. mag->view_dispatcher = view_dispatcher_alloc();
  20. mag->scene_manager = scene_manager_alloc(&mag_scene_handlers, mag);
  21. view_dispatcher_enable_queue(mag->view_dispatcher);
  22. view_dispatcher_set_event_callback_context(mag->view_dispatcher, mag);
  23. view_dispatcher_set_custom_event_callback(
  24. mag->view_dispatcher, mag_debug_custom_event_callback);
  25. view_dispatcher_set_navigation_event_callback(
  26. mag->view_dispatcher, mag_debug_back_event_callback);
  27. mag->mag_dev = mag_device_alloc();
  28. // Open GUI record
  29. mag->gui = furi_record_open(RECORD_GUI);
  30. // Open Notification record
  31. mag->notifications = furi_record_open(RECORD_NOTIFICATION);
  32. // Submenu
  33. mag->submenu = submenu_alloc();
  34. view_dispatcher_add_view(mag->view_dispatcher, MagViewSubmenu, submenu_get_view(mag->submenu));
  35. // Dialog
  36. mag->dialog_ex = dialog_ex_alloc();
  37. view_dispatcher_add_view(
  38. mag->view_dispatcher, MagViewDialogEx, dialog_ex_get_view(mag->dialog_ex));
  39. // Popup
  40. mag->popup = popup_alloc();
  41. view_dispatcher_add_view(mag->view_dispatcher, MagViewPopup, popup_get_view(mag->popup));
  42. // Loading
  43. mag->loading = loading_alloc();
  44. view_dispatcher_add_view(mag->view_dispatcher, MagViewLoading, loading_get_view(mag->loading));
  45. // Widget
  46. mag->widget = widget_alloc();
  47. view_dispatcher_add_view(mag->view_dispatcher, MagViewWidget, widget_get_view(mag->widget));
  48. // Text Input
  49. mag->text_input = text_input_alloc();
  50. view_dispatcher_add_view(
  51. mag->view_dispatcher, MagViewTextInput, text_input_get_view(mag->text_input));
  52. return mag;
  53. }
  54. static void mag_free(Mag* mag) {
  55. furi_assert(mag);
  56. furi_string_free(mag->file_name);
  57. furi_string_free(mag->file_path);
  58. // Mag device
  59. mag_device_free(mag->mag_dev);
  60. mag->mag_dev = NULL;
  61. // Submenu
  62. view_dispatcher_remove_view(mag->view_dispatcher, MagViewSubmenu);
  63. submenu_free(mag->submenu);
  64. // DialogEx
  65. view_dispatcher_remove_view(mag->view_dispatcher, MagViewDialogEx);
  66. dialog_ex_free(mag->dialog_ex);
  67. // Popup
  68. view_dispatcher_remove_view(mag->view_dispatcher, MagViewPopup);
  69. popup_free(mag->popup);
  70. // Loading
  71. view_dispatcher_remove_view(mag->view_dispatcher, MagViewLoading);
  72. loading_free(mag->loading);
  73. // Widget
  74. view_dispatcher_remove_view(mag->view_dispatcher, MagViewWidget);
  75. widget_free(mag->widget);
  76. // TextInput
  77. view_dispatcher_remove_view(mag->view_dispatcher, MagViewTextInput);
  78. text_input_free(mag->text_input);
  79. // View Dispatcher
  80. view_dispatcher_free(mag->view_dispatcher);
  81. // Scene Manager
  82. scene_manager_free(mag->scene_manager);
  83. // GUI
  84. furi_record_close(RECORD_GUI);
  85. mag->gui = NULL;
  86. // Notifications
  87. furi_record_close(RECORD_NOTIFICATION);
  88. mag->notifications = NULL;
  89. furi_record_close(RECORD_STORAGE);
  90. furi_record_close(RECORD_DIALOGS);
  91. free(mag);
  92. }
  93. // entry point for app
  94. int32_t mag_app(void* p) {
  95. Mag* mag = mag_alloc();
  96. UNUSED(p);
  97. mag_make_app_folder(mag);
  98. view_dispatcher_attach_to_gui(mag->view_dispatcher, mag->gui, ViewDispatcherTypeFullscreen);
  99. scene_manager_next_scene(mag->scene_manager, MagSceneStart);
  100. view_dispatcher_run(mag->view_dispatcher);
  101. mag_free(mag);
  102. return 0;
  103. }
  104. bool mag_save_key(Mag* mag) {
  105. furi_assert(mag);
  106. bool result = false;
  107. mag_make_app_folder(mag);
  108. if(furi_string_end_with(mag->file_path, MAG_APP_EXTENSION)) {
  109. size_t filename_start = furi_string_search_rchar(mag->file_path, '/');
  110. furi_string_left(mag->file_path, filename_start);
  111. }
  112. furi_string_cat_printf(
  113. mag->file_path, "/%s%s", furi_string_get_cstr(mag->file_name), MAG_APP_EXTENSION);
  114. result = mag_save_key_data(mag, mag->file_path);
  115. return result;
  116. }
  117. bool mag_load_key_from_file_select(Mag* mag) {
  118. furi_assert(mag);
  119. DialogsFileBrowserOptions browser_options;
  120. dialog_file_browser_set_basic_options(&browser_options, MAG_APP_EXTENSION, &I_mag_10px);
  121. browser_options.base_path = MAG_APP_FOLDER;
  122. // Input events and views are managed by file_browser
  123. bool result =
  124. dialog_file_browser_show(mag->dialogs, mag->file_path, mag->file_path, &browser_options);
  125. if(result) {
  126. result = mag_load_key_data(mag, mag->file_path, true);
  127. }
  128. return result;
  129. }
  130. bool mag_delete_key(Mag* mag) {
  131. furi_assert(mag);
  132. return storage_simply_remove(mag->storage, furi_string_get_cstr(mag->file_path));
  133. }
  134. bool mag_load_key_data(Mag* mag, FuriString* path, bool show_dialog) {
  135. bool result = false;
  136. UNUSED(mag);
  137. UNUSED(path);
  138. UNUSED(show_dialog);
  139. // TODO: Needs reworking from LFRFID version, as that goes through some custom protocol by key type.
  140. // Alternatively, co-opt the "protocol" typing as our way of encoding track # (Track 1, 2, 3, or some combination thereof)
  141. return result;
  142. }
  143. bool mag_save_key_data(Mag* mag, FuriString* path) {
  144. bool result = false;
  145. UNUSED(path);
  146. //bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, furi_string_get_cstr(path));
  147. // TODO: needs reworking from LFRFID version
  148. if(!result) {
  149. dialog_message_show_storage_error(mag->dialogs, "Cannot save\nkey file");
  150. }
  151. return result;
  152. }
  153. void mag_make_app_folder(Mag* mag) {
  154. furi_assert(mag);
  155. if(!storage_simply_mkdir(mag->storage, MAG_APP_FOLDER)) {
  156. dialog_message_show_storage_error(mag->dialogs, "Cannot create\napp folder");
  157. }
  158. }
  159. void mag_text_store_set(Mag* mag, const char* text, ...) {
  160. furi_assert(mag);
  161. va_list args;
  162. va_start(args, text);
  163. vsnprintf(mag->text_store, MAG_TEXT_STORE_SIZE, text, args);
  164. va_end(args);
  165. }
  166. void mag_text_store_clear(Mag* mag) {
  167. furi_assert(mag);
  168. memset(mag->text_store, 0, sizeof(mag->text_store));
  169. }
  170. void mag_popup_timeout_callback(void* context) {
  171. Mag* mag = context;
  172. view_dispatcher_send_custom_event(mag->view_dispatcher, MagEventPopupClosed);
  173. }
  174. void mag_widget_callback(GuiButtonType result, InputType type, void* context) {
  175. Mag* mag = context;
  176. if(type == InputTypeShort) {
  177. view_dispatcher_send_custom_event(mag->view_dispatcher, result);
  178. }
  179. }
  180. void mag_text_input_callback(void* context) {
  181. Mag* mag = context;
  182. view_dispatcher_send_custom_event(mag->view_dispatcher, MagEventNext);
  183. }
  184. void mag_show_loading_popup(void* context, bool show) {
  185. Mag* mag = context;
  186. TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
  187. if(show) {
  188. // Raise timer priority so that animations can play
  189. vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
  190. view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewLoading);
  191. } else {
  192. // Restore default timer priority
  193. vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
  194. }
  195. }