Просмотр исходного кода

[FL-2753] RFID app port to plain C (#1710)

* LF RFID: port to plain C
* LFRFID debug port to C, new reading screen
* LFRFID debug: fix pvs-studio warnings
* RFID read view: remove unused input callback
* RFID read view: animation update
Nikolay Minaylov 3 лет назад
Родитель
Сommit
0f6f9ad52e
100 измененных файлов с 2304 добавлено и 2641 удалено
  1. 3 1
      applications/gui/modules/validators.c
  2. 316 0
      applications/lfrfid/lfrfid.c
  3. 0 218
      applications/lfrfid/lfrfid_app.cpp
  4. 0 137
      applications/lfrfid/lfrfid_app.h
  5. 0 10
      applications/lfrfid/lfrfid_app_launcher.cpp
  6. 1 1
      applications/lfrfid/lfrfid_cli.c
  7. 145 0
      applications/lfrfid/lfrfid_i.h
  8. 0 88
      applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp
  9. 0 16
      applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h
  10. 0 38
      applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp
  11. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_delete_success.h
  12. 0 36
      applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp
  13. 0 9
      applications/lfrfid/scene/lfrfid_app_scene_emulate.h
  14. 0 59
      applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp
  15. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h
  16. 0 63
      applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp
  17. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h
  18. 0 77
      applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp
  19. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_raw_info.h
  20. 0 46
      applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp
  21. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_raw_name.h
  22. 0 107
      applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp
  23. 0 15
      applications/lfrfid/scene/lfrfid_app_scene_raw_read.h
  24. 0 45
      applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp
  25. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_raw_success.h
  26. 0 100
      applications/lfrfid/scene/lfrfid_app_scene_read.cpp
  27. 0 9
      applications/lfrfid/scene/lfrfid_app_scene_read.h
  28. 0 60
      applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp
  29. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_read_menu.h
  30. 0 96
      applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp
  31. 0 16
      applications/lfrfid/scene/lfrfid_app_scene_read_success.h
  32. 0 59
      applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp
  33. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h
  34. 0 66
      applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp
  35. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_rpc.h
  36. 0 45
      applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp
  37. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_save_data.h
  38. 0 72
      applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp
  39. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_save_name.h
  40. 0 50
      applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp
  41. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_save_success.h
  42. 0 53
      applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp
  43. 0 15
      applications/lfrfid/scene/lfrfid_app_scene_save_type.h
  44. 0 48
      applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp
  45. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_saved_info.h
  46. 0 67
      applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp
  47. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h
  48. 0 16
      applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp
  49. 0 9
      applications/lfrfid/scene/lfrfid_app_scene_select_key.h
  50. 0 67
      applications/lfrfid/scene/lfrfid_app_scene_start.cpp
  51. 0 13
      applications/lfrfid/scene/lfrfid_app_scene_start.h
  52. 0 88
      applications/lfrfid/scene/lfrfid_app_scene_write.cpp
  53. 0 9
      applications/lfrfid/scene/lfrfid_app_scene_write.h
  54. 0 38
      applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp
  55. 0 12
      applications/lfrfid/scene/lfrfid_app_scene_write_success.h
  56. 30 0
      applications/lfrfid/scenes/lfrfid_scene.c
  57. 29 0
      applications/lfrfid/scenes/lfrfid_scene.h
  58. 24 0
      applications/lfrfid/scenes/lfrfid_scene_config.h
  59. 68 0
      applications/lfrfid/scenes/lfrfid_scene_delete_confirm.c
  60. 35 0
      applications/lfrfid/scenes/lfrfid_scene_delete_success.c
  61. 44 0
      applications/lfrfid/scenes/lfrfid_scene_emulate.c
  62. 39 0
      applications/lfrfid/scenes/lfrfid_scene_exit_confirm.c
  63. 79 0
      applications/lfrfid/scenes/lfrfid_scene_extra_actions.c
  64. 64 0
      applications/lfrfid/scenes/lfrfid_scene_raw_info.c
  65. 58 0
      applications/lfrfid/scenes/lfrfid_scene_raw_name.c
  66. 126 0
      applications/lfrfid/scenes/lfrfid_scene_raw_read.c
  67. 39 0
      applications/lfrfid/scenes/lfrfid_scene_raw_success.c
  68. 109 0
      applications/lfrfid/scenes/lfrfid_scene_read.c
  69. 58 0
      applications/lfrfid/scenes/lfrfid_scene_read_key_menu.c
  70. 79 0
      applications/lfrfid/scenes/lfrfid_scene_read_success.c
  71. 39 0
      applications/lfrfid/scenes/lfrfid_scene_retry_confirm.c
  72. 67 0
      applications/lfrfid/scenes/lfrfid_scene_rpc.c
  73. 51 0
      applications/lfrfid/scenes/lfrfid_scene_save_data.c
  74. 76 0
      applications/lfrfid/scenes/lfrfid_scene_save_name.c
  75. 43 0
      applications/lfrfid/scenes/lfrfid_scene_save_success.c
  76. 86 0
      applications/lfrfid/scenes/lfrfid_scene_save_type.c
  77. 51 0
      applications/lfrfid/scenes/lfrfid_scene_saved_info.c
  78. 69 0
      applications/lfrfid/scenes/lfrfid_scene_saved_key_menu.c
  79. 22 0
      applications/lfrfid/scenes/lfrfid_scene_select_key.c
  80. 72 0
      applications/lfrfid/scenes/lfrfid_scene_start.c
  81. 96 0
      applications/lfrfid/scenes/lfrfid_scene_write.c
  82. 38 0
      applications/lfrfid/scenes/lfrfid_scene_write_success.c
  83. 0 115
      applications/lfrfid/view/container_vm.cpp
  84. 0 17
      applications/lfrfid/view/container_vm.h
  85. 0 65
      applications/lfrfid/view/elements/button_element.cpp
  86. 0 28
      applications/lfrfid/view/elements/button_element.h
  87. 0 15
      applications/lfrfid/view/elements/generic_element.cpp
  88. 0 21
      applications/lfrfid/view/elements/generic_element.h
  89. 0 25
      applications/lfrfid/view/elements/icon_element.cpp
  90. 0 17
      applications/lfrfid/view/elements/icon_element.h
  91. 0 47
      applications/lfrfid/view/elements/string_element.cpp
  92. 0 28
      applications/lfrfid/view/elements/string_element.h
  93. 117 0
      applications/lfrfid/views/lfrfid_view_read.c
  94. 19 0
      applications/lfrfid/views/lfrfid_view_read.h
  95. 81 0
      applications/lfrfid_debug/lfrfid_debug.c
  96. 0 17
      applications/lfrfid_debug/lfrfid_debug_app.cpp
  97. 0 40
      applications/lfrfid_debug/lfrfid_debug_app.h
  98. 0 11
      applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp
  99. 31 0
      applications/lfrfid_debug/lfrfid_debug_i.h
  100. 0 47
      applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp

+ 3 - 1
applications/gui/modules/validators.c

@@ -42,7 +42,9 @@ ValidatorIsFile* validator_is_file_alloc_init(
 
     instance->app_path_folder = strdup(app_path_folder);
     instance->app_extension = app_extension;
-    instance->current_name = strdup(current_name);
+    if(current_name != NULL) {
+        instance->current_name = strdup(current_name);
+    }
 
     return instance;
 }

+ 316 - 0
applications/lfrfid/lfrfid.c

@@ -0,0 +1,316 @@
+#include "lfrfid_i.h"
+
+static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    LfRfid* app = context;
+    return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+static bool lfrfid_debug_back_event_callback(void* context) {
+    furi_assert(context);
+    LfRfid* app = context;
+    return scene_manager_handle_back_event(app->scene_manager);
+}
+
+static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
+    furi_assert(context);
+    LfRfid* app = (LfRfid*)context;
+
+    if(rpc_event == RpcAppEventSessionClose) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcSessionClose);
+        // Detach RPC
+        rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
+        app->rpc_ctx = NULL;
+    } else if(rpc_event == RpcAppEventAppExit) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventExit);
+    } else if(rpc_event == RpcAppEventLoadFile) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventRpcLoadFile);
+    } else {
+        rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
+    }
+}
+
+static LfRfid* lfrfid_alloc() {
+    LfRfid* lfrfid = malloc(sizeof(LfRfid));
+
+    lfrfid->storage = furi_record_open(RECORD_STORAGE);
+    lfrfid->dialogs = furi_record_open(RECORD_DIALOGS);
+
+    string_init(lfrfid->file_name);
+    string_init(lfrfid->raw_file_name);
+    string_init_set_str(lfrfid->file_path, LFRFID_APP_FOLDER);
+
+    lfrfid->dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
+
+    size_t size = protocol_dict_get_max_data_size(lfrfid->dict);
+    lfrfid->new_key_data = (uint8_t*)malloc(size);
+    lfrfid->old_key_data = (uint8_t*)malloc(size);
+
+    lfrfid->lfworker = lfrfid_worker_alloc(lfrfid->dict);
+
+    lfrfid->view_dispatcher = view_dispatcher_alloc();
+    lfrfid->scene_manager = scene_manager_alloc(&lfrfid_scene_handlers, lfrfid);
+    view_dispatcher_enable_queue(lfrfid->view_dispatcher);
+    view_dispatcher_set_event_callback_context(lfrfid->view_dispatcher, lfrfid);
+    view_dispatcher_set_custom_event_callback(
+        lfrfid->view_dispatcher, lfrfid_debug_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(
+        lfrfid->view_dispatcher, lfrfid_debug_back_event_callback);
+
+    // Open GUI record
+    lfrfid->gui = furi_record_open(RECORD_GUI);
+
+    // Open Notification record
+    lfrfid->notifications = furi_record_open(RECORD_NOTIFICATION);
+
+    // Submenu
+    lfrfid->submenu = submenu_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewSubmenu, submenu_get_view(lfrfid->submenu));
+
+    // Dialog
+    lfrfid->dialog_ex = dialog_ex_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewDialogEx, dialog_ex_get_view(lfrfid->dialog_ex));
+
+    // Popup
+    lfrfid->popup = popup_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewPopup, popup_get_view(lfrfid->popup));
+
+    // Widget
+    lfrfid->widget = widget_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewWidget, widget_get_view(lfrfid->widget));
+
+    // Text Input
+    lfrfid->text_input = text_input_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewTextInput, text_input_get_view(lfrfid->text_input));
+
+    // Byte Input
+    lfrfid->byte_input = byte_input_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewByteInput, byte_input_get_view(lfrfid->byte_input));
+
+    // Read custom view
+    lfrfid->read_view = lfrfid_view_read_alloc();
+    view_dispatcher_add_view(
+        lfrfid->view_dispatcher, LfRfidViewRead, lfrfid_view_read_get_view(lfrfid->read_view));
+
+    return lfrfid;
+}
+
+static void lfrfid_free(LfRfid* lfrfid) {
+    furi_assert(lfrfid);
+
+    string_clear(lfrfid->raw_file_name);
+    string_clear(lfrfid->file_name);
+    string_clear(lfrfid->file_path);
+    protocol_dict_free(lfrfid->dict);
+
+    lfrfid_worker_free(lfrfid->lfworker);
+
+    if(lfrfid->rpc_ctx) {
+        rpc_system_app_set_callback(lfrfid->rpc_ctx, NULL, NULL);
+        rpc_system_app_send_exited(lfrfid->rpc_ctx);
+    }
+
+    free(lfrfid->new_key_data);
+    free(lfrfid->old_key_data);
+
+    // Submenu
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewSubmenu);
+    submenu_free(lfrfid->submenu);
+
+    // DialogEx
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewDialogEx);
+    dialog_ex_free(lfrfid->dialog_ex);
+
+    // Popup
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewPopup);
+    popup_free(lfrfid->popup);
+
+    // Widget
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewWidget);
+    widget_free(lfrfid->widget);
+
+    // TextInput
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewTextInput);
+    text_input_free(lfrfid->text_input);
+
+    // ByteInput
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewByteInput);
+    byte_input_free(lfrfid->byte_input);
+
+    // Read custom view
+    view_dispatcher_remove_view(lfrfid->view_dispatcher, LfRfidViewRead);
+    lfrfid_view_read_free(lfrfid->read_view);
+
+    // View Dispatcher
+    view_dispatcher_free(lfrfid->view_dispatcher);
+
+    // Scene Manager
+    scene_manager_free(lfrfid->scene_manager);
+
+    // GUI
+    furi_record_close(RECORD_GUI);
+    lfrfid->gui = NULL;
+
+    // Notifications
+    furi_record_close(RECORD_NOTIFICATION);
+    lfrfid->notifications = NULL;
+
+    furi_record_close(RECORD_STORAGE);
+    furi_record_close(RECORD_DIALOGS);
+
+    free(lfrfid);
+}
+
+int32_t lfrfid_app(void* p) {
+    LfRfid* app = lfrfid_alloc();
+    char* args = p;
+
+    lfrfid_make_app_folder(app);
+
+    if(args && strlen(args)) {
+        uint32_t rpc_ctx_ptr = 0;
+        if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
+            app->rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
+            rpc_system_app_set_callback(app->rpc_ctx, rpc_command_callback, app);
+            rpc_system_app_send_started(app->rpc_ctx);
+            view_dispatcher_attach_to_gui(
+                app->view_dispatcher, app->gui, ViewDispatcherTypeDesktop);
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneRpc);
+        } else {
+            string_set_str(app->file_path, args);
+            lfrfid_load_key_data(app, app->file_path, true);
+            view_dispatcher_attach_to_gui(
+                app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
+        }
+
+    } else {
+        view_dispatcher_attach_to_gui(
+            app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+        scene_manager_next_scene(app->scene_manager, LfRfidSceneStart);
+    }
+
+    view_dispatcher_run(app->view_dispatcher);
+
+    lfrfid_free(app);
+
+    return 0;
+}
+
+bool lfrfid_save_key(LfRfid* app) {
+    furi_assert(app);
+
+    bool result = false;
+
+    lfrfid_make_app_folder(app);
+
+    if(string_end_with_str_p(app->file_path, LFRFID_APP_EXTENSION)) {
+        size_t filename_start = string_search_rchar(app->file_path, '/');
+        string_left(app->file_path, filename_start);
+    }
+
+    string_cat_printf(
+        app->file_path, "/%s%s", string_get_cstr(app->file_name), LFRFID_APP_EXTENSION);
+
+    result = lfrfid_save_key_data(app, app->file_path);
+    return result;
+}
+
+bool lfrfid_load_key_from_file_select(LfRfid* app) {
+    furi_assert(app);
+
+    bool result = dialog_file_browser_show(
+        app->dialogs,
+        app->file_path,
+        app->file_path,
+        LFRFID_APP_EXTENSION,
+        true,
+        &I_125_10px,
+        true);
+
+    if(result) {
+        result = lfrfid_load_key_data(app, app->file_path, true);
+    }
+
+    return result;
+}
+
+bool lfrfid_delete_key(LfRfid* app) {
+    furi_assert(app);
+
+    return storage_simply_remove(app->storage, string_get_cstr(app->file_path));
+}
+
+bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog) {
+    bool result = false;
+
+    do {
+        app->protocol_id = lfrfid_dict_file_load(app->dict, string_get_cstr(path));
+        if(app->protocol_id == PROTOCOL_NO) break;
+
+        path_extract_filename(path, app->file_name, true);
+        result = true;
+    } while(0);
+
+    if((!result) && (show_dialog)) {
+        dialog_message_show_storage_error(app->dialogs, "Cannot load\nkey file");
+    }
+
+    return result;
+}
+
+bool lfrfid_save_key_data(LfRfid* app, string_t path) {
+    bool result = lfrfid_dict_file_save(app->dict, app->protocol_id, string_get_cstr(path));
+
+    if(!result) {
+        dialog_message_show_storage_error(app->dialogs, "Cannot save\nkey file");
+    }
+
+    return result;
+}
+
+void lfrfid_make_app_folder(LfRfid* app) {
+    furi_assert(app);
+
+    if(!storage_simply_mkdir(app->storage, LFRFID_APP_FOLDER)) {
+        dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
+    }
+}
+
+void lfrfid_text_store_set(LfRfid* app, const char* text, ...) {
+    furi_assert(app);
+    va_list args;
+    va_start(args, text);
+
+    vsnprintf(app->text_store, LFRFID_TEXT_STORE_SIZE, text, args);
+
+    va_end(args);
+}
+
+void lfrfid_text_store_clear(LfRfid* app) {
+    furi_assert(app);
+    memset(app->text_store, 0, sizeof(app->text_store));
+}
+
+void lfrfid_popup_timeout_callback(void* context) {
+    LfRfid* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventPopupClosed);
+}
+
+void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context) {
+    LfRfid* app = context;
+    if(type == InputTypeShort) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, result);
+    }
+}
+
+void lfrfid_text_input_callback(void* context) {
+    LfRfid* app = context;
+    view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventNext);
+}

+ 0 - 218
applications/lfrfid/lfrfid_app.cpp

@@ -1,218 +0,0 @@
-#include "lfrfid_app.h"
-#include "assets_icons.h"
-#include <core/common_defines.h>
-#include "m-string.h"
-#include "scene/lfrfid_app_scene_start.h"
-#include "scene/lfrfid_app_scene_read.h"
-#include "scene/lfrfid_app_scene_read_success.h"
-#include "scene/lfrfid_app_scene_retry_confirm.h"
-#include "scene/lfrfid_app_scene_exit_confirm.h"
-#include "scene/lfrfid_app_scene_read_menu.h"
-#include "scene/lfrfid_app_scene_write.h"
-#include "scene/lfrfid_app_scene_write_success.h"
-#include "scene/lfrfid_app_scene_emulate.h"
-#include "scene/lfrfid_app_scene_save_name.h"
-#include "scene/lfrfid_app_scene_save_success.h"
-#include "scene/lfrfid_app_scene_select_key.h"
-#include "scene/lfrfid_app_scene_saved_key_menu.h"
-#include "scene/lfrfid_app_scene_save_data.h"
-#include "scene/lfrfid_app_scene_save_type.h"
-#include "scene/lfrfid_app_scene_saved_info.h"
-#include "scene/lfrfid_app_scene_delete_confirm.h"
-#include "scene/lfrfid_app_scene_delete_success.h"
-#include "scene/lfrfid_app_scene_rpc.h"
-#include "scene/lfrfid_app_scene_extra_actions.h"
-#include "scene/lfrfid_app_scene_raw_info.h"
-#include "scene/lfrfid_app_scene_raw_name.h"
-#include "scene/lfrfid_app_scene_raw_read.h"
-#include "scene/lfrfid_app_scene_raw_success.h"
-
-#include <toolbox/path.h>
-#include <flipper_format/flipper_format.h>
-
-#include <rpc/rpc_app.h>
-
-const char* LfRfidApp::app_folder = ANY_PATH("lfrfid");
-const char* LfRfidApp::app_sd_folder = EXT_PATH("lfrfid");
-const char* LfRfidApp::app_extension = ".rfid";
-const char* LfRfidApp::app_filetype = "Flipper RFID key";
-
-LfRfidApp::LfRfidApp()
-    : scene_controller{this}
-    , notification{RECORD_NOTIFICATION}
-    , storage{RECORD_STORAGE}
-    , dialogs{RECORD_DIALOGS}
-    , text_store(40) {
-    string_init(file_name);
-    string_init(raw_file_name);
-    string_init_set_str(file_path, app_folder);
-
-    dict = protocol_dict_alloc(lfrfid_protocols, LFRFIDProtocolMax);
-
-    size_t size = protocol_dict_get_max_data_size(dict);
-    new_key_data = (uint8_t*)malloc(size);
-    old_key_data = (uint8_t*)malloc(size);
-
-    lfworker = lfrfid_worker_alloc(dict);
-}
-
-LfRfidApp::~LfRfidApp() {
-    string_clear(raw_file_name);
-    string_clear(file_name);
-    string_clear(file_path);
-    protocol_dict_free(dict);
-
-    lfrfid_worker_free(lfworker);
-
-    if(rpc_ctx) {
-        rpc_system_app_set_callback(rpc_ctx, NULL, NULL);
-        rpc_system_app_send_exited(rpc_ctx);
-    }
-
-    free(new_key_data);
-    free(old_key_data);
-}
-
-static void rpc_command_callback(RpcAppSystemEvent rpc_event, void* context) {
-    furi_assert(context);
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-
-    if(rpc_event == RpcAppEventSessionClose) {
-        LfRfidApp::Event event;
-        event.type = LfRfidApp::EventType::RpcSessionClose;
-        app->view_controller.send_event(&event);
-        // Detach RPC
-        rpc_system_app_set_callback(app->rpc_ctx, NULL, NULL);
-        app->rpc_ctx = NULL;
-    } else if(rpc_event == RpcAppEventAppExit) {
-        LfRfidApp::Event event;
-        event.type = LfRfidApp::EventType::Exit;
-        app->view_controller.send_event(&event);
-    } else if(rpc_event == RpcAppEventLoadFile) {
-        LfRfidApp::Event event;
-        event.type = LfRfidApp::EventType::RpcLoadFile;
-        app->view_controller.send_event(&event);
-    } else {
-        rpc_system_app_confirm(app->rpc_ctx, rpc_event, false);
-    }
-}
-
-void LfRfidApp::run(void* _args) {
-    const char* args = reinterpret_cast<const char*>(_args);
-
-    make_app_folder();
-
-    if(args && strlen(args)) {
-        uint32_t rpc_ctx_ptr = 0;
-        if(sscanf(args, "RPC %lX", &rpc_ctx_ptr) == 1) {
-            rpc_ctx = (RpcAppSystem*)rpc_ctx_ptr;
-            rpc_system_app_set_callback(rpc_ctx, rpc_command_callback, this);
-            rpc_system_app_send_started(rpc_ctx);
-            view_controller.attach_to_gui(ViewDispatcherTypeDesktop);
-            scene_controller.add_scene(SceneType::Rpc, new LfRfidAppSceneRpc());
-            scene_controller.process(100, SceneType::Rpc);
-        } else {
-            string_set_str(file_path, args);
-            load_key_data(file_path, true);
-            view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
-            scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
-            scene_controller.process(100, SceneType::Emulate);
-        }
-
-    } else {
-        view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
-        scene_controller.add_scene(SceneType::Start, new LfRfidAppSceneStart());
-        scene_controller.add_scene(SceneType::Read, new LfRfidAppSceneRead());
-        scene_controller.add_scene(SceneType::RetryConfirm, new LfRfidAppSceneRetryConfirm());
-        scene_controller.add_scene(SceneType::ExitConfirm, new LfRfidAppSceneExitConfirm());
-        scene_controller.add_scene(SceneType::ReadSuccess, new LfRfidAppSceneReadSuccess());
-        scene_controller.add_scene(SceneType::ReadKeyMenu, new LfRfidAppSceneReadKeyMenu());
-        scene_controller.add_scene(SceneType::Write, new LfRfidAppSceneWrite());
-        scene_controller.add_scene(SceneType::WriteSuccess, new LfRfidAppSceneWriteSuccess());
-        scene_controller.add_scene(SceneType::Emulate, new LfRfidAppSceneEmulate());
-        scene_controller.add_scene(SceneType::SaveName, new LfRfidAppSceneSaveName());
-        scene_controller.add_scene(SceneType::SaveSuccess, new LfRfidAppSceneSaveSuccess());
-        scene_controller.add_scene(SceneType::SelectKey, new LfRfidAppSceneSelectKey());
-        scene_controller.add_scene(SceneType::SavedKeyMenu, new LfRfidAppSceneSavedKeyMenu());
-        scene_controller.add_scene(SceneType::SaveData, new LfRfidAppSceneSaveData());
-        scene_controller.add_scene(SceneType::SaveType, new LfRfidAppSceneSaveType());
-        scene_controller.add_scene(SceneType::SavedInfo, new LfRfidAppSceneSavedInfo());
-        scene_controller.add_scene(SceneType::DeleteConfirm, new LfRfidAppSceneDeleteConfirm());
-        scene_controller.add_scene(SceneType::DeleteSuccess, new LfRfidAppSceneDeleteSuccess());
-        scene_controller.add_scene(SceneType::ExtraActions, new LfRfidAppSceneExtraActions());
-        scene_controller.add_scene(SceneType::RawInfo, new LfRfidAppSceneRawInfo());
-        scene_controller.add_scene(SceneType::RawName, new LfRfidAppSceneRawName());
-        scene_controller.add_scene(SceneType::RawRead, new LfRfidAppSceneRawRead());
-        scene_controller.add_scene(SceneType::RawSuccess, new LfRfidAppSceneRawSuccess());
-        scene_controller.process(100);
-    }
-}
-
-bool LfRfidApp::save_key() {
-    bool result = false;
-
-    make_app_folder();
-
-    if(string_end_with_str_p(file_path, app_extension)) {
-        size_t filename_start = string_search_rchar(file_path, '/');
-        string_left(file_path, filename_start);
-    }
-
-    string_cat_printf(file_path, "/%s%s", string_get_cstr(file_name), app_extension);
-
-    result = save_key_data(file_path);
-    return result;
-}
-
-bool LfRfidApp::load_key_from_file_select(bool need_restore) {
-    if(!need_restore) {
-        string_set_str(file_path, app_folder);
-    }
-
-    bool result = dialog_file_browser_show(
-        dialogs, file_path, file_path, app_extension, true, &I_125_10px, true);
-
-    if(result) {
-        result = load_key_data(file_path, true);
-    }
-
-    return result;
-}
-
-bool LfRfidApp::delete_key() {
-    return storage_simply_remove(storage, string_get_cstr(file_path));
-}
-
-bool LfRfidApp::load_key_data(string_t path, bool show_dialog) {
-    bool result = false;
-
-    do {
-        protocol_id = lfrfid_dict_file_load(dict, string_get_cstr(path));
-        if(protocol_id == PROTOCOL_NO) break;
-
-        path_extract_filename(path, file_name, true);
-        result = true;
-    } while(0);
-
-    if((!result) && (show_dialog)) {
-        dialog_message_show_storage_error(dialogs, "Cannot load\nkey file");
-    }
-
-    return result;
-}
-
-bool LfRfidApp::save_key_data(string_t path) {
-    bool result = lfrfid_dict_file_save(dict, protocol_id, string_get_cstr(path));
-
-    if(!result) {
-        dialog_message_show_storage_error(dialogs, "Cannot save\nkey file");
-    }
-
-    return result;
-}
-
-void LfRfidApp::make_app_folder() {
-    if(!storage_simply_mkdir(storage, app_folder)) {
-        dialog_message_show_storage_error(dialogs, "Cannot create\napp folder");
-    }
-}

+ 0 - 137
applications/lfrfid/lfrfid_app.h

@@ -1,137 +0,0 @@
-#pragma once
-#include "m-string.h"
-#include <furi.h>
-#include <furi_hal.h>
-
-#include <generic_scene.hpp>
-#include <scene_controller.hpp>
-#include <view_controller.hpp>
-#include <record_controller.hpp>
-#include <text_store.h>
-
-#include <view_modules/submenu_vm.h>
-#include <view_modules/popup_vm.h>
-#include <view_modules/dialog_ex_vm.h>
-#include <view_modules/text_input_vm.h>
-#include <view_modules/byte_input_vm.h>
-#include "view/container_vm.h"
-
-#include <notification/notification_messages.h>
-#include <storage/storage.h>
-#include <dialogs/dialogs.h>
-
-#include "rpc/rpc_app.h"
-
-#include <toolbox/protocols/protocol_dict.h>
-#include <lfrfid/lfrfid_dict_file.h>
-#include <lfrfid/protocols/lfrfid_protocols.h>
-#include <lfrfid/lfrfid_worker.h>
-
-#define LFRFID_KEY_NAME_SIZE 22
-
-class LfRfidApp {
-public:
-    enum class EventType : uint8_t {
-        GENERIC_EVENT_ENUM_VALUES,
-        Next,
-        MenuSelected,
-        Stay,
-        Retry,
-        Exit,
-        ReadEventSenseStart,
-        ReadEventSenseEnd,
-        ReadEventSenseCardStart,
-        ReadEventSenseCardEnd,
-        ReadEventStartASK,
-        ReadEventStartPSK,
-        ReadEventDone,
-        ReadEventOverrun,
-        ReadEventError,
-        WriteEventOK,
-        WriteEventProtocolCannotBeWritten,
-        WriteEventFobCannotBeWritten,
-        WriteEventTooLongToWrite,
-        RpcLoadFile,
-        RpcSessionClose,
-    };
-
-    enum class SceneType : uint8_t {
-        GENERIC_SCENE_ENUM_VALUES,
-        Read,
-        ReadSuccess,
-        RetryConfirm,
-        ExitConfirm,
-        ReadKeyMenu,
-        Write,
-        WriteSuccess,
-        Emulate,
-        SaveName,
-        SaveSuccess,
-        SelectKey,
-        SavedKeyMenu,
-        SaveData,
-        SaveType,
-        SavedInfo,
-        DeleteConfirm,
-        DeleteSuccess,
-        Rpc,
-        ExtraActions,
-        RawInfo,
-        RawName,
-        RawRead,
-        RawSuccess,
-    };
-
-    class Event {
-    public:
-        union {
-            int32_t signed_int;
-        } payload;
-
-        EventType type;
-    };
-
-    SceneController<GenericScene<LfRfidApp>, LfRfidApp> scene_controller;
-    ViewController<LfRfidApp, SubmenuVM, PopupVM, DialogExVM, TextInputVM, ByteInputVM, ContainerVM>
-        view_controller;
-
-    ~LfRfidApp();
-    LfRfidApp();
-
-    RecordController<NotificationApp> notification;
-    RecordController<Storage> storage;
-    RecordController<DialogsApp> dialogs;
-
-    TextStore text_store;
-
-    string_t file_path;
-
-    RpcAppSystem* rpc_ctx;
-
-    void run(void* args);
-
-    static const char* app_folder;
-    static const char* app_sd_folder;
-    static const char* app_extension;
-    static const char* app_filetype;
-
-    bool save_key();
-    bool load_key_from_file_select(bool need_restore);
-    bool delete_key();
-
-    bool load_key_data(string_t path, bool show_dialog);
-    bool save_key_data(string_t path);
-
-    void make_app_folder();
-
-    ProtocolDict* dict;
-    LFRFIDWorker* lfworker;
-    string_t file_name;
-    ProtocolId protocol_id;
-    LFRFIDWorkerReadType read_type;
-
-    uint8_t* old_key_data;
-    uint8_t* new_key_data;
-
-    string_t raw_file_name;
-};

+ 0 - 10
applications/lfrfid/lfrfid_app_launcher.cpp

@@ -1,10 +0,0 @@
-#include "lfrfid_app.h"
-
-// app enter function
-extern "C" int32_t lfrfid_app(void* args) {
-    LfRfidApp* app = new LfRfidApp();
-    app->run(args);
-    delete app;
-
-    return 0;
-}

+ 1 - 1
applications/lfrfid/lfrfid_cli.c

@@ -114,7 +114,7 @@ static void lfrfid_cli_read(Cli* cli, string_t args) {
         string_t info;
         string_init(info);
         protocol_dict_render_data(dict, info, context.protocol);
-        if(string_size(info) > 0) {
+        if(!string_empty_p(info)) {
             printf("%s\r\n", string_get_cstr(info));
         }
         string_clear(info);

+ 145 - 0
applications/lfrfid/lfrfid_i.h

@@ -0,0 +1,145 @@
+#pragma once
+
+#include "m-string.h"
+
+#include <furi.h>
+#include <furi_hal.h>
+
+#include <gui/gui.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+#include <cli/cli.h>
+#include <notification/notification_messages.h>
+
+#include <gui/modules/submenu.h>
+#include <gui/modules/dialog_ex.h>
+#include <gui/modules/popup.h>
+#include <gui/modules/text_input.h>
+#include <gui/modules/byte_input.h>
+#include <gui/modules/widget.h>
+
+#include <lfrfid/views/lfrfid_view_read.h>
+
+#include <notification/notification_messages.h>
+#include <dialogs/dialogs.h>
+#include <storage/storage.h>
+#include <flipper_format/flipper_format.h>
+
+#include <rpc/rpc_app.h>
+
+#include <toolbox/protocols/protocol_dict.h>
+#include <toolbox/path.h>
+#include <lfrfid/lfrfid_dict_file.h>
+#include <lfrfid/protocols/lfrfid_protocols.h>
+#include <lfrfid/lfrfid_worker.h>
+
+#include <lfrfid/scenes/lfrfid_scene.h>
+
+#define LFRFID_KEY_NAME_SIZE 22
+#define LFRFID_TEXT_STORE_SIZE 40
+
+#define LFRFID_APP_FOLDER ANY_PATH("lfrfid")
+#define LFRFID_SD_FOLDER EXT_PATH("lfrfid")
+#define LFRFID_APP_EXTENSION ".rfid"
+#define LFRFID_APP_SHADOW_EXTENSION ".shd"
+
+#define LFRFID_APP_RAW_ASK_EXTENSION ".ask.raw"
+#define LFRFID_APP_RAW_PSK_EXTENSION ".psk.raw"
+
+enum LfRfidCustomEvent {
+    LfRfidEventNext = 100,
+    LfRfidEventExit,
+    LfRfidEventPopupClosed,
+    LfRfidEventReadSenseStart,
+    LfRfidEventReadSenseEnd,
+    LfRfidEventReadSenseCardStart,
+    LfRfidEventReadSenseCardEnd,
+    LfRfidEventReadStartASK,
+    LfRfidEventReadStartPSK,
+    LfRfidEventReadDone,
+    LfRfidEventReadOverrun,
+    LfRfidEventReadError,
+    LfRfidEventWriteOK,
+    LfRfidEventWriteProtocolCannotBeWritten,
+    LfRfidEventWriteFobCannotBeWritten,
+    LfRfidEventWriteTooLongToWrite,
+    LfRfidEventRpcLoadFile,
+    LfRfidEventRpcSessionClose,
+};
+
+typedef enum {
+    LfRfidRpcStateIdle,
+    LfRfidRpcStateEmulating,
+} LfRfidRpcState;
+
+typedef struct LfRfid LfRfid;
+
+struct LfRfid {
+    LFRFIDWorker* lfworker;
+    ViewDispatcher* view_dispatcher;
+    Gui* gui;
+    NotificationApp* notifications;
+    SceneManager* scene_manager;
+    Storage* storage;
+    DialogsApp* dialogs;
+    Widget* widget;
+
+    char text_store[LFRFID_TEXT_STORE_SIZE + 1];
+    string_t file_path;
+    string_t file_name;
+    string_t raw_file_name;
+
+    ProtocolDict* dict;
+    ProtocolId protocol_id;
+    ProtocolId protocol_id_next;
+    LFRFIDWorkerReadType read_type;
+
+    uint8_t* old_key_data;
+    uint8_t* new_key_data;
+
+    RpcAppSystem* rpc_ctx;
+    LfRfidRpcState rpc_state;
+
+    // Common Views
+    Submenu* submenu;
+    DialogEx* dialog_ex;
+    Popup* popup;
+    TextInput* text_input;
+    ByteInput* byte_input;
+
+    // Custom views
+    LfRfidReadView* read_view;
+};
+
+typedef enum {
+    LfRfidViewSubmenu,
+    LfRfidViewDialogEx,
+    LfRfidViewPopup,
+    LfRfidViewWidget,
+    LfRfidViewTextInput,
+    LfRfidViewByteInput,
+    LfRfidViewRead,
+} LfRfidView;
+
+bool lfrfid_save_key(LfRfid* app);
+
+bool lfrfid_load_key_from_file_select(LfRfid* app);
+
+bool lfrfid_delete_key(LfRfid* app);
+
+bool lfrfid_load_key_data(LfRfid* app, string_t path, bool show_dialog);
+
+bool lfrfid_save_key_data(LfRfid* app, string_t path);
+
+void lfrfid_make_app_folder(LfRfid* app);
+
+void lfrfid_text_store_set(LfRfid* app, const char* text, ...);
+
+void lfrfid_text_store_clear(LfRfid* app);
+
+void lfrfid_popup_timeout_callback(void* context);
+
+void lfrfid_widget_callback(GuiButtonType result, InputType type, void* context);
+
+void lfrfid_text_input_callback(void* context);

+ 0 - 88
applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.cpp

@@ -1,88 +0,0 @@
-#include "lfrfid_app_scene_delete_confirm.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-void LfRfidAppSceneDeleteConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    string_init(string_data);
-    string_init(string_header);
-
-    auto container = app->view_controller.get<ContainerVM>();
-
-    auto button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Left, "Back");
-    button->set_callback(app, LfRfidAppSceneDeleteConfirm::back_callback);
-
-    button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Right, "Delete");
-    button->set_callback(app, LfRfidAppSceneDeleteConfirm::delete_callback);
-
-    auto line_1 = container->add<StringElement>();
-    auto line_2 = container->add<StringElement>();
-    auto line_3 = container->add<StringElement>();
-
-    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-    uint8_t* data = (uint8_t*)malloc(size);
-    protocol_dict_get_data(app->dict, app->protocol_id, data, size);
-    for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) {
-        if(i != 0) {
-            string_cat_printf(string_data, " ");
-        }
-
-        string_cat_printf(string_data, "%02X", data[i]);
-    }
-    free(data);
-
-    string_printf(string_header, "Delete %s?", string_get_cstr(app->file_name));
-    line_1->set_text(
-        string_get_cstr(string_header), 64, 0, 128 - 2, AlignCenter, AlignTop, FontPrimary);
-    line_2->set_text(
-        string_get_cstr(string_data), 64, 19, 0, AlignCenter, AlignTop, FontSecondary);
-    line_3->set_text(
-        protocol_dict_get_name(app->dict, app->protocol_id),
-        64,
-        49,
-        0,
-        AlignCenter,
-        AlignBottom,
-        FontSecondary);
-
-    app->view_controller.switch_to<ContainerVM>();
-}
-
-bool LfRfidAppSceneDeleteConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        app->delete_key();
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteSuccess);
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Stay) {
-        app->scene_controller.switch_to_previous_scene();
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Back) {
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneDeleteConfirm::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ContainerVM>()->clean();
-    string_clear(string_data);
-    string_clear(string_header);
-}
-
-void LfRfidAppSceneDeleteConfirm::back_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Stay;
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneDeleteConfirm::delete_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}

+ 0 - 16
applications/lfrfid/scene/lfrfid_app_scene_delete_confirm.h

@@ -1,16 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneDeleteConfirm : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void back_callback(void* context);
-    static void delete_callback(void* context);
-
-    string_t string_header;
-    string_t string_data;
-};

+ 0 - 38
applications/lfrfid/scene/lfrfid_app_scene_delete_success.cpp

@@ -1,38 +0,0 @@
-#include "lfrfid_app_scene_delete_success.h"
-
-void LfRfidAppSceneDeleteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto popup = app->view_controller.get<PopupVM>();
-
-    popup->set_icon(0, 2, &I_DolphinMafia_115x62);
-    popup->set_header("Deleted", 83, 19, AlignLeft, AlignBottom);
-    popup->set_context(app);
-    popup->set_callback(LfRfidAppSceneDeleteSuccess::timeout_callback);
-    popup->set_timeout(1500);
-    popup->enable_timeout();
-
-    app->view_controller.switch_to<PopupVM>();
-}
-
-bool LfRfidAppSceneDeleteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Back) {
-        app->scene_controller.search_and_switch_to_previous_scene(
-            {LfRfidApp::SceneType::SelectKey});
-
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneDeleteSuccess::on_exit(LfRfidApp* app) {
-    app->view_controller.get<PopupVM>()->clean();
-}
-
-void LfRfidAppSceneDeleteSuccess::timeout_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Back;
-    app->view_controller.send_event(&event);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_delete_success.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneDeleteSuccess : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void timeout_callback(void* context);
-};

+ 0 - 36
applications/lfrfid/scene/lfrfid_app_scene_emulate.cpp

@@ -1,36 +0,0 @@
-#include "lfrfid_app_scene_emulate.h"
-#include <core/common_defines.h>
-#include <dolphin/dolphin.h>
-
-void LfRfidAppSceneEmulate::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    DOLPHIN_DEED(DolphinDeedRfidEmulate);
-    auto popup = app->view_controller.get<PopupVM>();
-
-    popup->set_header("Emulating", 89, 30, AlignCenter, AlignTop);
-    if(string_size(app->file_name)) {
-        popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
-    } else {
-        popup->set_text(
-            protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop);
-    }
-    popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
-
-    app->view_controller.switch_to<PopupVM>();
-    lfrfid_worker_start_thread(app->lfworker);
-    lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
-    notification_message(app->notification, &sequence_blink_start_magenta);
-}
-
-bool LfRfidAppSceneEmulate::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    UNUSED(app);
-    UNUSED(event);
-    bool consumed = false;
-    return consumed;
-}
-
-void LfRfidAppSceneEmulate::on_exit(LfRfidApp* app) {
-    app->view_controller.get<PopupVM>()->clean();
-    lfrfid_worker_stop(app->lfworker);
-    lfrfid_worker_stop_thread(app->lfworker);
-    notification_message(app->notification, &sequence_blink_stop);
-}

+ 0 - 9
applications/lfrfid/scene/lfrfid_app_scene_emulate.h

@@ -1,9 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneEmulate : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-};

+ 0 - 59
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp

@@ -1,59 +0,0 @@
-#include "lfrfid_app_scene_exit_confirm.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto container = app->view_controller.get<ContainerVM>();
-
-    auto button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Left, "Exit");
-    button->set_callback(app, LfRfidAppSceneExitConfirm::exit_callback);
-
-    button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Right, "Stay");
-    button->set_callback(app, LfRfidAppSceneExitConfirm::stay_callback);
-
-    auto line_1 = container->add<StringElement>();
-    auto line_2 = container->add<StringElement>();
-
-    line_1->set_text("Exit to RFID Menu?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
-    line_2->set_text(
-        "All unsaved data will be lost!", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
-
-    app->view_controller.switch_to<ContainerVM>();
-}
-
-bool LfRfidAppSceneExitConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Start});
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Stay) {
-        app->scene_controller.switch_to_previous_scene();
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Back) {
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneExitConfirm::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ContainerVM>()->clean();
-}
-
-void LfRfidAppSceneExitConfirm::exit_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneExitConfirm::stay_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Stay;
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneExitConfirm : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void exit_callback(void* context);
-    static void stay_callback(void* context);
-};

+ 0 - 63
applications/lfrfid/scene/lfrfid_app_scene_extra_actions.cpp

@@ -1,63 +0,0 @@
-#include "lfrfid_app_scene_extra_actions.h"
-
-typedef enum {
-    SubmenuASK,
-    SubmenuPSK,
-    SubmenuRAW,
-} SubmenuIndex;
-
-void LfRfidAppSceneExtraActions::on_enter(LfRfidApp* app, bool need_restore) {
-    auto submenu = app->view_controller.get<SubmenuVM>();
-
-    submenu->add_item("Read ASK (Animal, Ordinary Card)", SubmenuASK, submenu_callback, app);
-    submenu->add_item("Read PSK (Indala)", SubmenuPSK, submenu_callback, app);
-
-    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
-        submenu->add_item("Read RAW RFID data", SubmenuRAW, submenu_callback, app);
-    }
-
-    if(need_restore) {
-        submenu->set_selected_item(submenu_item_selected);
-    }
-
-    app->view_controller.switch_to<SubmenuVM>();
-}
-
-bool LfRfidAppSceneExtraActions::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::MenuSelected) {
-        submenu_item_selected = event->payload.signed_int;
-        switch(event->payload.signed_int) {
-        case SubmenuASK:
-            app->read_type = LFRFIDWorkerReadTypeASKOnly;
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
-            break;
-        case SubmenuPSK:
-            app->read_type = LFRFIDWorkerReadTypePSKOnly;
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
-            break;
-        case SubmenuRAW:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawName);
-            break;
-        }
-
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneExtraActions::on_exit(LfRfidApp* app) {
-    app->view_controller.get<SubmenuVM>()->clean();
-}
-
-void LfRfidAppSceneExtraActions::submenu_callback(void* context, uint32_t index) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-
-    event.type = LfRfidApp::EventType::MenuSelected;
-    event.payload.signed_int = index;
-
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_extra_actions.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneExtraActions : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void submenu_callback(void* context, uint32_t index);
-    uint32_t submenu_item_selected = 0;
-};

+ 0 - 77
applications/lfrfid/scene/lfrfid_app_scene_raw_info.cpp

@@ -1,77 +0,0 @@
-#include "lfrfid_app_scene_raw_info.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-static void ok_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}
-
-static void back_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Back;
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneRawInfo::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    string_init(string_info);
-
-    auto container = app->view_controller.get<ContainerVM>();
-
-    bool sd_exist = storage_sd_status(app->storage) == FSE_OK;
-    if(!sd_exist) {
-        auto icon = container->add<IconElement>();
-        icon->set_icon(0, 0, &I_SDQuestion_35x43);
-        auto line = container->add<StringElement>();
-        line->set_text(
-            "No SD card found.\nThis function will not\nwork without\nSD card.",
-            81,
-            4,
-            0,
-            AlignCenter,
-            AlignTop,
-            FontSecondary);
-
-        auto button = container->add<ButtonElement>();
-        button->set_type(ButtonElement::Type::Left, "Back");
-        button->set_callback(app, back_callback);
-    } else {
-        string_printf(
-            string_info,
-            "RAW RFID data reader\r\n"
-            "1) Put the Flipper on your card\r\n"
-            "2) Press OK\r\n"
-            "3) Wait until data is read");
-
-        auto line = container->add<StringElement>();
-        line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
-
-        auto button = container->add<ButtonElement>();
-        button->set_type(ButtonElement::Type::Center, "OK");
-        button->set_callback(app, ok_callback);
-    }
-
-    app->view_controller.switch_to<ContainerVM>();
-}
-
-bool LfRfidAppSceneRawInfo::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-    if(event->type == LfRfidApp::EventType::Next) {
-        app->scene_controller.switch_to_scene({LfRfidApp::SceneType::RawRead});
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Back) {
-        app->scene_controller.search_and_switch_to_previous_scene(
-            {LfRfidApp::SceneType::ExtraActions});
-        consumed = true;
-    }
-    return consumed;
-}
-
-void LfRfidAppSceneRawInfo::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ContainerVM>()->clean();
-    string_clear(string_info);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_raw_info.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRawInfo : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    string_t string_info;
-};

+ 0 - 46
applications/lfrfid/scene/lfrfid_app_scene_raw_name.cpp

@@ -1,46 +0,0 @@
-
-#include "lfrfid_app_scene_raw_name.h"
-#include "m-string.h"
-#include <lib/toolbox/random_name.h>
-#include <lib/toolbox/path.h>
-
-void LfRfidAppSceneRawName::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    const char* key_name = string_get_cstr(app->raw_file_name);
-
-    bool key_name_empty = (string_size(app->raw_file_name) == 0);
-    if(key_name_empty) {
-        app->text_store.set("RfidRecord");
-    } else {
-        app->text_store.set("%s", key_name);
-    }
-
-    auto text_input = app->view_controller.get<TextInputVM>();
-    text_input->set_header_text("Name the raw file");
-
-    text_input->set_result_callback(
-        save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty);
-
-    app->view_controller.switch_to<TextInputVM>();
-}
-
-bool LfRfidAppSceneRawName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        string_set_str(app->raw_file_name, app->text_store.text);
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawInfo);
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneRawName::on_exit(LfRfidApp* app) {
-    app->view_controller.get<TextInputVM>()->clean();
-}
-
-void LfRfidAppSceneRawName::save_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_raw_name.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRawName : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void save_callback(void* context);
-};

+ 0 - 107
applications/lfrfid/scene/lfrfid_app_scene_raw_read.cpp

@@ -1,107 +0,0 @@
-#include "lfrfid_app_scene_raw_read.h"
-#include <dolphin/dolphin.h>
-
-#define RAW_READ_TIME 5000
-
-static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* ctx) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
-    LfRfidApp::Event event;
-
-    switch(result) {
-    case LFRFIDWorkerReadRawFileError:
-        event.type = LfRfidApp::EventType::ReadEventError;
-        break;
-    case LFRFIDWorkerReadRawOverrun:
-        event.type = LfRfidApp::EventType::ReadEventOverrun;
-        break;
-    }
-
-    app->view_controller.send_event(&event);
-}
-
-static void timer_callback(void* ctx) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::ReadEventDone;
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneRawRead::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    string_init(string_file_name);
-    auto popup = app->view_controller.get<PopupVM>();
-    popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
-    app->view_controller.switch_to<PopupVM>();
-    lfrfid_worker_start_thread(app->lfworker);
-    app->make_app_folder();
-
-    timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app);
-    furi_timer_start(timer, RAW_READ_TIME);
-    string_printf(
-        string_file_name, "%s/%s.ask.raw", app->app_sd_folder, string_get_cstr(app->raw_file_name));
-    popup->set_header("Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop);
-    lfrfid_worker_read_raw_start(
-        app->lfworker,
-        string_get_cstr(string_file_name),
-        LFRFIDWorkerReadTypeASKOnly,
-        lfrfid_read_callback,
-        app);
-
-    notification_message(app->notification, &sequence_blink_start_cyan);
-
-    is_psk = false;
-    error = false;
-}
-
-bool LfRfidAppSceneRawRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    UNUSED(app);
-    bool consumed = true;
-    auto popup = app->view_controller.get<PopupVM>();
-
-    switch(event->type) {
-    case LfRfidApp::EventType::ReadEventError:
-        error = true;
-        popup->set_header("Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop);
-        notification_message(app->notification, &sequence_blink_start_red);
-        furi_timer_stop(timer);
-        break;
-    case LfRfidApp::EventType::ReadEventDone:
-        if(!error) {
-            if(is_psk) {
-                notification_message(app->notification, &sequence_success);
-                app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::RawSuccess);
-            } else {
-                popup->set_header("Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop);
-                notification_message(app->notification, &sequence_blink_start_yellow);
-                lfrfid_worker_stop(app->lfworker);
-                string_printf(
-                    string_file_name,
-                    "%s/%s.psk.raw",
-                    app->app_sd_folder,
-                    string_get_cstr(app->raw_file_name));
-                lfrfid_worker_read_raw_start(
-                    app->lfworker,
-                    string_get_cstr(string_file_name),
-                    LFRFIDWorkerReadTypePSKOnly,
-                    lfrfid_read_callback,
-                    app);
-                furi_timer_start(timer, RAW_READ_TIME);
-                is_psk = true;
-            }
-        }
-        break;
-    default:
-        consumed = false;
-        break;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneRawRead::on_exit(LfRfidApp* app) {
-    notification_message(app->notification, &sequence_blink_stop);
-    app->view_controller.get<PopupVM>()->clean();
-    lfrfid_worker_stop(app->lfworker);
-    lfrfid_worker_stop_thread(app->lfworker);
-    furi_timer_free(timer);
-    string_clear(string_file_name);
-}

+ 0 - 15
applications/lfrfid/scene/lfrfid_app_scene_raw_read.h

@@ -1,15 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRawRead : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    string_t string_file_name;
-    FuriTimer* timer;
-    bool is_psk;
-    bool error;
-};

+ 0 - 45
applications/lfrfid/scene/lfrfid_app_scene_raw_success.cpp

@@ -1,45 +0,0 @@
-#include "lfrfid_app_scene_raw_success.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-void LfRfidAppSceneRawSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    string_init(string_info);
-
-    string_printf(string_info, "RAW RFID read success!\r\n");
-    string_cat_printf(string_info, "Now you can analyze files\r\n");
-    string_cat_printf(string_info, "Or send them to developers");
-
-    auto container = app->view_controller.get<ContainerVM>();
-
-    auto line = container->add<StringElement>();
-    line->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
-
-    auto button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Center, "OK");
-    button->set_callback(app, LfRfidAppSceneRawSuccess::ok_callback);
-
-    app->view_controller.switch_to<ContainerVM>();
-}
-
-bool LfRfidAppSceneRawSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-    if(event->type == LfRfidApp::EventType::Next) {
-        app->scene_controller.search_and_switch_to_previous_scene(
-            {LfRfidApp::SceneType::ExtraActions});
-        consumed = true;
-    }
-    return consumed;
-}
-
-void LfRfidAppSceneRawSuccess::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ContainerVM>()->clean();
-    string_clear(string_info);
-}
-
-void LfRfidAppSceneRawSuccess::ok_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_raw_success.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRawSuccess : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    string_t string_info;
-    static void ok_callback(void* context);
-};

+ 0 - 100
applications/lfrfid/scene/lfrfid_app_scene_read.cpp

@@ -1,100 +0,0 @@
-#include "lfrfid_app_scene_read.h"
-#include <dolphin/dolphin.h>
-
-static void lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* ctx) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
-    LfRfidApp::Event event;
-
-    switch(result) {
-    case LFRFIDWorkerReadSenseStart:
-        event.type = LfRfidApp::EventType::ReadEventSenseStart;
-        break;
-    case LFRFIDWorkerReadSenseEnd:
-        event.type = LfRfidApp::EventType::ReadEventSenseEnd;
-        break;
-    case LFRFIDWorkerReadSenseCardStart:
-        event.type = LfRfidApp::EventType::ReadEventSenseCardStart;
-        break;
-    case LFRFIDWorkerReadSenseCardEnd:
-        event.type = LfRfidApp::EventType::ReadEventSenseCardEnd;
-        break;
-    case LFRFIDWorkerReadDone:
-        event.type = LfRfidApp::EventType::ReadEventDone;
-        break;
-    case LFRFIDWorkerReadStartASK:
-        event.type = LfRfidApp::EventType::ReadEventStartASK;
-        break;
-    case LFRFIDWorkerReadStartPSK:
-        event.type = LfRfidApp::EventType::ReadEventStartPSK;
-        break;
-    }
-
-    event.payload.signed_int = protocol;
-
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneRead::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto popup = app->view_controller.get<PopupVM>();
-
-    DOLPHIN_DEED(DolphinDeedRfidRead);
-    if(app->read_type == LFRFIDWorkerReadTypePSKOnly) {
-        popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop);
-    } else {
-        popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop);
-    }
-
-    popup->set_icon(0, 3, &I_RFIDDolphinReceive_97x61);
-
-    app->view_controller.switch_to<PopupVM>();
-    lfrfid_worker_start_thread(app->lfworker);
-    lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app);
-
-    notification_message(app->notification, &sequence_blink_start_cyan);
-}
-
-bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = true;
-    auto popup = app->view_controller.get<PopupVM>();
-
-    switch(event->type) {
-    case LfRfidApp::EventType::ReadEventSenseStart:
-        notification_message(app->notification, &sequence_blink_stop);
-        notification_message(app->notification, &sequence_blink_start_yellow);
-        break;
-    case LfRfidApp::EventType::ReadEventSenseCardStart:
-        notification_message(app->notification, &sequence_blink_stop);
-        notification_message(app->notification, &sequence_blink_start_green);
-        break;
-    case LfRfidApp::EventType::ReadEventSenseEnd:
-    case LfRfidApp::EventType::ReadEventSenseCardEnd:
-        notification_message(app->notification, &sequence_blink_stop);
-        notification_message(app->notification, &sequence_blink_start_cyan);
-        break;
-    case LfRfidApp::EventType::ReadEventDone:
-        app->protocol_id = event->payload.signed_int;
-        DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
-        notification_message(app->notification, &sequence_success);
-        string_reset(app->file_name);
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess);
-        break;
-    case LfRfidApp::EventType::ReadEventStartPSK:
-        popup->set_header("Reading\nLF RFID\nPSK", 89, 30, AlignCenter, AlignTop);
-        break;
-    case LfRfidApp::EventType::ReadEventStartASK:
-        popup->set_header("Reading\nLF RFID\nASK", 89, 30, AlignCenter, AlignTop);
-        break;
-    default:
-        consumed = false;
-        break;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneRead::on_exit(LfRfidApp* app) {
-    notification_message(app->notification, &sequence_blink_stop);
-    app->view_controller.get<PopupVM>()->clean();
-    lfrfid_worker_stop(app->lfworker);
-    lfrfid_worker_stop_thread(app->lfworker);
-}

+ 0 - 9
applications/lfrfid/scene/lfrfid_app_scene_read.h

@@ -1,9 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRead : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-};

+ 0 - 60
applications/lfrfid/scene/lfrfid_app_scene_read_menu.cpp

@@ -1,60 +0,0 @@
-#include "lfrfid_app_scene_read_menu.h"
-
-typedef enum {
-    SubmenuSave,
-    SubmenuEmulate,
-    SubmenuWrite,
-} SubmenuIndex;
-
-void LfRfidAppSceneReadKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
-    auto submenu = app->view_controller.get<SubmenuVM>();
-
-    submenu->add_item("Save", SubmenuSave, submenu_callback, app);
-    submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app);
-    submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
-
-    if(need_restore) {
-        submenu->set_selected_item(submenu_item_selected);
-    }
-
-    app->view_controller.switch_to<SubmenuVM>();
-}
-
-bool LfRfidAppSceneReadKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::MenuSelected) {
-        submenu_item_selected = event->payload.signed_int;
-        switch(event->payload.signed_int) {
-        case SubmenuWrite:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write);
-            break;
-        case SubmenuSave:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName);
-            break;
-        case SubmenuEmulate:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate);
-            break;
-        }
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Back) {
-        app->scene_controller.switch_to_previous_scene();
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneReadKeyMenu::on_exit(LfRfidApp* app) {
-    app->view_controller.get<SubmenuVM>()->clean();
-}
-
-void LfRfidAppSceneReadKeyMenu::submenu_callback(void* context, uint32_t index) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-
-    event.type = LfRfidApp::EventType::MenuSelected;
-    event.payload.signed_int = index;
-
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_read_menu.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneReadKeyMenu : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void submenu_callback(void* context, uint32_t index);
-    uint32_t submenu_item_selected = 0;
-};

+ 0 - 96
applications/lfrfid/scene/lfrfid_app_scene_read_success.cpp

@@ -1,96 +0,0 @@
-#include "lfrfid_app_scene_read_success.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-void LfRfidAppSceneReadSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    string_init(string_info);
-    string_init(string_header);
-
-    string_init_printf(
-        string_header,
-        "%s[%s]",
-        protocol_dict_get_name(app->dict, app->protocol_id),
-        protocol_dict_get_manufacturer(app->dict, app->protocol_id));
-
-    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-    uint8_t* data = (uint8_t*)malloc(size);
-    protocol_dict_get_data(app->dict, app->protocol_id, data, size);
-    for(uint8_t i = 0; i < size; i++) {
-        if(i != 0) {
-            string_cat_printf(string_info, " ");
-        }
-
-        if(i >= 9) {
-            string_cat_printf(string_info, "...");
-            break;
-        } else {
-            string_cat_printf(string_info, "%02X", data[i]);
-        }
-    }
-    free(data);
-
-    string_t render_data;
-    string_init(render_data);
-    protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id);
-    string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data));
-    string_clear(render_data);
-
-    auto container = app->view_controller.get<ContainerVM>();
-
-    auto button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Left, "Retry");
-    button->set_callback(app, LfRfidAppSceneReadSuccess::back_callback);
-
-    button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Right, "More");
-    button->set_callback(app, LfRfidAppSceneReadSuccess::more_callback);
-
-    auto header = container->add<StringElement>();
-    header->set_text(string_get_cstr(string_header), 0, 2, 0, AlignLeft, AlignTop, FontPrimary);
-
-    auto text = container->add<StringElement>();
-    text->set_text(string_get_cstr(string_info), 0, 16, 0, AlignLeft, AlignTop, FontSecondary);
-
-    app->view_controller.switch_to<ContainerVM>();
-
-    notification_message_block(app->notification, &sequence_set_green_255);
-}
-
-bool LfRfidAppSceneReadSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadKeyMenu);
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Retry) {
-        app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::RetryConfirm});
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Back) {
-        app->scene_controller.switch_to_next_scene({LfRfidApp::SceneType::ExitConfirm});
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneReadSuccess::on_exit(LfRfidApp* app) {
-    notification_message_block(app->notification, &sequence_reset_green);
-    app->view_controller.get<ContainerVM>()->clean();
-    string_clear(string_info);
-    string_clear(string_header);
-}
-
-void LfRfidAppSceneReadSuccess::back_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Retry;
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneReadSuccess::more_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}

+ 0 - 16
applications/lfrfid/scene/lfrfid_app_scene_read_success.h

@@ -1,16 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneReadSuccess : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void back_callback(void* context);
-    static void more_callback(void* context);
-
-    string_t string_header;
-    string_t string_info;
-};

+ 0 - 59
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.cpp

@@ -1,59 +0,0 @@
-#include "lfrfid_app_scene_retry_confirm.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-void LfRfidAppSceneRetryConfirm::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto container = app->view_controller.get<ContainerVM>();
-
-    auto button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Left, "Exit");
-    button->set_callback(app, LfRfidAppSceneRetryConfirm::exit_callback);
-
-    button = container->add<ButtonElement>();
-    button->set_type(ButtonElement::Type::Right, "Stay");
-    button->set_callback(app, LfRfidAppSceneRetryConfirm::stay_callback);
-
-    auto line_1 = container->add<StringElement>();
-    auto line_2 = container->add<StringElement>();
-
-    line_1->set_text("Return to Reading?", 64, 19, 128 - 2, AlignCenter, AlignBottom, FontPrimary);
-    line_2->set_text(
-        "All unsaved data will be lost!", 64, 29, 0, AlignCenter, AlignBottom, FontSecondary);
-
-    app->view_controller.switch_to<ContainerVM>();
-}
-
-bool LfRfidAppSceneRetryConfirm::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        app->scene_controller.search_and_switch_to_previous_scene({LfRfidApp::SceneType::Read});
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Stay) {
-        app->scene_controller.switch_to_previous_scene();
-        consumed = true;
-    } else if(event->type == LfRfidApp::EventType::Back) {
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneRetryConfirm::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ContainerVM>()->clean();
-}
-
-void LfRfidAppSceneRetryConfirm::exit_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneRetryConfirm::stay_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Stay;
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_retry_confirm.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRetryConfirm : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void exit_callback(void* context);
-    static void stay_callback(void* context);
-};

+ 0 - 66
applications/lfrfid/scene/lfrfid_app_scene_rpc.cpp

@@ -1,66 +0,0 @@
-#include "lfrfid_app_scene_rpc.h"
-#include <core/common_defines.h>
-#include <dolphin/dolphin.h>
-#include <rpc/rpc_app.h>
-
-void LfRfidAppSceneRpc::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto popup = app->view_controller.get<PopupVM>();
-
-    popup->set_header("LF RFID", 89, 42, AlignCenter, AlignBottom);
-    popup->set_text("RPC mode", 89, 44, AlignCenter, AlignTop);
-    popup->set_icon(0, 12, &I_RFIDDolphinSend_97x61);
-
-    app->view_controller.switch_to<PopupVM>();
-
-    notification_message(app->notification, &sequence_display_backlight_on);
-}
-
-bool LfRfidAppSceneRpc::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    UNUSED(app);
-    UNUSED(event);
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Exit) {
-        consumed = true;
-        LfRfidApp::Event view_event;
-        view_event.type = LfRfidApp::EventType::Back;
-        app->view_controller.send_event(&view_event);
-        rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
-    } else if(event->type == LfRfidApp::EventType::RpcSessionClose) {
-        consumed = true;
-        LfRfidApp::Event view_event;
-        view_event.type = LfRfidApp::EventType::Back;
-        app->view_controller.send_event(&view_event);
-    } else if(event->type == LfRfidApp::EventType::RpcLoadFile) {
-        const char* arg = rpc_system_app_get_data(app->rpc_ctx);
-        consumed = true;
-        bool result = false;
-        if(arg && !emulating) {
-            string_set_str(app->file_path, arg);
-            if(app->load_key_data(app->file_path, false)) {
-                lfrfid_worker_start_thread(app->lfworker);
-                lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
-                emulating = true;
-
-                auto popup = app->view_controller.get<PopupVM>();
-                app->text_store.set("emulating\n%s", string_get_cstr(app->file_name));
-                popup->set_text(app->text_store.text, 89, 44, AlignCenter, AlignTop);
-
-                notification_message(app->notification, &sequence_blink_start_magenta);
-                result = true;
-            }
-        }
-        rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result);
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneRpc::on_exit(LfRfidApp* app) {
-    if(emulating) {
-        lfrfid_worker_stop(app->lfworker);
-        lfrfid_worker_stop_thread(app->lfworker);
-        notification_message(app->notification, &sequence_blink_stop);
-    }
-    app->view_controller.get<PopupVM>()->clean();
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_rpc.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneRpc : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    bool emulating = false;
-};

+ 0 - 45
applications/lfrfid/scene/lfrfid_app_scene_save_data.cpp

@@ -1,45 +0,0 @@
-#include "lfrfid_app_scene_save_data.h"
-#include <dolphin/dolphin.h>
-
-void LfRfidAppSceneSaveData::on_enter(LfRfidApp* app, bool need_restore) {
-    auto byte_input = app->view_controller.get<ByteInputVM>();
-    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-
-    if(need_restore) {
-        protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
-    } else {
-        protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
-    }
-
-    protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size);
-
-    byte_input->set_header_text("Enter the data in hex");
-
-    byte_input->set_result_callback(save_callback, NULL, app, app->new_key_data, size);
-
-    app->view_controller.switch_to<ByteInputVM>();
-}
-
-bool LfRfidAppSceneSaveData::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-        protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size);
-        DOLPHIN_DEED(DolphinDeedRfidAdd);
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveName);
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneSaveData::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ByteInputVM>()->clean();
-}
-
-void LfRfidAppSceneSaveData::save_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_save_data.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSaveData : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void save_callback(void* context);
-};

+ 0 - 72
applications/lfrfid/scene/lfrfid_app_scene_save_name.cpp

@@ -1,72 +0,0 @@
-#include "lfrfid_app_scene_save_name.h"
-#include "m-string.h"
-#include <lib/toolbox/random_name.h>
-#include <lib/toolbox/path.h>
-
-void LfRfidAppSceneSaveName::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    const char* key_name = string_get_cstr(app->file_name);
-
-    bool key_name_empty = (string_size(app->file_name) == 0);
-    if(key_name_empty) {
-        string_set_str(app->file_path, app->app_folder);
-        set_random_name(app->text_store.text, app->text_store.text_size);
-    } else {
-        app->text_store.set("%s", key_name);
-    }
-
-    auto text_input = app->view_controller.get<TextInputVM>();
-    text_input->set_header_text("Name the card");
-
-    text_input->set_result_callback(
-        save_callback, app, app->text_store.text, LFRFID_KEY_NAME_SIZE, key_name_empty);
-
-    string_t folder_path;
-    string_init(folder_path);
-
-    path_extract_dirname(string_get_cstr(app->file_path), folder_path);
-
-    ValidatorIsFile* validator_is_file =
-        validator_is_file_alloc_init(string_get_cstr(folder_path), app->app_extension, key_name);
-    text_input->set_validator(validator_is_file_callback, validator_is_file);
-
-    string_clear(folder_path);
-
-    app->view_controller.switch_to<TextInputVM>();
-}
-
-bool LfRfidAppSceneSaveName::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Next) {
-        if(string_size(app->file_name) > 0) {
-            app->delete_key();
-        }
-
-        string_set_str(app->file_name, app->text_store.text);
-
-        if(app->save_key()) {
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveSuccess);
-        } else {
-            app->scene_controller.search_and_switch_to_previous_scene(
-                {LfRfidApp::SceneType::ReadKeyMenu});
-        }
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneSaveName::on_exit(LfRfidApp* app) {
-    void* validator_context =
-        app->view_controller.get<TextInputVM>()->get_validator_callback_context();
-    app->view_controller.get<TextInputVM>()->set_validator(NULL, NULL);
-    validator_is_file_free((ValidatorIsFile*)validator_context);
-
-    app->view_controller.get<TextInputVM>()->clean();
-}
-
-void LfRfidAppSceneSaveName::save_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Next;
-    app->view_controller.send_event(&event);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_save_name.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSaveName : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void save_callback(void* context);
-};

+ 0 - 50
applications/lfrfid/scene/lfrfid_app_scene_save_success.cpp

@@ -1,50 +0,0 @@
-#include "lfrfid_app_scene_save_success.h"
-#include <gui/scene_manager.h>
-#include <dolphin/dolphin.h>
-#include <stdint.h>
-
-void LfRfidAppSceneSaveSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto popup = app->view_controller.get<PopupVM>();
-
-    DOLPHIN_DEED(DolphinDeedRfidSave);
-    popup->set_icon(32, 5, &I_DolphinNice_96x59);
-    popup->set_header("Saved!", 5, 7, AlignLeft, AlignTop);
-    popup->set_context(app);
-    popup->set_callback(LfRfidAppSceneSaveSuccess::timeout_callback);
-    popup->set_timeout(1500);
-    popup->enable_timeout();
-
-    app->view_controller.switch_to<PopupVM>();
-}
-
-bool LfRfidAppSceneSaveSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Back) {
-        bool result = app->scene_controller.has_previous_scene(
-            {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
-
-        if(result) {
-            app->scene_controller.search_and_switch_to_previous_scene(
-                {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
-        } else {
-            app->scene_controller.search_and_switch_to_another_scene(
-                {LfRfidApp::SceneType::SaveType}, LfRfidApp::SceneType::SelectKey);
-        }
-
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneSaveSuccess::on_exit(LfRfidApp* app) {
-    app->view_controller.get<PopupVM>()->clean();
-}
-
-void LfRfidAppSceneSaveSuccess::timeout_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Back;
-    app->view_controller.send_event(&event);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_save_success.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSaveSuccess : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void timeout_callback(void* context);
-};

+ 0 - 53
applications/lfrfid/scene/lfrfid_app_scene_save_type.cpp

@@ -1,53 +0,0 @@
-#include "lfrfid_app_scene_save_type.h"
-
-void LfRfidAppSceneSaveType::on_enter(LfRfidApp* app, bool need_restore) {
-    auto submenu = app->view_controller.get<SubmenuVM>();
-
-    for(uint8_t i = 0; i < keys_count; i++) {
-        string_init_printf(
-            submenu_name[i],
-            "%s %s",
-            protocol_dict_get_manufacturer(app->dict, i),
-            protocol_dict_get_name(app->dict, i));
-        submenu->add_item(string_get_cstr(submenu_name[i]), i, submenu_callback, app);
-    }
-
-    if(need_restore) {
-        submenu->set_selected_item(submenu_item_selected);
-    }
-
-    app->view_controller.switch_to<SubmenuVM>();
-
-    // clear key name
-    string_reset(app->file_name);
-}
-
-bool LfRfidAppSceneSaveType::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::MenuSelected) {
-        submenu_item_selected = event->payload.signed_int;
-        app->protocol_id = event->payload.signed_int;
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData);
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneSaveType::on_exit(LfRfidApp* app) {
-    app->view_controller.get<SubmenuVM>()->clean();
-    for(uint8_t i = 0; i < keys_count; i++) {
-        string_clear(submenu_name[i]);
-    }
-}
-
-void LfRfidAppSceneSaveType::submenu_callback(void* context, uint32_t index) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-
-    event.type = LfRfidApp::EventType::MenuSelected;
-    event.payload.signed_int = index;
-
-    app->view_controller.send_event(&event);
-}

+ 0 - 15
applications/lfrfid/scene/lfrfid_app_scene_save_type.h

@@ -1,15 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSaveType : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void submenu_callback(void* context, uint32_t index);
-    uint32_t submenu_item_selected = 0;
-    static const uint8_t keys_count = static_cast<uint8_t>(LFRFIDProtocol::LFRFIDProtocolMax);
-    string_t submenu_name[keys_count];
-};

+ 0 - 48
applications/lfrfid/scene/lfrfid_app_scene_saved_info.cpp

@@ -1,48 +0,0 @@
-#include "lfrfid_app_scene_saved_info.h"
-#include "../view/elements/button_element.h"
-#include "../view/elements/icon_element.h"
-#include "../view/elements/string_element.h"
-
-void LfRfidAppSceneSavedInfo::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    string_init(string_info);
-
-    string_printf(
-        string_info,
-        "%s [%s]\r\n",
-        string_get_cstr(app->file_name),
-        protocol_dict_get_name(app->dict, app->protocol_id));
-
-    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-    uint8_t* data = (uint8_t*)malloc(size);
-    protocol_dict_get_data(app->dict, app->protocol_id, data, size);
-    for(uint8_t i = 0; i < size; i++) {
-        if(i != 0) {
-            string_cat_printf(string_info, " ");
-        }
-
-        string_cat_printf(string_info, "%02X", data[i]);
-    }
-    free(data);
-
-    string_t render_data;
-    string_init(render_data);
-    protocol_dict_render_data(app->dict, render_data, app->protocol_id);
-    string_cat_printf(string_info, "\r\n%s", string_get_cstr(render_data));
-    string_clear(render_data);
-
-    auto container = app->view_controller.get<ContainerVM>();
-
-    auto line_1 = container->add<StringElement>();
-    line_1->set_text(string_get_cstr(string_info), 0, 1, 0, AlignLeft, AlignTop, FontSecondary);
-
-    app->view_controller.switch_to<ContainerVM>();
-}
-
-bool LfRfidAppSceneSavedInfo::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) {
-    return false;
-}
-
-void LfRfidAppSceneSavedInfo::on_exit(LfRfidApp* app) {
-    app->view_controller.get<ContainerVM>()->clean();
-    string_clear(string_info);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_saved_info.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSavedInfo : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    string_t string_info;
-};

+ 0 - 67
applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.cpp

@@ -1,67 +0,0 @@
-#include "lfrfid_app_scene_saved_key_menu.h"
-
-typedef enum {
-    SubmenuEmulate,
-    SubmenuWrite,
-    SubmenuEdit,
-    SubmenuDelete,
-    SubmenuInfo,
-} SubmenuIndex;
-
-void LfRfidAppSceneSavedKeyMenu::on_enter(LfRfidApp* app, bool need_restore) {
-    auto submenu = app->view_controller.get<SubmenuVM>();
-
-    submenu->add_item("Emulate", SubmenuEmulate, submenu_callback, app);
-    submenu->add_item("Write", SubmenuWrite, submenu_callback, app);
-    submenu->add_item("Edit", SubmenuEdit, submenu_callback, app);
-    submenu->add_item("Delete", SubmenuDelete, submenu_callback, app);
-    submenu->add_item("Info", SubmenuInfo, submenu_callback, app);
-
-    if(need_restore) {
-        submenu->set_selected_item(submenu_item_selected);
-    }
-
-    app->view_controller.switch_to<SubmenuVM>();
-}
-
-bool LfRfidAppSceneSavedKeyMenu::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::MenuSelected) {
-        submenu_item_selected = event->payload.signed_int;
-        switch(event->payload.signed_int) {
-        case SubmenuEmulate:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Emulate);
-            break;
-        case SubmenuWrite:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Write);
-            break;
-        case SubmenuEdit:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveData);
-            break;
-        case SubmenuDelete:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::DeleteConfirm);
-            break;
-        case SubmenuInfo:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedInfo);
-            break;
-        }
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneSavedKeyMenu::on_exit(LfRfidApp* app) {
-    app->view_controller.get<SubmenuVM>()->clean();
-}
-
-void LfRfidAppSceneSavedKeyMenu::submenu_callback(void* context, uint32_t index) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-
-    event.type = LfRfidApp::EventType::MenuSelected;
-    event.payload.signed_int = index;
-
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_saved_key_menu.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSavedKeyMenu : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void submenu_callback(void* context, uint32_t index);
-    uint32_t submenu_item_selected = 0;
-};

+ 0 - 16
applications/lfrfid/scene/lfrfid_app_scene_select_key.cpp

@@ -1,16 +0,0 @@
-#include "lfrfid_app_scene_select_key.h"
-
-void LfRfidAppSceneSelectKey::on_enter(LfRfidApp* app, bool need_restore) {
-    if(app->load_key_from_file_select(need_restore)) {
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SavedKeyMenu);
-    } else {
-        app->scene_controller.switch_to_previous_scene();
-    }
-}
-
-bool LfRfidAppSceneSelectKey::on_event(LfRfidApp* /* app */, LfRfidApp::Event* /* event */) {
-    return false;
-}
-
-void LfRfidAppSceneSelectKey::on_exit(LfRfidApp* /* app */) {
-}

+ 0 - 9
applications/lfrfid/scene/lfrfid_app_scene_select_key.h

@@ -1,9 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneSelectKey : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-};

+ 0 - 67
applications/lfrfid/scene/lfrfid_app_scene_start.cpp

@@ -1,67 +0,0 @@
-#include "lfrfid_app_scene_start.h"
-
-typedef enum {
-    SubmenuRead,
-    SubmenuSaved,
-    SubmenuAddManually,
-    SubmenuExtraActions,
-} SubmenuIndex;
-
-void LfRfidAppSceneStart::on_enter(LfRfidApp* app, bool need_restore) {
-    auto submenu = app->view_controller.get<SubmenuVM>();
-
-    submenu->add_item("Read", SubmenuRead, submenu_callback, app);
-    submenu->add_item("Saved", SubmenuSaved, submenu_callback, app);
-    submenu->add_item("Add Manually", SubmenuAddManually, submenu_callback, app);
-    submenu->add_item("Extra Actions", SubmenuExtraActions, submenu_callback, app);
-
-    if(need_restore) {
-        submenu->set_selected_item(submenu_item_selected);
-    }
-
-    app->view_controller.switch_to<SubmenuVM>();
-
-    // clear key
-    string_reset(app->file_name);
-    app->protocol_id = PROTOCOL_NO;
-    app->read_type = LFRFIDWorkerReadTypeAuto;
-}
-
-bool LfRfidAppSceneStart::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::MenuSelected) {
-        submenu_item_selected = event->payload.signed_int;
-        switch(event->payload.signed_int) {
-        case SubmenuRead:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::Read);
-            break;
-        case SubmenuSaved:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SelectKey);
-            break;
-        case SubmenuAddManually:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::SaveType);
-            break;
-        case SubmenuExtraActions:
-            app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ExtraActions);
-            break;
-        }
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneStart::on_exit(LfRfidApp* app) {
-    app->view_controller.get<SubmenuVM>()->clean();
-}
-
-void LfRfidAppSceneStart::submenu_callback(void* context, uint32_t index) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-
-    event.type = LfRfidApp::EventType::MenuSelected;
-    event.payload.signed_int = index;
-
-    app->view_controller.send_event(&event);
-}

+ 0 - 13
applications/lfrfid/scene/lfrfid_app_scene_start.h

@@ -1,13 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneStart : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void submenu_callback(void* context, uint32_t index);
-    uint32_t submenu_item_selected = 0;
-};

+ 0 - 88
applications/lfrfid/scene/lfrfid_app_scene_write.cpp

@@ -1,88 +0,0 @@
-#include "lfrfid_app_scene_write.h"
-
-static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* ctx) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(ctx);
-    LfRfidApp::Event event;
-
-    switch(result) {
-    case LFRFIDWorkerWriteOK:
-        event.type = LfRfidApp::EventType::WriteEventOK;
-        break;
-    case LFRFIDWorkerWriteProtocolCannotBeWritten:
-        event.type = LfRfidApp::EventType::WriteEventProtocolCannotBeWritten;
-        break;
-    case LFRFIDWorkerWriteFobCannotBeWritten:
-        event.type = LfRfidApp::EventType::WriteEventFobCannotBeWritten;
-        break;
-    case LFRFIDWorkerWriteTooLongToWrite:
-        event.type = LfRfidApp::EventType::WriteEventTooLongToWrite;
-        break;
-    }
-
-    app->view_controller.send_event(&event);
-}
-
-void LfRfidAppSceneWrite::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto popup = app->view_controller.get<PopupVM>();
-
-    popup->set_header("Writing", 89, 30, AlignCenter, AlignTop);
-    if(string_size(app->file_name)) {
-        popup->set_text(string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
-    } else {
-        popup->set_text(
-            protocol_dict_get_name(app->dict, app->protocol_id), 89, 43, AlignCenter, AlignTop);
-    }
-    popup->set_icon(0, 3, &I_RFIDDolphinSend_97x61);
-
-    app->view_controller.switch_to<PopupVM>();
-
-    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-    app->old_key_data = (uint8_t*)malloc(size);
-    protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
-
-    lfrfid_worker_start_thread(app->lfworker);
-    lfrfid_worker_write_start(
-        app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app);
-    notification_message(app->notification, &sequence_blink_start_magenta);
-}
-
-bool LfRfidAppSceneWrite::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = true;
-    auto popup = app->view_controller.get<PopupVM>();
-
-    switch(event->type) {
-    case LfRfidApp::EventType::WriteEventOK:
-        notification_message(app->notification, &sequence_success);
-        app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::WriteSuccess);
-        break;
-    case LfRfidApp::EventType::WriteEventProtocolCannotBeWritten:
-        popup->set_icon(72, 17, &I_DolphinCommon_56x48);
-        popup->set_header("Error", 64, 3, AlignCenter, AlignTop);
-        popup->set_text("This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
-        notification_message(app->notification, &sequence_blink_start_red);
-        break;
-    case LfRfidApp::EventType::WriteEventFobCannotBeWritten:
-    case LfRfidApp::EventType::WriteEventTooLongToWrite:
-        popup->set_icon(72, 17, &I_DolphinCommon_56x48);
-        popup->set_header("Still trying to write...", 64, 3, AlignCenter, AlignTop);
-        popup->set_text(
-            "Make sure this\ncard is writable\nand not\nprotected.", 3, 17, AlignLeft, AlignTop);
-        notification_message(app->notification, &sequence_blink_start_yellow);
-        break;
-    default:
-        consumed = false;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneWrite::on_exit(LfRfidApp* app) {
-    notification_message(app->notification, &sequence_blink_stop);
-    app->view_controller.get<PopupVM>()->clean();
-    lfrfid_worker_stop(app->lfworker);
-    lfrfid_worker_stop_thread(app->lfworker);
-
-    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
-    protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
-    free(app->old_key_data);
-}

+ 0 - 9
applications/lfrfid/scene/lfrfid_app_scene_write.h

@@ -1,9 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneWrite : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-};

+ 0 - 38
applications/lfrfid/scene/lfrfid_app_scene_write_success.cpp

@@ -1,38 +0,0 @@
-#include "lfrfid_app_scene_write_success.h"
-
-void LfRfidAppSceneWriteSuccess::on_enter(LfRfidApp* app, bool /* need_restore */) {
-    auto popup = app->view_controller.get<PopupVM>();
-    popup->set_header("Successfully\nwritten!", 94, 3, AlignCenter, AlignTop);
-    popup->set_icon(0, 6, &I_RFIDDolphinSuccess_108x57);
-    popup->set_context(app);
-    popup->set_callback(LfRfidAppSceneWriteSuccess::timeout_callback);
-    popup->set_timeout(1500);
-    popup->enable_timeout();
-
-    app->view_controller.switch_to<PopupVM>();
-    notification_message_block(app->notification, &sequence_set_green_255);
-}
-
-bool LfRfidAppSceneWriteSuccess::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidApp::EventType::Back) {
-        app->scene_controller.search_and_switch_to_previous_scene(
-            {LfRfidApp::SceneType::ReadKeyMenu, LfRfidApp::SceneType::SelectKey});
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidAppSceneWriteSuccess::on_exit(LfRfidApp* app) {
-    notification_message_block(app->notification, &sequence_reset_green);
-    app->view_controller.get<PopupVM>()->clean();
-}
-
-void LfRfidAppSceneWriteSuccess::timeout_callback(void* context) {
-    LfRfidApp* app = static_cast<LfRfidApp*>(context);
-    LfRfidApp::Event event;
-    event.type = LfRfidApp::EventType::Back;
-    app->view_controller.send_event(&event);
-}

+ 0 - 12
applications/lfrfid/scene/lfrfid_app_scene_write_success.h

@@ -1,12 +0,0 @@
-#pragma once
-#include "../lfrfid_app.h"
-
-class LfRfidAppSceneWriteSuccess : public GenericScene<LfRfidApp> {
-public:
-    void on_enter(LfRfidApp* app, bool need_restore) final;
-    bool on_event(LfRfidApp* app, LfRfidApp::Event* event) final;
-    void on_exit(LfRfidApp* app) final;
-
-private:
-    static void timeout_callback(void* context);
-};

+ 30 - 0
applications/lfrfid/scenes/lfrfid_scene.c

@@ -0,0 +1,30 @@
+#include "lfrfid_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const lfrfid_on_enter_handlers[])(void*) = {
+#include "lfrfid_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 lfrfid_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "lfrfid_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 lfrfid_on_exit_handlers[])(void* context) = {
+#include "lfrfid_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers lfrfid_scene_handlers = {
+    .on_enter_handlers = lfrfid_on_enter_handlers,
+    .on_event_handlers = lfrfid_on_event_handlers,
+    .on_exit_handlers = lfrfid_on_exit_handlers,
+    .scene_num = LfRfidSceneNum,
+};

+ 29 - 0
applications/lfrfid/scenes/lfrfid_scene.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include <gui/scene_manager.h>
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) LfRfidScene##id,
+typedef enum {
+#include "lfrfid_scene_config.h"
+    LfRfidSceneNum,
+} LfRfidScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers lfrfid_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "lfrfid_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 "lfrfid_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 "lfrfid_scene_config.h"
+#undef ADD_SCENE

+ 24 - 0
applications/lfrfid/scenes/lfrfid_scene_config.h

@@ -0,0 +1,24 @@
+ADD_SCENE(lfrfid, start, Start)
+ADD_SCENE(lfrfid, read, Read)
+ADD_SCENE(lfrfid, read_success, ReadSuccess)
+ADD_SCENE(lfrfid, retry_confirm, RetryConfirm)
+ADD_SCENE(lfrfid, exit_confirm, ExitConfirm)
+ADD_SCENE(lfrfid, delete_confirm, DeleteConfirm)
+ADD_SCENE(lfrfid, read_key_menu, ReadKeyMenu)
+ADD_SCENE(lfrfid, write, Write)
+ADD_SCENE(lfrfid, write_success, WriteSuccess)
+ADD_SCENE(lfrfid, emulate, Emulate)
+ADD_SCENE(lfrfid, save_name, SaveName)
+ADD_SCENE(lfrfid, save_success, SaveSuccess)
+ADD_SCENE(lfrfid, select_key, SelectKey)
+ADD_SCENE(lfrfid, saved_key_menu, SavedKeyMenu)
+ADD_SCENE(lfrfid, save_data, SaveData)
+ADD_SCENE(lfrfid, save_type, SaveType)
+ADD_SCENE(lfrfid, saved_info, SavedInfo)
+ADD_SCENE(lfrfid, delete_success, DeleteSuccess)
+ADD_SCENE(lfrfid, extra_actions, ExtraActions)
+ADD_SCENE(lfrfid, raw_info, RawInfo)
+ADD_SCENE(lfrfid, raw_name, RawName)
+ADD_SCENE(lfrfid, raw_read, RawRead)
+ADD_SCENE(lfrfid, raw_success, RawSuccess)
+ADD_SCENE(lfrfid, rpc, Rpc)

+ 68 - 0
applications/lfrfid/scenes/lfrfid_scene_delete_confirm.c

@@ -0,0 +1,68 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_delete_confirm_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    string_t tmp_string;
+    string_init(tmp_string);
+
+    widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app);
+    widget_add_button_element(widget, GuiButtonTypeRight, "Delete", lfrfid_widget_callback, app);
+
+    string_printf(tmp_string, "Delete %s?", string_get_cstr(app->file_name));
+    widget_add_string_element(
+        widget, 64, 0, AlignCenter, AlignTop, FontPrimary, string_get_cstr(tmp_string));
+
+    string_reset(tmp_string);
+    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+    uint8_t* data = (uint8_t*)malloc(size);
+    protocol_dict_get_data(app->dict, app->protocol_id, data, size);
+    for(uint8_t i = 0; i < MIN(size, (size_t)8); i++) {
+        if(i != 0) {
+            string_cat_printf(tmp_string, " ");
+        }
+
+        string_cat_printf(tmp_string, "%02X", data[i]);
+    }
+    free(data);
+
+    widget_add_string_element(
+        widget, 64, 19, AlignCenter, AlignTop, FontSecondary, string_get_cstr(tmp_string));
+    widget_add_string_element(
+        widget,
+        64,
+        49,
+        AlignCenter,
+        AlignBottom,
+        FontSecondary,
+        protocol_dict_get_name(app->dict, app->protocol_id));
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+    string_clear(tmp_string);
+}
+
+bool lfrfid_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true; // Ignore Back button presses
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == GuiButtonTypeLeft) {
+            scene_manager_previous_scene(scene_manager);
+        } else if(event.event == GuiButtonTypeRight) {
+            lfrfid_delete_key(app);
+            scene_manager_next_scene(scene_manager, LfRfidSceneDeleteSuccess);
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_delete_confirm_on_exit(void* context) {
+    LfRfid* app = context;
+    widget_reset(app->widget);
+}

+ 35 - 0
applications/lfrfid/scenes/lfrfid_scene_delete_success.c

@@ -0,0 +1,35 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_delete_success_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    popup_set_icon(popup, 0, 2, &I_DolphinMafia_115x62);
+    popup_set_header(popup, "Deleted", 83, 19, AlignLeft, AlignBottom);
+    popup_set_context(popup, app);
+    popup_set_callback(popup, lfrfid_popup_timeout_callback);
+    popup_set_timeout(popup, 1500);
+    popup_enable_timeout(popup);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+}
+
+bool lfrfid_scene_delete_success_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    if((event.type == SceneManagerEventTypeBack) ||
+       ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) {
+        scene_manager_search_and_switch_to_previous_scene(
+            app->scene_manager, LfRfidSceneSelectKey);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_delete_success_on_exit(void* context) {
+    LfRfid* app = context;
+
+    popup_reset(app->popup);
+}

+ 44 - 0
applications/lfrfid/scenes/lfrfid_scene_emulate.c

@@ -0,0 +1,44 @@
+#include "../lfrfid_i.h"
+#include <dolphin/dolphin.h>
+
+void lfrfid_scene_emulate_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    DOLPHIN_DEED(DolphinDeedRfidEmulate);
+
+    popup_set_header(popup, "Emulating", 89, 30, AlignCenter, AlignTop);
+    if(!string_empty_p(app->file_name)) {
+        popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
+    } else {
+        popup_set_text(
+            popup,
+            protocol_dict_get_name(app->dict, app->protocol_id),
+            89,
+            43,
+            AlignCenter,
+            AlignTop);
+    }
+    popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
+
+    lfrfid_worker_start_thread(app->lfworker);
+    lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
+    notification_message(app->notifications, &sequence_blink_start_magenta);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+}
+
+bool lfrfid_scene_emulate_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    bool consumed = false;
+    return consumed;
+}
+
+void lfrfid_scene_emulate_on_exit(void* context) {
+    LfRfid* app = context;
+    notification_message(app->notifications, &sequence_blink_stop);
+    popup_reset(app->popup);
+    lfrfid_worker_stop(app->lfworker);
+    lfrfid_worker_stop_thread(app->lfworker);
+}

+ 39 - 0
applications/lfrfid/scenes/lfrfid_scene_exit_confirm.c

@@ -0,0 +1,39 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_exit_confirm_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app);
+    widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app);
+    widget_add_string_element(
+        widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to RFID Menu?");
+    widget_add_string_element(
+        widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+}
+
+bool lfrfid_scene_exit_confirm_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true; // Ignore Back button presses
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == GuiButtonTypeLeft) {
+            scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneStart);
+        } else if(event.event == GuiButtonTypeRight) {
+            scene_manager_previous_scene(scene_manager);
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_exit_confirm_on_exit(void* context) {
+    LfRfid* app = context;
+    widget_reset(app->widget);
+}

+ 79 - 0
applications/lfrfid/scenes/lfrfid_scene_extra_actions.c

@@ -0,0 +1,79 @@
+#include "../lfrfid_i.h"
+
+typedef enum {
+    SubmenuIndexASK,
+    SubmenuIndexPSK,
+    SubmenuIndexRAW,
+} SubmenuIndex;
+
+static void lfrfid_scene_extra_actions_submenu_callback(void* context, uint32_t index) {
+    LfRfid* app = context;
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void lfrfid_scene_extra_actions_on_enter(void* context) {
+    LfRfid* app = context;
+    Submenu* submenu = app->submenu;
+
+    submenu_add_item(
+        submenu,
+        "Read ASK (Animal, Ordinary Card)",
+        SubmenuIndexASK,
+        lfrfid_scene_extra_actions_submenu_callback,
+        app);
+    submenu_add_item(
+        submenu,
+        "Read PSK (Indala)",
+        SubmenuIndexPSK,
+        lfrfid_scene_extra_actions_submenu_callback,
+        app);
+
+    if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) {
+        submenu_add_item(
+            submenu,
+            "Read RAW RFID data",
+            SubmenuIndexRAW,
+            lfrfid_scene_extra_actions_submenu_callback,
+            app);
+    }
+
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneExtraActions));
+
+    // clear key
+    string_reset(app->file_name);
+    app->protocol_id = PROTOCOL_NO;
+    app->read_type = LFRFIDWorkerReadTypeAuto;
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
+}
+
+bool lfrfid_scene_extra_actions_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SubmenuIndexASK) {
+            app->read_type = LFRFIDWorkerReadTypeASKOnly;
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
+            consumed = true;
+        } else if(event.event == SubmenuIndexPSK) {
+            app->read_type = LFRFIDWorkerReadTypePSKOnly;
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
+            consumed = true;
+        } else if(event.event == SubmenuIndexRAW) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneRawName);
+            consumed = true;
+        }
+        scene_manager_set_scene_state(app->scene_manager, LfRfidSceneExtraActions, event.event);
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_extra_actions_on_exit(void* context) {
+    LfRfid* app = context;
+
+    submenu_reset(app->submenu);
+}

+ 64 - 0
applications/lfrfid/scenes/lfrfid_scene_raw_info.c

@@ -0,0 +1,64 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_raw_info_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    // string_t tmp_string;
+    // string_init(tmp_string);
+
+    bool sd_exist = storage_sd_status(app->storage) == FSE_OK;
+    if(!sd_exist) {
+        widget_add_icon_element(widget, 0, 0, &I_SDQuestion_35x43);
+        widget_add_string_multiline_element(
+            widget,
+            81,
+            4,
+            AlignCenter,
+            AlignTop,
+            FontSecondary,
+            "No SD card found.\nThis function will not\nwork without\nSD card.");
+
+        widget_add_button_element(widget, GuiButtonTypeLeft, "Back", lfrfid_widget_callback, app);
+    } else {
+        widget_add_string_multiline_element(
+            widget,
+            0,
+            1,
+            AlignLeft,
+            AlignTop,
+            FontSecondary,
+            "RAW RFID data reader\n1) Put the Flipper on your card\n2) Press OK\n3) Wait until data is read");
+
+        widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app);
+    }
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+    //string_clear(tmp_string);
+}
+
+bool lfrfid_scene_raw_info_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true;
+        scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneExtraActions);
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == GuiButtonTypeCenter) {
+            scene_manager_next_scene(scene_manager, LfRfidSceneRawRead);
+        } else if(event.event == GuiButtonTypeLeft) {
+            scene_manager_search_and_switch_to_previous_scene(
+                scene_manager, LfRfidSceneExtraActions);
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_raw_info_on_exit(void* context) {
+    LfRfid* app = context;
+    widget_reset(app->widget);
+}

+ 58 - 0
applications/lfrfid/scenes/lfrfid_scene_raw_name.c

@@ -0,0 +1,58 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_raw_name_on_enter(void* context) {
+    LfRfid* app = context;
+    TextInput* text_input = app->text_input;
+
+    const char* key_name = string_get_cstr(app->raw_file_name);
+
+    bool key_name_is_empty = string_empty_p(app->file_name);
+    if(key_name_is_empty) {
+        lfrfid_text_store_set(app, "RfidRecord");
+    } else {
+        lfrfid_text_store_set(app, "%s", key_name);
+    }
+
+    text_input_set_header_text(text_input, "Name the raw file");
+
+    text_input_set_result_callback(
+        text_input,
+        lfrfid_text_input_callback,
+        app,
+        app->text_store,
+        LFRFID_KEY_NAME_SIZE,
+        key_name_is_empty);
+
+    ValidatorIsFile* validator_is_file =
+        validator_is_file_alloc_init(LFRFID_SD_FOLDER, LFRFID_APP_RAW_ASK_EXTENSION, NULL);
+    text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput);
+}
+
+bool lfrfid_scene_raw_name_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == LfRfidEventNext) {
+            consumed = true;
+            string_set_str(app->raw_file_name, app->text_store);
+            scene_manager_next_scene(scene_manager, LfRfidSceneRawInfo);
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_raw_name_on_exit(void* context) {
+    LfRfid* app = context;
+    TextInput* text_input = app->text_input;
+
+    void* validator_context = text_input_get_validator_callback_context(text_input);
+    text_input_set_validator(text_input, NULL, NULL);
+    validator_is_file_free((ValidatorIsFile*)validator_context);
+
+    text_input_reset(text_input);
+}

+ 126 - 0
applications/lfrfid/scenes/lfrfid_scene_raw_read.c

@@ -0,0 +1,126 @@
+#include "../lfrfid_i.h"
+
+#define RAW_READ_TIME 5000
+
+typedef struct {
+    string_t string_file_name;
+    FuriTimer* timer;
+    bool is_psk;
+    bool error;
+} LfRfidReadRawState;
+
+static void lfrfid_read_callback(LFRFIDWorkerReadRawResult result, void* context) {
+    LfRfid* app = context;
+
+    if(result == LFRFIDWorkerReadRawFileError) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadError);
+    } else if(result == LFRFIDWorkerReadRawOverrun) {
+        view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadOverrun);
+    }
+}
+
+static void timer_callback(void* context) {
+    LfRfid* app = context;
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, LfRfidEventReadDone);
+}
+
+void lfrfid_scene_raw_read_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    LfRfidReadRawState* state = malloc(sizeof(LfRfidReadRawState));
+    scene_manager_set_scene_state(app->scene_manager, LfRfidSceneRawRead, (uint32_t)state);
+    string_init(state->string_file_name);
+
+    popup_set_icon(popup, 0, 3, &I_RFIDDolphinReceive_97x61);
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+    lfrfid_worker_start_thread(app->lfworker);
+    lfrfid_make_app_folder(app);
+
+    state->timer = furi_timer_alloc(timer_callback, FuriTimerTypeOnce, app);
+    furi_timer_start(state->timer, RAW_READ_TIME);
+    string_printf(
+        state->string_file_name,
+        "%s/%s%s",
+        LFRFID_SD_FOLDER,
+        string_get_cstr(app->raw_file_name),
+        LFRFID_APP_RAW_ASK_EXTENSION);
+    popup_set_header(popup, "Reading\nRAW RFID\nASK", 89, 30, AlignCenter, AlignTop);
+    lfrfid_worker_read_raw_start(
+        app->lfworker,
+        string_get_cstr(state->string_file_name),
+        LFRFIDWorkerReadTypeASKOnly,
+        lfrfid_read_callback,
+        app);
+
+    notification_message(app->notifications, &sequence_blink_start_cyan);
+
+    state->is_psk = false;
+    state->error = false;
+}
+
+bool lfrfid_scene_raw_read_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+    LfRfidReadRawState* state =
+        (LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead);
+    bool consumed = false;
+
+    furi_assert(state);
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == LfRfidEventReadError) {
+            consumed = true;
+            state->error = true;
+            popup_set_header(
+                popup, "Reading\nRAW RFID\nFile error", 89, 30, AlignCenter, AlignTop);
+            notification_message(app->notifications, &sequence_blink_start_red);
+            furi_timer_stop(state->timer);
+        } else if(event.event == LfRfidEventReadDone) {
+            consumed = true;
+            if(!state->error) {
+                if(state->is_psk) {
+                    notification_message(app->notifications, &sequence_success);
+                    scene_manager_next_scene(app->scene_manager, LfRfidSceneRawSuccess);
+                } else {
+                    popup_set_header(
+                        popup, "Reading\nRAW RFID\nPSK", 89, 30, AlignCenter, AlignTop);
+                    notification_message(app->notifications, &sequence_blink_start_yellow);
+                    lfrfid_worker_stop(app->lfworker);
+                    string_printf(
+                        state->string_file_name,
+                        "%s/%s%s",
+                        LFRFID_SD_FOLDER,
+                        string_get_cstr(app->raw_file_name),
+                        LFRFID_APP_RAW_PSK_EXTENSION);
+                    lfrfid_worker_read_raw_start(
+                        app->lfworker,
+                        string_get_cstr(state->string_file_name),
+                        LFRFIDWorkerReadTypePSKOnly,
+                        lfrfid_read_callback,
+                        app);
+                    furi_timer_start(state->timer, RAW_READ_TIME);
+                    state->is_psk = true;
+                }
+            }
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_raw_read_on_exit(void* context) {
+    LfRfid* app = context;
+    LfRfidReadRawState* state =
+        (LfRfidReadRawState*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneRawRead);
+
+    notification_message(app->notifications, &sequence_blink_stop);
+    popup_reset(app->popup);
+    lfrfid_worker_stop(app->lfworker);
+    lfrfid_worker_stop_thread(app->lfworker);
+    furi_timer_free(state->timer);
+
+    string_clear(state->string_file_name);
+    free(state);
+}

+ 39 - 0
applications/lfrfid/scenes/lfrfid_scene_raw_success.c

@@ -0,0 +1,39 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_raw_success_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    widget_add_button_element(widget, GuiButtonTypeCenter, "OK", lfrfid_widget_callback, app);
+
+    widget_add_string_multiline_element(
+        widget,
+        0,
+        1,
+        AlignLeft,
+        AlignTop,
+        FontSecondary,
+        "RAW RFID read success!\nNow you can analyze files\nOr send them to developers");
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+}
+
+bool lfrfid_scene_raw_success_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == GuiButtonTypeCenter) {
+            scene_manager_search_and_switch_to_previous_scene(
+                scene_manager, LfRfidSceneExtraActions);
+        }
+    }
+    return consumed;
+}
+
+void lfrfid_scene_raw_success_on_exit(void* context) {
+    LfRfid* app = context;
+    widget_reset(app->widget);
+}

+ 109 - 0
applications/lfrfid/scenes/lfrfid_scene_read.c

@@ -0,0 +1,109 @@
+#include "../lfrfid_i.h"
+#include <dolphin/dolphin.h>
+
+static const NotificationSequence sequence_blink_set_yellow = {
+    &message_blink_set_color_yellow,
+    NULL,
+};
+
+static const NotificationSequence sequence_blink_set_green = {
+    &message_blink_set_color_green,
+    NULL,
+};
+
+static const NotificationSequence sequence_blink_set_cyan = {
+    &message_blink_set_color_cyan,
+    NULL,
+};
+
+static void
+    lfrfid_read_callback(LFRFIDWorkerReadResult result, ProtocolId protocol, void* context) {
+    LfRfid* app = context;
+    uint32_t event = 0;
+
+    if(result == LFRFIDWorkerReadSenseStart) {
+        event = LfRfidEventReadSenseStart;
+    } else if(result == LFRFIDWorkerReadSenseEnd) {
+        event = LfRfidEventReadSenseEnd;
+    } else if(result == LFRFIDWorkerReadSenseCardStart) {
+        event = LfRfidEventReadSenseCardStart;
+    } else if(result == LFRFIDWorkerReadSenseCardEnd) {
+        event = LfRfidEventReadSenseCardEnd;
+    } else if(result == LFRFIDWorkerReadDone) {
+        event = LfRfidEventReadDone;
+        app->protocol_id_next = protocol;
+    } else if(result == LFRFIDWorkerReadStartASK) {
+        event = LfRfidEventReadStartASK;
+    } else if(result == LFRFIDWorkerReadStartPSK) {
+        event = LfRfidEventReadStartPSK;
+    } else {
+        return;
+    }
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void lfrfid_scene_read_on_enter(void* context) {
+    LfRfid* app = context;
+
+    DOLPHIN_DEED(DolphinDeedRfidRead);
+    if(app->read_type == LFRFIDWorkerReadTypePSKOnly) {
+        lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPskOnly);
+    } else if(app->read_type == LFRFIDWorkerReadTypeASKOnly) {
+        lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAskOnly);
+    }
+
+    lfrfid_worker_start_thread(app->lfworker);
+    lfrfid_worker_read_start(app->lfworker, app->read_type, lfrfid_read_callback, app);
+
+    notification_message(app->notifications, &sequence_blink_start_cyan);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewRead);
+}
+
+bool lfrfid_scene_read_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == LfRfidEventReadSenseStart) {
+            notification_message(app->notifications, &sequence_blink_set_yellow);
+            consumed = true;
+        } else if(event.event == LfRfidEventReadSenseCardStart) {
+            notification_message(app->notifications, &sequence_blink_set_green);
+            consumed = true;
+        } else if(
+            (event.event == LfRfidEventReadSenseEnd) ||
+            (event.event == LfRfidEventReadSenseCardEnd)) {
+            notification_message(app->notifications, &sequence_blink_set_cyan);
+            consumed = true;
+        } else if(event.event == LfRfidEventReadDone) {
+            app->protocol_id = app->protocol_id_next;
+            DOLPHIN_DEED(DolphinDeedRfidReadSuccess);
+            notification_message(app->notifications, &sequence_success);
+            string_reset(app->file_name);
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneReadSuccess);
+            consumed = true;
+        } else if(event.event == LfRfidEventReadStartPSK) {
+            if(app->read_type == LFRFIDWorkerReadTypeAuto) {
+                lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadPsk);
+            }
+            consumed = true;
+        } else if(event.event == LfRfidEventReadStartASK) {
+            if(app->read_type == LFRFIDWorkerReadTypeAuto) {
+                lfrfid_view_read_set_read_mode(app->read_view, LfRfidReadAsk);
+            }
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_read_on_exit(void* context) {
+    LfRfid* app = context;
+    notification_message(app->notifications, &sequence_blink_stop);
+    popup_reset(app->popup);
+    lfrfid_worker_stop(app->lfworker);
+    lfrfid_worker_stop_thread(app->lfworker);
+}

+ 58 - 0
applications/lfrfid/scenes/lfrfid_scene_read_key_menu.c

@@ -0,0 +1,58 @@
+#include "../lfrfid_i.h"
+
+typedef enum {
+    SubmenuIndexSave,
+    SubmenuIndexEmulate,
+    SubmenuIndexWrite,
+} SubmenuIndex;
+
+void lfrfid_scene_read_key_menu_submenu_callback(void* context, uint32_t index) {
+    LfRfid* app = context;
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void lfrfid_scene_read_key_menu_on_enter(void* context) {
+    LfRfid* app = context;
+    Submenu* submenu = app->submenu;
+
+    submenu_add_item(
+        submenu, "Save", SubmenuIndexSave, lfrfid_scene_read_key_menu_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_read_key_menu_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Write", SubmenuIndexWrite, lfrfid_scene_read_key_menu_submenu_callback, app);
+
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu));
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
+}
+
+bool lfrfid_scene_read_key_menu_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SubmenuIndexWrite) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
+            consumed = true;
+        } else if(event.event == SubmenuIndexSave) {
+            string_reset(app->file_name);
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveName);
+            consumed = true;
+        } else if(event.event == SubmenuIndexEmulate) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
+            consumed = true;
+        }
+        scene_manager_set_scene_state(app->scene_manager, LfRfidSceneReadKeyMenu, event.event);
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_read_key_menu_on_exit(void* context) {
+    LfRfid* app = context;
+
+    submenu_reset(app->submenu);
+}

+ 79 - 0
applications/lfrfid/scenes/lfrfid_scene_read_success.c

@@ -0,0 +1,79 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_read_success_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    string_t tmp_string;
+    string_init(tmp_string);
+
+    widget_add_button_element(widget, GuiButtonTypeLeft, "Retry", lfrfid_widget_callback, app);
+    widget_add_button_element(widget, GuiButtonTypeRight, "More", lfrfid_widget_callback, app);
+
+    string_printf(
+        tmp_string,
+        "%s[%s]",
+        protocol_dict_get_name(app->dict, app->protocol_id),
+        protocol_dict_get_manufacturer(app->dict, app->protocol_id));
+
+    widget_add_string_element(
+        widget, 0, 2, AlignLeft, AlignTop, FontPrimary, string_get_cstr(tmp_string));
+
+    string_reset(tmp_string);
+    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+    uint8_t* data = (uint8_t*)malloc(size);
+    protocol_dict_get_data(app->dict, app->protocol_id, data, size);
+    for(uint8_t i = 0; i < size; i++) {
+        if(i != 0) {
+            string_cat_printf(tmp_string, " ");
+        }
+
+        if(i >= 9) {
+            string_cat_printf(tmp_string, "...");
+            break;
+        } else {
+            string_cat_printf(tmp_string, "%02X", data[i]);
+        }
+    }
+    free(data);
+
+    string_t render_data;
+    string_init(render_data);
+    protocol_dict_render_brief_data(app->dict, render_data, app->protocol_id);
+    string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data));
+    string_clear(render_data);
+
+    widget_add_string_element(
+        widget, 0, 16, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string));
+
+    notification_message_block(app->notifications, &sequence_set_green_255);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+    string_clear(tmp_string);
+}
+
+bool lfrfid_scene_read_success_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        scene_manager_next_scene(scene_manager, LfRfidSceneExitConfirm);
+        consumed = true;
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == GuiButtonTypeLeft) {
+            scene_manager_next_scene(scene_manager, LfRfidSceneRetryConfirm);
+        } else if(event.event == GuiButtonTypeRight) {
+            scene_manager_next_scene(scene_manager, LfRfidSceneReadKeyMenu);
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_read_success_on_exit(void* context) {
+    LfRfid* app = context;
+    notification_message_block(app->notifications, &sequence_reset_green);
+    widget_reset(app->widget);
+}

+ 39 - 0
applications/lfrfid/scenes/lfrfid_scene_retry_confirm.c

@@ -0,0 +1,39 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_retry_confirm_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    widget_add_button_element(widget, GuiButtonTypeLeft, "Exit", lfrfid_widget_callback, app);
+    widget_add_button_element(widget, GuiButtonTypeRight, "Stay", lfrfid_widget_callback, app);
+    widget_add_string_element(
+        widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Return to reading?");
+    widget_add_string_element(
+        widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost!");
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+}
+
+bool lfrfid_scene_retry_confirm_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true; // Ignore Back button presses
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == GuiButtonTypeLeft) {
+            scene_manager_search_and_switch_to_previous_scene(scene_manager, LfRfidSceneRead);
+        } else if(event.event == GuiButtonTypeRight) {
+            scene_manager_previous_scene(scene_manager);
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_retry_confirm_on_exit(void* context) {
+    LfRfid* app = context;
+    widget_reset(app->widget);
+}

+ 67 - 0
applications/lfrfid/scenes/lfrfid_scene_rpc.c

@@ -0,0 +1,67 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_rpc_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    popup_set_header(popup, "LF RFID", 89, 42, AlignCenter, AlignBottom);
+    popup_set_text(popup, "RPC mode", 89, 44, AlignCenter, AlignTop);
+    popup_set_icon(popup, 0, 12, &I_RFIDDolphinSend_97x61);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+
+    notification_message(app->notifications, &sequence_display_backlight_on);
+
+    app->rpc_state = LfRfidRpcStateIdle;
+}
+
+bool lfrfid_scene_rpc_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+    UNUSED(event);
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        consumed = true;
+        if(event.event == LfRfidEventExit) {
+            rpc_system_app_confirm(app->rpc_ctx, RpcAppEventAppExit, true);
+            scene_manager_stop(app->scene_manager);
+            view_dispatcher_stop(app->view_dispatcher);
+        } else if(event.event == LfRfidEventRpcSessionClose) {
+            scene_manager_stop(app->scene_manager);
+            view_dispatcher_stop(app->view_dispatcher);
+        } else if(event.event == LfRfidEventRpcLoadFile) {
+            const char* arg = rpc_system_app_get_data(app->rpc_ctx);
+            bool result = false;
+            if(arg && (app->rpc_state == LfRfidRpcStateIdle)) {
+                string_set_str(app->file_path, arg);
+                if(lfrfid_load_key_data(app, app->file_path, false)) {
+                    lfrfid_worker_start_thread(app->lfworker);
+                    lfrfid_worker_emulate_start(app->lfworker, (LFRFIDProtocol)app->protocol_id);
+                    app->rpc_state = LfRfidRpcStateEmulating;
+
+                    lfrfid_text_store_set(app, "emulating\n%s", string_get_cstr(app->file_name));
+                    popup_set_text(popup, app->text_store, 89, 44, AlignCenter, AlignTop);
+
+                    notification_message(app->notifications, &sequence_blink_start_magenta);
+                    result = true;
+                }
+            }
+            rpc_system_app_confirm(app->rpc_ctx, RpcAppEventLoadFile, result);
+        }
+    }
+    return consumed;
+}
+
+void lfrfid_scene_rpc_on_exit(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    if(app->rpc_state == LfRfidRpcStateEmulating) {
+        lfrfid_worker_stop(app->lfworker);
+        lfrfid_worker_stop_thread(app->lfworker);
+        notification_message(app->notifications, &sequence_blink_stop);
+    }
+
+    popup_reset(popup);
+}

+ 51 - 0
applications/lfrfid/scenes/lfrfid_scene_save_data.c

@@ -0,0 +1,51 @@
+#include "../lfrfid_i.h"
+#include <dolphin/dolphin.h>
+
+void lfrfid_scene_save_data_on_enter(void* context) {
+    LfRfid* app = context;
+    ByteInput* byte_input = app->byte_input;
+
+    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+
+    bool need_restore = scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveData);
+
+    if(need_restore) {
+        protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
+    } else {
+        protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
+    }
+
+    protocol_dict_get_data(app->dict, app->protocol_id, app->new_key_data, size);
+
+    byte_input_set_header_text(byte_input, "Enter the data in hex");
+
+    byte_input_set_result_callback(
+        byte_input, lfrfid_text_input_callback, NULL, app, app->new_key_data, size);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewByteInput);
+}
+
+bool lfrfid_scene_save_data_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == LfRfidEventNext) {
+            consumed = true;
+            size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+            protocol_dict_set_data(app->dict, app->protocol_id, app->new_key_data, size);
+            DOLPHIN_DEED(DolphinDeedRfidAdd);
+            scene_manager_next_scene(scene_manager, LfRfidSceneSaveName);
+            scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 1);
+        }
+    } else if(event.type == SceneManagerEventTypeBack) {
+        scene_manager_set_scene_state(scene_manager, LfRfidSceneSaveData, 0);
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_save_data_on_exit(void* context) {
+    UNUSED(context);
+}

+ 76 - 0
applications/lfrfid/scenes/lfrfid_scene_save_name.c

@@ -0,0 +1,76 @@
+#include "m-string.h"
+#include <lib/toolbox/random_name.h>
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_save_name_on_enter(void* context) {
+    LfRfid* app = context;
+    TextInput* text_input = app->text_input;
+    string_t folder_path;
+    string_init(folder_path);
+
+    bool key_name_is_empty = string_empty_p(app->file_name);
+    if(key_name_is_empty) {
+        string_set_str(app->file_path, LFRFID_APP_FOLDER);
+        set_random_name(app->text_store, LFRFID_TEXT_STORE_SIZE);
+        string_set_str(folder_path, LFRFID_APP_FOLDER);
+    } else {
+        lfrfid_text_store_set(app, "%s", string_get_cstr(app->file_name));
+        path_extract_dirname(string_get_cstr(app->file_path), folder_path);
+    }
+
+    text_input_set_header_text(text_input, "Name the card");
+    text_input_set_result_callback(
+        text_input,
+        lfrfid_text_input_callback,
+        app,
+        app->text_store,
+        LFRFID_KEY_NAME_SIZE,
+        key_name_is_empty);
+
+    FURI_LOG_I("", "%s %s", string_get_cstr(folder_path), app->text_store);
+
+    ValidatorIsFile* validator_is_file = validator_is_file_alloc_init(
+        string_get_cstr(folder_path), LFRFID_APP_EXTENSION, string_get_cstr(app->file_name));
+    text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
+
+    string_clear(folder_path);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewTextInput);
+}
+
+bool lfrfid_scene_save_name_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    SceneManager* scene_manager = app->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == LfRfidEventNext) {
+            consumed = true;
+            if(!string_empty_p(app->file_name)) {
+                lfrfid_delete_key(app);
+            }
+
+            string_set_str(app->file_name, app->text_store);
+
+            if(lfrfid_save_key(app)) {
+                scene_manager_next_scene(scene_manager, LfRfidSceneSaveSuccess);
+            } else {
+                scene_manager_search_and_switch_to_previous_scene(
+                    scene_manager, LfRfidSceneReadKeyMenu);
+            }
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_save_name_on_exit(void* context) {
+    LfRfid* app = context;
+    TextInput* text_input = app->text_input;
+
+    void* validator_context = text_input_get_validator_callback_context(text_input);
+    text_input_set_validator(text_input, NULL, NULL);
+    validator_is_file_free((ValidatorIsFile*)validator_context);
+
+    text_input_reset(text_input);
+}

+ 43 - 0
applications/lfrfid/scenes/lfrfid_scene_save_success.c

@@ -0,0 +1,43 @@
+#include "../lfrfid_i.h"
+#include <dolphin/dolphin.h>
+
+void lfrfid_scene_save_success_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    DOLPHIN_DEED(DolphinDeedRfidSave);
+    popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
+    popup_set_header(popup, "Saved!", 5, 7, AlignLeft, AlignTop);
+    popup_set_context(popup, app);
+    popup_set_callback(popup, lfrfid_popup_timeout_callback);
+    popup_set_timeout(popup, 1500);
+    popup_enable_timeout(popup);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+}
+
+bool lfrfid_scene_save_success_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey};
+
+    if((event.type == SceneManagerEventTypeBack) ||
+       ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) {
+        bool result = scene_manager_search_and_switch_to_previous_scene_one_of(
+            app->scene_manager, prev_scenes, COUNT_OF(prev_scenes));
+        if(!result) {
+            scene_manager_search_and_switch_to_another_scene(
+                app->scene_manager, LfRfidSceneSelectKey);
+        }
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_save_success_on_exit(void* context) {
+    LfRfid* app = context;
+
+    popup_reset(app->popup);
+}

+ 86 - 0
applications/lfrfid/scenes/lfrfid_scene_save_type.c

@@ -0,0 +1,86 @@
+#include "../lfrfid_i.h"
+
+typedef struct {
+    string_t menu_item_name[LFRFIDProtocolMax];
+    uint32_t line_sel;
+} SaveTypeCtx;
+
+static void lfrfid_scene_save_type_submenu_callback(void* context, uint32_t index) {
+    LfRfid* app = context;
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void lfrfid_scene_save_type_on_enter(void* context) {
+    LfRfid* app = context;
+    Submenu* submenu = app->submenu;
+
+    SaveTypeCtx* state = malloc(sizeof(SaveTypeCtx));
+    for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) {
+        if(strcmp(
+               protocol_dict_get_manufacturer(app->dict, i),
+               protocol_dict_get_name(app->dict, i)) != 0) {
+            string_init_printf(
+                state->menu_item_name[i],
+                "%s %s",
+                protocol_dict_get_manufacturer(app->dict, i),
+                protocol_dict_get_name(app->dict, i));
+        } else {
+            string_init_printf(
+                state->menu_item_name[i], "%s", protocol_dict_get_name(app->dict, i));
+        }
+        submenu_add_item(
+            submenu,
+            string_get_cstr(state->menu_item_name[i]),
+            i,
+            lfrfid_scene_save_type_submenu_callback,
+            app);
+    }
+
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType));
+
+    scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, (uint32_t)state);
+
+    // clear key name
+    string_reset(app->file_name);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
+}
+
+bool lfrfid_scene_save_type_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    SaveTypeCtx* state =
+        (SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType);
+    furi_check(state);
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        app->protocol_id = event.event;
+        state->line_sel = event.event;
+        scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_save_type_on_exit(void* context) {
+    LfRfid* app = context;
+    SaveTypeCtx* state =
+        (SaveTypeCtx*)scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSaveType);
+    furi_check(state);
+
+    submenu_reset(app->submenu);
+
+    for(uint8_t i = 0; i < LFRFIDProtocolMax; i++) {
+        string_clear(state->menu_item_name[i]);
+    }
+
+    uint32_t line_sel = state->line_sel;
+
+    free(state);
+
+    scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSaveType, line_sel);
+}

+ 51 - 0
applications/lfrfid/scenes/lfrfid_scene_saved_info.c

@@ -0,0 +1,51 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_saved_info_on_enter(void* context) {
+    LfRfid* app = context;
+    Widget* widget = app->widget;
+
+    string_t tmp_string;
+    string_init(tmp_string);
+
+    string_printf(
+        tmp_string,
+        "%s [%s]\r\n",
+        string_get_cstr(app->file_name),
+        protocol_dict_get_name(app->dict, app->protocol_id));
+
+    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+    uint8_t* data = (uint8_t*)malloc(size);
+    protocol_dict_get_data(app->dict, app->protocol_id, data, size);
+    for(uint8_t i = 0; i < size; i++) {
+        if(i != 0) {
+            string_cat_printf(tmp_string, " ");
+        }
+
+        string_cat_printf(tmp_string, "%02X", data[i]);
+    }
+    free(data);
+
+    string_t render_data;
+    string_init(render_data);
+    protocol_dict_render_data(app->dict, render_data, app->protocol_id);
+    string_cat_printf(tmp_string, "\r\n%s", string_get_cstr(render_data));
+    string_clear(render_data);
+
+    widget_add_string_multiline_element(
+        widget, 0, 1, AlignLeft, AlignTop, FontSecondary, string_get_cstr(tmp_string));
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewWidget);
+    string_clear(tmp_string);
+}
+
+bool lfrfid_scene_saved_info_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    bool consumed = false;
+    return consumed;
+}
+
+void lfrfid_scene_saved_info_on_exit(void* context) {
+    LfRfid* app = context;
+    widget_reset(app->widget);
+}

+ 69 - 0
applications/lfrfid/scenes/lfrfid_scene_saved_key_menu.c

@@ -0,0 +1,69 @@
+#include "../lfrfid_i.h"
+
+typedef enum {
+    SubmenuIndexEmulate,
+    SubmenuIndexWrite,
+    SubmenuIndexEdit,
+    SubmenuIndexDelete,
+    SubmenuIndexInfo,
+} SubmenuIndex;
+
+static void lfrfid_scene_saved_key_menu_submenu_callback(void* context, uint32_t index) {
+    LfRfid* app = context;
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void lfrfid_scene_saved_key_menu_on_enter(void* context) {
+    LfRfid* app = context;
+    Submenu* submenu = app->submenu;
+
+    submenu_add_item(
+        submenu, "Emulate", SubmenuIndexEmulate, lfrfid_scene_saved_key_menu_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Write", SubmenuIndexWrite, lfrfid_scene_saved_key_menu_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Edit", SubmenuIndexEdit, lfrfid_scene_saved_key_menu_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Delete", SubmenuIndexDelete, lfrfid_scene_saved_key_menu_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Info", SubmenuIndexInfo, lfrfid_scene_saved_key_menu_submenu_callback, app);
+
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu));
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
+}
+
+bool lfrfid_scene_saved_key_menu_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SubmenuIndexEmulate) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneEmulate);
+            consumed = true;
+        } else if(event.event == SubmenuIndexWrite) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneWrite);
+            consumed = true;
+        } else if(event.event == SubmenuIndexEdit) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveData);
+            consumed = true;
+        } else if(event.event == SubmenuIndexDelete) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneDeleteConfirm);
+            consumed = true;
+        } else if(event.event == SubmenuIndexInfo) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedInfo);
+            consumed = true;
+        }
+        scene_manager_set_scene_state(app->scene_manager, LfRfidSceneSavedKeyMenu, event.event);
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_saved_key_menu_on_exit(void* context) {
+    LfRfid* app = context;
+
+    submenu_reset(app->submenu);
+}

+ 22 - 0
applications/lfrfid/scenes/lfrfid_scene_select_key.c

@@ -0,0 +1,22 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_select_key_on_enter(void* context) {
+    LfRfid* app = context;
+
+    if(lfrfid_load_key_from_file_select(app)) {
+        scene_manager_next_scene(app->scene_manager, LfRfidSceneSavedKeyMenu);
+    } else {
+        scene_manager_previous_scene(app->scene_manager);
+    }
+}
+
+bool lfrfid_scene_select_key_on_event(void* context, SceneManagerEvent event) {
+    UNUSED(context);
+    UNUSED(event);
+    bool consumed = false;
+    return consumed;
+}
+
+void lfrfid_scene_select_key_on_exit(void* context) {
+    UNUSED(context);
+}

+ 72 - 0
applications/lfrfid/scenes/lfrfid_scene_start.c

@@ -0,0 +1,72 @@
+#include "../lfrfid_i.h"
+
+typedef enum {
+    SubmenuIndexRead,
+    SubmenuIndexSaved,
+    SubmenuIndexAddManually,
+    SubmenuIndexExtraActions,
+} SubmenuIndex;
+
+static void lfrfid_scene_start_submenu_callback(void* context, uint32_t index) {
+    LfRfid* app = context;
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void lfrfid_scene_start_on_enter(void* context) {
+    LfRfid* app = context;
+    Submenu* submenu = app->submenu;
+
+    submenu_add_item(submenu, "Read", SubmenuIndexRead, lfrfid_scene_start_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Saved", SubmenuIndexSaved, lfrfid_scene_start_submenu_callback, app);
+    submenu_add_item(
+        submenu, "Add Manually", SubmenuIndexAddManually, lfrfid_scene_start_submenu_callback, app);
+    submenu_add_item(
+        submenu,
+        "Extra Actions",
+        SubmenuIndexExtraActions,
+        lfrfid_scene_start_submenu_callback,
+        app);
+
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(app->scene_manager, LfRfidSceneStart));
+
+    // clear key
+    string_reset(app->file_name);
+    app->protocol_id = PROTOCOL_NO;
+    app->read_type = LFRFIDWorkerReadTypeAuto;
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewSubmenu);
+}
+
+bool lfrfid_scene_start_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == SubmenuIndexRead) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneRead);
+            consumed = true;
+        } else if(event.event == SubmenuIndexSaved) {
+            string_set_str(app->file_path, LFRFID_APP_FOLDER);
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneSelectKey);
+            consumed = true;
+        } else if(event.event == SubmenuIndexAddManually) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneSaveType);
+            consumed = true;
+        } else if(event.event == SubmenuIndexExtraActions) {
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneExtraActions);
+            consumed = true;
+        }
+        scene_manager_set_scene_state(app->scene_manager, LfRfidSceneStart, event.event);
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_start_on_exit(void* context) {
+    LfRfid* app = context;
+
+    submenu_reset(app->submenu);
+}

+ 96 - 0
applications/lfrfid/scenes/lfrfid_scene_write.c

@@ -0,0 +1,96 @@
+#include "../lfrfid_i.h"
+
+static void lfrfid_write_callback(LFRFIDWorkerWriteResult result, void* context) {
+    LfRfid* app = context;
+    uint32_t event = 0;
+
+    if(result == LFRFIDWorkerWriteOK) {
+        event = LfRfidEventWriteOK;
+    } else if(result == LFRFIDWorkerWriteProtocolCannotBeWritten) {
+        event = LfRfidEventWriteProtocolCannotBeWritten;
+    } else if(result == LFRFIDWorkerWriteFobCannotBeWritten) {
+        event = LfRfidEventWriteFobCannotBeWritten;
+    } else if(result == LFRFIDWorkerWriteTooLongToWrite) {
+        event = LfRfidEventWriteTooLongToWrite;
+    }
+
+    view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void lfrfid_scene_write_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    popup_set_header(popup, "Writing", 89, 30, AlignCenter, AlignTop);
+    if(!string_empty_p(app->file_name)) {
+        popup_set_text(popup, string_get_cstr(app->file_name), 89, 43, AlignCenter, AlignTop);
+    } else {
+        popup_set_text(
+            popup,
+            protocol_dict_get_name(app->dict, app->protocol_id),
+            89,
+            43,
+            AlignCenter,
+            AlignTop);
+    }
+    popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+
+    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+    app->old_key_data = (uint8_t*)malloc(size);
+    protocol_dict_get_data(app->dict, app->protocol_id, app->old_key_data, size);
+
+    lfrfid_worker_start_thread(app->lfworker);
+    lfrfid_worker_write_start(
+        app->lfworker, (LFRFIDProtocol)app->protocol_id, lfrfid_write_callback, app);
+    notification_message(app->notifications, &sequence_blink_start_magenta);
+}
+
+bool lfrfid_scene_write_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == LfRfidEventWriteOK) {
+            notification_message(app->notifications, &sequence_success);
+            scene_manager_next_scene(app->scene_manager, LfRfidSceneWriteSuccess);
+            consumed = true;
+        } else if(event.event == LfRfidEventWriteProtocolCannotBeWritten) {
+            popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
+            popup_set_header(popup, "Error", 64, 3, AlignCenter, AlignTop);
+            popup_set_text(popup, "This protocol\ncannot be written", 3, 17, AlignLeft, AlignTop);
+            notification_message(app->notifications, &sequence_blink_start_red);
+            consumed = true;
+        } else if(
+            (event.event == LfRfidEventWriteFobCannotBeWritten) ||
+            (event.event == LfRfidEventWriteTooLongToWrite)) {
+            popup_set_icon(popup, 72, 17, &I_DolphinCommon_56x48);
+            popup_set_header(popup, "Still trying to write...", 64, 3, AlignCenter, AlignTop);
+            popup_set_text(
+                popup,
+                "Make sure this\ncard is writable\nand not\nprotected.",
+                3,
+                17,
+                AlignLeft,
+                AlignTop);
+            notification_message(app->notifications, &sequence_blink_start_yellow);
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_write_on_exit(void* context) {
+    LfRfid* app = context;
+    notification_message(app->notifications, &sequence_blink_stop);
+    popup_reset(app->popup);
+    lfrfid_worker_stop(app->lfworker);
+    lfrfid_worker_stop_thread(app->lfworker);
+
+    size_t size = protocol_dict_get_data_size(app->dict, app->protocol_id);
+    protocol_dict_set_data(app->dict, app->protocol_id, app->old_key_data, size);
+    free(app->old_key_data);
+}

+ 38 - 0
applications/lfrfid/scenes/lfrfid_scene_write_success.c

@@ -0,0 +1,38 @@
+#include "../lfrfid_i.h"
+
+void lfrfid_scene_write_success_on_enter(void* context) {
+    LfRfid* app = context;
+    Popup* popup = app->popup;
+
+    popup_set_header(popup, "Successfully\nwritten!", 94, 3, AlignCenter, AlignTop);
+    popup_set_icon(popup, 0, 6, &I_RFIDDolphinSuccess_108x57);
+    popup_set_context(popup, app);
+    popup_set_callback(popup, lfrfid_popup_timeout_callback);
+    popup_set_timeout(popup, 1500);
+    popup_enable_timeout(popup);
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, LfRfidViewPopup);
+    notification_message_block(app->notifications, &sequence_set_green_255);
+}
+
+bool lfrfid_scene_write_success_on_event(void* context, SceneManagerEvent event) {
+    LfRfid* app = context;
+    bool consumed = false;
+
+    const uint32_t prev_scenes[] = {LfRfidSceneReadKeyMenu, LfRfidSceneSelectKey};
+
+    if((event.type == SceneManagerEventTypeBack) ||
+       ((event.type == SceneManagerEventTypeCustom) && (event.event == LfRfidEventPopupClosed))) {
+        scene_manager_search_and_switch_to_previous_scene_one_of(
+            app->scene_manager, prev_scenes, COUNT_OF(prev_scenes));
+        consumed = true;
+    }
+
+    return consumed;
+}
+
+void lfrfid_scene_write_success_on_exit(void* context) {
+    LfRfid* app = context;
+    notification_message_block(app->notifications, &sequence_reset_green);
+    popup_reset(app->popup);
+}

+ 0 - 115
applications/lfrfid/view/container_vm.cpp

@@ -1,115 +0,0 @@
-#include "container_vm.h"
-#include "elements/generic_element.h"
-#include "elements/string_element.h"
-#include "elements/icon_element.h"
-#include "elements/button_element.h"
-#include <list>
-
-class ContainerVMData {
-public:
-    ContainerVMData(){};
-
-    ~ContainerVMData() {
-        for(auto& it : elements) delete it;
-    };
-
-    std::list<GenericElement*> elements;
-
-    template <typename T> T add(const T element, View* view) {
-        elements.push_back(element);
-        element->set_parent_view(view);
-        return element;
-    }
-
-    void clean() {
-        for(auto& it : elements) delete it;
-        elements.clear();
-    }
-};
-
-struct ContainerVMModel {
-    ContainerVMData* data;
-};
-
-ContainerVM::ContainerVM() {
-    view = view_alloc();
-    view_set_context(view, this);
-    view_allocate_model(view, ViewModelTypeLocking, sizeof(ContainerVMModel));
-
-    with_view_model_cpp(view, ContainerVMModel, model, {
-        model->data = new ContainerVMData();
-        return true;
-    });
-
-    view_set_draw_callback(view, view_draw_callback);
-    view_set_input_callback(view, view_input_callback);
-}
-
-ContainerVM::~ContainerVM() {
-    with_view_model_cpp(view, ContainerVMModel, model, {
-        delete model->data;
-        model->data = NULL;
-        return false;
-    });
-
-    view_free(view);
-}
-
-View* ContainerVM::get_view() {
-    return view;
-}
-
-void ContainerVM::clean() {
-    with_view_model_cpp(view, ContainerVMModel, model, {
-        model->data->clean();
-        return true;
-    });
-}
-
-template <typename T> T* ContainerVM::add() {
-    T* element = new T();
-
-    with_view_model_cpp(view, ContainerVMModel, model, {
-        model->data->add(element, view);
-        return true;
-    });
-
-    return element;
-}
-
-void ContainerVM::view_draw_callback(Canvas* canvas, void* model) {
-    ContainerVMData* data = static_cast<ContainerVMModel*>(model)->data;
-
-    canvas_clear(canvas);
-    canvas_set_color(canvas, ColorBlack);
-    canvas_set_font(canvas, FontPrimary);
-
-    for(const auto& element : data->elements) {
-        element->draw(canvas);
-    }
-}
-
-bool ContainerVM::view_input_callback(InputEvent* event, void* context) {
-    bool consumed = false;
-    View* view = static_cast<ContainerVM*>(context)->view;
-
-    with_view_model_cpp(view, ContainerVMModel, model, {
-        for(const auto& element : model->data->elements) {
-            if(element->input(event)) {
-                consumed = true;
-            }
-
-            if(consumed) {
-                break;
-            }
-        }
-
-        return consumed;
-    });
-
-    return consumed;
-}
-
-template StringElement* ContainerVM::add<StringElement>();
-template IconElement* ContainerVM::add<IconElement>();
-template ButtonElement* ContainerVM::add<ButtonElement>();

+ 0 - 17
applications/lfrfid/view/container_vm.h

@@ -1,17 +0,0 @@
-#pragma once
-#include <view_modules/generic_view_module.h>
-
-class ContainerVM : public GenericViewModule {
-public:
-    ContainerVM();
-    ~ContainerVM() final;
-    View* get_view() final;
-    void clean() final;
-
-    template <typename T> T* add();
-
-private:
-    View* view;
-    static void view_draw_callback(Canvas* canvas, void* model);
-    static bool view_input_callback(InputEvent* event, void* context);
-};

+ 0 - 65
applications/lfrfid/view/elements/button_element.cpp

@@ -1,65 +0,0 @@
-#include "button_element.h"
-#include <gui/elements.h>
-
-ButtonElement::ButtonElement() {
-}
-
-ButtonElement::~ButtonElement() {
-}
-
-void ButtonElement::draw(Canvas* canvas) {
-    if(text != nullptr) {
-        canvas_set_font(canvas, FontSecondary);
-        switch(type) {
-        case Type::Left:
-            elements_button_left(canvas, text);
-            break;
-        case Type::Center:
-            elements_button_center(canvas, text);
-            break;
-        case Type::Right:
-            elements_button_right(canvas, text);
-            break;
-        }
-    }
-}
-
-bool ButtonElement::input(InputEvent* event) {
-    bool consumed = false;
-    if(event->type == InputTypeShort && callback != nullptr) {
-        switch(type) {
-        case Type::Left:
-            if(event->key == InputKeyLeft) {
-                callback(context);
-                consumed = true;
-            }
-            break;
-        case Type::Center:
-            if(event->key == InputKeyOk) {
-                callback(context);
-                consumed = true;
-            }
-            break;
-        case Type::Right:
-            if(event->key == InputKeyRight) {
-                callback(context);
-                consumed = true;
-            }
-            break;
-        }
-    }
-
-    return consumed;
-}
-
-void ButtonElement::set_type(Type _type, const char* _text) {
-    lock_model();
-    type = _type;
-    text = _text;
-    unlock_model(true);
-}
-
-void ButtonElement::set_callback(void* _context, ButtonElementCallback _callback) {
-    context = _context;
-    callback = _callback;
-}

+ 0 - 28
applications/lfrfid/view/elements/button_element.h

@@ -1,28 +0,0 @@
-#pragma once
-#include "generic_element.h"
-
-typedef void (*ButtonElementCallback)(void* context);
-
-class ButtonElement : public GenericElement {
-public:
-    ButtonElement();
-    ~ButtonElement() final;
-    void draw(Canvas* canvas) final;
-    bool input(InputEvent* event) final;
-
-    enum class Type : uint8_t {
-        Left,
-        Center,
-        Right,
-    };
-
-    void set_type(Type type, const char* text);
-    void set_callback(void* context, ButtonElementCallback callback);
-
-private:
-    Type type = Type::Left;
-    const char* text = nullptr;
-
-    void* context = nullptr;
-    ButtonElementCallback callback = nullptr;
-};

+ 0 - 15
applications/lfrfid/view/elements/generic_element.cpp

@@ -1,15 +0,0 @@
-#include "generic_element.h"
-
-void GenericElement::lock_model() {
-    furi_assert(view != nullptr);
-    view_get_model(view);
-}
-
-void GenericElement::unlock_model(bool need_redraw) {
-    furi_assert(view != nullptr);
-    view_commit_model(view, need_redraw);
-}
-
-void GenericElement::set_parent_view(View* _view) {
-    view = _view;
-}

+ 0 - 21
applications/lfrfid/view/elements/generic_element.h

@@ -1,21 +0,0 @@
-#pragma once
-#include <gui/gui.h>
-#include <gui/view.h>
-
-class GenericElement {
-public:
-    GenericElement(){};
-    virtual ~GenericElement(){};
-    virtual void draw(Canvas* canvas) = 0;
-    virtual bool input(InputEvent* event) = 0;
-
-    // TODO that must be accessible only to ContainerVMData
-    void set_parent_view(View* view);
-
-    // TODO that must be accessible only to inheritors
-    void lock_model();
-    void unlock_model(bool need_redraw);
-
-private:
-    View* view = nullptr;
-};

+ 0 - 25
applications/lfrfid/view/elements/icon_element.cpp

@@ -1,25 +0,0 @@
-#include "icon_element.h"
-
-IconElement::IconElement() {
-}
-
-IconElement::~IconElement() {
-}
-
-void IconElement::draw(Canvas* canvas) {
-    if(icon != NULL) {
-        canvas_draw_icon(canvas, x, y, icon);
-    }
-}
-
-bool IconElement::input(InputEvent* /* event */) {
-    return false;
-}
-
-void IconElement::set_icon(uint8_t _x, uint8_t _y, const Icon* _icon) {
-    lock_model();
-    icon = _icon;
-    x = _x;
-    y = _y;
-    unlock_model(true);
-}

+ 0 - 17
applications/lfrfid/view/elements/icon_element.h

@@ -1,17 +0,0 @@
-#pragma once
-#include "generic_element.h"
-
-class IconElement : public GenericElement {
-public:
-    IconElement();
-    ~IconElement() final;
-    void draw(Canvas* canvas) final;
-    bool input(InputEvent* event) final;
-
-    void set_icon(uint8_t x = 0, uint8_t y = 0, const Icon* icon = NULL);
-
-private:
-    const Icon* icon = NULL;
-    uint8_t x = 0;
-    uint8_t y = 0;
-};

+ 0 - 47
applications/lfrfid/view/elements/string_element.cpp

@@ -1,47 +0,0 @@
-#include "string_element.h"
-#include <gui/elements.h>
-
-StringElement::StringElement() {
-}
-
-StringElement::~StringElement() {
-}
-
-void StringElement::draw(Canvas* canvas) {
-    if(text) {
-        string_t line;
-        string_init(line);
-        string_set_str(line, text);
-
-        canvas_set_font(canvas, font);
-        if(fit_width != 0) {
-            elements_string_fit_width(canvas, line, fit_width);
-        }
-        elements_multiline_text_aligned(canvas, x, y, horizontal, vertical, string_get_cstr(line));
-
-        string_clear(line);
-    }
-}
-
-bool StringElement::input(InputEvent* /* event */) {
-    return false;
-}
-
-void StringElement::set_text(
-    const char* _text,
-    uint8_t _x,
-    uint8_t _y,
-    uint8_t _fit_w,
-    Align _horizontal,
-    Align _vertical,
-    Font _font) {
-    lock_model();
-    text = _text;
-    x = _x;
-    y = _y;
-    fit_width = _fit_w;
-    horizontal = _horizontal;
-    vertical = _vertical;
-    font = _font;
-    unlock_model(true);
-}

+ 0 - 28
applications/lfrfid/view/elements/string_element.h

@@ -1,28 +0,0 @@
-#pragma once
-#include "generic_element.h"
-
-class StringElement : public GenericElement {
-public:
-    StringElement();
-    ~StringElement() final;
-    void draw(Canvas* canvas) final;
-    bool input(InputEvent* event) final;
-
-    void set_text(
-        const char* text = NULL,
-        uint8_t x = 0,
-        uint8_t y = 0,
-        uint8_t fit_width = 0,
-        Align horizontal = AlignLeft,
-        Align vertical = AlignTop,
-        Font font = FontPrimary);
-
-private:
-    const char* text = NULL;
-    uint8_t x = 0;
-    uint8_t y = 0;
-    uint8_t fit_width = 0;
-    Align horizontal = AlignLeft;
-    Align vertical = AlignTop;
-    Font font = FontPrimary;
-};

+ 117 - 0
applications/lfrfid/views/lfrfid_view_read.c

@@ -0,0 +1,117 @@
+#include "lfrfid_view_read.h"
+#include <gui/elements.h>
+
+#define TEMP_STR_LEN 128
+
+struct LfRfidReadView {
+    View* view;
+};
+
+typedef struct {
+    IconAnimation* icon;
+    LfRfidReadViewMode read_mode;
+} LfRfidReadViewModel;
+
+static void lfrfid_view_read_draw_callback(Canvas* canvas, void* _model) {
+    LfRfidReadViewModel* model = _model;
+    canvas_set_color(canvas, ColorBlack);
+
+    canvas_draw_icon(canvas, 0, 8, &I_NFC_manual);
+
+    canvas_set_font(canvas, FontPrimary);
+
+    if(model->read_mode == LfRfidReadAsk) {
+        canvas_draw_str(canvas, 70, 16, "Reading 1/2");
+
+        canvas_draw_str(canvas, 77, 29, "ASK");
+        canvas_draw_icon(canvas, 70, 22, &I_ButtonRight_4x7);
+        canvas_draw_icon_animation(canvas, 102, 21, model->icon);
+
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 77, 43, "PSK");
+    } else if(model->read_mode == LfRfidReadPsk) {
+        canvas_draw_str(canvas, 70, 16, "Reading 2/2");
+
+        canvas_draw_str(canvas, 77, 43, "PSK");
+        canvas_draw_icon(canvas, 70, 36, &I_ButtonRight_4x7);
+        canvas_draw_icon_animation(canvas, 102, 35, model->icon);
+
+        canvas_set_font(canvas, FontSecondary);
+        canvas_draw_str(canvas, 77, 29, "ASK");
+    } else {
+        canvas_draw_str(canvas, 72, 16, "Reading");
+
+        if(model->read_mode == LfRfidReadAskOnly) {
+            canvas_draw_str(canvas, 77, 35, "ASK");
+        } else {
+            canvas_draw_str(canvas, 77, 35, "PSK");
+        }
+        canvas_draw_icon_animation(canvas, 102, 27, model->icon);
+    }
+
+    canvas_set_font(canvas, FontSecondary);
+    canvas_draw_str(canvas, 61, 56, "Don't move card");
+}
+
+void lfrfid_view_read_enter(void* context) {
+    LfRfidReadView* read_view = context;
+    with_view_model(
+        read_view->view, (LfRfidReadViewModel * model) {
+            icon_animation_start(model->icon);
+            return true;
+        });
+}
+
+void lfrfid_view_read_exit(void* context) {
+    LfRfidReadView* read_view = context;
+    with_view_model(
+        read_view->view, (LfRfidReadViewModel * model) {
+            icon_animation_stop(model->icon);
+            return false;
+        });
+}
+
+LfRfidReadView* lfrfid_view_read_alloc() {
+    LfRfidReadView* read_view = malloc(sizeof(LfRfidReadView));
+    read_view->view = view_alloc();
+    view_set_context(read_view->view, read_view);
+    view_allocate_model(read_view->view, ViewModelTypeLocking, sizeof(LfRfidReadViewModel));
+
+    with_view_model(
+        read_view->view, (LfRfidReadViewModel * model) {
+            model->icon = icon_animation_alloc(&A_Round_loader_8x8);
+            view_tie_icon_animation(read_view->view, model->icon);
+            return false;
+        });
+
+    view_set_draw_callback(read_view->view, lfrfid_view_read_draw_callback);
+    view_set_enter_callback(read_view->view, lfrfid_view_read_enter);
+    view_set_exit_callback(read_view->view, lfrfid_view_read_exit);
+
+    return read_view;
+}
+
+void lfrfid_view_read_free(LfRfidReadView* read_view) {
+    with_view_model(
+        read_view->view, (LfRfidReadViewModel * model) {
+            icon_animation_free(model->icon);
+            return false;
+        });
+
+    view_free(read_view->view);
+    free(read_view);
+}
+
+View* lfrfid_view_read_get_view(LfRfidReadView* read_view) {
+    return read_view->view;
+}
+
+void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode) {
+    with_view_model(
+        read_view->view, (LfRfidReadViewModel * model) {
+            icon_animation_stop(model->icon);
+            icon_animation_start(model->icon);
+            model->read_mode = mode;
+            return true;
+        });
+}

+ 19 - 0
applications/lfrfid/views/lfrfid_view_read.h

@@ -0,0 +1,19 @@
+#pragma once
+#include <gui/view.h>
+
+typedef enum {
+    LfRfidReadAsk,
+    LfRfidReadPsk,
+    LfRfidReadAskOnly,
+    LfRfidReadPskOnly
+} LfRfidReadViewMode;
+
+typedef struct LfRfidReadView LfRfidReadView;
+
+LfRfidReadView* lfrfid_view_read_alloc();
+
+void lfrfid_view_read_free(LfRfidReadView* read_view);
+
+View* lfrfid_view_read_get_view(LfRfidReadView* read_view);
+
+void lfrfid_view_read_set_read_mode(LfRfidReadView* read_view, LfRfidReadViewMode mode);

+ 81 - 0
applications/lfrfid_debug/lfrfid_debug.c

@@ -0,0 +1,81 @@
+#include "lfrfid_debug_i.h"
+
+static bool lfrfid_debug_custom_event_callback(void* context, uint32_t event) {
+    furi_assert(context);
+    LfRfidDebug* app = context;
+    return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+static bool lfrfid_debug_back_event_callback(void* context) {
+    furi_assert(context);
+    LfRfidDebug* app = context;
+    return scene_manager_handle_back_event(app->scene_manager);
+}
+
+static LfRfidDebug* lfrfid_debug_alloc() {
+    LfRfidDebug* app = malloc(sizeof(LfRfidDebug));
+
+    app->view_dispatcher = view_dispatcher_alloc();
+    app->scene_manager = scene_manager_alloc(&lfrfid_debug_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, lfrfid_debug_custom_event_callback);
+    view_dispatcher_set_navigation_event_callback(
+        app->view_dispatcher, lfrfid_debug_back_event_callback);
+
+    // Open GUI record
+    app->gui = furi_record_open(RECORD_GUI);
+    view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+    // Submenu
+    app->submenu = submenu_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher, LfRfidDebugViewSubmenu, submenu_get_view(app->submenu));
+
+    // Tune view
+    app->tune_view = lfrfid_debug_view_tune_alloc();
+    view_dispatcher_add_view(
+        app->view_dispatcher,
+        LfRfidDebugViewTune,
+        lfrfid_debug_view_tune_get_view(app->tune_view));
+
+    return app;
+}
+
+static void lfrfid_debug_free(LfRfidDebug* app) {
+    furi_assert(app);
+
+    // Submenu
+    view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewSubmenu);
+    submenu_free(app->submenu);
+
+    // Tune view
+    view_dispatcher_remove_view(app->view_dispatcher, LfRfidDebugViewTune);
+    lfrfid_debug_view_tune_free(app->tune_view);
+
+    // View Dispatcher
+    view_dispatcher_free(app->view_dispatcher);
+
+    // Scene Manager
+    scene_manager_free(app->scene_manager);
+
+    // GUI
+    furi_record_close(RECORD_GUI);
+    app->gui = NULL;
+
+    free(app);
+}
+
+int32_t lfrfid_debug_app(void* p) {
+    UNUSED(p);
+    LfRfidDebug* app = lfrfid_debug_alloc();
+
+    scene_manager_next_scene(app->scene_manager, LfRfidDebugSceneStart);
+
+    view_dispatcher_run(app->view_dispatcher);
+
+    lfrfid_debug_free(app);
+
+    return 0;
+}

+ 0 - 17
applications/lfrfid_debug/lfrfid_debug_app.cpp

@@ -1,17 +0,0 @@
-#include "lfrfid_debug_app.h"
-#include "scene/lfrfid_debug_app_scene_start.h"
-#include "scene/lfrfid_debug_app_scene_tune.h"
-
-LfRfidDebugApp::LfRfidDebugApp()
-    : scene_controller{this} {
-}
-
-LfRfidDebugApp::~LfRfidDebugApp() {
-}
-
-void LfRfidDebugApp::run() {
-    view_controller.attach_to_gui(ViewDispatcherTypeFullscreen);
-    scene_controller.add_scene(SceneType::Start, new LfRfidDebugAppSceneStart());
-    scene_controller.add_scene(SceneType::TuneScene, new LfRfidDebugAppSceneTune());
-    scene_controller.process(100);
-}

+ 0 - 40
applications/lfrfid_debug/lfrfid_debug_app.h

@@ -1,40 +0,0 @@
-#pragma once
-#include <furi.h>
-#include <furi_hal.h>
-
-#include <generic_scene.hpp>
-#include <scene_controller.hpp>
-#include <view_controller.hpp>
-
-#include <view_modules/submenu_vm.h>
-#include "view_modules/lfrfid_view_tune_vm.h"
-
-class LfRfidDebugApp {
-public:
-    enum class EventType : uint8_t {
-        GENERIC_EVENT_ENUM_VALUES,
-        MenuSelected,
-    };
-
-    enum class SceneType : uint8_t {
-        GENERIC_SCENE_ENUM_VALUES,
-        TuneScene,
-    };
-
-    class Event {
-    public:
-        union {
-            int32_t menu_index;
-        } payload;
-
-        EventType type;
-    };
-
-    SceneController<GenericScene<LfRfidDebugApp>, LfRfidDebugApp> scene_controller;
-    ViewController<LfRfidDebugApp, SubmenuVM, LfRfidViewTuneVM> view_controller;
-
-    ~LfRfidDebugApp();
-    LfRfidDebugApp();
-
-    void run();
-};

+ 0 - 11
applications/lfrfid_debug/lfrfid_debug_app_launcher.cpp

@@ -1,11 +0,0 @@
-#include "lfrfid_debug_app.h"
-
-// app enter function
-extern "C" int32_t lfrfid_debug_app(void* p) {
-    UNUSED(p);
-    LfRfidDebugApp* app = new LfRfidDebugApp();
-    app->run();
-    delete app;
-
-    return 0;
-}

+ 31 - 0
applications/lfrfid_debug/lfrfid_debug_i.h

@@ -0,0 +1,31 @@
+#pragma once
+#include <furi.h>
+#include <furi_hal.h>
+
+#include <gui/gui.h>
+#include <gui/view.h>
+#include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+
+#include <gui/modules/submenu.h>
+
+#include <lfrfid_debug/views/lfrfid_debug_view_tune.h>
+
+#include <lfrfid_debug/scenes/lfrfid_debug_scene.h>
+
+typedef struct LfRfidDebug LfRfidDebug;
+
+struct LfRfidDebug {
+    Gui* gui;
+    ViewDispatcher* view_dispatcher;
+    SceneManager* scene_manager;
+
+    // Common Views
+    Submenu* submenu;
+    LfRfidTuneView* tune_view;
+};
+
+typedef enum {
+    LfRfidDebugViewSubmenu,
+    LfRfidDebugViewTune,
+} LfRfidDebugView;

+ 0 - 47
applications/lfrfid_debug/scene/lfrfid_debug_app_scene_start.cpp

@@ -1,47 +0,0 @@
-#include "lfrfid_debug_app_scene_start.h"
-
-typedef enum {
-    SubmenuTune,
-} SubmenuIndex;
-
-void LfRfidDebugAppSceneStart::on_enter(LfRfidDebugApp* app, bool need_restore) {
-    auto submenu = app->view_controller.get<SubmenuVM>();
-    auto callback = cbc::obtain_connector(this, &LfRfidDebugAppSceneStart::submenu_callback);
-
-    submenu->add_item("Tune", SubmenuTune, callback, app);
-
-    if(need_restore) {
-        submenu->set_selected_item(submenu_item_selected);
-    }
-    app->view_controller.switch_to<SubmenuVM>();
-}
-
-bool LfRfidDebugAppSceneStart::on_event(LfRfidDebugApp* app, LfRfidDebugApp::Event* event) {
-    bool consumed = false;
-
-    if(event->type == LfRfidDebugApp::EventType::MenuSelected) {
-        submenu_item_selected = event->payload.menu_index;
-        switch(event->payload.menu_index) {
-        case SubmenuTune:
-            app->scene_controller.switch_to_next_scene(LfRfidDebugApp::SceneType::TuneScene);
-            break;
-        }
-        consumed = true;
-    }
-
-    return consumed;
-}
-
-void LfRfidDebugAppSceneStart::on_exit(LfRfidDebugApp* app) {
-    app->view_controller.get<SubmenuVM>()->clean();
-}
-
-void LfRfidDebugAppSceneStart::submenu_callback(void* context, uint32_t index) {
-    LfRfidDebugApp* app = static_cast<LfRfidDebugApp*>(context);
-    LfRfidDebugApp::Event event;
-
-    event.type = LfRfidDebugApp::EventType::MenuSelected;
-    event.payload.menu_index = index;
-
-    app->view_controller.send_event(&event);
-}

Некоторые файлы не были показаны из-за большого количества измененных файлов