zinongli 1 год назад
Родитель
Сommit
57b7747118
2 измененных файлов с 102 добавлено и 129 удалено
  1. 93 125
      key_copier.c
  2. 9 4
      key_copier.h

+ 93 - 125
key_copier.c

@@ -3,22 +3,20 @@
 #include <gui/gui.h>
 #include <gui/view.h>
 #include <gui/view_dispatcher.h>
-#include <gui/modules/popup.h>
 #include <gui/modules/submenu.h>
 #include <gui/modules/text_input.h>
 #include <gui/modules/widget.h>
 #include <gui/modules/variable_item_list.h>
 #include <notification/notification.h>
 #include <notification/notification_messages.h>
-#include "key_copier_icons.h"
-#include "key_formats.h"
-#include "key_copier.h"
 #include <applications/services/storage/storage.h>
 #include <applications/services/dialogs/dialogs.h>
 #include <stdbool.h>
 #include <math.h>
 #include <flipper_format.h>
-
+#include "key_copier_icons.h"
+#include "key_formats.h"
+#include "key_copier.h"
 #define TAG "KeyCopier"
 
 #define INCHES_PER_PX 0.00978
@@ -49,7 +47,6 @@ typedef enum {
 
 typedef enum {
     KeyCopierEventIdRedrawScreen = 0, // Custom event to redraw the screen
-    KeyCopierEventIdOkPressed = 42, // Custom event to process OK button getting pressed down
 } KeyCopierEventId;
 
 typedef struct {
@@ -64,6 +61,7 @@ typedef struct {
     View* view_load; // The load view
     Widget* widget_about; // The about screen
     VariableItem* key_name_item; // The name setting item (so we can update the text)
+    VariableItem* format_item;
     char* temp_buffer; // Temporary buffer for text input
     uint32_t temp_buffer_size; // Size of temporary buffer
 
@@ -79,9 +77,9 @@ typedef struct {
     uint8_t* depth; // The cutting depth
     bool data_loaded;
     KeyFormat format;
-} KeyCopierMeasureModel;
+} KeyCopierModel;
 
-void initialize_model(KeyCopierMeasureModel* model) {
+void initialize_model(KeyCopierModel* model) {
     if(model->depth != NULL) {
         free(model->depth);
     }
@@ -160,7 +158,7 @@ void initialize_format_names(char** format_names) {
 static const char* format_config_label = "Key Format";
 static void key_copier_format_change(VariableItem* item) {
     KeyCopierApp* app = variable_item_get_context(item);
-    KeyCopierMeasureModel* model = view_get_model(app->view_measure);
+    KeyCopierModel* model = view_get_model(app->view_measure);
     if(model->data_loaded) {
         variable_item_set_current_value_index(item, model->format_index);
     } else {
@@ -181,6 +179,28 @@ static void key_copier_format_change(VariableItem* item) {
     }
 }
 
+static void key_copier_config_enter_callback(void* context) {
+    KeyCopierApp* app = (KeyCopierApp*)context;
+    KeyCopierModel* my_model = view_get_model(app->view_measure);
+    variable_item_list_reset(app->variable_item_list_config);
+    // Recreate this view every time we enter it so that it's always updated
+    app->format_item = variable_item_list_add(
+        app->variable_item_list_config,
+        format_config_label,
+        COUNT_OF(all_formats),
+        key_copier_format_change,
+        app);
+
+    View* view_config_i = variable_item_list_get_view(app->variable_item_list_config);
+    variable_item_set_current_value_index(app->format_item, my_model->format_index);
+    key_copier_format_change(app->format_item);
+    view_set_previous_callback(view_config_i, key_copier_navigation_submenu_callback);
+    view_dispatcher_remove_view(
+        app->view_dispatcher, KeyCopierViewConfigure_i); // delete the last one
+    view_dispatcher_add_view(app->view_dispatcher, KeyCopierViewConfigure_i, view_config_i);
+    view_dispatcher_switch_to_view(app->view_dispatcher, KeyCopierViewConfigure_i); // recreate it
+}
+
 /**
  * Our 2nd sample setting is a text field.  When the user clicks OK on the configuration 
  * setting we use a text input screen to allow the user to enter a name.  This function is
@@ -189,11 +209,11 @@ static void key_copier_format_change(VariableItem* item) {
 static const char* key_name_entry_text = "Enter name";
 static void key_copier_file_saver(void* context) {
     KeyCopierApp* app = (KeyCopierApp*)context;
-    KeyCopierMeasureModel* model = view_get_model(app->view_measure);
+    KeyCopierModel* model = view_get_model(app->view_measure);
     bool redraw = true;
     with_view_model(
         app->view_measure,
-        KeyCopierMeasureModel * model,
+        KeyCopierModel * model,
         { furi_string_set(model->key_name_str, app->temp_buffer); },
         redraw);
     FuriString* file_path = furi_string_alloc();
@@ -202,7 +222,7 @@ static void key_copier_file_saver(void* context) {
         "%s/%s%s",
         STORAGE_APP_DATA_PATH_PREFIX,
         furi_string_get_cstr(model->key_name_str),
-        KEY_COPIER_SAVE_EXTENSION);
+        KEY_COPIER_FILE_EXTENSION);
 
     Storage* storage = furi_record_open(RECORD_STORAGE);
     storage_simply_mkdir(storage, STORAGE_APP_DATA_PATH_PREFIX);
@@ -212,22 +232,22 @@ static void key_copier_file_saver(void* context) {
         const uint32_t version = 1;
         const uint32_t pin_num_buffer = (uint32_t)model->format.pin_num;
         const uint32_t macs_buffer = (uint32_t)model->format.macs;
+        FuriString* buffer = furi_string_alloc();
         if(!flipper_format_file_open_always(flipper_format, furi_string_get_cstr(file_path)))
             break;
         if(!flipper_format_write_header_cstr(flipper_format, "Flipper Key Copier File", version))
             break;
         if(!flipper_format_write_string_cstr(
-               flipper_format, "Key Format", model->format.format_name))
+               flipper_format, "Format Name", model->format.format_name))
             break;
         if(!flipper_format_write_string_cstr(
-               flipper_format, "Key Format Short", model->format.format_short_name))
+               flipper_format, "Format Short Name", model->format.format_short_name))
             break;
         if(!flipper_format_write_uint32(flipper_format, "Number of Pins", &pin_num_buffer, 1))
             break;
         if(!flipper_format_write_uint32(
                flipper_format, "Maximum Adjacent Cut Specification (MACS)", &macs_buffer, 1))
             break;
-        FuriString* buffer = furi_string_alloc();
         for(int i = 0; i < model->format.pin_num; i++) {
             if(i < model->format.pin_num - 1) {
                 furi_string_cat_printf(buffer, "%d-", model->depth[i]);
@@ -235,9 +255,7 @@ static void key_copier_file_saver(void* context) {
                 furi_string_cat_printf(buffer, "%d", model->depth[i]);
             }
         }
-        if(!flipper_format_write_string(
-               flipper_format, "Bitting Pattern", buffer))
-            break;
+        if(!flipper_format_write_string(flipper_format, "Bitting Pattern", buffer)) break;
         furi_string_free(buffer);
         // signal that the file was written successfully
     } while(0);
@@ -261,7 +279,7 @@ static void key_copier_view_save_callback(void* context) {
     bool redraw = false;
     with_view_model(
         app->view_measure,
-        KeyCopierMeasureModel * model,
+        KeyCopierModel * model,
         {
             strncpy(
                 app->temp_buffer,
@@ -288,16 +306,44 @@ static void key_copier_view_save_callback(void* context) {
     view_dispatcher_switch_to_view(app->view_dispatcher, KeyCopierViewTextInput);
 }
 
-static inline int min(int a, int b) {
-    return (a < b) ? a : b;
-}
+static void t5577_writer_view_load_callback(void* context) {
+    KeyCopierApp* app = (KeyCopierApp*)context;
+    KeyCopierModel* model = view_get_model(app->view_measure);
+    DialogsFileBrowserOptions browser_options;
+    Storage* storage = furi_record_open(RECORD_STORAGE);
+    storage_simply_mkdir(storage, STORAGE_APP_DATA_PATH_PREFIX);
+    dialog_file_browser_set_basic_options(&browser_options, KEY_COPIER_FILE_EXTENSION, &I_icon);
+    browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
+    furi_string_set(app->file_path, browser_options.base_path);
+    if(dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options)) {
+        FlipperFormat* flipper_format = flipper_format_file_alloc(storage);
+        do {
+            if(!flipper_format_file_open_existing(
+                   flipper_format, furi_string_get_cstr(app->file_path)))
+                break;
+            FuriString* format_buffer = furi_string_alloc();
+            FuriString* depth_buffer = furi_string_alloc();
+            if(!flipper_format_read_string(flipper_format, "Format Name", format_buffer)) break;
+            if(!flipper_format_read_string(flipper_format, "Bitting Pattern", depth_buffer)) break;
+            for(size_t i = 0; i < COUNT_OF(all_formats); i++) {
+                if(!strcmp(furi_string_get_cstr(format_buffer), all_formats[i].format_name)) {
+                    model->format_index = (uint32_t)i;
+                    model->format = all_formats[model->format_index];
+                }
+            }
 
-static inline int max(int a, int b) {
-    return (a > b) ? a : b;
+            for(int i = 0; i < model->format.pin_num; i++) {
+                model->depth[i] = (uint8_t)(furi_string_get_char(depth_buffer, i * 2) - '0');
+            }
+            model->data_loaded = true;
+            // signal that the file was read successfully
+        } while(0);
+        flipper_format_free(flipper_format);
+        furi_record_close(RECORD_STORAGE);
+    }
+    view_dispatcher_switch_to_view(app->view_dispatcher, KeyCopierViewSubmenu);
 }
 
-static double inches_per_px = (double)INCHES_PER_PX;
-
 /**
  * @brief      Callback for drawing the game screen.
  * @details    This function is called when the screen needs to be redrawn, like when the model gets updated.
@@ -305,7 +351,8 @@ static double inches_per_px = (double)INCHES_PER_PX;
  * @param      model   The model - MyModel object.
 */
 static void key_copier_view_measure_draw_callback(Canvas* canvas, void* model) {
-    KeyCopierMeasureModel* my_model = (KeyCopierMeasureModel*)model;
+    static double inches_per_px = (double)INCHES_PER_PX;
+    KeyCopierModel* my_model = (KeyCopierModel*)model;
     KeyFormat my_format = my_model->format;
 
     int pin_half_width_px = (int)round((my_format.pin_width_inch / inches_per_px) / 2);
@@ -441,69 +488,6 @@ static void key_copier_view_measure_draw_callback(Canvas* canvas, void* model) {
     furi_string_free(xstr);
 }
 
-/**
- * @brief      Callback for timer elapsed.
- * @details    This function is called when the timer is elapsed.  We use this to queue a redraw event.
- * @param      context  The context - KeyCopierApp object.
-*/
-static void key_copier_view_measure_timer_callback(void* context) {
-    KeyCopierApp* app = (KeyCopierApp*)context;
-    view_dispatcher_send_custom_event(app->view_dispatcher, KeyCopierEventIdRedrawScreen);
-}
-
-/**
- * @brief      Callback when the user starts the game screen.
- * @details    This function is called when the user enters the game screen.  We start a timer to
- *           redraw the screen periodically (so the random number is refreshed).
- * @param      context  The context - KeyCopierApp object.
-*/
-static void key_copier_view_measure_enter_callback(void* context) {
-    uint32_t period = furi_ms_to_ticks(500);
-    KeyCopierApp* app = (KeyCopierApp*)context;
-    furi_assert(app->timer == NULL);
-    app->timer =
-        furi_timer_alloc(key_copier_view_measure_timer_callback, FuriTimerTypePeriodic, context);
-    furi_timer_start(app->timer, period);
-}
-
-/**
- * @brief      Callback when the user exits the game screen.
- * @details    This function is called when the user exits the game screen.  We stop the timer.
- * @param      context  The context - KeyCopierApp object.
-*/
-static void key_copier_view_measure_exit_callback(void* context) {
-    KeyCopierApp* app = (KeyCopierApp*)context;
-    furi_timer_stop(app->timer);
-    furi_timer_free(app->timer);
-    app->timer = NULL;
-}
-
-/**
- * @brief      Callback for custom events.
- * @details    This function is called when a custom event is sent to the view dispatcher.
- * @param      event    The event id - KeyCopierEventId value.
- * @param      context  The context - KeyCopierApp object.
-*/
-static bool key_copier_view_measure_custom_event_callback(uint32_t event, void* context) {
-    KeyCopierApp* app = (KeyCopierApp*)context;
-    switch(event) {
-    case KeyCopierEventIdRedrawScreen:
-        // Redraw screen by passing true to last parameter of with_view_model.
-        {
-            bool redraw = true;
-            with_view_model(
-                app->view_measure, KeyCopierMeasureModel * _model, { UNUSED(_model); }, redraw);
-            return true;
-        }
-    case KeyCopierEventIdOkPressed:
-        // Process the OK button.  We go to the saving scene.
-        view_dispatcher_switch_to_view(app->view_dispatcher, KeyCopierViewTextInput);
-        return true;
-    default:
-        return false;
-    }
-}
-
 /**
  * @brief      Callback for game screen input.
  * @details    This function is called when the user presses a button while on the game screen.
@@ -520,7 +504,7 @@ static bool key_copier_view_measure_input_callback(InputEvent* event, void* cont
             bool redraw = true;
             with_view_model(
                 app->view_measure,
-                KeyCopierMeasureModel * model,
+                KeyCopierModel * model,
                 {
                     if(model->pin_slc > 1) {
                         model->pin_slc--;
@@ -534,7 +518,7 @@ static bool key_copier_view_measure_input_callback(InputEvent* event, void* cont
             bool redraw = true;
             with_view_model(
                 app->view_measure,
-                KeyCopierMeasureModel * model,
+                KeyCopierModel * model,
                 {
                     if(model->pin_slc < model->format.pin_num) {
                         model->pin_slc++;
@@ -548,7 +532,7 @@ static bool key_copier_view_measure_input_callback(InputEvent* event, void* cont
             bool redraw = true;
             with_view_model(
                 app->view_measure,
-                KeyCopierMeasureModel * model,
+                KeyCopierModel * model,
                 {
                     if(model->depth[model->pin_slc - 1] > model->format.min_depth_ind) {
                         if(model->pin_slc == 1) { //first pin only limited by the next one
@@ -582,7 +566,7 @@ static bool key_copier_view_measure_input_callback(InputEvent* event, void* cont
             bool redraw = true;
             with_view_model(
                 app->view_measure,
-                KeyCopierMeasureModel * model,
+                KeyCopierModel * model,
                 {
                     if(model->depth[model->pin_slc - 1] < model->format.max_depth_ind) {
                         if(model->pin_slc == 1) { //first pin only limited by the next one
@@ -615,12 +599,6 @@ static bool key_copier_view_measure_input_callback(InputEvent* event, void* cont
             // Handle other keys or do nothing
             break;
         }
-    } else if(event->key == InputKeyOk) {
-        // We choose to send a custom event when user presses OK button.  key_copier_custom_event_callback will
-        // handle our KeyCopierEventIdOkPressed event.  We could have just put the code from
-        // key_copier_custom_event_callback here, it's a matter of preference.
-        view_dispatcher_send_custom_event(app->view_dispatcher, KeyCopierEventIdOkPressed);
-        return true;
     }
 
     return false;
@@ -640,7 +618,8 @@ static KeyCopierApp* key_copier_app_alloc() {
     view_dispatcher_enable_queue(app->view_dispatcher);
     view_dispatcher_attach_to_gui(app->view_dispatcher, gui, ViewDispatcherTypeFullscreen);
     view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
-
+    app->dialogs = furi_record_open(RECORD_DIALOGS);
+    app->file_path = furi_string_alloc();
     app->submenu = submenu_alloc();
     submenu_add_item(
         app->submenu, "Measure", KeyCopierSubmenuIndexMeasure, key_copier_submenu_callback, app);
@@ -669,34 +648,22 @@ static KeyCopierApp* key_copier_app_alloc() {
     view_set_draw_callback(app->view_measure, key_copier_view_measure_draw_callback);
     view_set_input_callback(app->view_measure, key_copier_view_measure_input_callback);
     view_set_previous_callback(app->view_measure, key_copier_navigation_submenu_callback);
-    view_set_enter_callback(app->view_measure, key_copier_view_measure_enter_callback);
-    view_set_exit_callback(app->view_measure, key_copier_view_measure_exit_callback);
     view_set_context(app->view_measure, app);
-    view_set_custom_callback(app->view_measure, key_copier_view_measure_custom_event_callback);
-    view_allocate_model(app->view_measure, ViewModelTypeLockFree, sizeof(KeyCopierMeasureModel));
-    KeyCopierMeasureModel* model = view_get_model(app->view_measure);
+    view_allocate_model(app->view_measure, ViewModelTypeLockFree, sizeof(KeyCopierModel));
+    KeyCopierModel* model = view_get_model(app->view_measure);
 
     initialize_model(model);
     view_dispatcher_add_view(app->view_dispatcher, KeyCopierViewMeasure, app->view_measure);
 
     app->variable_item_list_config = variable_item_list_alloc();
-    variable_item_list_reset(app->variable_item_list_config);
-    VariableItem* item = variable_item_list_add(
-        app->variable_item_list_config,
-        format_config_label,
-        COUNT_OF(format_names),
-        key_copier_format_change,
-        app);
-
-    view_set_previous_callback(
-        variable_item_list_get_view(app->variable_item_list_config),
-        key_copier_navigation_submenu_callback);
-    view_dispatcher_add_view(
-        app->view_dispatcher,
-        KeyCopierViewConfigure_e,
-        variable_item_list_get_view(app->variable_item_list_config));
-    variable_item_set_current_value_index(item, model->format_index);
-    variable_item_set_current_value_text(item, model->format.format_name);
+    app->view_config_e = view_alloc();
+    view_set_context(app->view_config_e, app);
+    view_set_previous_callback(app->view_config_e, key_copier_navigation_submenu_callback);
+    view_set_enter_callback(app->view_config_e, key_copier_config_enter_callback);
+    view_dispatcher_add_view(app->view_dispatcher, KeyCopierViewConfigure_e, app->view_config_e);
+    
+    View* view_buffer = view_alloc();
+    view_dispatcher_add_view(app->view_dispatcher, KeyCopierViewConfigure_i, view_buffer);
 
     app->view_save = view_alloc();
     view_set_context(app->view_save, app);
@@ -706,7 +673,7 @@ static KeyCopierApp* key_copier_app_alloc() {
 
     app->view_load = view_alloc();
     view_set_context(app->view_load, app);
-    view_set_enter_callback(app->view_load, key_copier_view_save_callback);
+    view_set_enter_callback(app->view_load, t5577_writer_view_load_callback);
     view_set_previous_callback(app->view_load, key_copier_navigation_submenu_callback);
     view_dispatcher_add_view(app->view_dispatcher, KeyCopierViewLoad, app->view_load);
 
@@ -751,7 +718,7 @@ static void key_copier_app_free(KeyCopierApp* app) {
     view_dispatcher_remove_view(app->view_dispatcher, KeyCopierViewMeasure);
     with_view_model(
         app->view_measure,
-        KeyCopierMeasureModel * model,
+        KeyCopierModel * model,
         {
             if(model->depth != NULL) {
                 free(model->depth);
@@ -760,6 +727,7 @@ static void key_copier_app_free(KeyCopierApp* app) {
         false);
     view_free(app->view_measure);
     view_dispatcher_remove_view(app->view_dispatcher, KeyCopierViewConfigure_e);
+    view_dispatcher_remove_view(app->view_dispatcher, KeyCopierViewConfigure_i);
     view_dispatcher_remove_view(app->view_dispatcher, KeyCopierViewSave);
     view_dispatcher_remove_view(app->view_dispatcher, KeyCopierViewLoad);
     variable_item_list_free(app->variable_item_list_config);

+ 9 - 4
key_copier.h

@@ -1,4 +1,9 @@
-#define KEY_COPIER_FILE_NAME_SIZE 25
-#define KEY_COPIER_APPS_DATA_FOLDER EXT_PATH("apps_data")
-#define KEY_COPIER_SAVE_FOLDER      EXT_PATH("apps_data/key_copier")
-#define KEY_COPIER_SAVE_EXTENSION ".keycopy"
+#define KEY_COPIER_FILE_EXTENSION ".keycopy"
+
+static inline int min(int a, int b) {
+    return (a < b) ? a : b;
+}
+
+static inline int max(int a, int b) {
+    return (a > b) ? a : b;
+}