Save picopass as picopass or, for 26bit, as lfrfid (#1380)
This commit is contained in:
		
							parent
							
								
									f46ae5a704
								
							
						
					
					
						commit
						41bd1fb9a5
					
				| @ -56,6 +56,13 @@ Picopass* picopass_alloc() { | ||||
|     view_dispatcher_add_view( | ||||
|         picopass->view_dispatcher, PicopassViewPopup, popup_get_view(picopass->popup)); | ||||
| 
 | ||||
|     // Text Input
 | ||||
|     picopass->text_input = text_input_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         picopass->view_dispatcher, | ||||
|         PicopassViewTextInput, | ||||
|         text_input_get_view(picopass->text_input)); | ||||
| 
 | ||||
|     // Custom Widget
 | ||||
|     picopass->widget = widget_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
| @ -67,6 +74,10 @@ Picopass* picopass_alloc() { | ||||
| void picopass_free(Picopass* picopass) { | ||||
|     furi_assert(picopass); | ||||
| 
 | ||||
|     // Picopass device
 | ||||
|     picopass_device_free(picopass->dev); | ||||
|     picopass->dev = NULL; | ||||
| 
 | ||||
|     // Submenu
 | ||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewMenu); | ||||
|     submenu_free(picopass->submenu); | ||||
| @ -75,6 +86,10 @@ void picopass_free(Picopass* picopass) { | ||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewPopup); | ||||
|     popup_free(picopass->popup); | ||||
| 
 | ||||
|     // TextInput
 | ||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewTextInput); | ||||
|     text_input_free(picopass->text_input); | ||||
| 
 | ||||
|     // Custom Widget
 | ||||
|     view_dispatcher_remove_view(picopass->view_dispatcher, PicopassViewWidget); | ||||
|     widget_free(picopass->widget); | ||||
| @ -97,12 +112,22 @@ void picopass_free(Picopass* picopass) { | ||||
|     furi_record_close("notification"); | ||||
|     picopass->notifications = NULL; | ||||
| 
 | ||||
|     picopass_device_free(picopass->dev); | ||||
|     picopass->dev = NULL; | ||||
| 
 | ||||
|     free(picopass); | ||||
| } | ||||
| 
 | ||||
| void picopass_text_store_set(Picopass* picopass, const char* text, ...) { | ||||
|     va_list args; | ||||
|     va_start(args, text); | ||||
| 
 | ||||
|     vsnprintf(picopass->text_store, sizeof(picopass->text_store), text, args); | ||||
| 
 | ||||
|     va_end(args); | ||||
| } | ||||
| 
 | ||||
| void picopass_text_store_clear(Picopass* picopass) { | ||||
|     memset(picopass->text_store, 0, sizeof(picopass->text_store)); | ||||
| } | ||||
| 
 | ||||
| static const NotificationSequence picopass_sequence_blink_start_blue = { | ||||
|     &message_blink_start_10, | ||||
|     &message_blink_set_color_blue, | ||||
|  | ||||
| @ -5,6 +5,9 @@ | ||||
| 
 | ||||
| #define TAG "PicopassDevice" | ||||
| 
 | ||||
| static const char* picopass_file_header = "Flipper Picopass device"; | ||||
| static const uint32_t picopass_file_version = 1; | ||||
| 
 | ||||
| PicopassDevice* picopass_device_alloc() { | ||||
|     PicopassDevice* picopass_dev = malloc(sizeof(PicopassDevice)); | ||||
|     picopass_dev->storage = furi_record_open("storage"); | ||||
| @ -12,6 +15,116 @@ PicopassDevice* picopass_device_alloc() { | ||||
|     return picopass_dev; | ||||
| } | ||||
| 
 | ||||
| void picopass_device_set_name(PicopassDevice* dev, const char* name) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     strlcpy(dev->dev_name, name, PICOPASS_DEV_NAME_MAX_LEN); | ||||
| } | ||||
| 
 | ||||
| static bool picopass_device_save_file( | ||||
|     PicopassDevice* dev, | ||||
|     const char* dev_name, | ||||
|     const char* folder, | ||||
|     const char* extension, | ||||
|     bool use_load_path) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
|     bool saved = false; | ||||
|     FlipperFormat* file = flipper_format_file_alloc(dev->storage); | ||||
|     PicopassPacs* pacs = &dev->dev_data.pacs; | ||||
|     ApplicationArea* AA1 = &dev->dev_data.AA1; | ||||
|     string_t temp_str; | ||||
|     string_init(temp_str); | ||||
| 
 | ||||
|     do { | ||||
|         if(use_load_path && !string_empty_p(dev->load_path)) { | ||||
|             // Get directory name
 | ||||
|             path_extract_dirname(string_get_cstr(dev->load_path), temp_str); | ||||
|             // Create picopass directory if necessary
 | ||||
|             if(!storage_simply_mkdir(dev->storage, string_get_cstr(temp_str))) break; | ||||
|             // Make path to file to save
 | ||||
|             string_cat_printf(temp_str, "/%s%s", dev_name, extension); | ||||
|         } else { | ||||
|             // Create picopass directory if necessary
 | ||||
|             if(!storage_simply_mkdir(dev->storage, PICOPASS_APP_FOLDER)) break; | ||||
|             // First remove picopass device file if it was saved
 | ||||
|             string_printf(temp_str, "%s/%s%s", folder, dev_name, extension); | ||||
|         } | ||||
|         // Open file
 | ||||
|         if(!flipper_format_file_open_always(file, string_get_cstr(temp_str))) break; | ||||
| 
 | ||||
|         if(dev->format == PicopassDeviceSaveFormatHF) { | ||||
|             // Write header
 | ||||
|             if(!flipper_format_write_header_cstr(file, picopass_file_header, picopass_file_version)) | ||||
|                 break; | ||||
|             if(pacs->record.valid) { | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, "Facility Code", (uint32_t*)&pacs->record.FacilityCode, 1)) | ||||
|                     break; | ||||
|                 if(!flipper_format_write_uint32( | ||||
|                        file, "Card Number", (uint32_t*)&pacs->record.CardNumber, 1)) | ||||
|                     break; | ||||
|                 if(!flipper_format_write_hex( | ||||
|                        file, "Credential", pacs->credential, PICOPASS_BLOCK_LEN)) | ||||
|                     break; | ||||
|                 if(!flipper_format_write_hex(file, "PIN", pacs->pin0, PICOPASS_BLOCK_LEN)) break; | ||||
|                 if(!flipper_format_write_hex(file, "PIN(cont.)", pacs->pin1, PICOPASS_BLOCK_LEN)) | ||||
|                     break; | ||||
| 
 | ||||
|                 if(!flipper_format_write_comment_cstr(file, "Picopass blocks")) break; | ||||
|                 // TODO: Save CSN, CFG, AA1, etc
 | ||||
|                 bool block_saved = true; | ||||
|                 for(size_t i = 0; i < 4; i++) { | ||||
|                     string_printf(temp_str, "Block %d", i + 6); | ||||
|                     if(!flipper_format_write_hex( | ||||
|                            file, | ||||
|                            string_get_cstr(temp_str), | ||||
|                            AA1->block[i].data, | ||||
|                            PICOPASS_BLOCK_LEN)) { | ||||
|                         block_saved = false; | ||||
|                         break; | ||||
|                     } | ||||
|                 } | ||||
|                 if(!block_saved) break; | ||||
|                 if(!flipper_format_write_comment_cstr(file, "This is currently incomplete")) break; | ||||
|             } | ||||
|         } else if(dev->format == PicopassDeviceSaveFormatLF) { | ||||
|             const char* lf_header = "Flipper RFID key"; | ||||
|             // Write header
 | ||||
|             if(!flipper_format_write_header_cstr(file, lf_header, 1)) break; | ||||
|             if(!flipper_format_write_comment_cstr( | ||||
|                    file, | ||||
|                    "This was generated from the Picopass plugin and may not match current lfrfid")) | ||||
|                 break; | ||||
|             // When lfrfid supports more formats, update this
 | ||||
|             if(!flipper_format_write_string_cstr(file, "Key type", "H10301")) break; | ||||
|             uint8_t H10301[3] = {0}; | ||||
|             H10301[0] = pacs->record.FacilityCode; | ||||
|             H10301[1] = pacs->record.CardNumber >> 8; | ||||
|             H10301[2] = pacs->record.CardNumber & 0x00FF; | ||||
|             if(!flipper_format_write_hex(file, "Data", H10301, 3)) break; | ||||
|         } | ||||
|         saved = true; | ||||
|     } while(0); | ||||
| 
 | ||||
|     if(!saved) { | ||||
|         dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file"); | ||||
|     } | ||||
|     string_clear(temp_str); | ||||
|     flipper_format_free(file); | ||||
|     return saved; | ||||
| } | ||||
| 
 | ||||
| bool picopass_device_save(PicopassDevice* dev, const char* dev_name) { | ||||
|     if(dev->format == PicopassDeviceSaveFormatHF) { | ||||
|         return picopass_device_save_file( | ||||
|             dev, dev_name, PICOPASS_APP_FOLDER, PICOPASS_APP_EXTENSION, true); | ||||
|     } else if(dev->format == PicopassDeviceSaveFormatLF) { | ||||
|         return picopass_device_save_file(dev, dev_name, "/any/lfrfid", ".rfid", true); | ||||
|     } | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| void picopass_device_clear(PicopassDevice* dev) { | ||||
|     furi_assert(dev); | ||||
| 
 | ||||
| @ -24,10 +137,10 @@ void picopass_device_free(PicopassDevice* picopass_dev) { | ||||
|     picopass_device_clear(picopass_dev); | ||||
|     furi_record_close("storage"); | ||||
|     furi_record_close("dialogs"); | ||||
|     string_clear(picopass_dev->load_path); | ||||
|     free(picopass_dev); | ||||
| } | ||||
| 
 | ||||
| void picopass_device_data_clear(PicopassDeviceData* dev_data) { | ||||
|     FURI_LOG_D(TAG, "picopass_device_data_clear"); | ||||
|     memset(&dev_data->AA1, 0, sizeof(ApplicationArea)); | ||||
| } | ||||
|  | ||||
| @ -7,6 +7,26 @@ | ||||
| 
 | ||||
| #include <rfal_picopass.h> | ||||
| 
 | ||||
| #define PICOPASS_DEV_NAME_MAX_LEN 22 | ||||
| #define PICOPASS_READER_DATA_MAX_SIZE 64 | ||||
| #define PICOPASS_BLOCK_LEN 8 | ||||
| 
 | ||||
| #define PICOPASS_APP_FOLDER "/any/picopass" | ||||
| #define PICOPASS_APP_EXTENSION ".picopass" | ||||
| #define PICOPASS_APP_SHADOW_EXTENSION ".pas" | ||||
| 
 | ||||
| typedef enum { | ||||
|     PicopassDeviceEncryptionUnknown = 0, | ||||
|     PicopassDeviceEncryptionNone = 0x14, | ||||
|     PicopassDeviceEncryptionDES = 0x15, | ||||
|     PicopassDeviceEncryption3DES = 0x17, | ||||
| } PicopassEncryption; | ||||
| 
 | ||||
| typedef enum { | ||||
|     PicopassDeviceSaveFormatHF, | ||||
|     PicopassDeviceSaveFormatLF, | ||||
| } PicopassDeviceSaveFormat; | ||||
| 
 | ||||
| typedef struct { | ||||
|     bool valid; | ||||
|     uint8_t bitLength; | ||||
| @ -16,7 +36,7 @@ typedef struct { | ||||
| 
 | ||||
| typedef struct { | ||||
|     bool biometrics; | ||||
|     uint8_t encryption; | ||||
|     PicopassEncryption encryption; | ||||
|     uint8_t credential[8]; | ||||
|     uint8_t pin0[8]; | ||||
|     uint8_t pin1[8]; | ||||
| @ -32,12 +52,19 @@ typedef struct { | ||||
|     Storage* storage; | ||||
|     DialogsApp* dialogs; | ||||
|     PicopassDeviceData dev_data; | ||||
|     char dev_name[PICOPASS_DEV_NAME_MAX_LEN + 1]; | ||||
|     string_t load_path; | ||||
|     PicopassDeviceSaveFormat format; | ||||
| } PicopassDevice; | ||||
| 
 | ||||
| PicopassDevice* picopass_device_alloc(); | ||||
| 
 | ||||
| void picopass_device_free(PicopassDevice* picopass_dev); | ||||
| 
 | ||||
| void picopass_device_set_name(PicopassDevice* dev, const char* name); | ||||
| 
 | ||||
| bool picopass_device_save(PicopassDevice* dev, const char* dev_name); | ||||
| 
 | ||||
| void picopass_device_data_clear(PicopassDeviceData* dev_data); | ||||
| 
 | ||||
| void picopass_device_clear(PicopassDevice* dev); | ||||
|  | ||||
| @ -14,6 +14,7 @@ | ||||
| 
 | ||||
| #include <gui/modules/submenu.h> | ||||
| #include <gui/modules/popup.h> | ||||
| #include <gui/modules/text_input.h> | ||||
| #include <gui/modules/widget.h> | ||||
| 
 | ||||
| #include <input/input.h> | ||||
| @ -23,6 +24,8 @@ | ||||
| #include <storage/storage.h> | ||||
| #include <lib/toolbox/path.h> | ||||
| 
 | ||||
| #define PICOPASS_TEXT_STORE_SIZE 128 | ||||
| 
 | ||||
| enum PicopassCustomEvent { | ||||
|     // Reserve first 100 events for button types and indexes, starting from 0
 | ||||
|     PicopassCustomEventReserved = 100, | ||||
| @ -31,7 +34,6 @@ enum PicopassCustomEvent { | ||||
|     PicopassCustomEventWorkerExit, | ||||
|     PicopassCustomEventByteInputDone, | ||||
|     PicopassCustomEventTextInputDone, | ||||
|     PicopassCustomEventDictAttackDone, | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
| @ -47,20 +49,29 @@ struct Picopass { | ||||
|     SceneManager* scene_manager; | ||||
|     PicopassDevice* dev; | ||||
| 
 | ||||
|     char text_store[PICOPASS_TEXT_STORE_SIZE + 1]; | ||||
|     string_t text_box_store; | ||||
| 
 | ||||
|     // Common Views
 | ||||
|     Submenu* submenu; | ||||
|     Popup* popup; | ||||
|     TextInput* text_input; | ||||
|     Widget* widget; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     PicopassViewMenu, | ||||
|     PicopassViewPopup, | ||||
|     PicopassViewTextInput, | ||||
|     PicopassViewWidget, | ||||
| } PicopassView; | ||||
| 
 | ||||
| Picopass* picopass_alloc(); | ||||
| 
 | ||||
| void picopass_text_store_set(Picopass* picopass, const char* text, ...); | ||||
| 
 | ||||
| void picopass_text_store_clear(Picopass* picopass); | ||||
| 
 | ||||
| void picopass_blink_start(Picopass* picopass); | ||||
| 
 | ||||
| void picopass_blink_stop(Picopass* picopass); | ||||
|  | ||||
| @ -114,8 +114,6 @@ void picopass_worker_start( | ||||
|     furi_assert(picopass_worker); | ||||
|     furi_assert(dev_data); | ||||
| 
 | ||||
|     FURI_LOG_D(TAG, "picopass_worker_start"); | ||||
| 
 | ||||
|     picopass_worker->callback = callback; | ||||
|     picopass_worker->context = context; | ||||
|     picopass_worker->dev_data = dev_data; | ||||
| @ -258,10 +256,8 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { | ||||
|     ReturnCode err; | ||||
| 
 | ||||
|     while(picopass_worker->state == PicopassWorkerStateDetect) { | ||||
|         FURI_LOG_D(TAG, "PicopassWorkerStateDetect"); | ||||
|         if(picopass_detect_card(1000) == ERR_NONE) { | ||||
|             // Process first found device
 | ||||
|             FURI_LOG_D(TAG, "picopass_read_card"); | ||||
|             err = picopass_read_card(AA1); | ||||
|             if(err != ERR_NONE) { | ||||
|                 FURI_LOG_E(TAG, "picopass_read_card error %d", err); | ||||
| @ -277,21 +273,18 @@ void picopass_worker_detect(PicopassWorker* picopass_worker) { | ||||
|                     FURI_LOG_E(TAG, "decrypt error %d", err); | ||||
|                     break; | ||||
|                 } | ||||
|                 FURI_LOG_D(TAG, "Decrypted 7"); | ||||
| 
 | ||||
|                 err = picopass_worker_decrypt(AA1->block[2].data, pacs->pin0); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E(TAG, "decrypt error %d", err); | ||||
|                     break; | ||||
|                 } | ||||
|                 FURI_LOG_D(TAG, "Decrypted 8"); | ||||
| 
 | ||||
|                 err = picopass_worker_decrypt(AA1->block[3].data, pacs->pin1); | ||||
|                 if(err != ERR_NONE) { | ||||
|                     FURI_LOG_E(TAG, "decrypt error %d", err); | ||||
|                     break; | ||||
|                 } | ||||
|                 FURI_LOG_D(TAG, "Decrypted 9"); | ||||
|             } else if(pacs->encryption == 0x14) { | ||||
|                 FURI_LOG_D(TAG, "No Encryption"); | ||||
|                 memcpy(pacs->credential, AA1->block[1].data, RFAL_PICOPASS_MAX_BLOCK_LEN); | ||||
|  | ||||
							
								
								
									
										65
									
								
								applications/picopass/scenes/picopass_scene_card_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								applications/picopass/scenes/picopass_scene_card_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | ||||
| #include "../picopass_i.h" | ||||
| 
 | ||||
| enum SubmenuIndex { | ||||
|     SubmenuIndexSave, | ||||
|     SubmenuIndexSaveAsLF, | ||||
| }; | ||||
| 
 | ||||
| void picopass_scene_card_menu_submenu_callback(void* context, uint32_t index) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(picopass->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_card_menu_on_enter(void* context) { | ||||
|     Picopass* picopass = context; | ||||
|     Submenu* submenu = picopass->submenu; | ||||
| 
 | ||||
|     submenu_add_item( | ||||
|         submenu, "Save", SubmenuIndexSave, picopass_scene_card_menu_submenu_callback, picopass); | ||||
|     if(picopass->dev->dev_data.pacs.record.valid) { | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Save as LF", | ||||
|             SubmenuIndexSaveAsLF, | ||||
|             picopass_scene_card_menu_submenu_callback, | ||||
|             picopass); | ||||
|     } | ||||
|     submenu_set_selected_item( | ||||
|         picopass->submenu, | ||||
|         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneCardMenu)); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool picopass_scene_card_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Picopass* picopass = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == SubmenuIndexSave) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSave); | ||||
|             scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); | ||||
|             picopass->dev->format = PicopassDeviceSaveFormatHF; | ||||
|             consumed = true; | ||||
|         } else if(event.event == SubmenuIndexSaveAsLF) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 picopass->scene_manager, PicopassSceneCardMenu, SubmenuIndexSaveAsLF); | ||||
|             picopass->dev->format = PicopassDeviceSaveFormatLF; | ||||
|             scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveName); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|             picopass->scene_manager, PicopassSceneStart); | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_card_menu_on_exit(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     submenu_reset(picopass->submenu); | ||||
| } | ||||
| @ -1,3 +1,7 @@ | ||||
| ADD_SCENE(picopass, start, Start) | ||||
| ADD_SCENE(picopass, read_card, ReadCard) | ||||
| ADD_SCENE(picopass, read_card_success, ReadCardSuccess) | ||||
| ADD_SCENE(picopass, card_menu, CardMenu) | ||||
| ADD_SCENE(picopass, save_name, SaveName) | ||||
| ADD_SCENE(picopass, save_success, SaveSuccess) | ||||
| ADD_SCENE(picopass, saved_menu, SavedMenu) | ||||
|  | ||||
| @ -45,6 +45,14 @@ void picopass_scene_read_card_success_on_enter(void* context) { | ||||
|         "Retry", | ||||
|         picopass_scene_read_card_success_widget_callback, | ||||
|         picopass); | ||||
| 
 | ||||
|     widget_add_button_element( | ||||
|         widget, | ||||
|         GuiButtonTypeRight, | ||||
|         "More", | ||||
|         picopass_scene_read_card_success_widget_callback, | ||||
|         picopass); | ||||
| 
 | ||||
|     if(pacs->record.valid) { | ||||
|         widget_add_string_element( | ||||
|             widget, 64, 12, AlignCenter, AlignCenter, FontPrimary, string_get_cstr(wiegand_str)); | ||||
| @ -65,6 +73,11 @@ bool picopass_scene_read_card_success_on_event(void* context, SceneManagerEvent | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == GuiButtonTypeLeft) { | ||||
|             consumed = scene_manager_previous_scene(picopass->scene_manager); | ||||
|         } else if(event.event == GuiButtonTypeRight) { | ||||
|             // Clear device name
 | ||||
|             picopass_device_set_name(picopass->dev, ""); | ||||
|             scene_manager_next_scene(picopass->scene_manager, PicopassSceneCardMenu); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
|  | ||||
							
								
								
									
										84
									
								
								applications/picopass/scenes/picopass_scene_save_name.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								applications/picopass/scenes/picopass_scene_save_name.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,84 @@ | ||||
| #include "../picopass_i.h" | ||||
| #include "m-string.h" | ||||
| #include <lib/toolbox/random_name.h> | ||||
| #include <gui/modules/validators.h> | ||||
| #include <toolbox/path.h> | ||||
| 
 | ||||
| void picopass_scene_save_name_text_input_callback(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventTextInputDone); | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_save_name_on_enter(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     TextInput* text_input = picopass->text_input; | ||||
|     bool dev_name_empty = false; | ||||
|     if(!strcmp(picopass->dev->dev_name, "")) { | ||||
|         set_random_name(picopass->text_store, sizeof(picopass->text_store)); | ||||
|         dev_name_empty = true; | ||||
|     } else { | ||||
|         picopass_text_store_set(picopass, picopass->dev->dev_name); | ||||
|     } | ||||
|     text_input_set_header_text(text_input, "Name the card"); | ||||
|     text_input_set_result_callback( | ||||
|         text_input, | ||||
|         picopass_scene_save_name_text_input_callback, | ||||
|         picopass, | ||||
|         picopass->text_store, | ||||
|         PICOPASS_DEV_NAME_MAX_LEN, | ||||
|         dev_name_empty); | ||||
| 
 | ||||
|     string_t folder_path; | ||||
|     string_init(folder_path); | ||||
| 
 | ||||
|     if(string_end_with_str_p(picopass->dev->load_path, PICOPASS_APP_EXTENSION)) { | ||||
|         path_extract_dirname(string_get_cstr(picopass->dev->load_path), folder_path); | ||||
|     } else { | ||||
|         string_set_str(folder_path, PICOPASS_APP_FOLDER); | ||||
|     } | ||||
| 
 | ||||
|     ValidatorIsFile* validator_is_file = validator_is_file_alloc_init( | ||||
|         string_get_cstr(folder_path), PICOPASS_APP_EXTENSION, picopass->dev->dev_name); | ||||
|     text_input_set_validator(text_input, validator_is_file_callback, validator_is_file); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewTextInput); | ||||
| 
 | ||||
|     string_clear(folder_path); | ||||
| } | ||||
| 
 | ||||
| bool picopass_scene_save_name_on_event(void* context, SceneManagerEvent event) { | ||||
|     Picopass* picopass = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == PicopassCustomEventTextInputDone) { | ||||
|             if(strcmp(picopass->dev->dev_name, "")) { | ||||
|                 // picopass_device_delete(picopass->dev, true);
 | ||||
|             } | ||||
|             strlcpy( | ||||
|                 picopass->dev->dev_name, picopass->text_store, strlen(picopass->text_store) + 1); | ||||
|             if(picopass_device_save(picopass->dev, picopass->text_store)) { | ||||
|                 scene_manager_next_scene(picopass->scene_manager, PicopassSceneSaveSuccess); | ||||
|                 consumed = true; | ||||
|             } else { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     picopass->scene_manager, PicopassSceneStart); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_save_name_on_exit(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     // Clear view
 | ||||
|     void* validator_context = text_input_get_validator_callback_context(picopass->text_input); | ||||
|     text_input_set_validator(picopass->text_input, NULL, NULL); | ||||
|     validator_is_file_free(validator_context); | ||||
| 
 | ||||
|     text_input_reset(picopass->text_input); | ||||
| } | ||||
							
								
								
									
										47
									
								
								applications/picopass/scenes/picopass_scene_save_success.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								applications/picopass/scenes/picopass_scene_save_success.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| #include "../picopass_i.h" | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| void picopass_scene_save_success_popup_callback(void* context) { | ||||
|     Picopass* picopass = context; | ||||
|     view_dispatcher_send_custom_event(picopass->view_dispatcher, PicopassCustomEventViewExit); | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_save_success_on_enter(void* context) { | ||||
|     Picopass* picopass = context; | ||||
|     DOLPHIN_DEED(DolphinDeedNfcSave); | ||||
| 
 | ||||
|     // Setup view
 | ||||
|     Popup* popup = picopass->popup; | ||||
|     popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59); | ||||
|     popup_set_header(popup, "Saved!", 13, 22, AlignLeft, AlignBottom); | ||||
|     popup_set_timeout(popup, 1500); | ||||
|     popup_set_context(popup, picopass); | ||||
|     popup_set_callback(popup, picopass_scene_save_success_popup_callback); | ||||
|     popup_enable_timeout(popup); | ||||
|     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewPopup); | ||||
| } | ||||
| 
 | ||||
| bool picopass_scene_save_success_on_event(void* context, SceneManagerEvent event) { | ||||
|     Picopass* picopass = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         if(event.event == PicopassCustomEventViewExit) { | ||||
|             if(scene_manager_has_previous_scene(picopass->scene_manager, PicopassSceneCardMenu)) { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     picopass->scene_manager, PicopassSceneCardMenu); | ||||
|             } else { | ||||
|                 consumed = scene_manager_search_and_switch_to_previous_scene( | ||||
|                     picopass->scene_manager, PicopassSceneStart); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_save_success_on_exit(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     // Clear view
 | ||||
|     popup_reset(picopass->popup); | ||||
| } | ||||
							
								
								
									
										35
									
								
								applications/picopass/scenes/picopass_scene_saved_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								applications/picopass/scenes/picopass_scene_saved_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | ||||
| #include "../picopass_i.h" | ||||
| 
 | ||||
| void picopass_scene_saved_menu_submenu_callback(void* context, uint32_t index) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(picopass->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_saved_menu_on_enter(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     submenu_set_selected_item( | ||||
|         picopass->submenu, | ||||
|         scene_manager_get_scene_state(picopass->scene_manager, PicopassSceneSavedMenu)); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(picopass->view_dispatcher, PicopassViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool picopass_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Picopass* picopass = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         scene_manager_set_scene_state( | ||||
|             picopass->scene_manager, PicopassSceneSavedMenu, event.event); | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void picopass_scene_saved_menu_on_exit(void* context) { | ||||
|     Picopass* picopass = context; | ||||
| 
 | ||||
|     submenu_reset(picopass->submenu); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Eric Betts
						Eric Betts