[FL-2152] New PIN lock (#989)
* [Fl-2152] New PIN Lock, part 1 * Fix errors & leaks, renaming * Add support to f6 * Fix error, remove duplicate code * Fix drawing corners of Lock Popup * FuriHal: insomnia if usb connected * Applications: cleanup timers use Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
| @ -81,7 +81,7 @@ OneShotView* one_shot_view_alloc(void) { | ||||
|     OneShotView* view = furi_alloc(sizeof(OneShotView)); | ||||
|     view->view = view_alloc(); | ||||
|     view->update_timer = | ||||
|         xTimerCreate("Update timer", 1000, pdTRUE, view, one_shot_view_update_timer_callback); | ||||
|         xTimerCreate(NULL, 1000, pdTRUE, view, one_shot_view_update_timer_callback); | ||||
| 
 | ||||
|     view_allocate_model(view->view, ViewModelTypeLocking, sizeof(OneShotViewModel)); | ||||
|     view_set_context(view->view, view); | ||||
|  | ||||
| @ -1,9 +1,3 @@ | ||||
| #include "animations/animation_manager.h" | ||||
| #include "desktop/scenes/desktop_scene.h" | ||||
| #include "desktop/scenes/desktop_scene_i.h" | ||||
| #include "desktop/views/desktop_locked.h" | ||||
| #include "desktop_i.h" | ||||
| 
 | ||||
| #include <storage/storage.h> | ||||
| #include <assets_icons.h> | ||||
| #include <gui/view_stack.h> | ||||
| @ -12,23 +6,38 @@ | ||||
| #include <portmacro.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "animations/animation_manager.h" | ||||
| #include "desktop/scenes/desktop_scene.h" | ||||
| #include "desktop/scenes/desktop_scene_i.h" | ||||
| #include "desktop/views/desktop_view_locked.h" | ||||
| #include "desktop/views/desktop_view_pin_input.h" | ||||
| #include "desktop/views/desktop_view_pin_timeout.h" | ||||
| #include "desktop_i.h" | ||||
| #include "desktop_helpers.h" | ||||
| 
 | ||||
| static void desktop_lock_icon_callback(Canvas* canvas, void* context) { | ||||
|     furi_assert(canvas); | ||||
|     canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8); | ||||
| } | ||||
| 
 | ||||
| bool desktop_custom_event_callback(void* context, uint32_t event) { | ||||
| static bool desktop_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     return scene_manager_handle_custom_event(desktop->scene_manager, event); | ||||
| } | ||||
| 
 | ||||
| bool desktop_back_event_callback(void* context) { | ||||
| static bool desktop_back_event_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     return scene_manager_handle_back_event(desktop->scene_manager); | ||||
| } | ||||
| 
 | ||||
| static void desktop_tick_event_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* app = context; | ||||
|     scene_manager_handle_tick_event(app->scene_manager); | ||||
| } | ||||
| 
 | ||||
| Desktop* desktop_alloc() { | ||||
|     Desktop* desktop = furi_alloc(sizeof(Desktop)); | ||||
| 
 | ||||
| @ -42,6 +51,8 @@ Desktop* desktop_alloc() { | ||||
|     view_dispatcher_enable_queue(desktop->view_dispatcher); | ||||
|     view_dispatcher_attach_to_gui( | ||||
|         desktop->view_dispatcher, desktop->gui, ViewDispatcherTypeDesktop); | ||||
|     view_dispatcher_set_tick_event_callback( | ||||
|         desktop->view_dispatcher, desktop_tick_event_callback, 500); | ||||
| 
 | ||||
|     view_dispatcher_set_event_callback_context(desktop->view_dispatcher, desktop); | ||||
|     view_dispatcher_set_custom_event_callback( | ||||
| @ -49,37 +60,60 @@ Desktop* desktop_alloc() { | ||||
|     view_dispatcher_set_navigation_event_callback( | ||||
|         desktop->view_dispatcher, desktop_back_event_callback); | ||||
| 
 | ||||
|     desktop->locked_view = desktop_locked_alloc(); | ||||
|     desktop->lock_menu = desktop_lock_menu_alloc(); | ||||
|     desktop->debug_view = desktop_debug_alloc(); | ||||
|     desktop->first_start_view = desktop_first_start_alloc(); | ||||
|     desktop->hw_mismatch_popup = popup_alloc(); | ||||
|     desktop->code_input = code_input_alloc(); | ||||
|     desktop->locked_view = desktop_view_locked_alloc(); | ||||
|     desktop->pin_input_view = desktop_view_pin_input_alloc(); | ||||
|     desktop->pin_timeout_view = desktop_view_pin_timeout_alloc(); | ||||
| 
 | ||||
|     desktop->main_view_stack = view_stack_alloc(); | ||||
|     desktop->main_view = desktop_main_alloc(); | ||||
|     View* dolphin_view = animation_manager_get_animation_view(desktop->animation_manager); | ||||
|     view_stack_add_view(desktop->main_view_stack, desktop_main_get_view(desktop->main_view)); | ||||
|     view_stack_add_view(desktop->main_view_stack, dolphin_view); | ||||
|     view_stack_add_view(desktop->main_view_stack, desktop_locked_get_view(desktop->locked_view)); | ||||
|     view_stack_add_view( | ||||
|         desktop->main_view_stack, desktop_view_locked_get_view(desktop->locked_view)); | ||||
| 
 | ||||
|     /* locked view (as animation view) attends in 2 scenes: main & locked,
 | ||||
|      * because it has to draw "Unlocked" label on main scene */ | ||||
|     desktop->locked_view_stack = view_stack_alloc(); | ||||
|     view_stack_add_view(desktop->locked_view_stack, dolphin_view); | ||||
|     view_stack_add_view( | ||||
|         desktop->locked_view_stack, desktop_view_locked_get_view(desktop->locked_view)); | ||||
| 
 | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, DesktopViewMain, view_stack_get_view(desktop->main_view_stack)); | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewIdMain, | ||||
|         view_stack_get_view(desktop->main_view_stack)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewLockMenu, | ||||
|         DesktopViewIdLocked, | ||||
|         view_stack_get_view(desktop->locked_view_stack)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewIdLockMenu, | ||||
|         desktop_lock_menu_get_view(desktop->lock_menu)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, DesktopViewDebug, desktop_debug_get_view(desktop->debug_view)); | ||||
|         desktop->view_dispatcher, DesktopViewIdDebug, desktop_debug_get_view(desktop->debug_view)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewFirstStart, | ||||
|         DesktopViewIdFirstStart, | ||||
|         desktop_first_start_get_view(desktop->first_start_view)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewHwMismatch, | ||||
|         DesktopViewIdHwMismatch, | ||||
|         popup_get_view(desktop->hw_mismatch_popup)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, DesktopViewPinSetup, code_input_get_view(desktop->code_input)); | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewIdPinTimeout, | ||||
|         desktop_view_pin_timeout_get_view(desktop->pin_timeout_view)); | ||||
|     view_dispatcher_add_view( | ||||
|         desktop->view_dispatcher, | ||||
|         DesktopViewIdPinInput, | ||||
|         desktop_view_pin_input_get_view(desktop->pin_input_view)); | ||||
| 
 | ||||
|     // Lock icon
 | ||||
|     desktop->lock_viewport = view_port_alloc(); | ||||
|     view_port_set_width(desktop->lock_viewport, icon_get_width(&I_Lock_8x8)); | ||||
| @ -93,27 +127,29 @@ Desktop* desktop_alloc() { | ||||
| void desktop_free(Desktop* desktop) { | ||||
|     furi_assert(desktop); | ||||
| 
 | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewMain); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLockMenu); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLocked); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewDebug); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewFirstStart); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewHwMismatch); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewPinSetup); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdFirstStart); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); | ||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); | ||||
| 
 | ||||
|     view_dispatcher_free(desktop->view_dispatcher); | ||||
|     scene_manager_free(desktop->scene_manager); | ||||
| 
 | ||||
|     animation_manager_free(desktop->animation_manager); | ||||
|     view_stack_free(desktop->main_view_stack); | ||||
|     view_stack_free(desktop->locked_view_stack); | ||||
|     desktop_main_free(desktop->main_view); | ||||
|     view_stack_free(desktop->locked_view_stack); | ||||
|     desktop_view_locked_free(desktop->locked_view); | ||||
|     desktop_lock_menu_free(desktop->lock_menu); | ||||
|     desktop_locked_free(desktop->locked_view); | ||||
|     desktop_view_locked_free(desktop->locked_view); | ||||
|     desktop_debug_free(desktop->debug_view); | ||||
|     desktop_first_start_free(desktop->first_start_view); | ||||
|     popup_free(desktop->hw_mismatch_popup); | ||||
|     code_input_free(desktop->code_input); | ||||
|     desktop_view_pin_timeout_free(desktop->pin_timeout_view); | ||||
| 
 | ||||
|     osSemaphoreDelete(desktop->unload_animation_semaphore); | ||||
| 
 | ||||
| @ -145,14 +181,18 @@ int32_t desktop_srv(void* p) { | ||||
|         SAVE_DESKTOP_SETTINGS(&desktop->settings); | ||||
|     } | ||||
| 
 | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { | ||||
|         furi_hal_usb_disable(); | ||||
|         scene_manager_set_scene_state( | ||||
|             desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin); | ||||
|     } | ||||
| 
 | ||||
|     scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||
| 
 | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock)) { | ||||
|         if(desktop->settings.pin_code.length > 0) { | ||||
|             scene_manager_set_scene_state( | ||||
|                 desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); | ||||
|             scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); | ||||
|         } else { | ||||
|             furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(desktop_is_first_start()) { | ||||
|         scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); | ||||
|     } | ||||
|  | ||||
							
								
								
									
										82
									
								
								applications/desktop/desktop_helpers.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,82 @@ | ||||
| #include <notification/notification.h> | ||||
| #include <notification/notification_messages.h> | ||||
| #include <stddef.h> | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/gui.h> | ||||
| 
 | ||||
| #include "desktop_helpers.h" | ||||
| #include "desktop_i.h" | ||||
| 
 | ||||
| static const NotificationSequence sequence_pin_fail = { | ||||
|     &message_display_on, | ||||
| 
 | ||||
|     &message_red_255, | ||||
|     &message_vibro_on, | ||||
|     &message_delay_100, | ||||
|     &message_vibro_off, | ||||
|     &message_red_0, | ||||
| 
 | ||||
|     &message_delay_250, | ||||
| 
 | ||||
|     &message_red_255, | ||||
|     &message_vibro_on, | ||||
|     &message_delay_100, | ||||
|     &message_vibro_off, | ||||
|     &message_red_0, | ||||
|     NULL, | ||||
| }; | ||||
| 
 | ||||
| static const uint8_t desktop_helpers_fails_timeout[] = { | ||||
|     0, | ||||
|     0, | ||||
|     0, | ||||
|     0, | ||||
|     30, | ||||
|     60, | ||||
|     90, | ||||
|     120, | ||||
|     150, | ||||
|     180, | ||||
|     /* +60 for every next fail */ | ||||
| }; | ||||
| 
 | ||||
| void desktop_helpers_emit_error_notification() { | ||||
|     NotificationApp* notification = furi_record_open("notification"); | ||||
|     notification_message(notification, &sequence_pin_fail); | ||||
|     furi_record_close("notification"); | ||||
| } | ||||
| 
 | ||||
| void desktop_helpers_lock_system(Desktop* desktop, bool hard_lock) { | ||||
|     view_port_enabled_set(desktop->lock_viewport, true); | ||||
|     if(hard_lock) { | ||||
|         furi_hal_rtc_set_flag(FuriHalRtcFlagLock); | ||||
|         furi_hal_usb_disable(); | ||||
|     } | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_set_lockdown(gui, true); | ||||
|     furi_record_close("gui"); | ||||
| } | ||||
| 
 | ||||
| void desktop_helpers_unlock_system(Desktop* desktop) { | ||||
|     furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); | ||||
|     furi_hal_usb_enable(); | ||||
|     view_port_enabled_set(desktop->lock_viewport, false); | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_set_lockdown(gui, false); | ||||
|     furi_record_close("gui"); | ||||
| } | ||||
| 
 | ||||
| uint32_t desktop_helpers_get_pin_fail_timeout(uint32_t pin_fails) { | ||||
|     uint32_t pin_timeout = 0; | ||||
|     uint32_t max_index = COUNT_OF(desktop_helpers_fails_timeout) - 1; | ||||
|     if(pin_fails <= max_index) { | ||||
|         pin_timeout = desktop_helpers_fails_timeout[pin_fails]; | ||||
|     } else { | ||||
|         pin_timeout = desktop_helpers_fails_timeout[max_index] + (pin_fails - max_index) * 60; | ||||
|     } | ||||
| 
 | ||||
|     return pin_timeout; | ||||
| } | ||||
							
								
								
									
										9
									
								
								applications/desktop/desktop_helpers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,9 @@ | ||||
| #pragma once | ||||
| #include <stdbool.h> | ||||
| #include <stdint.h> | ||||
| #include "desktop.h" | ||||
| 
 | ||||
| void desktop_helpers_emit_error_notification(); | ||||
| void desktop_helpers_lock_system(Desktop* desktop, bool hard_lock); | ||||
| void desktop_helpers_unlock_system(Desktop* desktop); | ||||
| uint32_t desktop_helpers_get_pin_fail_timeout(uint32_t pin_fails); | ||||
| @ -2,11 +2,13 @@ | ||||
| 
 | ||||
| #include "desktop.h" | ||||
| #include "animations/animation_manager.h" | ||||
| #include "views/desktop_main.h" | ||||
| #include "views/desktop_first_start.h" | ||||
| #include "views/desktop_lock_menu.h" | ||||
| #include "views/desktop_locked.h" | ||||
| #include "views/desktop_debug.h" | ||||
| #include "views/desktop_view_pin_timeout.h" | ||||
| #include "views/desktop_view_pin_input.h" | ||||
| #include "views/desktop_view_locked.h" | ||||
| #include "views/desktop_view_main.h" | ||||
| #include "views/desktop_view_first_start.h" | ||||
| #include "views/desktop_view_lock_menu.h" | ||||
| #include "views/desktop_view_debug.h" | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| 
 | ||||
| #include <furi.h> | ||||
| @ -14,21 +16,21 @@ | ||||
| #include <gui/view_stack.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/modules/popup.h> | ||||
| #include <gui/modules/code_input.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #define STATUS_BAR_Y_SHIFT 13 | ||||
| 
 | ||||
| typedef enum { | ||||
|     DesktopViewMain, | ||||
|     DesktopViewLockMenu, | ||||
|     DesktopViewLocked, | ||||
|     DesktopViewDebug, | ||||
|     DesktopViewFirstStart, | ||||
|     DesktopViewHwMismatch, | ||||
|     DesktopViewPinSetup, | ||||
|     DesktopViewTotal, | ||||
| } DesktopViewEnum; | ||||
|     DesktopViewIdMain, | ||||
|     DesktopViewIdLockMenu, | ||||
|     DesktopViewIdLocked, | ||||
|     DesktopViewIdDebug, | ||||
|     DesktopViewIdFirstStart, | ||||
|     DesktopViewIdHwMismatch, | ||||
|     DesktopViewIdPinInput, | ||||
|     DesktopViewIdPinTimeout, | ||||
|     DesktopViewIdTotal, | ||||
| } DesktopViewId; | ||||
| 
 | ||||
| struct Desktop { | ||||
|     // Scene
 | ||||
| @ -42,16 +44,15 @@ struct Desktop { | ||||
|     Popup* hw_mismatch_popup; | ||||
|     DesktopLockMenuView* lock_menu; | ||||
|     DesktopDebugView* debug_view; | ||||
|     CodeInput* code_input; | ||||
| 
 | ||||
|     DesktopViewLocked* locked_view; | ||||
|     DesktopMainView* main_view; | ||||
|     DesktopLockedView* locked_view; | ||||
|     DesktopViewPinTimeout* pin_timeout_view; | ||||
| 
 | ||||
|     ViewStack* main_view_stack; | ||||
|     ViewStack* locked_view_stack; | ||||
| 
 | ||||
|     DesktopSettings settings; | ||||
|     PinCode pincode_buffer; | ||||
|     DesktopViewPinInput* pin_input_view; | ||||
| 
 | ||||
|     ViewPort* lock_viewport; | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,6 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <furi_hal.h> | ||||
| #include <stdint.h> | ||||
| #include <stdbool.h> | ||||
| #include <toolbox/saved_struct.h> | ||||
| @ -9,6 +10,8 @@ | ||||
| #define DESKTOP_SETTINGS_MAGIC (0x17) | ||||
| #define PIN_MAX_LENGTH 12 | ||||
| 
 | ||||
| #define DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG "run_pin_setup" | ||||
| 
 | ||||
| #define SAVE_DESKTOP_SETTINGS(x) \ | ||||
|     saved_struct_save(           \ | ||||
|         DESKTOP_SETTINGS_PATH,   \ | ||||
| @ -25,12 +28,27 @@ | ||||
|         DESKTOP_SETTINGS_MAGIC,  \ | ||||
|         DESKTOP_SETTINGS_VER) | ||||
| 
 | ||||
| #define MAX_PIN_SIZE 10 | ||||
| #define MIN_PIN_SIZE 4 | ||||
| 
 | ||||
| typedef struct { | ||||
|     InputKey data[MAX_PIN_SIZE]; | ||||
|     uint8_t length; | ||||
|     uint8_t data[PIN_MAX_LENGTH]; | ||||
| } PinCode; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint16_t favorite; | ||||
|     PinCode pincode; | ||||
|     PinCode pin_code; | ||||
| } DesktopSettings; | ||||
| 
 | ||||
| static inline bool pins_are_equal(const PinCode* pin_code1, const PinCode* pin_code2) { | ||||
|     furi_assert(pin_code1); | ||||
|     furi_assert(pin_code2); | ||||
|     bool result = false; | ||||
| 
 | ||||
|     if(pin_code1->length == pin_code2->length) { | ||||
|         result = !memcmp(pin_code1->data, pin_code2->data, pin_code1->length); | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,10 @@ | ||||
| #include "desktop_settings_app.h" | ||||
| #include <furi.h> | ||||
| #include <gui/modules/popup.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #include "desktop_settings_app.h" | ||||
| #include "scenes/desktop_settings_scene.h" | ||||
| #include "../views/desktop_view_pin_input.h" | ||||
| 
 | ||||
| static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { | ||||
|     furi_assert(context); | ||||
| @ -30,17 +34,28 @@ DesktopSettingsApp* desktop_settings_app_alloc() { | ||||
| 
 | ||||
|     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||
| 
 | ||||
|     app->popup = popup_alloc(); | ||||
|     app->submenu = submenu_alloc(); | ||||
|     app->pin_input_view = desktop_view_pin_input_alloc(); | ||||
|     app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc(); | ||||
|     app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc(); | ||||
| 
 | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu)); | ||||
| 
 | ||||
|     app->code_input = code_input_alloc(); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup)); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, | ||||
|         DesktopSettingsAppViewPincodeInput, | ||||
|         code_input_get_view(app->code_input)); | ||||
| 
 | ||||
|     scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); | ||||
|         DesktopSettingsAppViewIdPinInput, | ||||
|         desktop_view_pin_input_get_view(app->pin_input_view)); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, | ||||
|         DesktopSettingsAppViewIdPinSetupHowto, | ||||
|         desktop_settings_view_pin_setup_howto_get_view(app->pin_setup_howto_view)); | ||||
|     view_dispatcher_add_view( | ||||
|         app->view_dispatcher, | ||||
|         DesktopSettingsAppViewIdPinSetupHowto2, | ||||
|         desktop_settings_view_pin_setup_howto2_get_view(app->pin_setup_howto2_view)); | ||||
|     return app; | ||||
| } | ||||
| 
 | ||||
| @ -48,9 +63,15 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { | ||||
|     furi_assert(app); | ||||
|     // Variable item list
 | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2); | ||||
|     submenu_free(app->submenu); | ||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewPincodeInput); | ||||
|     code_input_free(app->code_input); | ||||
|     popup_free(app->popup); | ||||
|     desktop_view_pin_input_free(app->pin_input_view); | ||||
|     desktop_settings_view_pin_setup_howto_free(app->pin_setup_howto_view); | ||||
|     desktop_settings_view_pin_setup_howto2_free(app->pin_setup_howto2_view); | ||||
|     // View dispatcher
 | ||||
|     view_dispatcher_free(app->view_dispatcher); | ||||
|     scene_manager_free(app->scene_manager); | ||||
| @ -62,6 +83,12 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { | ||||
| extern int32_t desktop_settings_app(void* p) { | ||||
|     DesktopSettingsApp* app = desktop_settings_app_alloc(); | ||||
|     LOAD_DESKTOP_SETTINGS(&app->settings); | ||||
|     if(!strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG)) { | ||||
|         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); | ||||
|     } else { | ||||
|         scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); | ||||
|     } | ||||
| 
 | ||||
|     view_dispatcher_run(app->view_dispatcher); | ||||
|     desktop_settings_app_free(app); | ||||
|     return 0; | ||||
|  | ||||
| @ -1,22 +1,22 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/gui.h> | ||||
| #include <gui/modules/popup.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/modules/submenu.h> | ||||
| #include <gui/modules/code_input.h> | ||||
| 
 | ||||
| #include "desktop_settings.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     CodeEventsSetPin, | ||||
|     CodeEventsChangePin, | ||||
|     CodeEventsDisablePin, | ||||
| } CodeEventsEnum; | ||||
| #include "desktop/views/desktop_view_pin_input.h" | ||||
| #include "views/desktop_settings_view_pin_setup_howto.h" | ||||
| #include "views/desktop_settings_view_pin_setup_howto2.h" | ||||
| 
 | ||||
| typedef enum { | ||||
|     DesktopSettingsAppViewMenu, | ||||
|     DesktopSettingsAppViewPincodeInput, | ||||
|     DesktopSettingsAppViewIdPopup, | ||||
|     DesktopSettingsAppViewIdPinInput, | ||||
|     DesktopSettingsAppViewIdPinSetupHowto, | ||||
|     DesktopSettingsAppViewIdPinSetupHowto2, | ||||
| } DesktopSettingsAppView; | ||||
| 
 | ||||
| typedef struct { | ||||
| @ -26,7 +26,13 @@ typedef struct { | ||||
|     SceneManager* scene_manager; | ||||
|     ViewDispatcher* view_dispatcher; | ||||
|     Submenu* submenu; | ||||
|     CodeInput* code_input; | ||||
|     Popup* popup; | ||||
|     DesktopViewPinInput* pin_input_view; | ||||
|     DesktopSettingsViewPinSetupHowto* pin_setup_howto_view; | ||||
|     DesktopSettingsViewPinSetupHowto2* pin_setup_howto2_view; | ||||
| 
 | ||||
|     PinCode pincode_buffer; | ||||
|     bool pincode_buffer_filled; | ||||
| 
 | ||||
|     uint8_t menu_idx; | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,11 @@ | ||||
| ADD_SCENE(desktop_settings, start, Start) | ||||
| ADD_SCENE(desktop_settings, favorite, Favorite) | ||||
| ADD_SCENE(desktop_settings, pincode_menu, PinCodeMenu) | ||||
| ADD_SCENE(desktop_settings, pincode_input, PinCodeInput) | ||||
| ADD_SCENE(desktop_settings, pin_menu, PinMenu) | ||||
| 
 | ||||
| ADD_SCENE(desktop_settings, pin_auth, PinAuth) | ||||
| ADD_SCENE(desktop_settings, pin_error, PinError) | ||||
| ADD_SCENE(desktop_settings, pin_disable, PinDisable) | ||||
| ADD_SCENE(desktop_settings, pin_setup, PinSetup) | ||||
| ADD_SCENE(desktop_settings, pin_setup_howto, PinSetupHowto) | ||||
| ADD_SCENE(desktop_settings, pin_setup_howto2, PinSetupHowto2) | ||||
| ADD_SCENE(desktop_settings, pin_setup_done, PinSetupDone) | ||||
|  | ||||
| @ -0,0 +1,7 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #define SCENE_STATE_PIN_AUTH_DISABLE (0) | ||||
| #define SCENE_STATE_PIN_AUTH_CHANGE_PIN (1) | ||||
| 
 | ||||
| #define SCENE_STATE_PIN_ERROR_MISMATCH (0) | ||||
| #define SCENE_STATE_PIN_ERROR_WRONG (1) | ||||
| @ -0,0 +1,95 @@ | ||||
| #include <stdint.h> | ||||
| #include <furi/check.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| #include "desktop/views/desktop_view_pin_input.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| #include "desktop_settings_scene_i.h" | ||||
| 
 | ||||
| #define SCENE_EVENT_EXIT (0U) | ||||
| #define SCENE_EVENT_PINS_EQUAL (1U) | ||||
| #define SCENE_EVENT_PINS_DIFFERENT (2U) | ||||
| 
 | ||||
| static void pin_auth_done_callback(const PinCode* pin_code, void* context) { | ||||
|     furi_assert(pin_code); | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     app->pincode_buffer = *pin_code; | ||||
|     if(pins_are_equal(&app->settings.pin_code, pin_code)) { | ||||
|         view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); | ||||
|     } else { | ||||
|         view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void pin_auth_back_callback(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_auth_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     LOAD_DESKTOP_SETTINGS(&app->settings); | ||||
|     furi_assert(app->settings.pin_code.length > 0); | ||||
| 
 | ||||
|     desktop_view_pin_input_set_context(app->pin_input_view, app); | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_auth_back_callback); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_auth_done_callback); | ||||
|     desktop_view_pin_input_set_label_button(app->pin_input_view, "OK"); | ||||
|     desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL); | ||||
|     desktop_view_pin_input_set_label_secondary( | ||||
|         app->pin_input_view, 0, 8, "Enter your current PIN:"); | ||||
|     desktop_view_pin_input_reset_pin(app->pin_input_view); | ||||
|     desktop_view_pin_input_unlock_input(app->pin_input_view); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_auth_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EVENT_PINS_DIFFERENT: | ||||
|             scene_manager_set_scene_state( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinError, SCENE_STATE_PIN_ERROR_WRONG); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinError); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case SCENE_EVENT_PINS_EQUAL: { | ||||
|             uint32_t state = | ||||
|                 scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinAuth); | ||||
|             if(state == SCENE_STATE_PIN_AUTH_CHANGE_PIN) { | ||||
|                 scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); | ||||
|             } else if(state == SCENE_STATE_PIN_AUTH_DISABLE) { | ||||
|                 scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinDisable); | ||||
|             } else { | ||||
|                 furi_assert(0); | ||||
|             } | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|         case SCENE_EVENT_EXIT: | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_auth_on_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL); | ||||
| } | ||||
| @ -0,0 +1,56 @@ | ||||
| #include <stdint.h> | ||||
| #include <furi/check.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/modules/popup.h> | ||||
| 
 | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "../desktop_settings.h" | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| 
 | ||||
| #define SCENE_EVENT_EXIT (0U) | ||||
| 
 | ||||
| static void pin_disable_back_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_disable_on_enter(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     app->settings.pin_code.length = 0; | ||||
|     memset(app->settings.pin_code.data, '0', sizeof(app->settings.pin_code.data)); | ||||
|     SAVE_DESKTOP_SETTINGS(&app->settings); | ||||
| 
 | ||||
|     popup_set_context(app->popup, app); | ||||
|     popup_set_callback(app->popup, pin_disable_back_callback); | ||||
|     popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_115x62); | ||||
|     popup_set_header(app->popup, "PIN\ndeleted!", 95, 9, AlignCenter, AlignCenter); | ||||
|     popup_set_timeout(app->popup, 1500); | ||||
|     popup_enable_timeout(app->popup); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_disable_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EVENT_EXIT: | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_disable_on_exit(void* context) { | ||||
| } | ||||
| @ -0,0 +1,76 @@ | ||||
| #include <stdint.h> | ||||
| #include <furi/check.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| #include "desktop/views/desktop_view_pin_input.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| #include "desktop_settings_scene_i.h" | ||||
| #include "../../desktop_helpers.h" | ||||
| #include "../desktop_settings_app.h" | ||||
| 
 | ||||
| #define SCENE_EVENT_EXIT (0U) | ||||
| 
 | ||||
| static void pin_error_back_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); | ||||
| } | ||||
| 
 | ||||
| static void pin_error_done_callback(const PinCode* pin_code, void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_error_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     desktop_helpers_emit_error_notification(); | ||||
| 
 | ||||
|     desktop_view_pin_input_set_context(app->pin_input_view, app); | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_error_back_callback); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_error_done_callback); | ||||
| 
 | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinError); | ||||
|     if(state == SCENE_STATE_PIN_ERROR_MISMATCH) { | ||||
|         desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN mismatch!"); | ||||
|     } else if(state == SCENE_STATE_PIN_ERROR_WRONG) { | ||||
|         desktop_view_pin_input_set_label_primary(app->pin_input_view, 35, 8, "Wrong PIN!"); | ||||
|     } else { | ||||
|         furi_assert(0); | ||||
|     } | ||||
|     desktop_view_pin_input_set_label_secondary(app->pin_input_view, 0, 8, NULL); | ||||
|     desktop_view_pin_input_set_label_button(app->pin_input_view, "Retry"); | ||||
|     desktop_view_pin_input_lock_input(app->pin_input_view); | ||||
|     desktop_view_pin_input_set_pin(app->pin_input_view, &app->pincode_buffer); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_error_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EVENT_EXIT: | ||||
|             scene_manager_previous_scene(app->scene_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_error_on_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     desktop_view_pin_input_unlock_input(app->pin_input_view); | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL); | ||||
| } | ||||
| @ -1,38 +1,45 @@ | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "applications.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| #include <gui/scene_manager.h> | ||||
| #include <applications.h> | ||||
| 
 | ||||
| static void desktop_settings_scene_pincode_menu_submenu_callback(void* context, uint32_t index) { | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| #include "desktop_settings_scene_i.h" | ||||
| 
 | ||||
| #define SCENE_EVENT_SET_PIN 0 | ||||
| #define SCENE_EVENT_CHANGE_PIN 1 | ||||
| #define SCENE_EVENT_DISABLE_PIN 2 | ||||
| 
 | ||||
| static void desktop_settings_scene_pin_menu_submenu_callback(void* context, uint32_t index) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, index); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pincode_menu_on_enter(void* context) { | ||||
| void desktop_settings_scene_pin_menu_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     Submenu* submenu = app->submenu; | ||||
|     submenu_reset(submenu); | ||||
| 
 | ||||
|     if(!app->settings.pincode.length) { | ||||
|     if(!app->settings.pin_code.length) { | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Set Pin", | ||||
|             CodeEventsSetPin, | ||||
|             desktop_settings_scene_pincode_menu_submenu_callback, | ||||
|             SCENE_EVENT_SET_PIN, | ||||
|             desktop_settings_scene_pin_menu_submenu_callback, | ||||
|             app); | ||||
| 
 | ||||
|     } else { | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Change Pin", | ||||
|             CodeEventsChangePin, | ||||
|             desktop_settings_scene_pincode_menu_submenu_callback, | ||||
|             SCENE_EVENT_CHANGE_PIN, | ||||
|             desktop_settings_scene_pin_menu_submenu_callback, | ||||
|             app); | ||||
| 
 | ||||
|         submenu_add_item( | ||||
|             submenu, | ||||
|             "Disable", | ||||
|             CodeEventsDisablePin, | ||||
|             desktop_settings_scene_pincode_menu_submenu_callback, | ||||
|             SCENE_EVENT_DISABLE_PIN, | ||||
|             desktop_settings_scene_pin_menu_submenu_callback, | ||||
|             app); | ||||
|     } | ||||
| 
 | ||||
| @ -41,28 +48,28 @@ void desktop_settings_scene_pincode_menu_on_enter(void* context) { | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEvent event) { | ||||
| bool desktop_settings_scene_pin_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case CodeEventsSetPin: | ||||
|             scene_manager_set_scene_state( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput); | ||||
|         case SCENE_EVENT_SET_PIN: | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case CodeEventsChangePin: | ||||
|         case SCENE_EVENT_CHANGE_PIN: | ||||
|             scene_manager_set_scene_state( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput); | ||||
|                 app->scene_manager, | ||||
|                 DesktopSettingsAppScenePinAuth, | ||||
|                 SCENE_STATE_PIN_AUTH_CHANGE_PIN); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case CodeEventsDisablePin: | ||||
|         case SCENE_EVENT_DISABLE_PIN: | ||||
|             scene_manager_set_scene_state( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput); | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinAuth, SCENE_STATE_PIN_AUTH_DISABLE); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         default: | ||||
| @ -73,7 +80,7 @@ bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEve | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pincode_menu_on_exit(void* context) { | ||||
| void desktop_settings_scene_pin_menu_on_exit(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     submenu_reset(app->submenu); | ||||
| } | ||||
| @ -0,0 +1,107 @@ | ||||
| #include <stdint.h> | ||||
| #include <furi/check.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| #include "desktop/views/desktop_view_pin_input.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| #include "desktop_settings_scene_i.h" | ||||
| 
 | ||||
| #define SCENE_EVENT_EXIT (0U) | ||||
| #define SCENE_EVENT_1ST_PIN_ENTERED (1U) | ||||
| #define SCENE_EVENT_PINS_EQUAL (2U) | ||||
| #define SCENE_EVENT_PINS_DIFFERENT (3U) | ||||
| 
 | ||||
| static void pin_setup_done_callback(const PinCode* pin_code, void* context) { | ||||
|     furi_assert(pin_code); | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     if(!app->pincode_buffer_filled) { | ||||
|         app->pincode_buffer = *pin_code; | ||||
|         app->pincode_buffer_filled = true; | ||||
|         view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_1ST_PIN_ENTERED); | ||||
|     } else { | ||||
|         app->pincode_buffer_filled = false; | ||||
|         if(pins_are_equal(&app->pincode_buffer, pin_code)) { | ||||
|             view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL); | ||||
|         } else { | ||||
|             view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void pin_setup_back_callback(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     app->pincode_buffer_filled = false; | ||||
|     desktop_view_pin_input_set_context(app->pin_input_view, app); | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_setup_back_callback); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback); | ||||
|     desktop_view_pin_input_set_label_button(app->pin_input_view, "OK"); | ||||
|     desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL); | ||||
|     desktop_view_pin_input_set_label_secondary( | ||||
|         app->pin_input_view, 0, 8, "Enter from 4 to 10 arrows:"); | ||||
|     desktop_view_pin_input_reset_pin(app->pin_input_view); | ||||
|     desktop_view_pin_input_unlock_input(app->pin_input_view); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_setup_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EVENT_1ST_PIN_ENTERED: | ||||
|             desktop_view_pin_input_set_label_button(app->pin_input_view, "OK"); | ||||
|             desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL); | ||||
|             desktop_view_pin_input_set_label_secondary( | ||||
|                 app->pin_input_view, 0, 8, "Confirm your PIN:"); | ||||
|             desktop_view_pin_input_reset_pin(app->pin_input_view); | ||||
|             desktop_view_pin_input_unlock_input(app->pin_input_view); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case SCENE_EVENT_PINS_DIFFERENT: | ||||
|             scene_manager_set_scene_state( | ||||
|                 app->scene_manager, | ||||
|                 DesktopSettingsAppScenePinError, | ||||
|                 SCENE_STATE_PIN_ERROR_MISMATCH); | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinError); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case SCENE_EVENT_PINS_EQUAL: | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto2); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case SCENE_EVENT_EXIT: { | ||||
|             uint32_t scene_found; | ||||
|             scene_found = scene_manager_search_and_switch_to_previous_scene( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||
|             if(!scene_found) { | ||||
|                 view_dispatcher_stop(app->view_dispatcher); | ||||
|             } | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
| 
 | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_on_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL); | ||||
| } | ||||
| @ -0,0 +1,77 @@ | ||||
| #include <furi.h> | ||||
| #include <notification/notification.h> | ||||
| #include <notification/notification_messages.h> | ||||
| #include <stdint.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| 
 | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| #include "desktop/views/desktop_view_pin_input.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| 
 | ||||
| #define SCENE_EVENT_DONE (0U) | ||||
| 
 | ||||
| static void pin_setup_done_callback(const PinCode* pin_code, void* context) { | ||||
|     furi_assert(pin_code); | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_DONE); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_done_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     app->settings.pin_code = app->pincode_buffer; | ||||
|     SAVE_DESKTOP_SETTINGS(&app->settings); | ||||
|     NotificationApp* notification = furi_record_open("notification"); | ||||
|     notification_message(notification, &sequence_single_vibro); | ||||
|     furi_record_close("notification"); | ||||
| 
 | ||||
|     desktop_view_pin_input_set_context(app->pin_input_view, app); | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback); | ||||
|     desktop_view_pin_input_set_pin(app->pin_input_view, &app->settings.pin_code); | ||||
|     desktop_view_pin_input_set_label_button(app->pin_input_view, "Done"); | ||||
|     desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN activated!"); | ||||
|     desktop_view_pin_input_set_label_secondary( | ||||
|         app->pin_input_view, 7, 45, "Remember or write it down"); | ||||
|     desktop_view_pin_input_lock_input(app->pin_input_view); | ||||
|     desktop_view_pin_input_set_pin_position(app->pin_input_view, 64, 24); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_setup_done_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EVENT_DONE: { | ||||
|             bool scene_found = false; | ||||
|             scene_found = scene_manager_search_and_switch_to_previous_scene( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||
|             if(!scene_found) { | ||||
|                 view_dispatcher_stop(app->view_dispatcher); | ||||
|             } | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeBack) { | ||||
|         consumed = true; | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_done_on_exit(void* context) { | ||||
|     furi_assert(context); | ||||
|     DesktopSettingsApp* app = context; | ||||
|     desktop_view_pin_input_set_pin_position(app->pin_input_view, 64, 32); | ||||
|     desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL); | ||||
|     desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL); | ||||
| } | ||||
| @ -0,0 +1,44 @@ | ||||
| #include <furi.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/view_dispatcher.h> | ||||
| 
 | ||||
| #include "desktop_settings_scene.h" | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "../views/desktop_settings_view_pin_setup_howto.h" | ||||
| 
 | ||||
| #define SCENE_EXIT_EVENT (0U) | ||||
| 
 | ||||
| static void desktop_settings_scene_pin_lock_done_callback(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_howto_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     desktop_settings_view_pin_setup_howto_set_callback( | ||||
|         app->pin_setup_howto_view, desktop_settings_scene_pin_lock_done_callback, app); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_setup_howto_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EXIT_EVENT: | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetup); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         default: | ||||
|             furi_assert(0); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_howto_on_exit(void* context) { | ||||
| } | ||||
| @ -0,0 +1,67 @@ | ||||
| #include <furi.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #include "desktop_settings_scene.h" | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "../views/desktop_settings_view_pin_setup_howto2.h" | ||||
| 
 | ||||
| #define SCENE_EXIT_EVENT (0U) | ||||
| #define SCENE_DONE_EVENT (1U) | ||||
| 
 | ||||
| static void desktop_settings_scene_pin_setup_howto2_done_callback(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_DONE_EVENT); | ||||
| } | ||||
| 
 | ||||
| static void desktop_settings_scene_pin_setup_howto2_exit_callback(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_howto2_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
| 
 | ||||
|     desktop_settings_view_pin_setup_howto2_set_context(app->pin_setup_howto2_view, app); | ||||
|     desktop_settings_view_pin_setup_howto2_set_ok_callback( | ||||
|         app->pin_setup_howto2_view, desktop_settings_scene_pin_setup_howto2_done_callback); | ||||
|     desktop_settings_view_pin_setup_howto2_set_cancel_callback( | ||||
|         app->pin_setup_howto2_view, desktop_settings_scene_pin_setup_howto2_exit_callback); | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pin_setup_howto2_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_DONE_EVENT: { | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupDone); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|         case SCENE_EXIT_EVENT: { | ||||
|             bool scene_found = false; | ||||
|             scene_found = scene_manager_search_and_switch_to_previous_scene( | ||||
|                 app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||
|             if(!scene_found) { | ||||
|                 view_dispatcher_stop(app->view_dispatcher); | ||||
|             } | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|         default: | ||||
|             furi_assert(0); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pin_setup_howto2_on_exit(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     desktop_settings_view_pin_setup_howto2_set_ok_callback(app->pin_setup_howto2_view, NULL); | ||||
|     desktop_settings_view_pin_setup_howto2_set_cancel_callback(app->pin_setup_howto2_view, NULL); | ||||
| } | ||||
| @ -1,64 +0,0 @@ | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| 
 | ||||
| #define SCENE_EXIT_EVENT (0U) | ||||
| 
 | ||||
| void desktop_settings_scene_ok_callback(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinCodeInput); | ||||
| 
 | ||||
|     if(state == CodeEventsDisablePin) { | ||||
|         memset(app->settings.pincode.data, 0, app->settings.pincode.length * sizeof(uint8_t)); | ||||
|         app->settings.pincode.length = 0; | ||||
|     } | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT); | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pincode_input_on_enter(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     CodeInput* code_input = app->code_input; | ||||
| 
 | ||||
|     uint32_t state = | ||||
|         scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinCodeInput); | ||||
|     bool update = state != CodeEventsDisablePin; | ||||
| 
 | ||||
|     code_input_set_header_text(code_input, "PIN Code Setup"); | ||||
|     code_input_set_result_callback( | ||||
|         code_input, | ||||
|         desktop_settings_scene_ok_callback, | ||||
|         NULL, | ||||
|         app, | ||||
|         app->settings.pincode.data, | ||||
|         &app->settings.pincode.length, | ||||
|         update); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewPincodeInput); | ||||
| } | ||||
| 
 | ||||
| bool desktop_settings_scene_pincode_input_on_event(void* context, SceneManagerEvent event) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EXIT_EVENT: | ||||
|             scene_manager_previous_scene(app->scene_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_scene_pincode_input_on_exit(void* context) { | ||||
|     DesktopSettingsApp* app = context; | ||||
|     SAVE_DESKTOP_SETTINGS(&app->settings); | ||||
|     code_input_set_result_callback(app->code_input, NULL, NULL, NULL, NULL, NULL, 0); | ||||
|     code_input_set_header_text(app->code_input, ""); | ||||
| } | ||||
| @ -1,11 +1,10 @@ | ||||
| #include <applications.h> | ||||
| 
 | ||||
| #include "../desktop_settings_app.h" | ||||
| #include "applications.h" | ||||
| #include "desktop_settings_scene.h" | ||||
| 
 | ||||
| enum DesktopSettingsStartSubmenuIndex { | ||||
|     DesktopSettingsStartSubmenuIndexFavorite, | ||||
|     DesktopSettingsStartSubmenuIndexPinSetup, | ||||
| }; | ||||
| #define SCENE_EVENT_SELECT_FAVORITE 0 | ||||
| #define SCENE_EVENT_SELECT_PIN_SETUP 1 | ||||
| 
 | ||||
| static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) { | ||||
|     DesktopSettingsApp* app = context; | ||||
| @ -19,14 +18,14 @@ void desktop_settings_scene_start_on_enter(void* context) { | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "Favorite App", | ||||
|         DesktopSettingsStartSubmenuIndexFavorite, | ||||
|         SCENE_EVENT_SELECT_FAVORITE, | ||||
|         desktop_settings_scene_start_submenu_callback, | ||||
|         app); | ||||
| 
 | ||||
|     submenu_add_item( | ||||
|         submenu, | ||||
|         "PIN Setup", | ||||
|         DesktopSettingsStartSubmenuIndexPinSetup, | ||||
|         SCENE_EVENT_SELECT_PIN_SETUP, | ||||
|         desktop_settings_scene_start_submenu_callback, | ||||
|         app); | ||||
| 
 | ||||
| @ -39,12 +38,12 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case DesktopSettingsStartSubmenuIndexFavorite: | ||||
|         case SCENE_EVENT_SELECT_FAVORITE: | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopSettingsStartSubmenuIndexPinSetup: | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeMenu); | ||||
|         case SCENE_EVENT_SELECT_PIN_SETUP: | ||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|  | ||||
| @ -0,0 +1,78 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/elements.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <toolbox/version.h> | ||||
| #include <assets_icons.h> | ||||
| #include <dolphin/helpers/dolphin_state.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #include "desktop_settings_view_pin_setup_howto.h" | ||||
| 
 | ||||
| struct DesktopSettingsViewPinSetupHowto { | ||||
|     View* view; | ||||
|     DesktopSettingsViewPinSetupHowtoDoneCallback callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| static void desktop_settings_view_pin_setup_howto_draw(Canvas* canvas, void* model) { | ||||
|     furi_assert(canvas); | ||||
|     furi_assert(model); | ||||
| 
 | ||||
|     canvas_draw_icon(canvas, 16, 18, &I_Pin_attention_dpad_29x29); | ||||
|     elements_button_right(canvas, "Next"); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Setting up PIN"); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols"); | ||||
| } | ||||
| 
 | ||||
| static bool desktop_settings_view_pin_setup_howto_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     DesktopSettingsViewPinSetupHowto* instance = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if((event->key == InputKeyRight) && (event->type == InputTypeShort)) { | ||||
|         instance->callback(instance->context); | ||||
|         consumed = true; | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto_set_callback( | ||||
|     DesktopSettingsViewPinSetupHowto* instance, | ||||
|     DesktopSettingsViewPinSetupHowtoDoneCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(callback); | ||||
|     instance->callback = callback; | ||||
|     instance->context = context; | ||||
| } | ||||
| 
 | ||||
| DesktopSettingsViewPinSetupHowto* desktop_settings_view_pin_setup_howto_alloc() { | ||||
|     DesktopSettingsViewPinSetupHowto* view = furi_alloc(sizeof(DesktopSettingsViewPinSetupHowto)); | ||||
|     view->view = view_alloc(); | ||||
|     view_allocate_model(view->view, ViewModelTypeLockFree, 1); | ||||
|     view_set_context(view->view, view); | ||||
|     view_set_draw_callback(view->view, desktop_settings_view_pin_setup_howto_draw); | ||||
|     view_set_input_callback(view->view, desktop_settings_view_pin_setup_howto_input); | ||||
| 
 | ||||
|     return view; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto_free(DesktopSettingsViewPinSetupHowto* instance) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     view_free(instance->view); | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| View* desktop_settings_view_pin_setup_howto_get_view(DesktopSettingsViewPinSetupHowto* instance) { | ||||
|     furi_assert(instance); | ||||
|     return instance->view; | ||||
| } | ||||
| @ -0,0 +1,15 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct DesktopSettingsViewPinSetupHowto DesktopSettingsViewPinSetupHowto; | ||||
| 
 | ||||
| typedef void (*DesktopSettingsViewPinSetupHowtoDoneCallback)(void*); | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto_set_callback( | ||||
|     DesktopSettingsViewPinSetupHowto* instance, | ||||
|     DesktopSettingsViewPinSetupHowtoDoneCallback callback, | ||||
|     void* context); | ||||
| DesktopSettingsViewPinSetupHowto* desktop_settings_view_pin_setup_howto_alloc(); | ||||
| void desktop_settings_view_pin_setup_howto_free(DesktopSettingsViewPinSetupHowto* instance); | ||||
| View* desktop_settings_view_pin_setup_howto_get_view(DesktopSettingsViewPinSetupHowto* instance); | ||||
| @ -0,0 +1,101 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/elements.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <toolbox/version.h> | ||||
| #include <assets_icons.h> | ||||
| #include <dolphin/helpers/dolphin_state.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #include "desktop_settings_view_pin_setup_howto2.h" | ||||
| 
 | ||||
| struct DesktopSettingsViewPinSetupHowto2 { | ||||
|     View* view; | ||||
|     DesktopSettingsViewPinSetupHowto2Callback cancel_callback; | ||||
|     DesktopSettingsViewPinSetupHowto2Callback ok_callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| static void desktop_settings_view_pin_setup_howto2_draw(Canvas* canvas, void* model) { | ||||
|     furi_assert(canvas); | ||||
|     furi_assert(model); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     elements_multiline_text_aligned( | ||||
|         canvas, | ||||
|         64, | ||||
|         24, | ||||
|         AlignCenter, | ||||
|         AlignCenter, | ||||
|         "Forgotten PIN can only be\n" | ||||
|         "reset with entire device.\n" | ||||
|         "Read docs How to reset PIN."); | ||||
| 
 | ||||
|     elements_button_right(canvas, "OK"); | ||||
|     elements_button_left(canvas, "Cancel"); | ||||
| } | ||||
| 
 | ||||
| static bool desktop_settings_view_pin_setup_howto2_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     DesktopSettingsViewPinSetupHowto2* instance = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort) { | ||||
|         if(event->key == InputKeyRight) { | ||||
|             instance->ok_callback(instance->context); | ||||
|             consumed = true; | ||||
|         } else if(event->key == InputKeyLeft) { | ||||
|             instance->cancel_callback(instance->context); | ||||
|             consumed = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto2_set_context( | ||||
|     DesktopSettingsViewPinSetupHowto2* instance, | ||||
|     void* context) { | ||||
|     furi_assert(instance); | ||||
|     instance->context = context; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto2_set_cancel_callback( | ||||
|     DesktopSettingsViewPinSetupHowto2* instance, | ||||
|     DesktopSettingsViewPinSetupHowto2Callback callback) { | ||||
|     furi_assert(instance); | ||||
|     instance->cancel_callback = callback; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto2_set_ok_callback( | ||||
|     DesktopSettingsViewPinSetupHowto2* instance, | ||||
|     DesktopSettingsViewPinSetupHowto2Callback callback) { | ||||
|     furi_assert(instance); | ||||
|     instance->ok_callback = callback; | ||||
| } | ||||
| 
 | ||||
| DesktopSettingsViewPinSetupHowto2* desktop_settings_view_pin_setup_howto2_alloc() { | ||||
|     DesktopSettingsViewPinSetupHowto2* view = | ||||
|         furi_alloc(sizeof(DesktopSettingsViewPinSetupHowto2)); | ||||
|     view->view = view_alloc(); | ||||
|     view_allocate_model(view->view, ViewModelTypeLockFree, 1); | ||||
|     view_set_context(view->view, view); | ||||
|     view_set_draw_callback(view->view, desktop_settings_view_pin_setup_howto2_draw); | ||||
|     view_set_input_callback(view->view, desktop_settings_view_pin_setup_howto2_input); | ||||
| 
 | ||||
|     return view; | ||||
| } | ||||
| 
 | ||||
| void desktop_settings_view_pin_setup_howto2_free(DesktopSettingsViewPinSetupHowto2* instance) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     view_free(instance->view); | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| View* desktop_settings_view_pin_setup_howto2_get_view(DesktopSettingsViewPinSetupHowto2* instance) { | ||||
|     furi_assert(instance); | ||||
|     return instance->view; | ||||
| } | ||||
| @ -0,0 +1,20 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct DesktopSettingsViewPinSetupHowto2 DesktopSettingsViewPinSetupHowto2; | ||||
| 
 | ||||
| typedef void (*DesktopSettingsViewPinSetupHowto2Callback)(void*); | ||||
| 
 | ||||
| DesktopSettingsViewPinSetupHowto2* desktop_settings_view_pin_setup_howto2_alloc(); | ||||
| void desktop_settings_view_pin_setup_howto2_free(DesktopSettingsViewPinSetupHowto2* instance); | ||||
| View* desktop_settings_view_pin_setup_howto2_get_view(DesktopSettingsViewPinSetupHowto2* instance); | ||||
| void desktop_settings_view_pin_setup_howto2_set_context( | ||||
|     DesktopSettingsViewPinSetupHowto2* instance, | ||||
|     void* context); | ||||
| void desktop_settings_view_pin_setup_howto2_set_cancel_callback( | ||||
|     DesktopSettingsViewPinSetupHowto2* instance, | ||||
|     DesktopSettingsViewPinSetupHowto2Callback callback); | ||||
| void desktop_settings_view_pin_setup_howto2_set_ok_callback( | ||||
|     DesktopSettingsViewPinSetupHowto2* instance, | ||||
|     DesktopSettingsViewPinSetupHowto2Callback callback); | ||||
| @ -3,5 +3,7 @@ ADD_SCENE(desktop, lock_menu, LockMenu) | ||||
| ADD_SCENE(desktop, debug, Debug) | ||||
| ADD_SCENE(desktop, first_start, FirstStart) | ||||
| ADD_SCENE(desktop, hw_mismatch, HwMismatch) | ||||
| ADD_SCENE(desktop, pinsetup, PinSetup) | ||||
| ADD_SCENE(desktop, fault, Fault) | ||||
| ADD_SCENE(desktop, locked, Locked) | ||||
| ADD_SCENE(desktop, pin_input, PinInput) | ||||
| ADD_SCENE(desktop, pin_timeout, PinTimeout) | ||||
|  | ||||
| @ -3,7 +3,7 @@ | ||||
| #include <dolphin/helpers/dolphin_deed.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "../views/desktop_debug.h" | ||||
| #include "../views/desktop_view_debug.h" | ||||
| #include "desktop_scene.h" | ||||
| 
 | ||||
| void desktop_scene_debug_callback(DesktopEvent event, void* context) { | ||||
| @ -17,7 +17,7 @@ void desktop_scene_debug_on_enter(void* context) { | ||||
|     desktop_debug_get_dolphin_data(desktop->debug_view); | ||||
| 
 | ||||
|     desktop_debug_set_callback(desktop->debug_view, desktop_scene_debug_callback, desktop); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewDebug); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdDebug); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { | ||||
|  | ||||
| @ -25,7 +25,7 @@ void desktop_scene_fault_on_enter(void* context) { | ||||
|     char* message = (char*)furi_hal_rtc_get_fault_data(); | ||||
|     popup_set_text(popup, message, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); | ||||
|     popup_set_callback(popup, desktop_scene_fault_callback); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_fault_on_event(void* context, SceneManagerEvent event) { | ||||
|  | ||||
| @ -2,7 +2,7 @@ | ||||
| #include <storage/storage.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "../views/desktop_first_start.h" | ||||
| #include "../views/desktop_view_first_start.h" | ||||
| #include "../views/desktop_events.h" | ||||
| 
 | ||||
| void desktop_scene_first_start_callback(DesktopEvent event, void* context) { | ||||
| @ -17,7 +17,7 @@ void desktop_scene_first_start_on_enter(void* context) { | ||||
|     desktop_first_start_set_callback( | ||||
|         first_start_view, desktop_scene_first_start_callback, desktop); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewFirstStart); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdFirstStart); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_first_start_on_event(void* context, SceneManagerEvent event) { | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| #include <gui/scene_manager.h> | ||||
| #include <furi_hal_version.h> | ||||
| #include <furi_hal.h> | ||||
| 
 | ||||
| #include "desktop_scene.h" | ||||
| #include "../desktop_i.h" | ||||
| @ -31,7 +31,7 @@ void desktop_scene_hw_mismatch_on_enter(void* context) { | ||||
|         popup, "!!!! HW Mismatch !!!!", 60, 14 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); | ||||
|     popup_set_text(popup, text_buffer, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); | ||||
|     popup_set_callback(popup, desktop_scene_hw_mismatch_callback); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event) { | ||||
|  | ||||
| @ -1,7 +1,4 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| typedef enum { | ||||
|     DesktopMainSceneStateUnlocked, | ||||
|     DesktopMainSceneStateLockedWithPin, | ||||
|     DesktopMainSceneStateLockedNoPin, | ||||
| } DesktopMainSceneState; | ||||
| #define SCENE_LOCKED_FIRST_ENTER 0 | ||||
| #define SCENE_LOCKED_REPEAT_ENTER 1 | ||||
|  | ||||
| @ -1,8 +1,13 @@ | ||||
| #include <gui/scene_manager.h> | ||||
| #include <applications.h> | ||||
| #include <furi_hal.h> | ||||
| #include <toolbox/saved_struct.h> | ||||
| #include <stdbool.h> | ||||
| #include <loader/loader.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "../views/desktop_lock_menu.h" | ||||
| #include "../desktop_settings/desktop_settings.h" | ||||
| #include "../views/desktop_view_lock_menu.h" | ||||
| #include "desktop_scene_i.h" | ||||
| #include "desktop_scene.h" | ||||
| 
 | ||||
| @ -15,36 +20,50 @@ void desktop_scene_lock_menu_on_enter(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
| 
 | ||||
|     LOAD_DESKTOP_SETTINGS(&desktop->settings); | ||||
| 
 | ||||
|     scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); | ||||
|     desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); | ||||
|     desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pincode.length > 0); | ||||
|     desktop_lock_menu_pin_set(desktop->lock_menu, desktop->settings.pin_code.length > 0); | ||||
|     desktop_lock_menu_set_idx(desktop->lock_menu, 0); | ||||
| 
 | ||||
|     uint8_t idx = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); | ||||
|     desktop_lock_menu_set_idx(desktop->lock_menu, idx); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLockMenu); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|     if(event.type == SceneManagerEventTypeTick) { | ||||
|         bool check_pin_changed = | ||||
|             scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLockMenu); | ||||
|         if(check_pin_changed) { | ||||
|             LOAD_DESKTOP_SETTINGS(&desktop->settings); | ||||
|             if(desktop->settings.pin_code.length > 0) { | ||||
|                 desktop_lock_menu_pin_set(desktop->lock_menu, 1); | ||||
|                 scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); | ||||
|             } | ||||
|         } | ||||
|     } else if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case DesktopLockMenuEventLock: | ||||
|             scene_manager_set_scene_state( | ||||
|                 desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedNoPin); | ||||
|             scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); | ||||
|             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||
|             scene_manager_set_scene_state( | ||||
|                 desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); | ||||
|             scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopLockMenuEventPinLock: | ||||
|             if(desktop->settings.pincode.length > 0) { | ||||
|             if(desktop->settings.pin_code.length > 0) { | ||||
|                 furi_hal_rtc_set_flag(FuriHalRtcFlagLock); | ||||
|                 scene_manager_set_scene_state( | ||||
|                     desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin); | ||||
|                 scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||
|                     desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); | ||||
|                 scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); | ||||
|             } else { | ||||
|                 scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); | ||||
|                 scene_manager_next_scene(desktop->scene_manager, DesktopScenePinSetup); | ||||
|                 Loader* loader = furi_record_open("loader"); | ||||
|                 LoaderStatus status = | ||||
|                     loader_start(loader, "Desktop", DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG); | ||||
|                 furi_check(status == LoaderStatusOk); | ||||
|                 furi_record_close("loader"); | ||||
|             } | ||||
| 
 | ||||
|             consumed = true; | ||||
|  | ||||
							
								
								
									
										109
									
								
								applications/desktop/scenes/desktop_scene_locked.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,109 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/view_stack.h> | ||||
| #include <stdint.h> | ||||
| #include <portmacro.h> | ||||
| 
 | ||||
| #include "../desktop.h" | ||||
| #include "../desktop_i.h" | ||||
| #include "../desktop_helpers.h" | ||||
| #include "../animations/animation_manager.h" | ||||
| #include "../views/desktop_events.h" | ||||
| #include "../views/desktop_view_pin_input.h" | ||||
| #include "../views/desktop_view_locked.h" | ||||
| #include "desktop_scene.h" | ||||
| #include "desktop_scene_i.h" | ||||
| 
 | ||||
| #define WRONG_PIN_HEADER_TIMEOUT 3000 | ||||
| #define INPUT_PIN_VIEW_TIMEOUT 15000 | ||||
| 
 | ||||
| static void desktop_scene_locked_callback(DesktopEvent event, void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||
| } | ||||
| 
 | ||||
| static void desktop_scene_locked_new_idle_animation_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = context; | ||||
|     view_dispatcher_send_custom_event( | ||||
|         desktop->view_dispatcher, DesktopAnimationEventNewIdleAnimation); | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_locked_on_enter(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
| 
 | ||||
|     // callbacks for 1-st layer
 | ||||
|     animation_manager_set_new_idle_callback( | ||||
|         desktop->animation_manager, desktop_scene_locked_new_idle_animation_callback); | ||||
|     animation_manager_set_check_callback(desktop->animation_manager, NULL); | ||||
|     animation_manager_set_interact_callback(desktop->animation_manager, NULL); | ||||
| 
 | ||||
|     // callbacks for 2-nd layer
 | ||||
|     desktop_view_locked_set_callback(desktop->locked_view, desktop_scene_locked_callback, desktop); | ||||
| 
 | ||||
|     bool switch_to_timeout_scene = false; | ||||
|     uint32_t state = scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneLocked); | ||||
|     if(state == SCENE_LOCKED_FIRST_ENTER) { | ||||
|         bool pin_locked = furi_hal_rtc_is_flag_set(FuriHalRtcFlagLock); | ||||
|         desktop_helpers_lock_system(desktop, pin_locked); | ||||
|         if(pin_locked) { | ||||
|             LOAD_DESKTOP_SETTINGS(&desktop->settings); | ||||
|             desktop_view_locked_lock(desktop->locked_view, true); | ||||
|             uint32_t pin_fails = furi_hal_rtc_get_pin_fails(); | ||||
|             uint32_t pin_timeout = desktop_helpers_get_pin_fail_timeout(pin_fails); | ||||
|             if(pin_timeout) { | ||||
|                 scene_manager_set_scene_state( | ||||
|                     desktop->scene_manager, DesktopScenePinTimeout, pin_timeout); | ||||
|                 switch_to_timeout_scene = true; | ||||
|             } else { | ||||
|                 desktop_view_locked_close_doors(desktop->locked_view); | ||||
|             } | ||||
|         } else { | ||||
|             desktop_view_locked_lock(desktop->locked_view, false); | ||||
|             desktop_view_locked_close_doors(desktop->locked_view); | ||||
|         } | ||||
|         scene_manager_set_scene_state( | ||||
|             desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_REPEAT_ENTER); | ||||
|     } | ||||
| 
 | ||||
|     if(switch_to_timeout_scene) { | ||||
|         scene_manager_next_scene(desktop->scene_manager, DesktopScenePinTimeout); | ||||
|     } else { | ||||
|         view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLocked); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case DesktopLockedEventUnlocked: | ||||
|             furi_hal_rtc_set_pin_fails(0); | ||||
|             desktop_helpers_unlock_system(desktop); | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopLockedEventUpdate: | ||||
|             desktop_view_locked_update(desktop->locked_view); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopLockedEventShowPinInput: | ||||
|             scene_manager_next_scene(desktop->scene_manager, DesktopScenePinInput); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopAnimationEventNewIdleAnimation: | ||||
|             animation_manager_new_idle_process(desktop->animation_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_locked_on_exit(void* context) { | ||||
| } | ||||
| @ -4,15 +4,14 @@ | ||||
| #include <assets_icons.h> | ||||
| #include <loader/loader.h> | ||||
| 
 | ||||
| #include "desktop/desktop_i.h" | ||||
| #include "desktop/views/desktop_main.h" | ||||
| #include "../desktop_i.h" | ||||
| #include "../views/desktop_events.h" | ||||
| #include "../views/desktop_view_main.h" | ||||
| #include "desktop_scene.h" | ||||
| #include "desktop_scene_i.h" | ||||
| 
 | ||||
| #define TAG "DesktopSrv" | ||||
| 
 | ||||
| #define MAIN_VIEW_DEFAULT (0UL) | ||||
| 
 | ||||
| static void desktop_scene_main_app_started_callback(const void* message, void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = context; | ||||
| @ -31,19 +30,22 @@ static void desktop_scene_main_app_started_callback(const void* message, void* c | ||||
| static void desktop_scene_main_new_idle_animation_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = context; | ||||
|     view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopMainEventNewIdleAnimation); | ||||
|     view_dispatcher_send_custom_event( | ||||
|         desktop->view_dispatcher, DesktopAnimationEventNewIdleAnimation); | ||||
| } | ||||
| 
 | ||||
| static void desktop_scene_main_check_animation_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = context; | ||||
|     view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopMainEventCheckAnimation); | ||||
|     view_dispatcher_send_custom_event( | ||||
|         desktop->view_dispatcher, DesktopAnimationEventCheckAnimation); | ||||
| } | ||||
| 
 | ||||
| static void desktop_scene_main_interact_animation_callback(void* context) { | ||||
|     furi_assert(context); | ||||
|     Desktop* desktop = context; | ||||
|     view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopMainEventInteractAnimation); | ||||
|     view_dispatcher_send_custom_event( | ||||
|         desktop->view_dispatcher, DesktopAnimationEventInteractAnimation); | ||||
| } | ||||
| 
 | ||||
| static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) { | ||||
| @ -80,7 +82,6 @@ void desktop_scene_main_on_enter(void* context) { | ||||
|         desktop->animation_manager, desktop_scene_main_check_animation_callback); | ||||
|     animation_manager_set_interact_callback( | ||||
|         desktop->animation_manager, desktop_scene_main_interact_animation_callback); | ||||
|     desktop_locked_set_callback(desktop->locked_view, desktop_scene_main_callback, desktop); | ||||
| 
 | ||||
|     furi_assert(osSemaphoreGetCount(desktop->unload_animation_semaphore) == 0); | ||||
|     Loader* loader = furi_record_open("loader"); | ||||
| @ -90,24 +91,7 @@ void desktop_scene_main_on_enter(void* context) { | ||||
| 
 | ||||
|     desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop); | ||||
| 
 | ||||
|     DesktopMainSceneState state = | ||||
|         scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneMain); | ||||
|     if(state == DesktopMainSceneStateLockedNoPin) { | ||||
|         desktop_locked_lock(desktop->locked_view); | ||||
|         view_port_enabled_set(desktop->lock_viewport, true); | ||||
|     } else if(state == DesktopMainSceneStateLockedWithPin) { | ||||
|         LOAD_DESKTOP_SETTINGS(&desktop->settings); | ||||
|         furi_assert(desktop->settings.pincode.length > 0); | ||||
|         desktop_locked_lock_pincode(desktop->locked_view, desktop->settings.pincode); | ||||
|         view_port_enabled_set(desktop->lock_viewport, true); | ||||
|         furi_hal_rtc_set_flag(FuriHalRtcFlagLock); | ||||
|         furi_hal_usb_disable(); | ||||
|     } else { | ||||
|         furi_assert(state == DesktopMainSceneStateUnlocked); | ||||
|         view_port_enabled_set(desktop->lock_viewport, false); | ||||
|     } | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewMain); | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdMain); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | ||||
| @ -154,15 +138,15 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
|         case DesktopMainEventCheckAnimation: | ||||
|         case DesktopAnimationEventCheckAnimation: | ||||
|             animation_manager_check_blocking_process(desktop->animation_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopMainEventNewIdleAnimation: | ||||
|         case DesktopAnimationEventNewIdleAnimation: | ||||
|             animation_manager_new_idle_process(desktop->animation_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopMainEventInteractAnimation: | ||||
|         case DesktopAnimationEventInteractAnimation: | ||||
|             animation_manager_interact_process(desktop->animation_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
| @ -175,16 +159,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | ||||
|             animation_manager_load_and_continue_animation(desktop->animation_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopMainEventUnlocked: | ||||
|             consumed = true; | ||||
|             furi_hal_rtc_reset_flag(FuriHalRtcFlagLock); | ||||
|             furi_hal_usb_enable(); | ||||
|             view_port_enabled_set(desktop->lock_viewport, false); | ||||
|             scene_manager_set_scene_state( | ||||
|                 desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateUnlocked); | ||||
|             break; | ||||
|         case DesktopMainEventUpdate: | ||||
|             desktop_locked_update(desktop->locked_view); | ||||
|         case DesktopLockedEventUpdate: | ||||
|             desktop_view_locked_update(desktop->locked_view); | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
| @ -213,5 +189,4 @@ void desktop_scene_main_on_exit(void* context) { | ||||
|     animation_manager_set_check_callback(desktop->animation_manager, NULL); | ||||
|     animation_manager_set_interact_callback(desktop->animation_manager, NULL); | ||||
|     animation_manager_set_context(desktop->animation_manager, desktop); | ||||
|     scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneMain, MAIN_VIEW_DEFAULT); | ||||
| } | ||||
|  | ||||
							
								
								
									
										162
									
								
								applications/desktop/scenes/desktop_scene_pin_input.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,162 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/scene_manager.h> | ||||
| #include <gui/view_stack.h> | ||||
| #include <stdint.h> | ||||
| #include <portmacro.h> | ||||
| #include <notification/notification.h> | ||||
| #include <notification/notification_messages.h> | ||||
| 
 | ||||
| #include "../desktop.h" | ||||
| #include "../desktop_i.h" | ||||
| #include "../animations/animation_manager.h" | ||||
| #include "../views/desktop_events.h" | ||||
| #include "../views/desktop_view_pin_input.h" | ||||
| #include "../desktop_helpers.h" | ||||
| #include "desktop_scene.h" | ||||
| #include "desktop_scene_i.h" | ||||
| 
 | ||||
| #define WRONG_PIN_HEADER_TIMEOUT 3000 | ||||
| #define INPUT_PIN_VIEW_TIMEOUT 15000 | ||||
| 
 | ||||
| typedef struct { | ||||
|     TimerHandle_t timer; | ||||
| } DesktopScenePinInputState; | ||||
| 
 | ||||
| static void desktop_scene_locked_light_red(bool value) { | ||||
|     NotificationApp* app = furi_record_open("notification"); | ||||
|     if(value) { | ||||
|         notification_message(app, &sequence_set_only_red_255); | ||||
|     } else { | ||||
|         notification_message(app, &sequence_reset_red); | ||||
|     } | ||||
|     furi_record_close("notification"); | ||||
| } | ||||
| 
 | ||||
| static void | ||||
|     desktop_scene_pin_input_set_timer(Desktop* desktop, bool enable, TickType_t new_period) { | ||||
|     furi_assert(desktop); | ||||
| 
 | ||||
|     DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state( | ||||
|         desktop->scene_manager, DesktopScenePinInput); | ||||
|     furi_assert(state); | ||||
|     if(enable) { | ||||
|         xTimerChangePeriod(state->timer, new_period, portMAX_DELAY); | ||||
|     } else { | ||||
|         xTimerStop(state->timer, portMAX_DELAY); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void desktop_scene_pin_input_back_callback(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventBack); | ||||
| } | ||||
| 
 | ||||
| static void desktop_scene_pin_input_done_callback(const PinCode* pin_code, void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     if(pins_are_equal(&desktop->settings.pin_code, pin_code)) { | ||||
|         view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinInputEventUnlocked); | ||||
|     } else { | ||||
|         view_dispatcher_send_custom_event( | ||||
|             desktop->view_dispatcher, DesktopPinInputEventUnlockFailed); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void desktop_scene_pin_input_timer_callback(TimerHandle_t timer) { | ||||
|     Desktop* desktop = pvTimerGetTimerID(timer); | ||||
| 
 | ||||
|     view_dispatcher_send_custom_event( | ||||
|         desktop->view_dispatcher, DesktopPinInputEventResetWrongPinLabel); | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_pin_input_on_enter(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
| 
 | ||||
|     desktop_view_pin_input_set_context(desktop->pin_input_view, desktop); | ||||
|     desktop_view_pin_input_set_back_callback( | ||||
|         desktop->pin_input_view, desktop_scene_pin_input_back_callback); | ||||
|     desktop_view_pin_input_set_timeout_callback( | ||||
|         desktop->pin_input_view, desktop_scene_pin_input_back_callback); | ||||
|     desktop_view_pin_input_set_done_callback( | ||||
|         desktop->pin_input_view, desktop_scene_pin_input_done_callback); | ||||
| 
 | ||||
|     DesktopScenePinInputState* state = furi_alloc(sizeof(DesktopScenePinInputState)); | ||||
|     state->timer = | ||||
|         xTimerCreate(NULL, 10000, pdFALSE, desktop, desktop_scene_pin_input_timer_callback); | ||||
|     scene_manager_set_scene_state(desktop->scene_manager, DesktopScenePinInput, (uint32_t)state); | ||||
| 
 | ||||
|     desktop_view_pin_input_hide_pin(desktop->pin_input_view, true); | ||||
|     desktop_view_pin_input_set_label_button(desktop->pin_input_view, "OK"); | ||||
|     desktop_view_pin_input_set_label_secondary(desktop->pin_input_view, 44, 25, "Enter PIN:"); | ||||
|     desktop_view_pin_input_set_pin_position(desktop->pin_input_view, 64, 37); | ||||
|     desktop_view_pin_input_reset_pin(desktop->pin_input_view); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdPinInput); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_pin_input_on_event(void* context, SceneManagerEvent event) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     bool consumed = false; | ||||
|     uint32_t pin_fails = 0; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case DesktopPinInputEventUnlockFailed: | ||||
|             pin_fails = furi_hal_rtc_get_pin_fails(); | ||||
|             pin_fails++; | ||||
|             furi_hal_rtc_set_pin_fails(pin_fails); | ||||
|             uint32_t pin_timeout = desktop_helpers_get_pin_fail_timeout(pin_fails); | ||||
|             if(pin_timeout > 0) { | ||||
|                 desktop_helpers_emit_error_notification(); | ||||
|                 scene_manager_set_scene_state( | ||||
|                     desktop->scene_manager, DesktopScenePinTimeout, pin_timeout); | ||||
|                 scene_manager_next_scene(desktop->scene_manager, DesktopScenePinTimeout); | ||||
|             } else { | ||||
|                 desktop_scene_locked_light_red(true); | ||||
|                 desktop_view_pin_input_set_label_primary(desktop->pin_input_view, 0, 0, NULL); | ||||
|                 desktop_view_pin_input_set_label_secondary( | ||||
|                     desktop->pin_input_view, 25, 25, "Wrong PIN try again:"); | ||||
|                 desktop_scene_pin_input_set_timer(desktop, true, WRONG_PIN_HEADER_TIMEOUT); | ||||
|                 desktop_view_pin_input_reset_pin(desktop->pin_input_view); | ||||
|             } | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopPinInputEventResetWrongPinLabel: | ||||
|             desktop_scene_locked_light_red(false); | ||||
|             desktop_view_pin_input_set_label_primary(desktop->pin_input_view, 0, 0, NULL); | ||||
|             desktop_view_pin_input_set_label_secondary( | ||||
|                 desktop->pin_input_view, 44, 25, "Enter PIN:"); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopPinInputEventUnlocked: | ||||
|             desktop_view_locked_unlock(desktop->locked_view); | ||||
|             furi_hal_rtc_set_pin_fails(0); | ||||
|             desktop_helpers_unlock_system(desktop); | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneMain); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         case DesktopPinInputEventBack: | ||||
|             scene_manager_search_and_switch_to_previous_scene( | ||||
|                 desktop->scene_manager, DesktopSceneLocked); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_pin_input_on_exit(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     desktop_scene_locked_light_red(false); | ||||
| 
 | ||||
|     DesktopScenePinInputState* state = (DesktopScenePinInputState*)scene_manager_get_scene_state( | ||||
|         desktop->scene_manager, DesktopScenePinInput); | ||||
|     xTimerStop(state->timer, portMAX_DELAY); | ||||
|     while(xTimerIsTimerActive(state->timer)) { | ||||
|         delay(1); | ||||
|     } | ||||
|     xTimerDelete(state->timer, portMAX_DELAY); | ||||
|     free(state); | ||||
| } | ||||
							
								
								
									
										46
									
								
								applications/desktop/scenes/desktop_scene_pin_timeout.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,46 @@ | ||||
| #include <furi.h> | ||||
| #include <FreeRTOS.h> | ||||
| #include <portmacro.h> | ||||
| #include <timer.h> | ||||
| #include <gui/scene_manager.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "../views/desktop_view_pin_timeout.h" | ||||
| #include "desktop_scene.h" | ||||
| #include "desktop_scene_i.h" | ||||
| 
 | ||||
| static void desktop_scene_pin_timeout_callback(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     view_dispatcher_send_custom_event(desktop->view_dispatcher, DesktopPinTimeoutExit); | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_pin_timeout_on_enter(void* context) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
| 
 | ||||
|     uint32_t timeout = | ||||
|         scene_manager_get_scene_state(desktop->scene_manager, DesktopScenePinTimeout); | ||||
|     desktop_view_pin_timeout_start(desktop->pin_timeout_view, timeout); | ||||
|     desktop_view_pin_timeout_set_callback( | ||||
|         desktop->pin_timeout_view, desktop_scene_pin_timeout_callback, desktop); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_pin_timeout_on_event(void* context, SceneManagerEvent event) { | ||||
|     Desktop* desktop = (Desktop*)context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case DesktopPinTimeoutExit: | ||||
|             scene_manager_previous_scene(desktop->scene_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_pin_timeout_on_exit(void* context) { | ||||
| } | ||||
| @ -1,50 +0,0 @@ | ||||
| #include "../desktop_i.h" | ||||
| 
 | ||||
| #define SCENE_EXIT_EVENT (0U) | ||||
| 
 | ||||
| void desktop_scene_ok_callback(void* context) { | ||||
|     Desktop* app = context; | ||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT); | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_pinsetup_on_enter(void* context) { | ||||
|     Desktop* app = context; | ||||
|     CodeInput* code_input = app->code_input; | ||||
| 
 | ||||
|     code_input_set_result_callback( | ||||
|         code_input, | ||||
|         desktop_scene_ok_callback, | ||||
|         NULL, | ||||
|         app, | ||||
|         app->settings.pincode.data, | ||||
|         &app->settings.pincode.length, | ||||
|         true); | ||||
| 
 | ||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopViewPinSetup); | ||||
| } | ||||
| 
 | ||||
| bool desktop_scene_pinsetup_on_event(void* context, SceneManagerEvent event) { | ||||
|     Desktop* app = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event.type == SceneManagerEventTypeCustom) { | ||||
|         switch(event.event) { | ||||
|         case SCENE_EXIT_EVENT: | ||||
|             scene_manager_previous_scene(app->scene_manager); | ||||
|             consumed = true; | ||||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_scene_pinsetup_on_exit(void* context) { | ||||
|     Desktop* app = context; | ||||
|     SAVE_DESKTOP_SETTINGS(&app->settings); | ||||
|     code_input_set_result_callback(app->code_input, NULL, NULL, NULL, NULL, NULL, 0); | ||||
|     code_input_set_header_text(app->code_input, ""); | ||||
| } | ||||
| @ -6,24 +6,35 @@ typedef enum { | ||||
|     DesktopMainEventOpenFavorite, | ||||
|     DesktopMainEventOpenMenu, | ||||
|     DesktopMainEventOpenDebug, | ||||
|     DesktopMainEventUpdate, | ||||
|     DesktopMainEventUnlocked, | ||||
|     DesktopMainEventRightShort, | ||||
|     DesktopMainEventCheckAnimation, | ||||
|     DesktopMainEventNewIdleAnimation, | ||||
|     DesktopMainEventInteractAnimation, | ||||
|     DesktopMainEventBeforeAppStarted, | ||||
|     DesktopMainEventAfterAppFinished, | ||||
|     DesktopLockedEventUnlock, | ||||
|     DesktopLockedEventCheckAnimation, | ||||
|     DesktopLockedEventMax, | ||||
| 
 | ||||
|     DesktopLockedEventUnlocked, | ||||
|     DesktopLockedEventUpdate, | ||||
|     DesktopLockedEventShowPinInput, | ||||
| 
 | ||||
|     DesktopPinInputEventResetWrongPinLabel, | ||||
|     DesktopPinInputEventUnlocked, | ||||
|     DesktopPinInputEventUnlockFailed, | ||||
|     DesktopPinInputEventBack, | ||||
| 
 | ||||
|     DesktopPinTimeoutExit, | ||||
| 
 | ||||
|     DesktopDebugEventDeed, | ||||
|     DesktopDebugEventWrongDeed, | ||||
|     DesktopDebugEventSaveState, | ||||
|     DesktopDebugEventExit, | ||||
| 
 | ||||
|     DesktopFirstStartCompleted, | ||||
|     DesktopFirstStartPoweroff, | ||||
| 
 | ||||
|     DesktopLockMenuEventLock, | ||||
|     DesktopLockMenuEventPinLock, | ||||
|     DesktopLockMenuEventExit, | ||||
| 
 | ||||
|     DesktopAnimationEventCheckAnimation, | ||||
|     DesktopAnimationEventNewIdleAnimation, | ||||
|     DesktopAnimationEventInteractAnimation, | ||||
| 
 | ||||
| } DesktopEvent; | ||||
|  | ||||
| @ -1,247 +0,0 @@ | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| #include "furi/check.h" | ||||
| #include "gui/view.h" | ||||
| #include "portmacro.h" | ||||
| #include <furi.h> | ||||
| #include <gui/gui_i.h> | ||||
| #include <gui/elements.h> | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_locked.h" | ||||
| #include <stdint.h> | ||||
| 
 | ||||
| #define DOOR_MOVING_INTERVAL_MS (1000 / 16) | ||||
| #define UNLOCKED_HINT_TIMEOUT_MS (2000) | ||||
| 
 | ||||
| struct DesktopLockedView { | ||||
|     View* view; | ||||
|     DesktopLockedViewCallback callback; | ||||
|     void* context; | ||||
| 
 | ||||
|     TimerHandle_t timer; | ||||
|     uint8_t lock_count; | ||||
|     uint32_t lock_lastpress; | ||||
| 
 | ||||
|     PinCode pincode; | ||||
|     PinCode pincode_input; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t hint_icon_expire_at; | ||||
|     bool unlocked_hint; | ||||
|     bool locked; | ||||
|     bool pin_locked; | ||||
| 
 | ||||
|     int8_t door_left_x; | ||||
|     int8_t door_right_x; | ||||
|     bool animation_seq_end; | ||||
| } DesktopLockedViewModel; | ||||
| 
 | ||||
| static void desktop_locked_unlock(DesktopLockedView* locked_view); | ||||
| 
 | ||||
| void desktop_locked_set_callback( | ||||
|     DesktopLockedView* locked_view, | ||||
|     DesktopLockedViewCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(locked_view); | ||||
|     furi_assert(callback); | ||||
|     locked_view->callback = callback; | ||||
|     locked_view->context = context; | ||||
| } | ||||
| 
 | ||||
| void locked_view_timer_callback(TimerHandle_t timer) { | ||||
|     DesktopLockedView* locked_view = pvTimerGetTimerID(timer); | ||||
|     locked_view->callback(DesktopMainEventUpdate, locked_view->context); | ||||
| } | ||||
| 
 | ||||
| static void desktop_locked_update_hint_icon_timeout(DesktopLockedView* locked_view) { | ||||
|     DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|     model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq(); | ||||
|     view_commit_model(locked_view->view, true); | ||||
| } | ||||
| 
 | ||||
| static void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) { | ||||
|     DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|     model->animation_seq_end = false; | ||||
|     model->door_left_x = DOOR_L_POS; | ||||
|     model->door_right_x = DOOR_R_POS; | ||||
|     view_commit_model(locked_view->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_locked_update(DesktopLockedView* locked_view) { | ||||
|     bool stop_timer = false; | ||||
| 
 | ||||
|     DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|     if(model->locked) { | ||||
|         if(model->door_left_x != DOOR_L_POS_MAX) { | ||||
|             model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS); | ||||
|             model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN); | ||||
|         } else { | ||||
|             model->animation_seq_end = true; | ||||
|         } | ||||
|         stop_timer = model->animation_seq_end; | ||||
|     } else { | ||||
|         model->unlocked_hint = false; | ||||
|         stop_timer = true; | ||||
|     } | ||||
|     view_commit_model(locked_view->view, true); | ||||
| 
 | ||||
|     if(stop_timer) { | ||||
|         xTimerStop(locked_view->timer, portMAX_DELAY); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void desktop_locked_draw(Canvas* canvas, void* model) { | ||||
|     DesktopLockedViewModel* m = model; | ||||
|     uint32_t now = osKernelGetTickCount(); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
| 
 | ||||
|     if(m->locked) { | ||||
|         if(!m->animation_seq_end) { | ||||
|             canvas_draw_icon(canvas, m->door_left_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55); | ||||
|             canvas_draw_icon(canvas, m->door_right_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55); | ||||
|             canvas_set_font(canvas, FontPrimary); | ||||
|             elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked"); | ||||
|         } else if((now < m->hint_icon_expire_at) && !m->pin_locked) { | ||||
|             canvas_set_font(canvas, FontSecondary); | ||||
|             canvas_draw_icon(canvas, 13, 2 + STATUS_BAR_Y_SHIFT, &I_LockPopup_100x49); | ||||
|             elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:"); | ||||
|         } | ||||
|     } else { | ||||
|         if(m->unlocked_hint) { | ||||
|             canvas_set_font(canvas, FontPrimary); | ||||
|             elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| View* desktop_locked_get_view(DesktopLockedView* locked_view) { | ||||
|     furi_assert(locked_view); | ||||
|     return locked_view->view; | ||||
| } | ||||
| 
 | ||||
| bool desktop_locked_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     DesktopLockedView* locked_view = context; | ||||
|     bool locked = false; | ||||
|     bool locked_with_pin = false; | ||||
|     uint32_t press_time = xTaskGetTickCount(); | ||||
| 
 | ||||
|     { | ||||
|         DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|         bool changed = false; | ||||
|         locked = model->locked; | ||||
|         locked_with_pin = model->pin_locked; | ||||
|         if(!locked && model->unlocked_hint && event->type == InputTypePress) { | ||||
|             model->unlocked_hint = false; | ||||
|             changed = true; | ||||
|         } | ||||
|         view_commit_model(locked_view->view, changed); | ||||
|     } | ||||
| 
 | ||||
|     if(!locked || (event->type != InputTypeShort)) { | ||||
|         return locked; | ||||
|     } | ||||
| 
 | ||||
|     if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { | ||||
|         locked_view->lock_lastpress = press_time; | ||||
|         locked_view->lock_count = 0; | ||||
|         locked_view->pincode_input.length = 0; | ||||
|     } | ||||
| 
 | ||||
|     if(locked_with_pin) { | ||||
|         locked_view->pincode_input.length = code_input_push( | ||||
|             locked_view->pincode_input.data, locked_view->pincode_input.length, event->key); | ||||
|         bool match = code_input_compare( | ||||
|             locked_view->pincode_input.data, | ||||
|             locked_view->pincode_input.length, | ||||
|             locked_view->pincode.data, | ||||
|             locked_view->pincode.length); | ||||
| 
 | ||||
|         if(match) { | ||||
|             desktop_locked_unlock(locked_view); | ||||
|         } | ||||
|     } else { | ||||
|         if(event->key == InputKeyBack) { | ||||
|             locked_view->lock_lastpress = press_time; | ||||
|             locked_view->lock_count++; | ||||
|             if(locked_view->lock_count == UNLOCK_CNT) { | ||||
|                 desktop_locked_unlock(locked_view); | ||||
|             } | ||||
|         } else { | ||||
|             desktop_locked_update_hint_icon_timeout(locked_view); | ||||
|             locked_view->lock_count = 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     locked_view->lock_lastpress = press_time; | ||||
| 
 | ||||
|     return locked; | ||||
| } | ||||
| 
 | ||||
| DesktopLockedView* desktop_locked_alloc() { | ||||
|     DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView)); | ||||
|     locked_view->view = view_alloc(); | ||||
|     locked_view->timer = | ||||
|         xTimerCreate("Locked view", 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback); | ||||
| 
 | ||||
|     view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopLockedViewModel)); | ||||
|     view_set_context(locked_view->view, locked_view); | ||||
|     view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_draw); | ||||
|     view_set_input_callback(locked_view->view, desktop_locked_input); | ||||
| 
 | ||||
|     return locked_view; | ||||
| } | ||||
| 
 | ||||
| void desktop_locked_free(DesktopLockedView* locked_view) { | ||||
|     furi_assert(locked_view); | ||||
|     osTimerDelete(locked_view->timer); | ||||
|     view_free(locked_view->view); | ||||
|     free(locked_view); | ||||
| } | ||||
| 
 | ||||
| void desktop_locked_lock(DesktopLockedView* locked_view) { | ||||
|     locked_view->pincode.length = 0; | ||||
|     DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|     model->locked = true; | ||||
|     model->pin_locked = false; | ||||
|     view_commit_model(locked_view->view, true); | ||||
|     desktop_locked_reset_door_pos(locked_view); | ||||
|     xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY); | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_set_lockdown(gui, true); | ||||
|     furi_record_close("gui"); | ||||
| } | ||||
| 
 | ||||
| void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode) { | ||||
|     locked_view->pincode = pincode; | ||||
|     locked_view->pincode_input.length = 0; | ||||
|     DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|     model->locked = true; | ||||
|     model->pin_locked = true; | ||||
|     view_commit_model(locked_view->view, true); | ||||
|     desktop_locked_reset_door_pos(locked_view); | ||||
|     xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY); | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_set_lockdown(gui, true); | ||||
|     furi_record_close("gui"); | ||||
| } | ||||
| 
 | ||||
| static void desktop_locked_unlock(DesktopLockedView* locked_view) { | ||||
|     furi_assert(locked_view); | ||||
| 
 | ||||
|     locked_view->lock_count = 0; | ||||
|     DesktopLockedViewModel* model = view_get_model(locked_view->view); | ||||
|     model->locked = false; | ||||
|     model->pin_locked = false; | ||||
|     model->unlocked_hint = true; | ||||
|     view_commit_model(locked_view->view, true); | ||||
|     locked_view->callback(DesktopMainEventUnlocked, locked_view->context); | ||||
|     xTimerChangePeriod(locked_view->timer, UNLOCKED_HINT_TIMEOUT_MS, portMAX_DELAY); | ||||
| 
 | ||||
|     Gui* gui = furi_record_open("gui"); | ||||
|     gui_set_lockdown(gui, false); | ||||
|     furi_record_close("gui"); | ||||
| } | ||||
| @ -1,36 +0,0 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <desktop/desktop_settings/desktop_settings.h> | ||||
| #include <gui/view.h> | ||||
| #include "desktop_events.h" | ||||
| 
 | ||||
| #define UNLOCK_RST_TIMEOUT 300 | ||||
| #define UNLOCK_CNT 3 | ||||
| 
 | ||||
| #define DOOR_L_POS -57 | ||||
| #define DOOR_L_POS_MAX 0 | ||||
| #define DOOR_R_POS 115 | ||||
| #define DOOR_R_POS_MIN 60 | ||||
| 
 | ||||
| typedef enum { | ||||
|     DesktopLockedWithPin, | ||||
|     DesktopLockedNoPin, | ||||
| } DesktopLockedSceneState; | ||||
| 
 | ||||
| typedef struct DesktopLockedView DesktopLockedView; | ||||
| 
 | ||||
| typedef void (*DesktopLockedViewCallback)(DesktopEvent event, void* context); | ||||
| 
 | ||||
| void desktop_locked_set_callback( | ||||
|     DesktopLockedView* locked_view, | ||||
|     DesktopLockedViewCallback callback, | ||||
|     void* context); | ||||
| 
 | ||||
| void desktop_locked_update(DesktopLockedView* locked_view); | ||||
| 
 | ||||
| View* desktop_locked_get_view(DesktopLockedView* locked_view); | ||||
| DesktopLockedView* desktop_locked_alloc(); | ||||
| void desktop_locked_free(DesktopLockedView* locked_view); | ||||
| 
 | ||||
| void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode); | ||||
| void desktop_locked_lock(DesktopLockedView* locked_view); | ||||
| @ -1,11 +1,11 @@ | ||||
| #include <toolbox/version.h> | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <dolphin/helpers/dolphin_state.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_debug.h" | ||||
| #include "dolphin/helpers/dolphin_state.h" | ||||
| #include "dolphin/dolphin.h" | ||||
| #include "desktop_view_debug.h" | ||||
| 
 | ||||
| void desktop_debug_set_callback( | ||||
|     DesktopDebugView* debug_view, | ||||
| @ -1,8 +1,9 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_first_start.h" | ||||
| #include "desktop_view_first_start.h" | ||||
| 
 | ||||
| #define DESKTOP_FIRST_START_POWEROFF_SHORT 5000 | ||||
| #define DESKTOP_FIRST_START_POWEROFF_LONG (60 * 60 * 1000) | ||||
| @ -2,7 +2,7 @@ | ||||
| #include <gui/elements.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_lock_menu.h" | ||||
| #include "desktop_view_lock_menu.h" | ||||
| 
 | ||||
| #define LOCK_MENU_ITEMS_NB 3 | ||||
| 
 | ||||
							
								
								
									
										233
									
								
								applications/desktop/views/desktop_view_locked.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,233 @@ | ||||
| #include <projdefs.h> | ||||
| #include <stdint.h> | ||||
| #include <furi.h> | ||||
| #include <gui/elements.h> | ||||
| #include <gui/icon.h> | ||||
| #include <gui/view.h> | ||||
| #include <portmacro.h> | ||||
| 
 | ||||
| #include "../desktop_settings/desktop_settings.h" | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_view_locked.h" | ||||
| 
 | ||||
| #define DOOR_MOVING_INTERVAL_MS (1000 / 16) | ||||
| #define UNLOCKED_HINT_TIMEOUT_MS (2000) | ||||
| 
 | ||||
| #define DOOR_OFFSET_START -55 | ||||
| #define DOOR_OFFSET_END 0 | ||||
| 
 | ||||
| #define DOOR_L_FINAL_POS 0 | ||||
| #define DOOR_R_FINAL_POS 60 | ||||
| 
 | ||||
| #define UNLOCK_CNT 3 | ||||
| #define UNLOCK_RST_TIMEOUT 600 | ||||
| 
 | ||||
| struct DesktopViewLocked { | ||||
|     View* view; | ||||
|     DesktopViewLockedCallback callback; | ||||
|     void* context; | ||||
| 
 | ||||
|     TimerHandle_t timer; | ||||
|     uint8_t lock_count; | ||||
|     uint32_t lock_lastpress; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t hint_icon_expire_at; | ||||
|     bool unlocked_hint; | ||||
|     bool locked; | ||||
|     bool pin_locked; | ||||
| 
 | ||||
|     int8_t door_offset; | ||||
|     bool doors_closing; | ||||
| } DesktopViewLockedModel; | ||||
| 
 | ||||
| void desktop_view_locked_set_callback( | ||||
|     DesktopViewLocked* locked_view, | ||||
|     DesktopViewLockedCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(locked_view); | ||||
|     furi_assert(callback); | ||||
|     locked_view->callback = callback; | ||||
|     locked_view->context = context; | ||||
| } | ||||
| 
 | ||||
| static void locked_view_timer_callback(TimerHandle_t timer) { | ||||
|     DesktopViewLocked* locked_view = pvTimerGetTimerID(timer); | ||||
|     locked_view->callback(DesktopLockedEventUpdate, locked_view->context); | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_locked_doors_draw(Canvas* canvas, DesktopViewLockedModel* model) { | ||||
|     int8_t offset = model->door_offset; | ||||
|     uint8_t door_left_x = DOOR_L_FINAL_POS + offset; | ||||
|     uint8_t door_right_x = DOOR_R_FINAL_POS - offset; | ||||
|     uint8_t height = icon_get_height(&I_DoorLeft_70x55); | ||||
|     canvas_draw_icon(canvas, door_left_x, canvas_height(canvas) - height, &I_DoorLeft_70x55); | ||||
|     canvas_draw_icon(canvas, door_right_x, canvas_height(canvas) - height, &I_DoorRight_70x55); | ||||
| } | ||||
| 
 | ||||
| static bool desktop_view_locked_doors_move(DesktopViewLockedModel* model) { | ||||
|     bool stop = false; | ||||
|     if(model->door_offset < DOOR_OFFSET_END) { | ||||
|         model->door_offset = CLAMP(model->door_offset + 5, DOOR_OFFSET_END, DOOR_OFFSET_START); | ||||
|         stop = true; | ||||
|     } | ||||
| 
 | ||||
|     return stop; | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_locked_update_hint_icon_timeout(DesktopViewLocked* locked_view) { | ||||
|     DesktopViewLockedModel* model = view_get_model(locked_view->view); | ||||
|     model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq(); | ||||
|     view_commit_model(locked_view->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_locked_update(DesktopViewLocked* locked_view) { | ||||
|     bool stop_timer = false; | ||||
| 
 | ||||
|     DesktopViewLockedModel* model = view_get_model(locked_view->view); | ||||
|     if(model->locked) { | ||||
|         model->doors_closing = desktop_view_locked_doors_move(model); | ||||
|         stop_timer = !model->doors_closing; | ||||
|     } else { | ||||
|         model->unlocked_hint = false; | ||||
|         stop_timer = true; | ||||
|     } | ||||
|     view_commit_model(locked_view->view, true); | ||||
| 
 | ||||
|     if(stop_timer) { | ||||
|         xTimerStop(locked_view->timer, portMAX_DELAY); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_locked_draw(Canvas* canvas, void* model) { | ||||
|     DesktopViewLockedModel* m = model; | ||||
|     uint32_t now = osKernelGetTickCount(); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
| 
 | ||||
|     if(m->locked) { | ||||
|         if(m->doors_closing) { | ||||
|             desktop_view_locked_doors_draw(canvas, m); | ||||
|             canvas_set_font(canvas, FontPrimary); | ||||
|             elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked"); | ||||
|         } else if((now < m->hint_icon_expire_at) && !m->pin_locked) { | ||||
|             canvas_set_font(canvas, FontSecondary); | ||||
|             elements_bold_rounded_frame(canvas, 14, 2 + STATUS_BAR_Y_SHIFT, 99, 48); | ||||
|             elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:"); | ||||
|             canvas_draw_icon(canvas, 65, 36 + STATUS_BAR_Y_SHIFT, &I_Back3_45x8); | ||||
|             canvas_draw_icon(canvas, 16, 7 + STATUS_BAR_Y_SHIFT, &I_WarningDolphin_45x42); | ||||
|             canvas_draw_dot(canvas, 17, 61); | ||||
|         } | ||||
|     } else { | ||||
|         if(m->unlocked_hint) { | ||||
|             canvas_set_font(canvas, FontPrimary); | ||||
|             elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| View* desktop_view_locked_get_view(DesktopViewLocked* locked_view) { | ||||
|     furi_assert(locked_view); | ||||
|     return locked_view->view; | ||||
| } | ||||
| 
 | ||||
| static bool desktop_view_locked_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
|     DesktopViewLocked* locked_view = context; | ||||
|     bool locked = false; | ||||
|     bool locked_with_pin = false; | ||||
|     bool doors_closing = false; | ||||
|     uint32_t press_time = xTaskGetTickCount(); | ||||
| 
 | ||||
|     { | ||||
|         DesktopViewLockedModel* model = view_get_model(locked_view->view); | ||||
|         bool changed = false; | ||||
|         locked = model->locked; | ||||
|         locked_with_pin = model->pin_locked; | ||||
|         doors_closing = model->doors_closing; | ||||
|         if(!locked && model->unlocked_hint && event->type == InputTypePress) { | ||||
|             model->unlocked_hint = false; | ||||
|             changed = true; | ||||
|         } | ||||
|         view_commit_model(locked_view->view, changed); | ||||
|     } | ||||
| 
 | ||||
|     if(!locked || doors_closing || (event->type != InputTypeShort)) { | ||||
|         return locked; | ||||
|     } | ||||
| 
 | ||||
|     if(locked_with_pin) { | ||||
|         locked_view->callback(DesktopLockedEventShowPinInput, locked_view->context); | ||||
|     } else { | ||||
|         if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { | ||||
|             locked_view->lock_lastpress = press_time; | ||||
|             locked_view->lock_count = 0; | ||||
|         } | ||||
| 
 | ||||
|         desktop_view_locked_update_hint_icon_timeout(locked_view); | ||||
|         if(event->key == InputKeyBack) { | ||||
|             locked_view->lock_lastpress = press_time; | ||||
|             locked_view->lock_count++; | ||||
|             if(locked_view->lock_count == UNLOCK_CNT) { | ||||
|                 desktop_view_locked_unlock(locked_view); | ||||
|                 locked_view->callback(DesktopLockedEventUnlocked, locked_view->context); | ||||
|             } | ||||
|         } else { | ||||
|             locked_view->lock_count = 0; | ||||
|         } | ||||
| 
 | ||||
|         locked_view->lock_lastpress = press_time; | ||||
|     } | ||||
| 
 | ||||
|     return locked; | ||||
| } | ||||
| 
 | ||||
| DesktopViewLocked* desktop_view_locked_alloc() { | ||||
|     DesktopViewLocked* locked_view = furi_alloc(sizeof(DesktopViewLocked)); | ||||
|     locked_view->view = view_alloc(); | ||||
|     locked_view->timer = | ||||
|         xTimerCreate(NULL, 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback); | ||||
| 
 | ||||
|     locked_view->view = view_alloc(); | ||||
|     view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopViewLockedModel)); | ||||
|     view_set_context(locked_view->view, locked_view); | ||||
|     view_set_draw_callback(locked_view->view, desktop_view_locked_draw); | ||||
|     view_set_input_callback(locked_view->view, desktop_view_locked_input); | ||||
| 
 | ||||
|     return locked_view; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_locked_free(DesktopViewLocked* locked_view) { | ||||
|     furi_assert(locked_view); | ||||
|     osTimerDelete(locked_view->timer); | ||||
|     view_free(locked_view->view); | ||||
|     free(locked_view); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_locked_close_doors(DesktopViewLocked* locked_view) { | ||||
|     DesktopViewLockedModel* model = view_get_model(locked_view->view); | ||||
|     model->doors_closing = true; | ||||
|     model->door_offset = DOOR_OFFSET_START; | ||||
|     view_commit_model(locked_view->view, true); | ||||
|     xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(DOOR_MOVING_INTERVAL_MS), portMAX_DELAY); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked) { | ||||
|     DesktopViewLockedModel* model = view_get_model(locked_view->view); | ||||
|     model->locked = true; | ||||
|     model->pin_locked = pin_locked; | ||||
|     view_commit_model(locked_view->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_locked_unlock(DesktopViewLocked* locked_view) { | ||||
|     furi_assert(locked_view); | ||||
| 
 | ||||
|     locked_view->lock_count = 0; | ||||
|     DesktopViewLockedModel* model = view_get_model(locked_view->view); | ||||
|     model->locked = false; | ||||
|     model->pin_locked = false; | ||||
|     model->unlocked_hint = true; | ||||
|     view_commit_model(locked_view->view, true); | ||||
|     xTimerChangePeriod(locked_view->timer, pdMS_TO_TICKS(UNLOCKED_HINT_TIMEOUT_MS), portMAX_DELAY); | ||||
| } | ||||
							
								
								
									
										21
									
								
								applications/desktop/views/desktop_view_locked.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,21 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include "../desktop_settings/desktop_settings.h" | ||||
| #include "../views/desktop_events.h" | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct DesktopViewLocked DesktopViewLocked; | ||||
| 
 | ||||
| typedef void (*DesktopViewLockedCallback)(DesktopEvent event, void* context); | ||||
| 
 | ||||
| void desktop_view_locked_set_callback( | ||||
|     DesktopViewLocked* locked_view, | ||||
|     DesktopViewLockedCallback callback, | ||||
|     void* context); | ||||
| void desktop_view_locked_update(DesktopViewLocked* locked_view); | ||||
| View* desktop_view_locked_get_view(DesktopViewLocked* locked_view); | ||||
| DesktopViewLocked* desktop_view_locked_alloc(); | ||||
| void desktop_view_locked_free(DesktopViewLocked* locked_view); | ||||
| void desktop_view_locked_lock(DesktopViewLocked* locked_view, bool pin_locked); | ||||
| void desktop_view_locked_unlock(DesktopViewLocked* locked_view); | ||||
| void desktop_view_locked_close_doors(DesktopViewLocked* locked_view); | ||||
| @ -7,7 +7,7 @@ | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_main.h" | ||||
| #include "desktop_view_main.h" | ||||
| 
 | ||||
| struct DesktopMainView { | ||||
|     View* view; | ||||
							
								
								
									
										340
									
								
								applications/desktop/views/desktop_view_pin_input.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,340 @@ | ||||
| #include <gui/canvas.h> | ||||
| #include <furi.h> | ||||
| #include <gui/view.h> | ||||
| #include <gui/elements.h> | ||||
| #include <stdint.h> | ||||
| #include <portmacro.h> | ||||
| 
 | ||||
| #include "desktop_view_pin_input.h" | ||||
| #include "../desktop_settings/desktop_settings.h" | ||||
| 
 | ||||
| #define NO_ACTIVITY_TIMEOUT 15000 | ||||
| 
 | ||||
| #define PIN_CELL_WIDTH 13 | ||||
| #define DEFAULT_PIN_X 64 | ||||
| #define DEFAULT_PIN_Y 32 | ||||
| 
 | ||||
| struct DesktopViewPinInput { | ||||
|     View* view; | ||||
|     DesktopViewPinInputCallback back_callback; | ||||
|     DesktopViewPinInputCallback timeout_callback; | ||||
|     DesktopViewPinInputDoneCallback done_callback; | ||||
|     void* context; | ||||
|     TimerHandle_t timer; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     PinCode pin; | ||||
|     bool pin_hidden; | ||||
|     bool locked_input; | ||||
|     uint8_t pin_x; | ||||
|     uint8_t pin_y; | ||||
|     const char* primary_str; | ||||
|     uint8_t primary_str_x; | ||||
|     uint8_t primary_str_y; | ||||
|     const char* secondary_str; | ||||
|     uint8_t secondary_str_x; | ||||
|     uint8_t secondary_str_y; | ||||
|     const char* button_label; | ||||
| } DesktopViewPinInputModel; | ||||
| 
 | ||||
| static bool desktop_view_pin_input_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     DesktopViewPinInput* pin_input = context; | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
| 
 | ||||
|     bool call_back_callback = false; | ||||
|     bool call_done_callback = false; | ||||
|     PinCode pin_code = {0}; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort) { | ||||
|         switch(event->key) { | ||||
|         case InputKeyRight: | ||||
|         case InputKeyLeft: | ||||
|         case InputKeyDown: | ||||
|         case InputKeyUp: | ||||
|             if(!model->locked_input) { | ||||
|                 if(model->pin.length < MAX_PIN_SIZE) { | ||||
|                     model->pin.data[model->pin.length++] = event->key; | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|         case InputKeyOk: | ||||
|             if(model->pin.length >= MIN_PIN_SIZE) { | ||||
|                 call_done_callback = true; | ||||
|                 pin_code = model->pin; | ||||
|             } | ||||
|             break; | ||||
|         case InputKeyBack: | ||||
|             if(!model->locked_input) { | ||||
|                 if(model->pin.length > 0) { | ||||
|                     model->pin.length = 0; | ||||
|                 } else { | ||||
|                     call_back_callback = true; | ||||
|                 } | ||||
|             } | ||||
|             break; | ||||
|         default: | ||||
|             furi_assert(0); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     view_commit_model(pin_input->view, true); | ||||
| 
 | ||||
|     if(call_done_callback && pin_input->done_callback) { | ||||
|         pin_input->done_callback(&pin_code, pin_input->context); | ||||
|     } else if(call_back_callback && pin_input->back_callback) { | ||||
|         pin_input->back_callback(pin_input->context); | ||||
|     } | ||||
| 
 | ||||
|     xTimerStart(pin_input->timer, 0); | ||||
| 
 | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_pin_input_draw_cells(Canvas* canvas, DesktopViewPinInputModel* model) { | ||||
|     furi_assert(canvas); | ||||
|     furi_assert(model); | ||||
| 
 | ||||
|     uint8_t draw_pin_size = MAX(4, model->pin.length + 1); | ||||
|     if(model->locked_input || (model->pin.length == MAX_PIN_SIZE)) { | ||||
|         draw_pin_size = model->pin.length; | ||||
|     } | ||||
| 
 | ||||
|     uint8_t x = model->pin_x - (draw_pin_size * (PIN_CELL_WIDTH - 1)) / 2; | ||||
|     uint8_t y = model->pin_y - (PIN_CELL_WIDTH / 2); | ||||
| 
 | ||||
|     for(int i = 0; i < draw_pin_size; ++i) { | ||||
|         canvas_draw_frame(canvas, x, y, PIN_CELL_WIDTH, PIN_CELL_WIDTH); | ||||
|         if(i < model->pin.length) { | ||||
|             if(model->pin_hidden) { | ||||
|                 canvas_draw_icon(canvas, x + 3, y + 3, &I_Pin_star_7x7); | ||||
|             } else { | ||||
|                 switch(model->pin.data[i]) { | ||||
|                 case InputKeyDown: | ||||
|                     canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_down_7x9); | ||||
|                     break; | ||||
|                 case InputKeyUp: | ||||
|                     canvas_draw_icon(canvas, x + 3, y + 2, &I_Pin_arrow_up7x9); | ||||
|                     break; | ||||
|                 case InputKeyLeft: | ||||
|                     canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_left_9x7); | ||||
|                     break; | ||||
|                 case InputKeyRight: | ||||
|                     canvas_draw_icon(canvas, x + 2, y + 3, &I_Pin_arrow_right_9x7); | ||||
|                     break; | ||||
|                 default: | ||||
|                     furi_assert(0); | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|         } else if(i == model->pin.length) { | ||||
|             canvas_draw_icon(canvas, x + 4, y + PIN_CELL_WIDTH + 1, &I_Pin_pointer_5x3); | ||||
|         } | ||||
|         x += PIN_CELL_WIDTH - 1; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_pin_input_draw(Canvas* canvas, void* context) { | ||||
|     furi_assert(canvas); | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     DesktopViewPinInputModel* model = context; | ||||
|     desktop_view_pin_input_draw_cells(canvas, model); | ||||
| 
 | ||||
|     if((model->pin.length > 0) && !model->locked_input) { | ||||
|         canvas_draw_icon(canvas, 4, 53, &I_Pin_back_full_40x8); | ||||
|     } | ||||
| 
 | ||||
|     if(model->button_label && ((model->pin.length >= MIN_PIN_SIZE) || model->locked_input)) { | ||||
|         elements_button_center(canvas, model->button_label); | ||||
|     } | ||||
| 
 | ||||
|     if(model->primary_str) { | ||||
|         canvas_set_font(canvas, FontPrimary); | ||||
|         canvas_draw_str(canvas, model->primary_str_x, model->primary_str_y, model->primary_str); | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|     } | ||||
| 
 | ||||
|     if(model->secondary_str) { | ||||
|         canvas_set_font(canvas, FontSecondary); | ||||
|         canvas_draw_str( | ||||
|             canvas, model->secondary_str_x, model->secondary_str_y, model->secondary_str); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_timer_callback(TimerHandle_t timer) { | ||||
|     DesktopViewPinInput* pin_input = pvTimerGetTimerID(timer); | ||||
| 
 | ||||
|     if(pin_input->timeout_callback) { | ||||
|         pin_input->timeout_callback(pin_input->context); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_pin_input_enter(void* context) { | ||||
|     DesktopViewPinInput* pin_input = context; | ||||
|     xTimerStart(pin_input->timer, portMAX_DELAY); | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_pin_input_exit(void* context) { | ||||
|     DesktopViewPinInput* pin_input = context; | ||||
|     xTimerStop(pin_input->timer, portMAX_DELAY); | ||||
| } | ||||
| 
 | ||||
| DesktopViewPinInput* desktop_view_pin_input_alloc(void) { | ||||
|     DesktopViewPinInput* pin_input = furi_alloc(sizeof(DesktopViewPinInput)); | ||||
|     pin_input->view = view_alloc(); | ||||
|     view_allocate_model(pin_input->view, ViewModelTypeLocking, sizeof(DesktopViewPinInputModel)); | ||||
|     view_set_context(pin_input->view, pin_input); | ||||
|     view_set_draw_callback(pin_input->view, desktop_view_pin_input_draw); | ||||
|     view_set_input_callback(pin_input->view, desktop_view_pin_input_input); | ||||
|     pin_input->timer = xTimerCreate( | ||||
|         NULL, | ||||
|         pdMS_TO_TICKS(NO_ACTIVITY_TIMEOUT), | ||||
|         pdFALSE, | ||||
|         pin_input, | ||||
|         desktop_view_pin_input_timer_callback); | ||||
|     view_set_enter_callback(pin_input->view, desktop_view_pin_input_enter); | ||||
|     view_set_exit_callback(pin_input->view, desktop_view_pin_input_exit); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->pin_x = DEFAULT_PIN_X; | ||||
|     model->pin_y = DEFAULT_PIN_Y; | ||||
|     model->pin.length = 0; | ||||
|     view_commit_model(pin_input->view, false); | ||||
| 
 | ||||
|     return pin_input; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_free(DesktopViewPinInput* pin_input) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     xTimerStop(pin_input->timer, portMAX_DELAY); | ||||
|     while(xTimerIsTimerActive(pin_input->timer)) { | ||||
|         delay(1); | ||||
|     } | ||||
|     xTimerDelete(pin_input->timer, portMAX_DELAY); | ||||
| 
 | ||||
|     view_free(pin_input->view); | ||||
|     free(pin_input); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_lock_input(DesktopViewPinInput* pin_input) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->locked_input = true; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_unlock_input(DesktopViewPinInput* pin_input) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->locked_input = false; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin) { | ||||
|     furi_assert(pin_input); | ||||
|     furi_assert(pin); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->pin = *pin; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_reset_pin(DesktopViewPinInput* pin_input) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->pin.length = 0; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_hide_pin(DesktopViewPinInput* pin_input, bool pin_hidden) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->pin_hidden = pin_hidden; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_label_button(DesktopViewPinInput* pin_input, const char* label) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->button_label = label; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_label_primary( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     const char* label) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->primary_str = label; | ||||
|     model->primary_str_x = x; | ||||
|     model->primary_str_y = y; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_label_secondary( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     const char* label) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->secondary_str = label; | ||||
|     model->secondary_str_x = x; | ||||
|     model->secondary_str_y = y; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_pin_position(DesktopViewPinInput* pin_input, uint8_t x, uint8_t y) { | ||||
|     furi_assert(pin_input); | ||||
| 
 | ||||
|     DesktopViewPinInputModel* model = view_get_model(pin_input->view); | ||||
|     model->pin_x = x; | ||||
|     model->pin_y = y; | ||||
|     view_commit_model(pin_input->view, true); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_context(DesktopViewPinInput* pin_input, void* context) { | ||||
|     furi_assert(pin_input); | ||||
|     pin_input->context = context; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_timeout_callback( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     DesktopViewPinInputCallback callback) { | ||||
|     furi_assert(pin_input); | ||||
|     pin_input->timeout_callback = callback; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_back_callback( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     DesktopViewPinInputCallback callback) { | ||||
|     furi_assert(pin_input); | ||||
|     pin_input->back_callback = callback; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_input_set_done_callback( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     DesktopViewPinInputDoneCallback callback) { | ||||
|     furi_assert(pin_input); | ||||
|     pin_input->done_callback = callback; | ||||
| } | ||||
| 
 | ||||
| View* desktop_view_pin_input_get_view(DesktopViewPinInput* pin_input) { | ||||
|     furi_assert(pin_input); | ||||
|     return pin_input->view; | ||||
| } | ||||
							
								
								
									
										40
									
								
								applications/desktop/views/desktop_view_pin_input.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,40 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| #include "desktop/desktop_settings/desktop_settings.h" | ||||
| 
 | ||||
| typedef void (*DesktopViewPinInputCallback)(void*); | ||||
| typedef void (*DesktopViewPinInputDoneCallback)(const PinCode* pin_code, void*); | ||||
| typedef struct DesktopViewPinInput DesktopViewPinInput; | ||||
| 
 | ||||
| DesktopViewPinInput* desktop_view_pin_input_alloc(void); | ||||
| void desktop_view_pin_input_free(DesktopViewPinInput*); | ||||
| 
 | ||||
| void desktop_view_pin_input_set_pin(DesktopViewPinInput* pin_input, const PinCode* pin); | ||||
| void desktop_view_pin_input_reset_pin(DesktopViewPinInput* pin_input); | ||||
| void desktop_view_pin_input_hide_pin(DesktopViewPinInput* pin_input, bool pin_hidden); | ||||
| void desktop_view_pin_input_set_label_button(DesktopViewPinInput* pin_input, const char* label); | ||||
| void desktop_view_pin_input_set_label_primary( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     const char* label); | ||||
| void desktop_view_pin_input_set_label_secondary( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     const char* label); | ||||
| void desktop_view_pin_input_set_pin_position(DesktopViewPinInput* pin_input, uint8_t x, uint8_t y); | ||||
| View* desktop_view_pin_input_get_view(DesktopViewPinInput*); | ||||
| void desktop_view_pin_input_set_done_callback( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     DesktopViewPinInputDoneCallback callback); | ||||
| void desktop_view_pin_input_set_back_callback( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     DesktopViewPinInputCallback callback); | ||||
| void desktop_view_pin_input_set_timeout_callback( | ||||
|     DesktopViewPinInput* pin_input, | ||||
|     DesktopViewPinInputCallback callback); | ||||
| void desktop_view_pin_input_set_context(DesktopViewPinInput* pin_input, void* context); | ||||
| void desktop_view_pin_input_lock_input(DesktopViewPinInput* pin_input); | ||||
| void desktop_view_pin_input_unlock_input(DesktopViewPinInput* pin_input); | ||||
							
								
								
									
										80
									
								
								applications/desktop/views/desktop_view_pin_setup_done.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,80 @@ | ||||
| #include <furi.h> | ||||
| #include <furi_hal.h> | ||||
| #include <gui/elements.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <toolbox/version.h> | ||||
| #include <assets_icons.h> | ||||
| #include <dolphin/helpers/dolphin_state.h> | ||||
| #include <dolphin/dolphin.h> | ||||
| 
 | ||||
| #include "../desktop_i.h" | ||||
| #include "desktop_view_pin_setup_done.h" | ||||
| 
 | ||||
| struct DesktopViewPinSetupDone { | ||||
|     View* view; | ||||
|     DesktopViewPinSetupDoneDoneCallback callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| static void desktop_view_pin_done_draw(Canvas* canvas, void* model) { | ||||
|     furi_assert(canvas); | ||||
|     furi_assert(model); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     elements_multiline_text_aligned( | ||||
|         canvas, 64, 0, AlignCenter, AlignTop, "Prepare to use\narrows as\nPIN symbols"); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols"); | ||||
| 
 | ||||
|     canvas_draw_icon(canvas, 16, 18, &I_Pin_attention_dpad_29x29); | ||||
|     elements_button_right(canvas, "Next"); | ||||
| } | ||||
| 
 | ||||
| static bool desktop_view_pin_done_input(InputEvent* event, void* context) { | ||||
|     furi_assert(event); | ||||
|     furi_assert(context); | ||||
| 
 | ||||
|     DesktopViewPinSetupDone* instance = context; | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if((event->key == InputKeyRight) && (event->type == InputTypeShort)) { | ||||
|         instance->callback(instance->context); | ||||
|         consumed = true; | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_done_set_callback( | ||||
|     DesktopViewPinSetupDone* instance, | ||||
|     DesktopViewPinSetupDoneDoneCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(instance); | ||||
|     furi_assert(callback); | ||||
|     instance->callback = callback; | ||||
|     instance->context = context; | ||||
| } | ||||
| 
 | ||||
| DesktopViewPinSetupDone* desktop_view_pin_done_alloc() { | ||||
|     DesktopViewPinSetupDone* view = furi_alloc(sizeof(DesktopViewPinSetupDone)); | ||||
|     view->view = view_alloc(); | ||||
|     view_allocate_model(view->view, ViewModelTypeLockFree, 1); | ||||
|     view_set_context(view->view, view); | ||||
|     view_set_draw_callback(view->view, desktop_view_pin_done_draw); | ||||
|     view_set_input_callback(view->view, desktop_view_pin_done_input); | ||||
| 
 | ||||
|     return view; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_done_free(DesktopViewPinSetupDone* instance) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     view_free(instance->view); | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| View* desktop_view_pin_done_get_view(DesktopViewPinSetupDone* instance) { | ||||
|     furi_assert(instance); | ||||
|     return instance->view; | ||||
| } | ||||
							
								
								
									
										15
									
								
								applications/desktop/views/desktop_view_pin_setup_done.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,15 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef struct DesktopViewPinSetupDone DesktopViewPinSetupDone; | ||||
| 
 | ||||
| typedef void (*DesktopViewPinSetupDoneDoneCallback)(void*); | ||||
| 
 | ||||
| void desktop_view_pin_done_set_callback( | ||||
|     DesktopViewPinSetupDone* instance, | ||||
|     DesktopViewPinSetupDoneDoneCallback callback, | ||||
|     void* context); | ||||
| DesktopViewPinSetupDone* desktop_view_pin_done_alloc(); | ||||
| void desktop_view_pin_done_free(DesktopViewPinSetupDone* instance); | ||||
| View* desktop_view_pin_done_get_view(DesktopViewPinSetupDone* instance); | ||||
							
								
								
									
										109
									
								
								applications/desktop/views/desktop_view_pin_timeout.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,109 @@ | ||||
| 
 | ||||
| #include <furi.h> | ||||
| #include <stdint.h> | ||||
| #include <stdio.h> | ||||
| #include <FreeRTOS.h> | ||||
| #include <portmacro.h> | ||||
| #include <projdefs.h> | ||||
| #include <input/input.h> | ||||
| #include <gui/canvas.h> | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| #include "desktop_view_pin_timeout.h" | ||||
| 
 | ||||
| struct DesktopViewPinTimeout { | ||||
|     View* view; | ||||
|     TimerHandle_t timer; | ||||
|     DesktopViewPinTimeoutDoneCallback callback; | ||||
|     void* context; | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint32_t time_left; | ||||
| } DesktopViewPinTimeoutModel; | ||||
| 
 | ||||
| void desktop_view_pin_timeout_set_callback( | ||||
|     DesktopViewPinTimeout* instance, | ||||
|     DesktopViewPinTimeoutDoneCallback callback, | ||||
|     void* context) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     instance->callback = callback; | ||||
|     instance->context = context; | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_pin_timeout_timer_callback(TimerHandle_t timer) { | ||||
|     DesktopViewPinTimeout* instance = pvTimerGetTimerID(timer); | ||||
|     bool stop = false; | ||||
| 
 | ||||
|     DesktopViewPinTimeoutModel* model = view_get_model(instance->view); | ||||
|     if(model->time_left > 0) { | ||||
|         --model->time_left; | ||||
|     } else { | ||||
|         stop = true; | ||||
|     } | ||||
|     view_commit_model(instance->view, true); | ||||
| 
 | ||||
|     if(stop) { | ||||
|         xTimerStop(instance->timer, portMAX_DELAY); | ||||
|         instance->callback(instance->context); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| static bool desktop_view_pin_timeout_input(InputEvent* event, void* context) { | ||||
|     return true; | ||||
| } | ||||
| 
 | ||||
| static void desktop_view_pin_timeout_draw(Canvas* canvas, void* _model) { | ||||
|     furi_assert(canvas); | ||||
|     furi_assert(_model); | ||||
| 
 | ||||
|     DesktopViewPinTimeoutModel* model = _model; | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontPrimary); | ||||
|     canvas_draw_str(canvas, 36, 31, "Wrong PIN!"); | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
|     char str[30] = {0}; | ||||
|     snprintf(str, sizeof(str), "Timeout: %lds", model->time_left); | ||||
|     canvas_draw_str_aligned(canvas, 64, 38, AlignCenter, AlignCenter, str); | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_timeout_free(DesktopViewPinTimeout* instance) { | ||||
|     view_free(instance->view); | ||||
|     xTimerDelete(instance->timer, portMAX_DELAY); | ||||
| 
 | ||||
|     free(instance); | ||||
| } | ||||
| 
 | ||||
| DesktopViewPinTimeout* desktop_view_pin_timeout_alloc(void) { | ||||
|     DesktopViewPinTimeout* instance = furi_alloc(sizeof(DesktopViewPinTimeout)); | ||||
|     instance->timer = xTimerCreate( | ||||
|         NULL, pdMS_TO_TICKS(1000), pdTRUE, instance, desktop_view_pin_timeout_timer_callback); | ||||
| 
 | ||||
|     instance->view = view_alloc(); | ||||
|     view_allocate_model(instance->view, ViewModelTypeLockFree, sizeof(DesktopViewPinTimeoutModel)); | ||||
| 
 | ||||
|     view_set_context(instance->view, instance); | ||||
|     view_set_draw_callback(instance->view, desktop_view_pin_timeout_draw); | ||||
|     view_set_input_callback(instance->view, desktop_view_pin_timeout_input); | ||||
| 
 | ||||
|     return instance; | ||||
| } | ||||
| 
 | ||||
| void desktop_view_pin_timeout_start(DesktopViewPinTimeout* instance, uint32_t time_left) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     DesktopViewPinTimeoutModel* model = view_get_model(instance->view); | ||||
|     // no race - always called when timer is stopped
 | ||||
|     model->time_left = time_left; | ||||
|     view_commit_model(instance->view, true); | ||||
| 
 | ||||
|     xTimerStart(instance->timer, portMAX_DELAY); | ||||
| } | ||||
| 
 | ||||
| View* desktop_view_pin_timeout_get_view(DesktopViewPinTimeout* instance) { | ||||
|     furi_assert(instance); | ||||
| 
 | ||||
|     return instance->view; | ||||
| } | ||||
							
								
								
									
										16
									
								
								applications/desktop/views/desktop_view_pin_timeout.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @ -0,0 +1,16 @@ | ||||
| #pragma once | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| typedef void (*DesktopViewPinTimeoutDoneCallback)(void*); | ||||
| typedef struct DesktopViewPinTimeout DesktopViewPinTimeout; | ||||
| 
 | ||||
| void desktop_view_pin_timeout_set_callback( | ||||
|     DesktopViewPinTimeout* instance, | ||||
|     DesktopViewPinTimeoutDoneCallback callback, | ||||
|     void* context); | ||||
| DesktopViewPinTimeout* desktop_view_pin_timeout_alloc(void); | ||||
| void desktop_view_pin_timeout_free(DesktopViewPinTimeout*); | ||||
| void desktop_view_pin_timeout_start(DesktopViewPinTimeout* instance, uint32_t time_left); | ||||
| View* desktop_view_pin_timeout_get_view(DesktopViewPinTimeout* instance); | ||||
| @ -80,15 +80,11 @@ Dolphin* dolphin_alloc() { | ||||
|     dolphin->event_queue = osMessageQueueNew(8, sizeof(DolphinEvent), NULL); | ||||
|     dolphin->pubsub = furi_pubsub_alloc(); | ||||
|     dolphin->butthurt_timer = xTimerCreate( | ||||
|         "Butthurt timer", HOURS_IN_TICKS(2 * 24), pdTRUE, dolphin, dolphin_butthurt_timer_callback); | ||||
|         NULL, HOURS_IN_TICKS(2 * 24), pdTRUE, dolphin, dolphin_butthurt_timer_callback); | ||||
|     dolphin->flush_timer = | ||||
|         xTimerCreate("Flush timer", 30 * 1000, pdFALSE, dolphin, dolphin_flush_timer_callback); | ||||
|         xTimerCreate(NULL, 30 * 1000, pdFALSE, dolphin, dolphin_flush_timer_callback); | ||||
|     dolphin->clear_limits_timer = xTimerCreate( | ||||
|         "Clear limits timer", | ||||
|         HOURS_IN_TICKS(24), | ||||
|         pdTRUE, | ||||
|         dolphin, | ||||
|         dolphin_clear_limits_timer_callback); | ||||
|         NULL, HOURS_IN_TICKS(24), pdTRUE, dolphin, dolphin_clear_limits_timer_callback); | ||||
| 
 | ||||
|     return dolphin; | ||||
| } | ||||
|  | ||||
| @ -1,4 +1,7 @@ | ||||
| #include "elements.h" | ||||
| #include <assets_icons.h> | ||||
| #include "furi_hal_resources.h" | ||||
| #include <furi_hal.h> | ||||
| #include "gui/canvas.h" | ||||
| 
 | ||||
| #include <gui/icon_i.h> | ||||
| @ -337,6 +340,47 @@ void elements_slightly_rounded_box( | ||||
|     canvas_draw_rbox(canvas, x, y, width, height, 1); | ||||
| } | ||||
| 
 | ||||
| void elements_bold_rounded_frame( | ||||
|     Canvas* canvas, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     uint8_t width, | ||||
|     uint8_t height) { | ||||
|     furi_assert(canvas); | ||||
| 
 | ||||
|     canvas_set_color(canvas, ColorWhite); | ||||
|     canvas_draw_box(canvas, x + 2, y + 2, width - 3, height - 3); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
| 
 | ||||
|     canvas_draw_line(canvas, x + 3, y, x + width - 3, y); | ||||
|     canvas_draw_line(canvas, x + 2, y + 1, x + width - 2, y + 1); | ||||
| 
 | ||||
|     canvas_draw_line(canvas, x, y + 3, x, y + height - 3); | ||||
|     canvas_draw_line(canvas, x + 1, y + 2, x + 1, y + height - 2); | ||||
| 
 | ||||
|     canvas_draw_line(canvas, x + width, y + 3, x + width, y + height - 3); | ||||
|     canvas_draw_line(canvas, x + width - 1, y + 2, x + width - 1, y + height - 2); | ||||
| 
 | ||||
|     canvas_draw_line(canvas, x + 3, y + height, x + width - 3, y + height); | ||||
|     canvas_draw_line(canvas, x + 2, y + height - 1, x + width - 2, y + height - 1); | ||||
| 
 | ||||
|     canvas_draw_dot(canvas, x + 2, y + 2); | ||||
|     canvas_draw_dot(canvas, x + 3, y + 2); | ||||
|     canvas_draw_dot(canvas, x + 2, y + 3); | ||||
| 
 | ||||
|     canvas_draw_dot(canvas, x + width - 2, y + 2); | ||||
|     canvas_draw_dot(canvas, x + width - 3, y + 2); | ||||
|     canvas_draw_dot(canvas, x + width - 2, y + 3); | ||||
| 
 | ||||
|     canvas_draw_dot(canvas, x + 2, y + height - 2); | ||||
|     canvas_draw_dot(canvas, x + 3, y + height - 2); | ||||
|     canvas_draw_dot(canvas, x + 2, y + height - 3); | ||||
| 
 | ||||
|     canvas_draw_dot(canvas, x + width - 2, y + height - 2); | ||||
|     canvas_draw_dot(canvas, x + width - 3, y + height - 2); | ||||
|     canvas_draw_dot(canvas, x + width - 2, y + height - 3); | ||||
| } | ||||
| 
 | ||||
| void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height) { | ||||
|     furi_assert(canvas); | ||||
|     canvas_draw_rframe(canvas, x + 4, y, width, height, 3); | ||||
|  | ||||
| @ -150,6 +150,19 @@ void elements_slightly_rounded_box( | ||||
|     uint8_t width, | ||||
|     uint8_t height); | ||||
| 
 | ||||
| /** Draw bold rounded frame
 | ||||
|  * | ||||
|  * @param   canvas          Canvas instance | ||||
|  * @param   x, y            top left corner coordinates | ||||
|  * @param   width, height   size of frame | ||||
|  */ | ||||
| void elements_bold_rounded_frame( | ||||
|     Canvas* canvas, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     uint8_t width, | ||||
|     uint8_t height); | ||||
| 
 | ||||
| /** Draw bubble frame for text
 | ||||
|  * | ||||
|  * @param   canvas  Canvas instance | ||||
|  | ||||
| @ -1,478 +0,0 @@ | ||||
| #include "code_input.h" | ||||
| #include <gui/elements.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #define MAX_CODE_LEN 10 | ||||
| 
 | ||||
| struct CodeInput { | ||||
|     View* view; | ||||
| }; | ||||
| 
 | ||||
| typedef enum { | ||||
|     CodeInputStateVerify, | ||||
|     CodeInputStateUpdate, | ||||
|     CodeInputStateTotal, | ||||
| } CodeInputStateEnum; | ||||
| 
 | ||||
| typedef enum { | ||||
|     CodeInputFirst, | ||||
|     CodeInputSecond, | ||||
|     CodeInputTotal, | ||||
| } CodeInputsEnum; | ||||
| 
 | ||||
| typedef struct { | ||||
|     uint8_t state; | ||||
|     uint8_t current; | ||||
|     bool ext_update; | ||||
| 
 | ||||
|     uint8_t input_length[CodeInputTotal]; | ||||
|     uint8_t local_buffer[CodeInputTotal][MAX_CODE_LEN]; | ||||
| 
 | ||||
|     CodeInputOkCallback ok_callback; | ||||
|     CodeInputFailCallback fail_callback; | ||||
|     void* callback_context; | ||||
| 
 | ||||
|     const char* header; | ||||
| 
 | ||||
|     uint8_t* ext_buffer; | ||||
|     uint8_t* ext_buffer_length; | ||||
| } CodeInputModel; | ||||
| 
 | ||||
| static const Icon* keys_assets[] = { | ||||
|     [InputKeyUp] = &I_ButtonUp_7x4, | ||||
|     [InputKeyDown] = &I_ButtonDown_7x4, | ||||
|     [InputKeyRight] = &I_ButtonRight_4x7, | ||||
|     [InputKeyLeft] = &I_ButtonLeft_4x7, | ||||
| }; | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Compare buffers | ||||
|  *  | ||||
|  * @param in Input buffer pointer | ||||
|  * @param len_in Input array length | ||||
|  * @param src Source buffer pointer | ||||
|  * @param len_src Source array length | ||||
|  */ | ||||
| 
 | ||||
| bool code_input_compare(uint8_t* in, size_t len_in, uint8_t* src, size_t len_src) { | ||||
|     bool result = false; | ||||
|     do { | ||||
|         result = (len_in && len_src); | ||||
|         if(!result) { | ||||
|             break; | ||||
|         } | ||||
|         result = (len_in == len_src); | ||||
|         if(!result) { | ||||
|             break; | ||||
|         } | ||||
|         for(size_t i = 0; i < len_in; i++) { | ||||
|             result = (in[i] == src[i]); | ||||
|             if(!result) { | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } while(false); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Compare local buffers | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static bool code_input_compare_local(CodeInputModel* model) { | ||||
|     uint8_t* source = model->local_buffer[CodeInputFirst]; | ||||
|     size_t source_length = model->input_length[CodeInputFirst]; | ||||
| 
 | ||||
|     uint8_t* input = model->local_buffer[CodeInputSecond]; | ||||
|     size_t input_length = model->input_length[CodeInputSecond]; | ||||
| 
 | ||||
|     return code_input_compare(input, input_length, source, source_length); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Compare ext with local | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static bool code_input_compare_ext(CodeInputModel* model) { | ||||
|     uint8_t* input = model->local_buffer[CodeInputFirst]; | ||||
|     size_t input_length = model->input_length[CodeInputFirst]; | ||||
| 
 | ||||
|     uint8_t* source = model->ext_buffer; | ||||
|     size_t source_length = *model->ext_buffer_length; | ||||
| 
 | ||||
|     return code_input_compare(input, input_length, source, source_length); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Set ext buffer | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static void code_input_set_ext(CodeInputModel* model) { | ||||
|     *model->ext_buffer_length = model->input_length[CodeInputFirst]; | ||||
|     for(size_t i = 0; i <= model->input_length[CodeInputFirst]; i++) { | ||||
|         model->ext_buffer[i] = model->local_buffer[CodeInputFirst][i]; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Draw input sequence | ||||
|  *  | ||||
|  * @param canvas  | ||||
|  * @param buffer  | ||||
|  * @param length  | ||||
|  * @param x  | ||||
|  * @param y  | ||||
|  * @param active | ||||
|  */ | ||||
| static void code_input_draw_sequence( | ||||
|     Canvas* canvas, | ||||
|     uint8_t* buffer, | ||||
|     uint8_t length, | ||||
|     uint8_t x, | ||||
|     uint8_t y, | ||||
|     bool active) { | ||||
|     uint8_t pos_x = x + 6; | ||||
|     uint8_t pos_y = y + 3; | ||||
| 
 | ||||
|     if(active) canvas_draw_icon(canvas, x - 4, y + 5, &I_ButtonRightSmall_3x5); | ||||
| 
 | ||||
|     elements_slightly_rounded_frame(canvas, x, y, 116, 15); | ||||
| 
 | ||||
|     for(size_t i = 0; i < length; i++) { | ||||
|         // maybe symmetrical assets? :-/
 | ||||
|         uint8_t offset_y = buffer[i] < 2 ? 2 + (buffer[i] * 2) : 1; | ||||
|         canvas_draw_icon(canvas, pos_x, pos_y + offset_y, keys_assets[buffer[i]]); | ||||
|         pos_x += buffer[i] > 1 ? 9 : 11; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reset input count | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static void code_input_reset_count(CodeInputModel* model) { | ||||
|     model->input_length[model->current] = 0; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Call input callback | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static void code_input_call_ok_callback(CodeInputModel* model) { | ||||
|     if(model->ok_callback != NULL) { | ||||
|         model->ok_callback(model->callback_context); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Call changed callback | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static void code_input_call_fail_callback(CodeInputModel* model) { | ||||
|     if(model->fail_callback != NULL) { | ||||
|         model->fail_callback(model->callback_context); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Handle Back button | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static bool code_input_handle_back(CodeInputModel* model) { | ||||
|     if(model->current && !model->input_length[model->current]) { | ||||
|         --model->current; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     if(model->input_length[model->current]) { | ||||
|         code_input_reset_count(model); | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     code_input_call_fail_callback(model); | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Handle OK button | ||||
|  *  | ||||
|  * @param model  | ||||
|  */ | ||||
| static void code_input_handle_ok(CodeInputModel* model) { | ||||
|     switch(model->state) { | ||||
|     case CodeInputStateVerify: | ||||
| 
 | ||||
|         if(code_input_compare_ext(model)) { | ||||
|             if(model->ext_update) { | ||||
|                 model->state = CodeInputStateUpdate; | ||||
|             } else { | ||||
|                 code_input_call_ok_callback(model); | ||||
|             } | ||||
|         } | ||||
|         code_input_reset_count(model); | ||||
|         break; | ||||
| 
 | ||||
|     case CodeInputStateUpdate: | ||||
| 
 | ||||
|         if(!model->current && model->input_length[model->current]) { | ||||
|             model->current++; | ||||
|         } else { | ||||
|             if(code_input_compare_local(model)) { | ||||
|                 if(model->ext_update) { | ||||
|                     code_input_set_ext(model); | ||||
|                 } | ||||
|                 code_input_call_ok_callback(model); | ||||
|             } else { | ||||
|                 code_input_reset_count(model); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Handle input | ||||
|  *  | ||||
|  * @param model  | ||||
|  * @param key  | ||||
|  */ | ||||
| 
 | ||||
| size_t code_input_push(uint8_t* buffer, size_t length, InputKey key) { | ||||
|     buffer[length] = key; | ||||
|     length = CLAMP(length + 1, MAX_CODE_LEN, 0); | ||||
|     return length; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Handle D-pad keys | ||||
|  *  | ||||
|  * @param model  | ||||
|  * @param key  | ||||
|  */ | ||||
| static void code_input_handle_dpad(CodeInputModel* model, InputKey key) { | ||||
|     uint8_t at = model->current; | ||||
|     size_t new_length = code_input_push(model->local_buffer[at], model->input_length[at], key); | ||||
|     model->input_length[at] = new_length; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Draw callback | ||||
|  *  | ||||
|  * @param canvas  | ||||
|  * @param _model  | ||||
|  */ | ||||
| static void code_input_view_draw_callback(Canvas* canvas, void* _model) { | ||||
|     CodeInputModel* model = _model; | ||||
|     uint8_t y_offset = 0; | ||||
|     canvas_clear(canvas); | ||||
|     canvas_set_color(canvas, ColorBlack); | ||||
| 
 | ||||
|     if(model->header && strlen(model->header)) { | ||||
|         canvas_draw_str(canvas, 2, 9, model->header); | ||||
|     } else { | ||||
|         y_offset = 4; | ||||
|     } | ||||
| 
 | ||||
|     canvas_set_font(canvas, FontSecondary); | ||||
| 
 | ||||
|     switch(model->state) { | ||||
|     case CodeInputStateVerify: | ||||
|         code_input_draw_sequence( | ||||
|             canvas, | ||||
|             model->local_buffer[CodeInputFirst], | ||||
|             model->input_length[CodeInputFirst], | ||||
|             6, | ||||
|             30 + y_offset, | ||||
|             true); | ||||
|         break; | ||||
|     case CodeInputStateUpdate: | ||||
|         code_input_draw_sequence( | ||||
|             canvas, | ||||
|             model->local_buffer[CodeInputFirst], | ||||
|             model->input_length[CodeInputFirst], | ||||
|             6, | ||||
|             14 + y_offset, | ||||
|             !model->current); | ||||
|         code_input_draw_sequence( | ||||
|             canvas, | ||||
|             model->local_buffer[CodeInputSecond], | ||||
|             model->input_length[CodeInputSecond], | ||||
|             6, | ||||
|             44 + y_offset, | ||||
|             model->current); | ||||
| 
 | ||||
|         if(model->current) canvas_draw_str(canvas, 2, 39 + y_offset, "Repeat code"); | ||||
| 
 | ||||
|         break; | ||||
|     default: | ||||
|         break; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Input callback | ||||
|  *  | ||||
|  * @param event  | ||||
|  * @param context  | ||||
|  * @return true  | ||||
|  * @return false  | ||||
|  */ | ||||
| static bool code_input_view_input_callback(InputEvent* event, void* context) { | ||||
|     CodeInput* code_input = context; | ||||
|     furi_assert(code_input); | ||||
|     bool consumed = false; | ||||
| 
 | ||||
|     if(event->type == InputTypeShort || event->type == InputTypeRepeat) { | ||||
|         switch(event->key) { | ||||
|         case InputKeyBack: | ||||
|             with_view_model( | ||||
|                 code_input->view, (CodeInputModel * model) { | ||||
|                     consumed = code_input_handle_back(model); | ||||
|                     return true; | ||||
|                 }); | ||||
|             break; | ||||
| 
 | ||||
|         case InputKeyOk: | ||||
|             with_view_model( | ||||
|                 code_input->view, (CodeInputModel * model) { | ||||
|                     code_input_handle_ok(model); | ||||
|                     return true; | ||||
|                 }); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         default: | ||||
| 
 | ||||
|             with_view_model( | ||||
|                 code_input->view, (CodeInputModel * model) { | ||||
|                     code_input_handle_dpad(model, event->key); | ||||
|                     return true; | ||||
|                 }); | ||||
|             consumed = true; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     return consumed; | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Reset all input-related data in model | ||||
|  *  | ||||
|  * @param model CodeInputModel | ||||
|  */ | ||||
| static void code_input_reset_model_input_data(CodeInputModel* model) { | ||||
|     model->current = 0; | ||||
|     model->input_length[CodeInputFirst] = 0; | ||||
|     model->input_length[CodeInputSecond] = 0; | ||||
|     model->ext_buffer = NULL; | ||||
|     model->ext_update = false; | ||||
|     model->state = 0; | ||||
| } | ||||
| 
 | ||||
| /** 
 | ||||
|  * @brief Allocate and initialize code input. This code input is used to enter codes. | ||||
|  *  | ||||
|  * @return CodeInput instance pointer | ||||
|  */ | ||||
| CodeInput* code_input_alloc() { | ||||
|     CodeInput* code_input = furi_alloc(sizeof(CodeInput)); | ||||
|     code_input->view = view_alloc(); | ||||
|     view_set_context(code_input->view, code_input); | ||||
|     view_allocate_model(code_input->view, ViewModelTypeLocking, sizeof(CodeInputModel)); | ||||
|     view_set_draw_callback(code_input->view, code_input_view_draw_callback); | ||||
|     view_set_input_callback(code_input->view, code_input_view_input_callback); | ||||
| 
 | ||||
|     with_view_model( | ||||
|         code_input->view, (CodeInputModel * model) { | ||||
|             model->header = ""; | ||||
|             model->ok_callback = NULL; | ||||
|             model->fail_callback = NULL; | ||||
|             model->callback_context = NULL; | ||||
|             code_input_reset_model_input_data(model); | ||||
|             return true; | ||||
|         }); | ||||
| 
 | ||||
|     return code_input; | ||||
| } | ||||
| 
 | ||||
| /** 
 | ||||
|  * @brief Deinitialize and free code input | ||||
|  *  | ||||
|  * @param code_input Code input instance | ||||
|  */ | ||||
| void code_input_free(CodeInput* code_input) { | ||||
|     furi_assert(code_input); | ||||
|     view_free(code_input->view); | ||||
|     free(code_input); | ||||
| } | ||||
| 
 | ||||
| /** 
 | ||||
|  * @brief Get code input view | ||||
|  *  | ||||
|  * @param code_input code input instance | ||||
|  * @return View instance that can be used for embedding | ||||
|  */ | ||||
| View* code_input_get_view(CodeInput* code_input) { | ||||
|     furi_assert(code_input); | ||||
|     return code_input->view; | ||||
| } | ||||
| 
 | ||||
| /** 
 | ||||
|  * @brief Set code input callbacks | ||||
|  *  | ||||
|  * @param code_input code input instance | ||||
|  * @param ok_callback input callback fn | ||||
|  * @param fail_callback code match callback fn | ||||
|  * @param callback_context callback context | ||||
|  * @param buffer buffer  | ||||
|  * @param buffer_length ptr to buffer length uint | ||||
|  * @param ext_update  true to update buffer  | ||||
|  */ | ||||
| void code_input_set_result_callback( | ||||
|     CodeInput* code_input, | ||||
|     CodeInputOkCallback ok_callback, | ||||
|     CodeInputFailCallback fail_callback, | ||||
|     void* callback_context, | ||||
|     uint8_t* buffer, | ||||
|     uint8_t* buffer_length, | ||||
|     bool ext_update) { | ||||
|     with_view_model( | ||||
|         code_input->view, (CodeInputModel * model) { | ||||
|             code_input_reset_model_input_data(model); | ||||
|             model->ok_callback = ok_callback; | ||||
|             model->fail_callback = fail_callback; | ||||
|             model->callback_context = callback_context; | ||||
| 
 | ||||
|             model->ext_buffer = buffer; | ||||
|             model->ext_buffer_length = buffer_length; | ||||
|             model->state = (*buffer_length == 0) ? 1 : 0; | ||||
|             model->ext_update = ext_update; | ||||
| 
 | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * @brief Set code input header text | ||||
|  *  | ||||
|  * @param code_input code input instance | ||||
|  * @param text text to be shown | ||||
|  */ | ||||
| void code_input_set_header_text(CodeInput* code_input, const char* text) { | ||||
|     with_view_model( | ||||
|         code_input->view, (CodeInputModel * model) { | ||||
|             model->header = text; | ||||
|             return true; | ||||
|         }); | ||||
| } | ||||
| @ -1,91 +0,0 @@ | ||||
| /**
 | ||||
|  * @file code_input.h | ||||
|  * GUI: CodeInput keyboard view module API | ||||
|  */ | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <gui/view.h> | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| extern "C" { | ||||
| #endif | ||||
| 
 | ||||
| /** Code input anonymous structure  */ | ||||
| typedef struct CodeInput CodeInput; | ||||
| 
 | ||||
| /** callback that is executed when entered code matches ext buffer */ | ||||
| typedef void (*CodeInputOkCallback)(void* context); | ||||
| 
 | ||||
| /** callback that is executed when entered code does not matches ext buffer */ | ||||
| typedef void (*CodeInputFailCallback)(void* context); | ||||
| 
 | ||||
| /** Allocate and initialize code input. This code input is used to enter codes.
 | ||||
|  * | ||||
|  * @return     CodeInput instance pointer | ||||
|  */ | ||||
| CodeInput* code_input_alloc(); | ||||
| 
 | ||||
| /** Deinitialize and free code input
 | ||||
|  * | ||||
|  * @param      code_input  Code input instance | ||||
|  */ | ||||
| void code_input_free(CodeInput* code_input); | ||||
| 
 | ||||
| /** Get code input view
 | ||||
|  * | ||||
|  * @param      code_input  code input instance | ||||
|  * | ||||
|  * @return     View instance that can be used for embedding | ||||
|  */ | ||||
| View* code_input_get_view(CodeInput* code_input); | ||||
| 
 | ||||
| /** Set code input result callback
 | ||||
|  * | ||||
|  * @param      code_input        code input instance | ||||
|  * @param      ok_callback    ok callback fn | ||||
|  * @param      fail_callback  fail callback fn | ||||
|  * @param      callback_context  callback context | ||||
|  * @param      buffer       buffer to use | ||||
|  * @param      buffer_length       buffer length | ||||
|  * @param      update  set true to update buffer  | ||||
|  */ | ||||
| void code_input_set_result_callback( | ||||
|     CodeInput* code_input, | ||||
|     CodeInputOkCallback ok_callback, | ||||
|     CodeInputFailCallback fail_callback, | ||||
|     void* callback_context, | ||||
|     uint8_t* buffer, | ||||
|     uint8_t* buffer_length, | ||||
|     bool update); | ||||
| 
 | ||||
| /** Set code input header text
 | ||||
|  * | ||||
|  * @param      code_input  code input instance | ||||
|  * @param      text        text to be shown | ||||
|  */ | ||||
| void code_input_set_header_text(CodeInput* code_input, const char* text); | ||||
| 
 | ||||
| /** Compare two buffers
 | ||||
|  * | ||||
|  * @param      in       buffer to compare to source | ||||
|  * @param      len_in   length of input buffer | ||||
|  * @param      src      source buffer | ||||
|  * @param      len_src  length of insourceput buffer | ||||
|  * @return     true if buffers match | ||||
|  */ | ||||
| 
 | ||||
| bool code_input_compare(uint8_t* in, size_t len_in, uint8_t* src, size_t len_src); | ||||
| 
 | ||||
| /** Push input into the end of array
 | ||||
|  * | ||||
|  * @param      buffer   buffer | ||||
|  * @param      length   length of buffer | ||||
|  * @param      key      input key | ||||
|  * @return     new length of input buffer | ||||
|  */ | ||||
| size_t code_input_push(uint8_t* buffer, size_t length, InputKey key); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
| @ -1,3 +1,4 @@ | ||||
| #include "applications.h" | ||||
| #include <furi.h> | ||||
| #include "loader/loader.h" | ||||
| #include "loader_i.h" | ||||
| @ -79,6 +80,12 @@ const FlipperApplication* loader_find_application_by_name(const char* name) { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) { | ||||
|         if(strcmp(name, FLIPPER_SETTINGS_APPS[i].name) == 0) { | ||||
|             application = &FLIPPER_SETTINGS_APPS[i]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||
|         for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { | ||||
|             if(strcmp(name, FLIPPER_DEBUG_APPS[i].name) == 0) { | ||||
|  | ||||
| @ -205,9 +205,6 @@ const uint8_t *_I_DoorLocked_10x56[] = {_I_DoorLocked_10x56_0}; | ||||
| const uint8_t _I_DoorRight_70x55_0[] = {0x01,0x00,0x16,0x01,0x81,0xcc,0x01,0x0f,0x60,0x04,0x3f,0x00,0x10,0xf8,0x08,0x0c,0x02,0x05,0x01,0x84,0x02,0x06,0x26,0x0a,0x10,0x8a,0xcc,0xe0,0x1d,0x68,0xe0,0x18,0xab,0xd0,0x0b,0x18,0x10,0x46,0xe6,0x16,0x1e,0x18,0x10,0x46,0xe4,0x28,0x2c,0x98,0x14,0x68,0x00,0x21,0x1d,0x10,0x8c,0x40,0x02,0x0e,0x10,0xa1,0x08,0xc8,0x40,0x42,0x62,0x11,0x94,0x03,0xfd,0xff,0x00,0x0c,0xff,0x0c,0x08,0x28,0x60,0xe4,0xc0,0x85,0x00,0x83,0x00,0x87,0xf1,0x00,0x8c,0x02,0x0b,0x07,0x24,0x84,0xff,0x04,0xc7,0x80,0xa0,0xe4,0xa0,0x81,0x41,0x04,0x17,0x02,0x41,0x49,0x81,0x0e,0x10,0xb2,0xa0,0x82,0x0e,0x9f,0xfc,0x0a,0x62,0xf2,0xc0,0x03,0x92,0xf0,0x08,0x2d,0x78,0x20,0xff,0x02,0x01,0x08,0xae,0x60,0x64,0x38,0x0d,0xb0,0x8d,0x08,0x82,0x11,0x58,0xc4,0x13,0xc0,0x35,0x68,0x62,0x68,0x81,0x09,0x08,0x84,0x40,0x81,0x0d,0x18,0x69,0x10,0x47,0x44,0x66,0x5f,0x21,0xa9,0x29,0x94,0x10,0x2f,0x23,0x53,0x14,0x60,0x42,0x3c,0x08,0xfc,0x02,0x2c,0x62,0x23,0x58,0xd0,0x22,0x00,0x83,0x3e,0x98,0x44,0x43,0x46,0x22,0x30,0x89,0xce,0x01,0x0f,0x70,0x04,0x3f,0x81,0x8a,0x3c,0x21,0xaa,0x70,0x1a,0xe3,0x44,0x1a,0xa6,0x01,0xd2,0x38,0x90,0x8a,0x40,0x20,0xe5,0x96,0x80,0x43,0x81,0x06,0x6b,0x28,0x07,0xf3,0xfe,0x00,0x19,0xf9,0x34,0xc1,0x08,0x8f,0x20,0xf1,0x3e,0x16,0x00,0xa8,0x19,0x00,0x10,0x76,0x03,0xe2,0x3e,0x90,0x45,0x38,0x01,0x42,0x05,0x88,0x44,0x67,0x15,0x70,0x41,0x38,0x04,0x10,0x24,0x03,0x00,0x10,0x20,0x4a,0x46,0xe9,0x46,0xe1,0x04,0x50,0x66,0x40,0x85,0x19,0x98,0x00,0xc0,}; | ||||
| const uint8_t *_I_DoorRight_70x55[] = {_I_DoorRight_70x55_0}; | ||||
| 
 | ||||
| const uint8_t _I_LockPopup_100x49_0[] = {0x01,0x00,0x37,0x01,0xfc,0x7f,0xc0,0x13,0x01,0xfe,0x03,0x2a,0x07,0x06,0x12,0xd4,0x1a,0x06,0x0c,0xa8,0x60,0x33,0xe0,0x12,0x08,0x40,0x32,0x3f,0xd0,0x70,0x64,0xe0,0x20,0x31,0x8a,0x00,0x32,0x2c,0x10,0x0b,0x00,0x32,0x62,0x10,0x0c,0x06,0x00,0x19,0x00,0x82,0xc0,0x83,0x22,0x08,0x04,0x18,0x11,0x6a,0x01,0x25,0x02,0x84,0x83,0x1e,0x02,0x04,0x10,0xe1,0x03,0x1e,0x3c,0x0c,0x9c,0x1c,0x02,0x43,0x00,0x84,0x4f,0xc1,0x8f,0x80,0xaf,0x40,0x39,0x14,0x00,0x63,0xd0,0x36,0xf0,0x09,0xc6,0x00,0x18,0xd4,0x3a,0x06,0x9c,0x08,0x20,0xc9,0xdf,0xc0,0x20,0x7f,0x00,0x65,0x40,0x3f,0x80,0xc7,0xd0,0x10,0x06,0x01,0x7f,0x06,0x34,0x8e,0xa1,0x3d,0x80,0x70,0x0b,0x4f,0x23,0xd0,0x50,0xa0,0x1f,0x08,0x78,0x66,0x11,0xe3,0xfc,0x83,0x83,0x1e,0x40,0x0c,0x1f,0xfb,0xec,0x41,0x8c,0x03,0x1e,0x07,0x00,0x4d,0x10,0x0a,0x04,0xc0,0x9b,0x30,0x0c,0x1f,0xff,0xff,0x9f,0x06,0x3e,0x01,0x80,0x48,0xe7,0x99,0x83,0x0d,0x6a,0xe0,0xc4,0x90,0x03,0x1a,0x76,0x0c,0x38,0xe0,0x34,0x45,0x25,0x02,0x06,0x0d,0xe0,0x18,0x3c,0x08,0x19,0x40,0x78,0x00,0xc1,0x81,0xc3,0x27,0xf8,0x48,0x26,0x82,0x7d,0x00,0xfc,0x40,0xfc,0x10,0xfc,0x04,0xfc,0x18,0x30,0x28,0x7d,0x02,0x3f,0x00,0x98,0x41,0x38,0x31,0x08,0x25,0x0e,0x19,0x1f,0x81,0x42,0x70,0x11,0xa2,0x08,0xe2,0x30,0x72,0x08,0x76,0x0a,0x19,0x0f,0x85,0x42,0x60,0x11,0x51,0x78,0xc2,0x20,0x32,0x08,0x26,0x00,0x18,0x91,0x00,0x60,0x91,0x44,0x08,0x34,0x08,0x64,0x1f,0xe4,0x07,0x3f,0x84,0x0d,0x58,0x44,0x01,0x83,0xdc,0x60,0x43,0xe1,0x39,0xa9,0xd0,0x60,0x70,0x16,0x78,0xca,0x01,0x8f,0x83,0x3d,0x10,0x33,0x29,0x00,0xc7,0xa1,0x83,0x3f,0x10,0x0c,0x79,0x30,0x32,0xa0,0xdf,0xc7,0xa0,0x80,0x22,0x07,0xf8,0x06,0x54,0x04,}; | ||||
| const uint8_t *_I_LockPopup_100x49[] = {_I_LockPopup_100x49_0}; | ||||
| 
 | ||||
| const uint8_t _I_PassportBottom_128x17_0[] = {0x01,0x00,0x5e,0x00,0x96,0x01,0x97,0xe1,0xff,0x00,0x2e,0x3e,0x68,0x0f,0x5a,0xc5,0x54,0x00,0xb9,0x50,0xfb,0x6a,0x35,0x40,0x05,0xcd,0x4e,0x03,0xfd,0x30,0x0f,0xf8,0x7f,0xa0,0x81,0xfe,0xf9,0x1b,0xfb,0xf3,0x01,0x47,0x66,0x02,0x1b,0x03,0x07,0xe7,0x02,0x0b,0x02,0x07,0xe5,0x82,0x0b,0xf2,0x1c,0xb0,0x01,0x67,0xf0,0x5f,0xd0,0x3f,0x23,0xf0,0x9b,0xc9,0xe5,0x80,0x03,0xd5,0xc0,0x00,0x86,0x01,0xf3,0xe6,0x1e,0x58,0x00,0x36,0xa8,0x06,0xac,0x04,0x30,0x6c,0x30,0xee,0x60,0x1f,0xe0,0x10,0xff,0x0d,0xfb,0x00,}; | ||||
| const uint8_t *_I_PassportBottom_128x17[] = {_I_PassportBottom_128x17_0}; | ||||
| 
 | ||||
| @ -447,6 +444,36 @@ const uint8_t *_I_Detailed_chip_17x13[] = {_I_Detailed_chip_17x13_0}; | ||||
| const uint8_t _I_Medium_chip_22x21_0[] = {0x01,0x00,0x35,0x00,0xfe,0x7f,0xe1,0xf0,0x28,0x04,0x43,0xf3,0xff,0x93,0xe1,0x6a,0x52,0x8e,0x2f,0xfe,0x51,0x25,0x80,0x4a,0x72,0xb6,0x79,0x55,0x76,0xc1,0x2e,0xaa,0xc0,0x25,0x51,0xdc,0x00,0x14,0x70,0x00,0x56,0xae,0x81,0x47,0x2b,0x7d,0x95,0x07,0x48,0x46,0x42,0x92,0x17,0x90,0xd4,0x87,0x64,}; | ||||
| const uint8_t *_I_Medium_chip_22x21[] = {_I_Medium_chip_22x21_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_arrow_down_7x9_0[] = {0x00,0x1C,0x1C,0x1C,0x1C,0x1C,0x7F,0x3E,0x1C,0x08,}; | ||||
| const uint8_t *_I_Pin_arrow_down_7x9[] = {_I_Pin_arrow_down_7x9_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_arrow_left_9x7_0[] = {0x00,0x08,0x00,0x0C,0x00,0xFE,0x01,0xFF,0x01,0xFE,0x01,0x0C,0x00,0x08,0x00,}; | ||||
| const uint8_t *_I_Pin_arrow_left_9x7[] = {_I_Pin_arrow_left_9x7_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_arrow_right_9x7_0[] = {0x00,0x20,0x00,0x60,0x00,0xFF,0x00,0xFF,0x01,0xFF,0x00,0x60,0x00,0x20,0x00,}; | ||||
| const uint8_t *_I_Pin_arrow_right_9x7[] = {_I_Pin_arrow_right_9x7_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_arrow_up7x9_0[] = {0x00,0x08,0x1C,0x3E,0x7F,0x1C,0x1C,0x1C,0x1C,0x1C,}; | ||||
| const uint8_t *_I_Pin_arrow_up7x9[] = {_I_Pin_arrow_up7x9_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_attention_dpad_29x29_0[] = {0x01,0x00,0x56,0x00,0x80,0x7f,0x20,0xe0,0x31,0x81,0xc6,0x20,0x1c,0x08,0x05,0x82,0x01,0x20,0xa0,0x60,0x20,0x11,0x0f,0x04,0x02,0x03,0x08,0xf8,0x40,0x60,0x50,0x4f,0xc4,0x0e,0x09,0x04,0x05,0x8c,0x12,0x04,0x03,0x18,0x44,0x08,0x42,0x30,0x88,0x08,0x0c,0x62,0x14,0x18,0x05,0x02,0x21,0x61,0x14,0x8c,0x43,0xe3,0x01,0xf8,0x44,0x7f,0x20,0x31,0x89,0x81,0xcc,0x1e,0x61,0x73,0x0f,0x98,0x9c,0xc5,0xe6,0x37,0x31,0xf9,0x91,0xcc,0x9e,0x65,0x73,0x2f,0x99,0x9c,0xcd,0xe6,}; | ||||
| const uint8_t *_I_Pin_attention_dpad_29x29[] = {_I_Pin_attention_dpad_29x29_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_back_arrow_10x8_0[] = {0x00,0x04,0x00,0x06,0x00,0xFF,0x00,0x06,0x01,0x04,0x02,0x00,0x02,0x00,0x01,0xF8,0x00,}; | ||||
| const uint8_t *_I_Pin_back_arrow_10x8[] = {_I_Pin_back_arrow_10x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_back_full_40x8_0[] = {0x01,0x00,0x26,0x00,0x82,0x01,0x0e,0x0c,0x02,0x18,0x14,0x03,0xfe,0x04,0x38,0x37,0xc6,0xc3,0x32,0xf7,0x41,0x20,0x59,0x0a,0x54,0xa6,0x01,0xf2,0x88,0xde,0x80,0x83,0x01,0xc8,0x42,0xa5,0x3f,0x88,0x05,0x82,0x65,0x2e,}; | ||||
| const uint8_t *_I_Pin_back_full_40x8[] = {_I_Pin_back_full_40x8_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_cell_13x13_0[] = {0x01,0x00,0x0a,0x00,0xff,0xc7,0xe0,0x31,0x00,0x0f,0x80,0x4c,0x2e,0x20,}; | ||||
| const uint8_t *_I_Pin_cell_13x13[] = {_I_Pin_cell_13x13_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_pointer_5x3_0[] = {0x00,0x04,0x0E,0x1F,}; | ||||
| const uint8_t *_I_Pin_pointer_5x3[] = {_I_Pin_pointer_5x3_0}; | ||||
| 
 | ||||
| const uint8_t _I_Pin_star_7x7_0[] = {0x00,0x49,0x2A,0x1C,0x7F,0x1C,0x2A,0x49,}; | ||||
| const uint8_t *_I_Pin_star_7x7[] = {_I_Pin_star_7x7_0}; | ||||
| 
 | ||||
| const uint8_t _I_passport_bad1_46x49_0[] = {0x01,0x00,0xd2,0x00,0xff,0x7f,0xc0,0x05,0x1f,0x02,0x1f,0xfe,0x7e,0x02,0x18,0x0f,0xe0,0x0a,0x57,0xff,0xf7,0x9c,0x0a,0x59,0xf8,0x0e,0x60,0x0a,0x56,0xf8,0x05,0x83,0xfc,0x05,0x18,0xbc,0x03,0x01,0xfd,0x02,0x8c,0x2c,0x5a,0x3f,0xa0,0x28,0xc1,0x40,0xa3,0xf4,0x02,0x8c,0x08,0x0a,0x77,0xf8,0x08,0x14,0x7d,0x13,0xfd,0xf9,0x14,0x80,0xab,0xd0,0x9f,0xd7,0xe0,0x10,0x60,0x2a,0x42,0x20,0x1a,0x09,0xfc,0xbe,0x01,0x10,0x02,0xa5,0x9c,0x0a,0x78,0x0e,0x74,0x04,0x0a,0x31,0x7a,0x06,0x7a,0x06,0x05,0x39,0xb0,0x44,0x80,0xa3,0x7e,0x02,0xa5,0xf0,0x0a,0x78,0x0a,0x00,0x14,0xf8,0x13,0xf0,0x29,0xc8,0x07,0x66,0x70,0x11,0xd8,0xea,0xa7,0xf1,0xb2,0x99,0x4c,0x00,0xa9,0xc0,0x9f,0x01,0x4e,0x01,0x3d,0x02,0x8c,0x38,0x0a,0x33,0xa8,0x6c,0x02,0x62,0x05,0x19,0xa0,0x14,0x78,0x00,0x51,0x94,0x01,0x46,0x01,0x03,0x02,0xa4,0x30,0x0a,0x2a,0x02,0x98,0x7c,0x25,0x60,0x52,0xe0,0x43,0xe5,0x80,0x51,0xc0,0x27,0x46,0x51,0x09,0x05,0x88,0xc0,0x66,0x80,0x52,0xfe,0x40,0x27,0x60,0x52,0xf8,0x7f,0xe7,0xa0,0x52,0xe0,0x5f,0xe7,0xc0,0x52,0x80,0x6f,0xe7,0xe0,0x53,0xde,0x01,0x50,0xe2,0x20,0x5f,0x02,0xbf,0xfb,0xfe,0x00,0x28,0xf8,}; | ||||
| const uint8_t *_I_passport_bad1_46x49[] = {_I_passport_bad1_46x49_0}; | ||||
| 
 | ||||
| @ -685,7 +712,6 @@ const Icon I_Back3_45x8 = {.width=45,.height=8,.frame_count=1,.frame_rate=0,.fra | ||||
| const Icon I_DoorLeft_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorLeft_70x55}; | ||||
| const Icon I_DoorLocked_10x56 = {.width=10,.height=56,.frame_count=1,.frame_rate=0,.frames=_I_DoorLocked_10x56}; | ||||
| const Icon I_DoorRight_70x55 = {.width=70,.height=55,.frame_count=1,.frame_rate=0,.frames=_I_DoorRight_70x55}; | ||||
| const Icon I_LockPopup_100x49 = {.width=100,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_LockPopup_100x49}; | ||||
| const Icon I_PassportBottom_128x17 = {.width=128,.height=17,.frame_count=1,.frame_rate=0,.frames=_I_PassportBottom_128x17}; | ||||
| const Icon I_PassportLeft_6x47 = {.width=6,.height=47,.frame_count=1,.frame_rate=0,.frames=_I_PassportLeft_6x47}; | ||||
| const Icon I_WarningDolphin_45x42 = {.width=45,.height=42,.frame_count=1,.frame_rate=0,.frames=_I_WarningDolphin_45x42}; | ||||
| @ -733,6 +759,16 @@ const Icon A_U2F_14 = {.width=14,.height=14,.frame_count=4,.frame_rate=3,.frames | ||||
| const Icon A_iButton_14 = {.width=14,.height=14,.frame_count=7,.frame_rate=3,.frames=_A_iButton_14}; | ||||
| const Icon I_Detailed_chip_17x13 = {.width=17,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Detailed_chip_17x13}; | ||||
| const Icon I_Medium_chip_22x21 = {.width=22,.height=21,.frame_count=1,.frame_rate=0,.frames=_I_Medium_chip_22x21}; | ||||
| const Icon I_Pin_arrow_down_7x9 = {.width=7,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_down_7x9}; | ||||
| const Icon I_Pin_arrow_left_9x7 = {.width=9,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_left_9x7}; | ||||
| const Icon I_Pin_arrow_right_9x7 = {.width=9,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_right_9x7}; | ||||
| const Icon I_Pin_arrow_up7x9 = {.width=7,.height=9,.frame_count=1,.frame_rate=0,.frames=_I_Pin_arrow_up7x9}; | ||||
| const Icon I_Pin_attention_dpad_29x29 = {.width=29,.height=29,.frame_count=1,.frame_rate=0,.frames=_I_Pin_attention_dpad_29x29}; | ||||
| const Icon I_Pin_back_arrow_10x8 = {.width=10,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Pin_back_arrow_10x8}; | ||||
| const Icon I_Pin_back_full_40x8 = {.width=40,.height=8,.frame_count=1,.frame_rate=0,.frames=_I_Pin_back_full_40x8}; | ||||
| const Icon I_Pin_cell_13x13 = {.width=13,.height=13,.frame_count=1,.frame_rate=0,.frames=_I_Pin_cell_13x13}; | ||||
| const Icon I_Pin_pointer_5x3 = {.width=5,.height=3,.frame_count=1,.frame_rate=0,.frames=_I_Pin_pointer_5x3}; | ||||
| const Icon I_Pin_star_7x7 = {.width=7,.height=7,.frame_count=1,.frame_rate=0,.frames=_I_Pin_star_7x7}; | ||||
| const Icon I_passport_bad1_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad1_46x49}; | ||||
| const Icon I_passport_bad2_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad2_46x49}; | ||||
| const Icon I_passport_bad3_46x49 = {.width=46,.height=49,.frame_count=1,.frame_rate=0,.frames=_I_passport_bad3_46x49}; | ||||
|  | ||||
| @ -62,7 +62,6 @@ extern const Icon I_Back3_45x8; | ||||
| extern const Icon I_DoorLeft_70x55; | ||||
| extern const Icon I_DoorLocked_10x56; | ||||
| extern const Icon I_DoorRight_70x55; | ||||
| extern const Icon I_LockPopup_100x49; | ||||
| extern const Icon I_PassportBottom_128x17; | ||||
| extern const Icon I_PassportLeft_6x47; | ||||
| extern const Icon I_WarningDolphin_45x42; | ||||
| @ -110,6 +109,16 @@ extern const Icon A_U2F_14; | ||||
| extern const Icon A_iButton_14; | ||||
| extern const Icon I_Detailed_chip_17x13; | ||||
| extern const Icon I_Medium_chip_22x21; | ||||
| extern const Icon I_Pin_arrow_down_7x9; | ||||
| extern const Icon I_Pin_arrow_left_9x7; | ||||
| extern const Icon I_Pin_arrow_right_9x7; | ||||
| extern const Icon I_Pin_arrow_up7x9; | ||||
| extern const Icon I_Pin_attention_dpad_29x29; | ||||
| extern const Icon I_Pin_back_arrow_10x8; | ||||
| extern const Icon I_Pin_back_full_40x8; | ||||
| extern const Icon I_Pin_cell_13x13; | ||||
| extern const Icon I_Pin_pointer_5x3; | ||||
| extern const Icon I_Pin_star_7x7; | ||||
| extern const Icon I_passport_bad1_46x49; | ||||
| extern const Icon I_passport_bad2_46x49; | ||||
| extern const Icon I_passport_bad3_46x49; | ||||
|  | ||||
| Before Width: | Height: | Size: 577 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_arrow_down_7x9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_arrow_left_9x7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_arrow_right_9x7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_arrow_up7x9.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_attention_dpad_29x29.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_back_arrow_10x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_back_full_40x8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_cell_13x13.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_pointer_5x3.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/PIN/Pin_star_7x7.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 3.5 KiB | 
| @ -89,17 +89,17 @@ uint16_t furi_hal_power_insomnia_level() { | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_insomnia_enter() { | ||||
|     vTaskSuspendAll(); | ||||
|     FURI_CRITICAL_ENTER(); | ||||
|     furi_assert(furi_hal_power.insomnia < UINT8_MAX); | ||||
|     furi_hal_power.insomnia++; | ||||
|     xTaskResumeAll(); | ||||
|     FURI_CRITICAL_EXIT(); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_insomnia_exit() { | ||||
|     vTaskSuspendAll(); | ||||
|     FURI_CRITICAL_ENTER(); | ||||
|     furi_assert(furi_hal_power.insomnia > 0); | ||||
|     furi_hal_power.insomnia--; | ||||
|     xTaskResumeAll(); | ||||
|     FURI_CRITICAL_EXIT(); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_power_sleep_available() { | ||||
|  | ||||
| @ -163,3 +163,11 @@ void furi_hal_rtc_set_fault_data(uint32_t value) { | ||||
| uint32_t furi_hal_rtc_get_fault_data() { | ||||
|     return furi_hal_rtc_get_register(FuriHalRtcRegisterFaultData); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_rtc_set_pin_fails(uint32_t value) { | ||||
|     furi_hal_rtc_set_register(FuriHalRtcRegisterPinFails, value); | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_rtc_get_pin_fails() { | ||||
|     return furi_hal_rtc_get_register(FuriHalRtcRegisterPinFails); | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "furi_hal_version.h" | ||||
| #include "furi_hal_usb_i.h" | ||||
| #include "furi_hal_usb.h" | ||||
| #include <furi_hal_power.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include "usb.h" | ||||
| @ -189,6 +190,8 @@ static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { | ||||
|     if((usb_if_cur != NULL) && (usb_config.connected == true)) { | ||||
|         usb_config.connected = false; | ||||
|         usb_if_cur->suspend(&udev); | ||||
| 
 | ||||
|         furi_hal_power_insomnia_exit(); | ||||
|     } | ||||
|     if(callback != NULL) { | ||||
|         callback(FuriHalUsbStateEventSuspend, cb_ctx); | ||||
| @ -199,6 +202,8 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { | ||||
|     if((usb_if_cur != NULL) && (usb_config.connected == false)) { | ||||
|         usb_config.connected = true; | ||||
|         usb_if_cur->wakeup(&udev); | ||||
| 
 | ||||
|         furi_hal_power_insomnia_enter(); | ||||
|     } | ||||
|     if(callback != NULL) { | ||||
|         callback(FuriHalUsbStateEventWakeup, cb_ctx); | ||||
|  | ||||
| @ -89,17 +89,17 @@ uint16_t furi_hal_power_insomnia_level() { | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_insomnia_enter() { | ||||
|     vTaskSuspendAll(); | ||||
|     FURI_CRITICAL_ENTER(); | ||||
|     furi_assert(furi_hal_power.insomnia < UINT8_MAX); | ||||
|     furi_hal_power.insomnia++; | ||||
|     xTaskResumeAll(); | ||||
|     FURI_CRITICAL_EXIT(); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_power_insomnia_exit() { | ||||
|     vTaskSuspendAll(); | ||||
|     FURI_CRITICAL_ENTER(); | ||||
|     furi_assert(furi_hal_power.insomnia > 0); | ||||
|     furi_hal_power.insomnia--; | ||||
|     xTaskResumeAll(); | ||||
|     FURI_CRITICAL_EXIT(); | ||||
| } | ||||
| 
 | ||||
| bool furi_hal_power_sleep_available() { | ||||
|  | ||||
| @ -163,3 +163,11 @@ void furi_hal_rtc_set_fault_data(uint32_t value) { | ||||
| uint32_t furi_hal_rtc_get_fault_data() { | ||||
|     return furi_hal_rtc_get_register(FuriHalRtcRegisterFaultData); | ||||
| } | ||||
| 
 | ||||
| void furi_hal_rtc_set_pin_fails(uint32_t value) { | ||||
|     furi_hal_rtc_set_register(FuriHalRtcRegisterPinFails, value); | ||||
| } | ||||
| 
 | ||||
| uint32_t furi_hal_rtc_get_pin_fails() { | ||||
|     return furi_hal_rtc_get_register(FuriHalRtcRegisterPinFails); | ||||
| } | ||||
|  | ||||
| @ -1,6 +1,7 @@ | ||||
| #include "furi_hal_version.h" | ||||
| #include "furi_hal_usb_i.h" | ||||
| #include "furi_hal_usb.h" | ||||
| #include <furi_hal_power.h> | ||||
| #include <furi.h> | ||||
| 
 | ||||
| #include "usb.h" | ||||
| @ -189,6 +190,8 @@ static void susp_evt(usbd_device* dev, uint8_t event, uint8_t ep) { | ||||
|     if((usb_if_cur != NULL) && (usb_config.connected == true)) { | ||||
|         usb_config.connected = false; | ||||
|         usb_if_cur->suspend(&udev); | ||||
| 
 | ||||
|         furi_hal_power_insomnia_exit(); | ||||
|     } | ||||
|     if(callback != NULL) { | ||||
|         callback(FuriHalUsbStateEventSuspend, cb_ctx); | ||||
| @ -199,6 +202,8 @@ static void wkup_evt(usbd_device* dev, uint8_t event, uint8_t ep) { | ||||
|     if((usb_if_cur != NULL) && (usb_config.connected == false)) { | ||||
|         usb_config.connected = true; | ||||
|         usb_if_cur->wakeup(&udev); | ||||
| 
 | ||||
|         furi_hal_power_insomnia_enter(); | ||||
|     } | ||||
|     if(callback != NULL) { | ||||
|         callback(FuriHalUsbStateEventWakeup, cb_ctx); | ||||
|  | ||||
| @ -38,6 +38,7 @@ typedef enum { | ||||
|     FuriHalRtcRegisterSystemVersion, | ||||
|     FuriHalRtcRegisterLfsFingerprint, | ||||
|     FuriHalRtcRegisterFaultData, | ||||
|     FuriHalRtcRegisterPinFails, | ||||
| } FuriHalRtcRegister; | ||||
| 
 | ||||
| /** Initialize RTC subsystem */ | ||||
| @ -67,6 +68,10 @@ void furi_hal_rtc_set_fault_data(uint32_t value); | ||||
| 
 | ||||
| uint32_t furi_hal_rtc_get_fault_data(); | ||||
| 
 | ||||
| void furi_hal_rtc_set_pin_fails(uint32_t value); | ||||
| 
 | ||||
| uint32_t furi_hal_rtc_get_pin_fails(); | ||||
| 
 | ||||
| #ifdef __cplusplus | ||||
| } | ||||
| #endif | ||||
|  | ||||
 Albert Kharisov
						Albert Kharisov