浏览代码

[FL-1962, FL-2464, FL-2465, FL-2466, FL-2560, FL-2637, FL-2595] Ibutton, Infrared, LfRFID GUI fixes (#1392)

* Ibutton, Infrared, LfRFID GUI fixes
* Loading screens update

Co-authored-by: あく <alleteam@gmail.com>
Nikolay Minaylov 3 年之前
父节点
当前提交
877c5c8122
共有 30 个文件被更改,包括 147 次插入44 次删除
  1. 3 10
      applications/archive/views/archive_browser_view.c
  2. 3 10
      applications/gui/modules/file_browser.c
  3. 7 8
      applications/gui/modules/loading.c
  4. 3 1
      applications/ibutton/scenes/ibutton_scene_add_type.c
  5. 2 2
      applications/ibutton/scenes/ibutton_scene_exit_confirm.c
  6. 4 1
      applications/ibutton/scenes/ibutton_scene_read_crc_error.c
  7. 4 2
      applications/ibutton/scenes/ibutton_scene_read_key_menu.c
  8. 4 1
      applications/ibutton/scenes/ibutton_scene_read_not_key_error.c
  9. 4 1
      applications/ibutton/scenes/ibutton_scene_saved_key_menu.c
  10. 4 1
      applications/ibutton/scenes/ibutton_scene_start.c
  11. 48 0
      applications/infrared/scenes/infrared_scene_ask_retry.c
  12. 1 0
      applications/infrared/scenes/infrared_scene_config.h
  13. 1 2
      applications/infrared/scenes/infrared_scene_learn_success.c
  14. 1 2
      applications/infrared/scenes/infrared_scene_remote_list.c
  15. 1 0
      applications/infrared/scenes/infrared_scene_start.c
  16. 1 1
      applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp
  17. 2 2
      applications/lfrfid/scene/lfrfid_app_scene_read.cpp
  18. 24 0
      applications/nfc/nfc.c
  19. 15 0
      applications/nfc/nfc_device.c
  20. 7 0
      applications/nfc/nfc_device.h
  21. 5 0
      applications/nfc/nfc_i.h
  22. 3 0
      applications/nfc/scenes/nfc_scene_file_select.c
  23. 二进制
      assets/icons/Archive/loading_10px.png
  24. 二进制
      assets/icons/Common/Loading_24/frame_01.png
  25. 二进制
      assets/icons/Common/Loading_24/frame_02.png
  26. 二进制
      assets/icons/Common/Loading_24/frame_03.png
  27. 二进制
      assets/icons/Common/Loading_24/frame_04.png
  28. 二进制
      assets/icons/Common/Loading_24/frame_05.png
  29. 二进制
      assets/icons/Common/Loading_24/frame_06.png
  30. 二进制
      assets/icons/Common/Loading_24/frame_07.png

+ 3 - 10
applications/archive/views/archive_browser_view.c

@@ -105,17 +105,10 @@ static void archive_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar, boo
 static void archive_draw_loading(Canvas* canvas, ArchiveBrowserViewModel* model) {
     furi_assert(model);
 
-    uint8_t width = 49;
-    uint8_t height = 47;
-    uint8_t x = 128 / 2 - width / 2;
-    uint8_t y = 64 / 2 - height / 2 + 6;
+    uint8_t x = 128 / 2 - 24 / 2;
+    uint8_t y = 64 / 2 - 24 / 2;
 
-    elements_bold_rounded_frame(canvas, x, y, width, height);
-
-    canvas_set_font(canvas, FontSecondary);
-    elements_multiline_text(canvas, x + 7, y + 13, "Loading...");
-
-    canvas_draw_icon(canvas, x + 13, y + 19, &A_Loading_24);
+    canvas_draw_icon(canvas, x, y, &A_Loading_24);
 }
 
 static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {

+ 3 - 10
applications/gui/modules/file_browser.c

@@ -354,19 +354,12 @@ static void browser_draw_frame(Canvas* canvas, uint16_t idx, bool scrollbar) {
 }
 
 static void browser_draw_loading(Canvas* canvas, FileBrowserModel* model) {
-    uint8_t width = 49;
-    uint8_t height = 47;
-    uint8_t x = 128 / 2 - width / 2;
-    uint8_t y = 64 / 2 - height / 2;
-
     UNUSED(model);
 
-    elements_bold_rounded_frame(canvas, x, y, width, height);
-
-    canvas_set_font(canvas, FontSecondary);
-    elements_multiline_text(canvas, x + 7, y + 13, "Loading...");
+    uint8_t x = 128 / 2 - 24 / 2;
+    uint8_t y = 64 / 2 - 24 / 2;
 
-    canvas_draw_icon(canvas, x + 13, y + 19, &A_Loading_24);
+    canvas_draw_icon(canvas, x, y, &A_Loading_24);
 }
 
 static void browser_draw_list(Canvas* canvas, FileBrowserModel* model) {

+ 7 - 8
applications/gui/modules/loading.c

@@ -20,17 +20,16 @@ typedef struct {
 static void loading_draw_callback(Canvas* canvas, void* _model) {
     LoadingModel* model = (LoadingModel*)_model;
 
-    uint8_t width = 49;
-    uint8_t height = 47;
-    uint8_t x = (canvas_width(canvas) - width) / 2;
-    uint8_t y = (canvas_height(canvas) - height) / 2;
+    canvas_set_color(canvas, ColorWhite);
+    canvas_draw_box(canvas, 0, 0, canvas_width(canvas), canvas_height(canvas));
+    canvas_set_color(canvas, ColorBlack);
 
-    elements_bold_rounded_frame(canvas, x, y, width, height);
+    uint8_t x = canvas_width(canvas) / 2 - 24 / 2;
+    uint8_t y = canvas_height(canvas) / 2 - 24 / 2;
 
-    canvas_set_font(canvas, FontSecondary);
-    elements_multiline_text(canvas, x + 7, y + 13, "Loading...");
+    canvas_draw_icon(canvas, x, y, &A_Loading_24);
 
-    canvas_draw_icon_animation(canvas, x + 13, y + 19, model->icon);
+    canvas_draw_icon_animation(canvas, x, y, model->icon);
 }
 
 static bool loading_input_callback(InputEvent* event, void* context) {

+ 3 - 1
applications/ibutton/scenes/ibutton_scene_add_type.c

@@ -23,7 +23,8 @@ void ibutton_scene_add_type_on_enter(void* context) {
     submenu_add_item(
         submenu, "Metakom", SubmenuIndexMetakom, ibutton_scene_add_type_submenu_callback, ibutton);
 
-    submenu_set_selected_item(submenu, SubmenuIndexCyfral);
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneAddType));
 
     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
 }
@@ -34,6 +35,7 @@ bool ibutton_scene_add_type_on_event(void* context, SceneManagerEvent event) {
     bool consumed = false;
 
     if(event.type == SceneManagerEventTypeCustom) {
+        scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneAddType, event.event);
         consumed = true;
         if(event.event == SubmenuIndexCyfral) {
             ibutton_key_set_type(key, iButtonKeyCyfral);

+ 2 - 2
applications/ibutton/scenes/ibutton_scene_exit_confirm.c

@@ -19,9 +19,9 @@ void ibutton_scene_exit_confirm_on_enter(void* context) {
     widget_add_button_element(
         widget, GuiButtonTypeRight, "Stay", ibutton_scene_exit_confirm_widget_callback, ibutton);
     widget_add_string_element(
-        widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu");
+        widget, 64, 19, AlignCenter, AlignBottom, FontPrimary, "Exit to iButton menu?");
     widget_add_string_element(
-        widget, 64, 29, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost");
+        widget, 64, 31, AlignCenter, AlignBottom, FontSecondary, "All unsaved data will be lost.");
 
     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewWidget);
 }

+ 4 - 1
applications/ibutton/scenes/ibutton_scene_read_crc_error.c

@@ -43,7 +43,10 @@ bool ibutton_scene_read_crc_error_on_event(void* context, SceneManagerEvent even
     SceneManager* scene_manager = ibutton->scene_manager;
     bool consumed = false;
 
-    if(event.type == SceneManagerEventTypeCustom) {
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true;
+        scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
+    } else if(event.type == SceneManagerEventTypeCustom) {
         consumed = true;
         if(event.event == DialogExResultRight) {
             scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);

+ 4 - 2
applications/ibutton/scenes/ibutton_scene_read_key_menu.c

@@ -31,8 +31,8 @@ void ibutton_scene_read_key_menu_on_enter(void* context) {
             ibutton_scene_read_key_menu_submenu_callback,
             ibutton);
     }
-
-    submenu_set_selected_item(submenu, SubmenuIndexSave);
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneReadKeyMenu));
 
     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
 }
@@ -42,6 +42,8 @@ bool ibutton_scene_read_key_menu_on_event(void* context, SceneManagerEvent event
     bool consumed = false;
 
     if(event.type == SceneManagerEventTypeCustom) {
+        scene_manager_set_scene_state(
+            ibutton->scene_manager, iButtonSceneReadKeyMenu, event.event);
         consumed = true;
         if(event.event == SubmenuIndexSave) {
             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneSaveName);

+ 4 - 1
applications/ibutton/scenes/ibutton_scene_read_not_key_error.c

@@ -44,7 +44,10 @@ bool ibutton_scene_read_not_key_error_on_event(void* context, SceneManagerEvent
     SceneManager* scene_manager = ibutton->scene_manager;
     bool consumed = false;
 
-    if(event.type == SceneManagerEventTypeCustom) {
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true;
+        scene_manager_next_scene(scene_manager, iButtonSceneExitConfirm);
+    } else if(event.type == SceneManagerEventTypeCustom) {
         consumed = true;
         if(event.event == DialogExResultRight) {
             scene_manager_next_scene(scene_manager, iButtonSceneReadKeyMenu);

+ 4 - 1
applications/ibutton/scenes/ibutton_scene_saved_key_menu.c

@@ -42,7 +42,8 @@ void ibutton_scene_saved_key_menu_on_enter(void* context) {
     submenu_add_item(
         submenu, "Info", SubmenuIndexInfo, ibutton_scene_saved_key_menu_submenu_callback, ibutton);
 
-    submenu_set_selected_item(submenu, SubmenuIndexEmulate);
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneSavedKeyMenu));
 
     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
 }
@@ -52,6 +53,8 @@ bool ibutton_scene_saved_key_menu_on_event(void* context, SceneManagerEvent even
     bool consumed = false;
 
     if(event.type == SceneManagerEventTypeCustom) {
+        scene_manager_set_scene_state(
+            ibutton->scene_manager, iButtonSceneSavedKeyMenu, event.event);
         consumed = true;
         if(event.event == SubmenuIndexEmulate) {
             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneEmulate);

+ 4 - 1
applications/ibutton/scenes/ibutton_scene_start.c

@@ -1,4 +1,5 @@
 #include "../ibutton_i.h"
+#include "ibutton/scenes/ibutton_scene.h"
 
 enum SubmenuIndex {
     SubmenuIndexRead,
@@ -22,7 +23,8 @@ void ibutton_scene_start_on_enter(void* context) {
     submenu_add_item(
         submenu, "Add Manually", SubmenuIndexAdd, ibutton_scene_start_submenu_callback, ibutton);
 
-    submenu_set_selected_item(submenu, SubmenuIndexRead);
+    submenu_set_selected_item(
+        submenu, scene_manager_get_scene_state(ibutton->scene_manager, iButtonSceneStart));
 
     view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewSubmenu);
 }
@@ -32,6 +34,7 @@ bool ibutton_scene_start_on_event(void* context, SceneManagerEvent event) {
     bool consumed = false;
 
     if(event.type == SceneManagerEventTypeCustom) {
+        scene_manager_set_scene_state(ibutton->scene_manager, iButtonSceneStart, event.event);
         consumed = true;
         if(event.event == SubmenuIndexRead) {
             scene_manager_next_scene(ibutton->scene_manager, iButtonSceneRead);

+ 48 - 0
applications/infrared/scenes/infrared_scene_ask_retry.c

@@ -0,0 +1,48 @@
+#include "../infrared_i.h"
+
+static void infrared_scene_dialog_result_callback(DialogExResult result, void* context) {
+    Infrared* infrared = context;
+    view_dispatcher_send_custom_event(infrared->view_dispatcher, result);
+}
+
+void infrared_scene_ask_retry_on_enter(void* context) {
+    Infrared* infrared = context;
+    DialogEx* dialog_ex = infrared->dialog_ex;
+
+    dialog_ex_set_header(dialog_ex, "Return to reading?", 64, 0, AlignCenter, AlignTop);
+    dialog_ex_set_text(
+        dialog_ex, "All unsaved data\nwill be lost", 64, 31, AlignCenter, AlignCenter);
+    dialog_ex_set_icon(dialog_ex, 0, 0, NULL);
+    dialog_ex_set_left_button_text(dialog_ex, "Exit");
+    dialog_ex_set_center_button_text(dialog_ex, NULL);
+    dialog_ex_set_right_button_text(dialog_ex, "Stay");
+    dialog_ex_set_result_callback(dialog_ex, infrared_scene_dialog_result_callback);
+    dialog_ex_set_context(dialog_ex, context);
+
+    view_dispatcher_switch_to_view(infrared->view_dispatcher, InfraredViewDialogEx);
+}
+
+bool infrared_scene_ask_retry_on_event(void* context, SceneManagerEvent event) {
+    Infrared* infrared = context;
+    SceneManager* scene_manager = infrared->scene_manager;
+    bool consumed = false;
+
+    if(event.type == SceneManagerEventTypeBack) {
+        consumed = true;
+    } else if(event.type == SceneManagerEventTypeCustom) {
+        if(event.event == DialogExResultLeft) {
+            scene_manager_search_and_switch_to_previous_scene(scene_manager, InfraredSceneLearn);
+            consumed = true;
+        } else if(event.event == DialogExResultRight) {
+            scene_manager_previous_scene(scene_manager);
+            consumed = true;
+        }
+    }
+
+    return consumed;
+}
+
+void infrared_scene_ask_retry_on_exit(void* context) {
+    Infrared* infrared = context;
+    dialog_ex_reset(infrared->dialog_ex);
+}

+ 1 - 0
applications/infrared/scenes/infrared_scene_config.h

@@ -1,5 +1,6 @@
 ADD_SCENE(infrared, start, Start)
 ADD_SCENE(infrared, ask_back, AskBack)
+ADD_SCENE(infrared, ask_retry, AskRetry)
 ADD_SCENE(infrared, edit, Edit)
 ADD_SCENE(infrared, edit_delete, EditDelete)
 ADD_SCENE(infrared, edit_delete_done, EditDeleteDone)

+ 1 - 2
applications/infrared/scenes/infrared_scene_learn_success.c

@@ -89,8 +89,7 @@ bool infrared_scene_learn_success_on_event(void* context, SceneManagerEvent even
     } else if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == DialogExResultLeft) {
             if(scene_state == InfraredSceneLearnSuccessStateIdle) {
-                scene_manager_search_and_switch_to_previous_scene(
-                    scene_manager, InfraredSceneLearn);
+                scene_manager_next_scene(scene_manager, InfraredSceneAskRetry);
             }
             consumed = true;
         } else if(event.event == DialogExResultRight) {

+ 1 - 2
applications/infrared/scenes/infrared_scene_remote_list.c

@@ -5,7 +5,6 @@ void infrared_scene_remote_list_on_enter(void* context) {
     SceneManager* scene_manager = infrared->scene_manager;
     ViewDispatcher* view_dispatcher = infrared->view_dispatcher;
 
-    string_set_str(infrared->file_path, INFRARED_APP_FOLDER);
     bool success = dialog_file_browser_show(
         infrared->dialogs,
         infrared->file_path,
@@ -16,7 +15,7 @@ void infrared_scene_remote_list_on_enter(void* context) {
         true);
 
     if(success) {
-        view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationHorizontal);
+        view_set_orientation(view_stack_get_view(infrared->view_stack), ViewOrientationVertical);
         view_dispatcher_switch_to_view(view_dispatcher, InfraredViewStack);
 
         infrared_show_loading_popup(infrared, true);

+ 1 - 0
applications/infrared/scenes/infrared_scene_start.c

@@ -66,6 +66,7 @@ bool infrared_scene_start_on_event(void* context, SceneManagerEvent event) {
             scene_manager_next_scene(scene_manager, InfraredSceneLearn);
             consumed = true;
         } else if(submenu_index == SubmenuIndexSavedRemotes) {
+            string_set_str(infrared->file_path, INFRARED_APP_FOLDER);
             scene_manager_next_scene(scene_manager, InfraredSceneRemoteList);
             consumed = true;
         } else if(submenu_index == SubmenuIndexDebug) {

+ 1 - 1
applications/lfrfid/scene/lfrfid_app_scene_exit_confirm.cpp

@@ -19,7 +19,7 @@ void LfRfidAppSceneExitConfirm::on_enter(LfRfidApp* app, bool /* need_restore */
 
     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, 29, 0, AlignCenter, AlignBottom, FontSecondary);
+        "All unsaved data will be lost.", 64, 31, 0, AlignCenter, AlignBottom, FontSecondary);
 
     app->view_controller.switch_to<ContainerVM>();
 }

+ 2 - 2
applications/lfrfid/scene/lfrfid_app_scene_read.cpp

@@ -22,9 +22,9 @@ bool LfRfidAppSceneRead::on_event(LfRfidApp* app, LfRfidApp::Event* event) {
             app->scene_controller.switch_to_next_scene(LfRfidApp::SceneType::ReadSuccess);
         } else {
             if(app->worker.any_read()) {
-                notification_message(app->notification, &sequence_blink_green_10);
+                notification_message(app->notification, &sequence_blink_yellow_10);
             } else if(app->worker.detect()) {
-                notification_message(app->notification, &sequence_blink_cyan_10);
+                notification_message(app->notification, &sequence_blink_yellow_10);
             } else {
                 notification_message(app->notification, &sequence_blink_cyan_10);
             }

+ 24 - 0
applications/nfc/nfc.c

@@ -125,6 +125,10 @@ Nfc* nfc_alloc() {
     nfc->popup = popup_alloc();
     view_dispatcher_add_view(nfc->view_dispatcher, NfcViewPopup, popup_get_view(nfc->popup));
 
+    // Loading
+    nfc->loading = loading_alloc();
+    view_dispatcher_add_view(nfc->view_dispatcher, NfcViewLoading, loading_get_view(nfc->loading));
+
     // Text Input
     nfc->text_input = text_input_alloc();
     view_dispatcher_add_view(
@@ -179,6 +183,10 @@ void nfc_free(Nfc* nfc) {
     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewPopup);
     popup_free(nfc->popup);
 
+    // Loading
+    view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewLoading);
+    loading_free(nfc->loading);
+
     // TextInput
     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewTextInput);
     text_input_free(nfc->text_input);
@@ -258,12 +266,27 @@ void nfc_blink_stop(Nfc* nfc) {
     notification_message(nfc->notifications, &sequence_blink_stop);
 }
 
+void nfc_show_loading_popup(void* context, bool show) {
+    Nfc* nfc = context;
+    TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
+
+    if(show) {
+        // Raise timer priority so that animations can play
+        vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
+        view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewLoading);
+    } else {
+        // Restore default timer priority
+        vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
+    }
+}
+
 int32_t nfc_app(void* p) {
     Nfc* nfc = nfc_alloc();
     char* args = p;
 
     // Check argument and run corresponding scene
     if((*args != '\0')) {
+        nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
         uint32_t rpc_ctx = 0;
         if(sscanf(p, "RPC %lX", &rpc_ctx) == 1) {
             nfc->rpc_ctx = (void*)rpc_ctx;
@@ -281,6 +304,7 @@ int32_t nfc_app(void* p) {
             // Exit app
             view_dispatcher_stop(nfc->view_dispatcher);
         }
+        nfc_device_set_loading_callback(nfc->dev, NULL, nfc);
     } else {
         scene_manager_next_scene(nfc->scene_manager, NfcSceneStart);
     }

+ 15 - 0
applications/nfc/nfc_device.c

@@ -846,6 +846,10 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path, bool show_dialog
     string_init(temp_str);
     bool deprecated_version = false;
 
+    if(dev->loading_cb) {
+        dev->loading_cb(dev->loading_cb_ctx, true);
+    }
+
     do {
         // Check existance of shadow file
         nfc_device_get_shadow_path(path, temp_str);
@@ -887,6 +891,10 @@ static bool nfc_device_load_data(NfcDevice* dev, string_t path, bool show_dialog
         parsed = true;
     } while(false);
 
+    if(dev->loading_cb) {
+        dev->loading_cb(dev->loading_cb_ctx, false);
+    }
+
     if((!parsed) && (show_dialog)) {
         if(deprecated_version) {
             dialog_message_show_storage_error(dev->dialogs, "File format deprecated");
@@ -1024,3 +1032,10 @@ bool nfc_device_restore(NfcDevice* dev, bool use_load_path) {
     string_clear(path);
     return restored;
 }
+
+void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context) {
+    furi_assert(dev);
+
+    dev->loading_cb = callback;
+    dev->loading_cb_ctx = context;
+}

+ 7 - 0
applications/nfc/nfc_device.h

@@ -18,6 +18,8 @@
 #define NFC_APP_EXTENSION ".nfc"
 #define NFC_APP_SHADOW_EXTENSION ".shd"
 
+typedef void (*NfcLoadingCallback)(void* context, bool state);
+
 typedef enum {
     NfcDeviceProtocolUnknown,
     NfcDeviceProtocolEMV,
@@ -59,6 +61,9 @@ typedef struct {
     string_t load_path;
     NfcDeviceSaveFormat format;
     bool shadow_file_exist;
+
+    NfcLoadingCallback loading_cb;
+    void* loading_cb_ctx;
 } NfcDevice;
 
 NfcDevice* nfc_device_alloc();
@@ -82,3 +87,5 @@ void nfc_device_clear(NfcDevice* dev);
 bool nfc_device_delete(NfcDevice* dev, bool use_load_path);
 
 bool nfc_device_restore(NfcDevice* dev, bool use_load_path);
+
+void nfc_device_set_loading_callback(NfcDevice* dev, NfcLoadingCallback callback, void* context);

+ 5 - 0
applications/nfc/nfc_i.h

@@ -18,6 +18,7 @@
 #include <gui/modules/submenu.h>
 #include <gui/modules/dialog_ex.h>
 #include <gui/modules/popup.h>
+#include <gui/modules/loading.h>
 #include <gui/modules/text_input.h>
 #include <gui/modules/byte_input.h>
 #include <gui/modules/text_box.h>
@@ -63,6 +64,7 @@ struct Nfc {
     Submenu* submenu;
     DialogEx* dialog_ex;
     Popup* popup;
+    Loading* loading;
     TextInput* text_input;
     ByteInput* byte_input;
     TextBox* text_box;
@@ -77,6 +79,7 @@ typedef enum {
     NfcViewMenu,
     NfcViewDialogEx,
     NfcViewPopup,
+    NfcViewLoading,
     NfcViewTextInput,
     NfcViewByteInput,
     NfcViewTextBox,
@@ -97,4 +100,6 @@ void nfc_blink_start(Nfc* nfc);
 
 void nfc_blink_stop(Nfc* nfc);
 
+void nfc_show_loading_popup(void* context, bool show);
+
 void nfc_rpc_exit_callback(Nfc* nfc);

+ 3 - 0
applications/nfc/scenes/nfc_scene_file_select.c

@@ -1,13 +1,16 @@
 #include "../nfc_i.h"
+#include "nfc/nfc_device.h"
 
 void nfc_scene_file_select_on_enter(void* context) {
     Nfc* nfc = context;
     // Process file_select return
+    nfc_device_set_loading_callback(nfc->dev, nfc_show_loading_popup, nfc);
     if(nfc_file_select(nfc->dev)) {
         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
     } else {
         scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);
     }
+    nfc_device_set_loading_callback(nfc->dev, NULL, nfc);
 }
 
 bool nfc_scene_file_select_on_event(void* context, SceneManagerEvent event) {

二进制
assets/icons/Archive/loading_10px.png


二进制
assets/icons/Common/Loading_24/frame_01.png


二进制
assets/icons/Common/Loading_24/frame_02.png


二进制
assets/icons/Common/Loading_24/frame_03.png


二进制
assets/icons/Common/Loading_24/frame_04.png


二进制
assets/icons/Common/Loading_24/frame_05.png


二进制
assets/icons/Common/Loading_24/frame_06.png


二进制
assets/icons/Common/Loading_24/frame_07.png