[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)); |     OneShotView* view = furi_alloc(sizeof(OneShotView)); | ||||||
|     view->view = view_alloc(); |     view->view = view_alloc(); | ||||||
|     view->update_timer = |     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_allocate_model(view->view, ViewModelTypeLocking, sizeof(OneShotViewModel)); | ||||||
|     view_set_context(view->view, view); |     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 <storage/storage.h> | ||||||
| #include <assets_icons.h> | #include <assets_icons.h> | ||||||
| #include <gui/view_stack.h> | #include <gui/view_stack.h> | ||||||
| @ -12,23 +6,38 @@ | |||||||
| #include <portmacro.h> | #include <portmacro.h> | ||||||
| #include <stdint.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) { | static void desktop_lock_icon_callback(Canvas* canvas, void* context) { | ||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|     canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8); |     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); |     furi_assert(context); | ||||||
|     Desktop* desktop = (Desktop*)context; |     Desktop* desktop = (Desktop*)context; | ||||||
|     return scene_manager_handle_custom_event(desktop->scene_manager, event); |     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); |     furi_assert(context); | ||||||
|     Desktop* desktop = (Desktop*)context; |     Desktop* desktop = (Desktop*)context; | ||||||
|     return scene_manager_handle_back_event(desktop->scene_manager); |     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_alloc() { | ||||||
|     Desktop* desktop = furi_alloc(sizeof(Desktop)); |     Desktop* desktop = furi_alloc(sizeof(Desktop)); | ||||||
| 
 | 
 | ||||||
| @ -42,6 +51,8 @@ Desktop* desktop_alloc() { | |||||||
|     view_dispatcher_enable_queue(desktop->view_dispatcher); |     view_dispatcher_enable_queue(desktop->view_dispatcher); | ||||||
|     view_dispatcher_attach_to_gui( |     view_dispatcher_attach_to_gui( | ||||||
|         desktop->view_dispatcher, desktop->gui, ViewDispatcherTypeDesktop); |         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_event_callback_context(desktop->view_dispatcher, desktop); | ||||||
|     view_dispatcher_set_custom_event_callback( |     view_dispatcher_set_custom_event_callback( | ||||||
| @ -49,37 +60,60 @@ Desktop* desktop_alloc() { | |||||||
|     view_dispatcher_set_navigation_event_callback( |     view_dispatcher_set_navigation_event_callback( | ||||||
|         desktop->view_dispatcher, desktop_back_event_callback); |         desktop->view_dispatcher, desktop_back_event_callback); | ||||||
| 
 | 
 | ||||||
|     desktop->locked_view = desktop_locked_alloc(); |  | ||||||
|     desktop->lock_menu = desktop_lock_menu_alloc(); |     desktop->lock_menu = desktop_lock_menu_alloc(); | ||||||
|     desktop->debug_view = desktop_debug_alloc(); |     desktop->debug_view = desktop_debug_alloc(); | ||||||
|     desktop->first_start_view = desktop_first_start_alloc(); |     desktop->first_start_view = desktop_first_start_alloc(); | ||||||
|     desktop->hw_mismatch_popup = popup_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_stack = view_stack_alloc(); | ||||||
|     desktop->main_view = desktop_main_alloc(); |     desktop->main_view = desktop_main_alloc(); | ||||||
|     View* dolphin_view = animation_manager_get_animation_view(desktop->animation_manager); |     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, 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, 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( |     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( |     view_dispatcher_add_view( | ||||||
|         desktop->view_dispatcher, |         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)); |         desktop_lock_menu_get_view(desktop->lock_menu)); | ||||||
|     view_dispatcher_add_view( |     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( |     view_dispatcher_add_view( | ||||||
|         desktop->view_dispatcher, |         desktop->view_dispatcher, | ||||||
|         DesktopViewFirstStart, |         DesktopViewIdFirstStart, | ||||||
|         desktop_first_start_get_view(desktop->first_start_view)); |         desktop_first_start_get_view(desktop->first_start_view)); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         desktop->view_dispatcher, |         desktop->view_dispatcher, | ||||||
|         DesktopViewHwMismatch, |         DesktopViewIdHwMismatch, | ||||||
|         popup_get_view(desktop->hw_mismatch_popup)); |         popup_get_view(desktop->hw_mismatch_popup)); | ||||||
|     view_dispatcher_add_view( |     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
 |     // Lock icon
 | ||||||
|     desktop->lock_viewport = view_port_alloc(); |     desktop->lock_viewport = view_port_alloc(); | ||||||
|     view_port_set_width(desktop->lock_viewport, icon_get_width(&I_Lock_8x8)); |     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) { | void desktop_free(Desktop* desktop) { | ||||||
|     furi_assert(desktop); |     furi_assert(desktop); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewMain); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdMain); | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLockMenu); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLockMenu); | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLocked); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdLocked); | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewDebug); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdDebug); | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewFirstStart); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdFirstStart); | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewHwMismatch); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdHwMismatch); | ||||||
|     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewPinSetup); |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinInput); | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewIdPinTimeout); | ||||||
| 
 | 
 | ||||||
|     view_dispatcher_free(desktop->view_dispatcher); |     view_dispatcher_free(desktop->view_dispatcher); | ||||||
|     scene_manager_free(desktop->scene_manager); |     scene_manager_free(desktop->scene_manager); | ||||||
| 
 | 
 | ||||||
|     animation_manager_free(desktop->animation_manager); |     animation_manager_free(desktop->animation_manager); | ||||||
|     view_stack_free(desktop->main_view_stack); |     view_stack_free(desktop->main_view_stack); | ||||||
|     view_stack_free(desktop->locked_view_stack); |  | ||||||
|     desktop_main_free(desktop->main_view); |     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_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_debug_free(desktop->debug_view); | ||||||
|     desktop_first_start_free(desktop->first_start_view); |     desktop_first_start_free(desktop->first_start_view); | ||||||
|     popup_free(desktop->hw_mismatch_popup); |     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); |     osSemaphoreDelete(desktop->unload_animation_semaphore); | ||||||
| 
 | 
 | ||||||
| @ -145,14 +181,18 @@ int32_t desktop_srv(void* p) { | |||||||
|         SAVE_DESKTOP_SETTINGS(&desktop->settings); |         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); |     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()) { |     if(desktop_is_first_start()) { | ||||||
|         scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); |         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 "desktop.h" | ||||||
| #include "animations/animation_manager.h" | #include "animations/animation_manager.h" | ||||||
| #include "views/desktop_main.h" | #include "views/desktop_view_pin_timeout.h" | ||||||
| #include "views/desktop_first_start.h" | #include "views/desktop_view_pin_input.h" | ||||||
| #include "views/desktop_lock_menu.h" | #include "views/desktop_view_locked.h" | ||||||
| #include "views/desktop_locked.h" | #include "views/desktop_view_main.h" | ||||||
| #include "views/desktop_debug.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 "desktop/desktop_settings/desktop_settings.h" | ||||||
| 
 | 
 | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| @ -14,21 +16,21 @@ | |||||||
| #include <gui/view_stack.h> | #include <gui/view_stack.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/modules/popup.h> | #include <gui/modules/popup.h> | ||||||
| #include <gui/modules/code_input.h> |  | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| 
 | 
 | ||||||
| #define STATUS_BAR_Y_SHIFT 13 | #define STATUS_BAR_Y_SHIFT 13 | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DesktopViewMain, |     DesktopViewIdMain, | ||||||
|     DesktopViewLockMenu, |     DesktopViewIdLockMenu, | ||||||
|     DesktopViewLocked, |     DesktopViewIdLocked, | ||||||
|     DesktopViewDebug, |     DesktopViewIdDebug, | ||||||
|     DesktopViewFirstStart, |     DesktopViewIdFirstStart, | ||||||
|     DesktopViewHwMismatch, |     DesktopViewIdHwMismatch, | ||||||
|     DesktopViewPinSetup, |     DesktopViewIdPinInput, | ||||||
|     DesktopViewTotal, |     DesktopViewIdPinTimeout, | ||||||
| } DesktopViewEnum; |     DesktopViewIdTotal, | ||||||
|  | } DesktopViewId; | ||||||
| 
 | 
 | ||||||
| struct Desktop { | struct Desktop { | ||||||
|     // Scene
 |     // Scene
 | ||||||
| @ -42,16 +44,15 @@ struct Desktop { | |||||||
|     Popup* hw_mismatch_popup; |     Popup* hw_mismatch_popup; | ||||||
|     DesktopLockMenuView* lock_menu; |     DesktopLockMenuView* lock_menu; | ||||||
|     DesktopDebugView* debug_view; |     DesktopDebugView* debug_view; | ||||||
|     CodeInput* code_input; |     DesktopViewLocked* locked_view; | ||||||
| 
 |  | ||||||
|     DesktopMainView* main_view; |     DesktopMainView* main_view; | ||||||
|     DesktopLockedView* locked_view; |     DesktopViewPinTimeout* pin_timeout_view; | ||||||
| 
 | 
 | ||||||
|     ViewStack* main_view_stack; |     ViewStack* main_view_stack; | ||||||
|     ViewStack* locked_view_stack; |     ViewStack* locked_view_stack; | ||||||
| 
 | 
 | ||||||
|     DesktopSettings settings; |     DesktopSettings settings; | ||||||
|     PinCode pincode_buffer; |     DesktopViewPinInput* pin_input_view; | ||||||
| 
 | 
 | ||||||
|     ViewPort* lock_viewport; |     ViewPort* lock_viewport; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,5 +1,6 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
|  | #include <furi_hal.h> | ||||||
| #include <stdint.h> | #include <stdint.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
| #include <toolbox/saved_struct.h> | #include <toolbox/saved_struct.h> | ||||||
| @ -9,6 +10,8 @@ | |||||||
| #define DESKTOP_SETTINGS_MAGIC (0x17) | #define DESKTOP_SETTINGS_MAGIC (0x17) | ||||||
| #define PIN_MAX_LENGTH 12 | #define PIN_MAX_LENGTH 12 | ||||||
| 
 | 
 | ||||||
|  | #define DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG "run_pin_setup" | ||||||
|  | 
 | ||||||
| #define SAVE_DESKTOP_SETTINGS(x) \ | #define SAVE_DESKTOP_SETTINGS(x) \ | ||||||
|     saved_struct_save(           \ |     saved_struct_save(           \ | ||||||
|         DESKTOP_SETTINGS_PATH,   \ |         DESKTOP_SETTINGS_PATH,   \ | ||||||
| @ -25,12 +28,27 @@ | |||||||
|         DESKTOP_SETTINGS_MAGIC,  \ |         DESKTOP_SETTINGS_MAGIC,  \ | ||||||
|         DESKTOP_SETTINGS_VER) |         DESKTOP_SETTINGS_VER) | ||||||
| 
 | 
 | ||||||
|  | #define MAX_PIN_SIZE 10 | ||||||
|  | #define MIN_PIN_SIZE 4 | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|  |     InputKey data[MAX_PIN_SIZE]; | ||||||
|     uint8_t length; |     uint8_t length; | ||||||
|     uint8_t data[PIN_MAX_LENGTH]; |  | ||||||
| } PinCode; | } PinCode; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint16_t favorite; |     uint16_t favorite; | ||||||
|     PinCode pincode; |     PinCode pin_code; | ||||||
| } DesktopSettings; | } 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 <furi.h> | ||||||
|  | #include <gui/modules/popup.h> | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | 
 | ||||||
|  | #include "desktop_settings_app.h" | ||||||
| #include "scenes/desktop_settings_scene.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) { | static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
| @ -30,17 +34,28 @@ DesktopSettingsApp* desktop_settings_app_alloc() { | |||||||
| 
 | 
 | ||||||
|     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); |     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||||
| 
 | 
 | ||||||
|  |     app->popup = popup_alloc(); | ||||||
|     app->submenu = submenu_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( |     view_dispatcher_add_view( | ||||||
|         app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu)); |         app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu)); | ||||||
| 
 |     view_dispatcher_add_view( | ||||||
|     app->code_input = code_input_alloc(); |         app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup)); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         app->view_dispatcher, |         app->view_dispatcher, | ||||||
|         DesktopSettingsAppViewPincodeInput, |         DesktopSettingsAppViewIdPinInput, | ||||||
|         code_input_get_view(app->code_input)); |         desktop_view_pin_input_get_view(app->pin_input_view)); | ||||||
| 
 |     view_dispatcher_add_view( | ||||||
|     scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); |         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; |     return app; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -48,9 +63,15 @@ void desktop_settings_app_free(DesktopSettingsApp* app) { | |||||||
|     furi_assert(app); |     furi_assert(app); | ||||||
|     // Variable item list
 |     // Variable item list
 | ||||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu); |     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); |     submenu_free(app->submenu); | ||||||
|     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewPincodeInput); |     popup_free(app->popup); | ||||||
|     code_input_free(app->code_input); |     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
 | ||||||
|     view_dispatcher_free(app->view_dispatcher); |     view_dispatcher_free(app->view_dispatcher); | ||||||
|     scene_manager_free(app->scene_manager); |     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) { | extern int32_t desktop_settings_app(void* p) { | ||||||
|     DesktopSettingsApp* app = desktop_settings_app_alloc(); |     DesktopSettingsApp* app = desktop_settings_app_alloc(); | ||||||
|     LOAD_DESKTOP_SETTINGS(&app->settings); |     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); |     view_dispatcher_run(app->view_dispatcher); | ||||||
|     desktop_settings_app_free(app); |     desktop_settings_app_free(app); | ||||||
|     return 0; |     return 0; | ||||||
|  | |||||||
| @ -1,22 +1,22 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <gui/gui.h> | #include <gui/gui.h> | ||||||
|  | #include <gui/modules/popup.h> | ||||||
| #include <gui/view_dispatcher.h> | #include <gui/view_dispatcher.h> | ||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <gui/modules/submenu.h> | #include <gui/modules/submenu.h> | ||||||
| #include <gui/modules/code_input.h> |  | ||||||
| 
 | 
 | ||||||
| #include "desktop_settings.h" | #include "desktop_settings.h" | ||||||
| 
 | #include "desktop/views/desktop_view_pin_input.h" | ||||||
| typedef enum { | #include "views/desktop_settings_view_pin_setup_howto.h" | ||||||
|     CodeEventsSetPin, | #include "views/desktop_settings_view_pin_setup_howto2.h" | ||||||
|     CodeEventsChangePin, |  | ||||||
|     CodeEventsDisablePin, |  | ||||||
| } CodeEventsEnum; |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DesktopSettingsAppViewMenu, |     DesktopSettingsAppViewMenu, | ||||||
|     DesktopSettingsAppViewPincodeInput, |     DesktopSettingsAppViewIdPopup, | ||||||
|  |     DesktopSettingsAppViewIdPinInput, | ||||||
|  |     DesktopSettingsAppViewIdPinSetupHowto, | ||||||
|  |     DesktopSettingsAppViewIdPinSetupHowto2, | ||||||
| } DesktopSettingsAppView; | } DesktopSettingsAppView; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -26,7 +26,13 @@ typedef struct { | |||||||
|     SceneManager* scene_manager; |     SceneManager* scene_manager; | ||||||
|     ViewDispatcher* view_dispatcher; |     ViewDispatcher* view_dispatcher; | ||||||
|     Submenu* submenu; |     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; |     uint8_t menu_idx; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,4 +1,11 @@ | |||||||
| ADD_SCENE(desktop_settings, start, Start) | ADD_SCENE(desktop_settings, start, Start) | ||||||
| ADD_SCENE(desktop_settings, favorite, Favorite) | ADD_SCENE(desktop_settings, favorite, Favorite) | ||||||
| ADD_SCENE(desktop_settings, pincode_menu, PinCodeMenu) | ADD_SCENE(desktop_settings, pin_menu, PinMenu) | ||||||
| ADD_SCENE(desktop_settings, pincode_input, PinCodeInput) | 
 | ||||||
|  | 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 <gui/scene_manager.h> | ||||||
| #include "applications.h" | #include <applications.h> | ||||||
| #include "desktop_settings_scene.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; |     DesktopSettingsApp* app = context; | ||||||
|     view_dispatcher_send_custom_event(app->view_dispatcher, index); |     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; |     DesktopSettingsApp* app = context; | ||||||
|     Submenu* submenu = app->submenu; |     Submenu* submenu = app->submenu; | ||||||
|     submenu_reset(submenu); |     submenu_reset(submenu); | ||||||
| 
 | 
 | ||||||
|     if(!app->settings.pincode.length) { |     if(!app->settings.pin_code.length) { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Set Pin", |             "Set Pin", | ||||||
|             CodeEventsSetPin, |             SCENE_EVENT_SET_PIN, | ||||||
|             desktop_settings_scene_pincode_menu_submenu_callback, |             desktop_settings_scene_pin_menu_submenu_callback, | ||||||
|             app); |             app); | ||||||
| 
 | 
 | ||||||
|     } else { |     } else { | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Change Pin", |             "Change Pin", | ||||||
|             CodeEventsChangePin, |             SCENE_EVENT_CHANGE_PIN, | ||||||
|             desktop_settings_scene_pincode_menu_submenu_callback, |             desktop_settings_scene_pin_menu_submenu_callback, | ||||||
|             app); |             app); | ||||||
| 
 | 
 | ||||||
|         submenu_add_item( |         submenu_add_item( | ||||||
|             submenu, |             submenu, | ||||||
|             "Disable", |             "Disable", | ||||||
|             CodeEventsDisablePin, |             SCENE_EVENT_DISABLE_PIN, | ||||||
|             desktop_settings_scene_pincode_menu_submenu_callback, |             desktop_settings_scene_pin_menu_submenu_callback, | ||||||
|             app); |             app); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -41,28 +48,28 @@ void desktop_settings_scene_pincode_menu_on_enter(void* context) { | |||||||
|     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu); |     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; |     DesktopSettingsApp* app = context; | ||||||
|     bool consumed = false; |     bool consumed = false; | ||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case CodeEventsSetPin: |         case SCENE_EVENT_SET_PIN: | ||||||
|             scene_manager_set_scene_state( |             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto); | ||||||
|                 app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event); |  | ||||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput); |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case CodeEventsChangePin: |         case SCENE_EVENT_CHANGE_PIN: | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event); |                 app->scene_manager, | ||||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput); |                 DesktopSettingsAppScenePinAuth, | ||||||
|  |                 SCENE_STATE_PIN_AUTH_CHANGE_PIN); | ||||||
|  |             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case CodeEventsDisablePin: |         case SCENE_EVENT_DISABLE_PIN: | ||||||
|             scene_manager_set_scene_state( |             scene_manager_set_scene_state( | ||||||
|                 app->scene_manager, DesktopSettingsAppScenePinCodeInput, event.event); |                 app->scene_manager, DesktopSettingsAppScenePinAuth, SCENE_STATE_PIN_AUTH_DISABLE); | ||||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeInput); |             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         default: |         default: | ||||||
| @ -73,7 +80,7 @@ bool desktop_settings_scene_pincode_menu_on_event(void* context, SceneManagerEve | |||||||
|     return consumed; |     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; |     DesktopSettingsApp* app = context; | ||||||
|     submenu_reset(app->submenu); |     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 "../desktop_settings_app.h" | ||||||
| #include "applications.h" |  | ||||||
| #include "desktop_settings_scene.h" | #include "desktop_settings_scene.h" | ||||||
| 
 | 
 | ||||||
| enum DesktopSettingsStartSubmenuIndex { | #define SCENE_EVENT_SELECT_FAVORITE 0 | ||||||
|     DesktopSettingsStartSubmenuIndexFavorite, | #define SCENE_EVENT_SELECT_PIN_SETUP 1 | ||||||
|     DesktopSettingsStartSubmenuIndexPinSetup, |  | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) { | static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) { | ||||||
|     DesktopSettingsApp* app = context; |     DesktopSettingsApp* app = context; | ||||||
| @ -19,14 +18,14 @@ void desktop_settings_scene_start_on_enter(void* context) { | |||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, |         submenu, | ||||||
|         "Favorite App", |         "Favorite App", | ||||||
|         DesktopSettingsStartSubmenuIndexFavorite, |         SCENE_EVENT_SELECT_FAVORITE, | ||||||
|         desktop_settings_scene_start_submenu_callback, |         desktop_settings_scene_start_submenu_callback, | ||||||
|         app); |         app); | ||||||
| 
 | 
 | ||||||
|     submenu_add_item( |     submenu_add_item( | ||||||
|         submenu, |         submenu, | ||||||
|         "PIN Setup", |         "PIN Setup", | ||||||
|         DesktopSettingsStartSubmenuIndexPinSetup, |         SCENE_EVENT_SELECT_PIN_SETUP, | ||||||
|         desktop_settings_scene_start_submenu_callback, |         desktop_settings_scene_start_submenu_callback, | ||||||
|         app); |         app); | ||||||
| 
 | 
 | ||||||
| @ -39,12 +38,12 @@ bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent even | |||||||
| 
 | 
 | ||||||
|     if(event.type == SceneManagerEventTypeCustom) { |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|         switch(event.event) { |         switch(event.event) { | ||||||
|         case DesktopSettingsStartSubmenuIndexFavorite: |         case SCENE_EVENT_SELECT_FAVORITE: | ||||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); |             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopSettingsStartSubmenuIndexPinSetup: |         case SCENE_EVENT_SELECT_PIN_SETUP: | ||||||
|             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinCodeMenu); |             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             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, debug, Debug) | ||||||
| ADD_SCENE(desktop, first_start, FirstStart) | ADD_SCENE(desktop, first_start, FirstStart) | ||||||
| ADD_SCENE(desktop, hw_mismatch, HwMismatch) | ADD_SCENE(desktop, hw_mismatch, HwMismatch) | ||||||
| ADD_SCENE(desktop, pinsetup, PinSetup) |  | ||||||
| ADD_SCENE(desktop, fault, Fault) | 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 <dolphin/helpers/dolphin_deed.h> | ||||||
| 
 | 
 | ||||||
| #include "../desktop_i.h" | #include "../desktop_i.h" | ||||||
| #include "../views/desktop_debug.h" | #include "../views/desktop_view_debug.h" | ||||||
| #include "desktop_scene.h" | #include "desktop_scene.h" | ||||||
| 
 | 
 | ||||||
| void desktop_scene_debug_callback(DesktopEvent event, void* context) { | 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_get_dolphin_data(desktop->debug_view); | ||||||
| 
 | 
 | ||||||
|     desktop_debug_set_callback(desktop->debug_view, desktop_scene_debug_callback, desktop); |     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) { | 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(); |     char* message = (char*)furi_hal_rtc_get_fault_data(); | ||||||
|     popup_set_text(popup, message, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); |     popup_set_text(popup, message, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); | ||||||
|     popup_set_callback(popup, desktop_scene_fault_callback); |     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) { | bool desktop_scene_fault_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <storage/storage.h> | #include <storage/storage.h> | ||||||
| 
 | 
 | ||||||
| #include "../desktop_i.h" | #include "../desktop_i.h" | ||||||
| #include "../views/desktop_first_start.h" | #include "../views/desktop_view_first_start.h" | ||||||
| #include "../views/desktop_events.h" | #include "../views/desktop_events.h" | ||||||
| 
 | 
 | ||||||
| void desktop_scene_first_start_callback(DesktopEvent event, void* context) { | 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( |     desktop_first_start_set_callback( | ||||||
|         first_start_view, desktop_scene_first_start_callback, desktop); |         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) { | bool desktop_scene_first_start_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -1,5 +1,5 @@ | |||||||
| #include <gui/scene_manager.h> | #include <gui/scene_manager.h> | ||||||
| #include <furi_hal_version.h> | #include <furi_hal.h> | ||||||
| 
 | 
 | ||||||
| #include "desktop_scene.h" | #include "desktop_scene.h" | ||||||
| #include "../desktop_i.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, "!!!! 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_text(popup, text_buffer, 60, 37 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignCenter); | ||||||
|     popup_set_callback(popup, desktop_scene_hw_mismatch_callback); |     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) { | bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event) { | ||||||
|  | |||||||
| @ -1,7 +1,4 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| typedef enum { | #define SCENE_LOCKED_FIRST_ENTER 0 | ||||||
|     DesktopMainSceneStateUnlocked, | #define SCENE_LOCKED_REPEAT_ENTER 1 | ||||||
|     DesktopMainSceneStateLockedWithPin, |  | ||||||
|     DesktopMainSceneStateLockedNoPin, |  | ||||||
| } DesktopMainSceneState; |  | ||||||
|  | |||||||
| @ -1,8 +1,13 @@ | |||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | #include <applications.h> | ||||||
|  | #include <furi_hal.h> | ||||||
| #include <toolbox/saved_struct.h> | #include <toolbox/saved_struct.h> | ||||||
| #include <stdbool.h> | #include <stdbool.h> | ||||||
|  | #include <loader/loader.h> | ||||||
| 
 | 
 | ||||||
| #include "../desktop_i.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_i.h" | ||||||
| #include "desktop_scene.h" | #include "desktop_scene.h" | ||||||
| 
 | 
 | ||||||
| @ -15,36 +20,50 @@ void desktop_scene_lock_menu_on_enter(void* context) { | |||||||
|     Desktop* desktop = (Desktop*)context; |     Desktop* desktop = (Desktop*)context; | ||||||
| 
 | 
 | ||||||
|     LOAD_DESKTOP_SETTINGS(&desktop->settings); |     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_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); |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdLockMenu); | ||||||
|     desktop_lock_menu_set_idx(desktop->lock_menu, idx); |  | ||||||
|     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLockMenu); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { | bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|     Desktop* desktop = (Desktop*)context; |     Desktop* desktop = (Desktop*)context; | ||||||
|     bool consumed = false; |     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) { |         switch(event.event) { | ||||||
|         case DesktopLockMenuEventLock: |         case DesktopLockMenuEventLock: | ||||||
|             scene_manager_set_scene_state( |  | ||||||
|                 desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedNoPin); |  | ||||||
|             scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 0); |             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; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopLockMenuEventPinLock: |         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( |                 scene_manager_set_scene_state( | ||||||
|                     desktop->scene_manager, DesktopSceneMain, DesktopMainSceneStateLockedWithPin); |                     desktop->scene_manager, DesktopSceneLocked, SCENE_LOCKED_FIRST_ENTER); | ||||||
|                 scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); |                 scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); | ||||||
|             } else { |             } else { | ||||||
|                 scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneLockMenu, 1); |                 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; |             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 <assets_icons.h> | ||||||
| #include <loader/loader.h> | #include <loader/loader.h> | ||||||
| 
 | 
 | ||||||
| #include "desktop/desktop_i.h" | #include "../desktop_i.h" | ||||||
| #include "desktop/views/desktop_main.h" | #include "../views/desktop_events.h" | ||||||
|  | #include "../views/desktop_view_main.h" | ||||||
| #include "desktop_scene.h" | #include "desktop_scene.h" | ||||||
| #include "desktop_scene_i.h" | #include "desktop_scene_i.h" | ||||||
| 
 | 
 | ||||||
| #define TAG "DesktopSrv" | #define TAG "DesktopSrv" | ||||||
| 
 | 
 | ||||||
| #define MAIN_VIEW_DEFAULT (0UL) |  | ||||||
| 
 |  | ||||||
| static void desktop_scene_main_app_started_callback(const void* message, void* context) { | static void desktop_scene_main_app_started_callback(const void* message, void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Desktop* desktop = 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) { | static void desktop_scene_main_new_idle_animation_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Desktop* desktop = 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) { | static void desktop_scene_main_check_animation_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Desktop* desktop = 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) { | static void desktop_scene_main_interact_animation_callback(void* context) { | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Desktop* desktop = 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) { | 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); |         desktop->animation_manager, desktop_scene_main_check_animation_callback); | ||||||
|     animation_manager_set_interact_callback( |     animation_manager_set_interact_callback( | ||||||
|         desktop->animation_manager, desktop_scene_main_interact_animation_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); |     furi_assert(osSemaphoreGetCount(desktop->unload_animation_semaphore) == 0); | ||||||
|     Loader* loader = furi_record_open("loader"); |     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); |     desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop); | ||||||
| 
 | 
 | ||||||
|     DesktopMainSceneState state = |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdMain); | ||||||
|         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); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | 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; |             consumed = true; | ||||||
|             break; |             break; | ||||||
| 
 | 
 | ||||||
|         case DesktopMainEventCheckAnimation: |         case DesktopAnimationEventCheckAnimation: | ||||||
|             animation_manager_check_blocking_process(desktop->animation_manager); |             animation_manager_check_blocking_process(desktop->animation_manager); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopMainEventNewIdleAnimation: |         case DesktopAnimationEventNewIdleAnimation: | ||||||
|             animation_manager_new_idle_process(desktop->animation_manager); |             animation_manager_new_idle_process(desktop->animation_manager); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopMainEventInteractAnimation: |         case DesktopAnimationEventInteractAnimation: | ||||||
|             animation_manager_interact_process(desktop->animation_manager); |             animation_manager_interact_process(desktop->animation_manager); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
| @ -175,16 +159,8 @@ bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | |||||||
|             animation_manager_load_and_continue_animation(desktop->animation_manager); |             animation_manager_load_and_continue_animation(desktop->animation_manager); | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             break; | ||||||
|         case DesktopMainEventUnlocked: |         case DesktopLockedEventUpdate: | ||||||
|             consumed = true; |             desktop_view_locked_update(desktop->locked_view); | ||||||
|             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); |  | ||||||
|             consumed = true; |             consumed = true; | ||||||
|             break; |             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_check_callback(desktop->animation_manager, NULL); | ||||||
|     animation_manager_set_interact_callback(desktop->animation_manager, NULL); |     animation_manager_set_interact_callback(desktop->animation_manager, NULL); | ||||||
|     animation_manager_set_context(desktop->animation_manager, desktop); |     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, |     DesktopMainEventOpenFavorite, | ||||||
|     DesktopMainEventOpenMenu, |     DesktopMainEventOpenMenu, | ||||||
|     DesktopMainEventOpenDebug, |     DesktopMainEventOpenDebug, | ||||||
|     DesktopMainEventUpdate, |  | ||||||
|     DesktopMainEventUnlocked, |  | ||||||
|     DesktopMainEventRightShort, |     DesktopMainEventRightShort, | ||||||
|     DesktopMainEventCheckAnimation, |  | ||||||
|     DesktopMainEventNewIdleAnimation, |  | ||||||
|     DesktopMainEventInteractAnimation, |  | ||||||
|     DesktopMainEventBeforeAppStarted, |     DesktopMainEventBeforeAppStarted, | ||||||
|     DesktopMainEventAfterAppFinished, |     DesktopMainEventAfterAppFinished, | ||||||
|     DesktopLockedEventUnlock, | 
 | ||||||
|     DesktopLockedEventCheckAnimation, |     DesktopLockedEventUnlocked, | ||||||
|     DesktopLockedEventMax, |     DesktopLockedEventUpdate, | ||||||
|  |     DesktopLockedEventShowPinInput, | ||||||
|  | 
 | ||||||
|  |     DesktopPinInputEventResetWrongPinLabel, | ||||||
|  |     DesktopPinInputEventUnlocked, | ||||||
|  |     DesktopPinInputEventUnlockFailed, | ||||||
|  |     DesktopPinInputEventBack, | ||||||
|  | 
 | ||||||
|  |     DesktopPinTimeoutExit, | ||||||
|  | 
 | ||||||
|     DesktopDebugEventDeed, |     DesktopDebugEventDeed, | ||||||
|     DesktopDebugEventWrongDeed, |     DesktopDebugEventWrongDeed, | ||||||
|     DesktopDebugEventSaveState, |     DesktopDebugEventSaveState, | ||||||
|     DesktopDebugEventExit, |     DesktopDebugEventExit, | ||||||
|  | 
 | ||||||
|     DesktopFirstStartCompleted, |     DesktopFirstStartCompleted, | ||||||
|     DesktopFirstStartPoweroff, |     DesktopFirstStartPoweroff, | ||||||
|  | 
 | ||||||
|     DesktopLockMenuEventLock, |     DesktopLockMenuEventLock, | ||||||
|     DesktopLockMenuEventPinLock, |     DesktopLockMenuEventPinLock, | ||||||
|     DesktopLockMenuEventExit, |     DesktopLockMenuEventExit, | ||||||
|  | 
 | ||||||
|  |     DesktopAnimationEventCheckAnimation, | ||||||
|  |     DesktopAnimationEventNewIdleAnimation, | ||||||
|  |     DesktopAnimationEventInteractAnimation, | ||||||
|  | 
 | ||||||
| } DesktopEvent; | } 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 <toolbox/version.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
|  | #include <dolphin/helpers/dolphin_state.h> | ||||||
|  | #include <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #include "../desktop_i.h" | #include "../desktop_i.h" | ||||||
| #include "desktop_debug.h" | #include "desktop_view_debug.h" | ||||||
| #include "dolphin/helpers/dolphin_state.h" |  | ||||||
| #include "dolphin/dolphin.h" |  | ||||||
| 
 | 
 | ||||||
| void desktop_debug_set_callback( | void desktop_debug_set_callback( | ||||||
|     DesktopDebugView* debug_view, |     DesktopDebugView* debug_view, | ||||||
| @ -1,8 +1,9 @@ | |||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi_hal.h> | #include <furi_hal.h> | ||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
|  | 
 | ||||||
| #include "../desktop_i.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_SHORT 5000 | ||||||
| #define DESKTOP_FIRST_START_POWEROFF_LONG (60 * 60 * 1000) | #define DESKTOP_FIRST_START_POWEROFF_LONG (60 * 60 * 1000) | ||||||
| @ -2,7 +2,7 @@ | |||||||
| #include <gui/elements.h> | #include <gui/elements.h> | ||||||
| 
 | 
 | ||||||
| #include "../desktop_i.h" | #include "../desktop_i.h" | ||||||
| #include "desktop_lock_menu.h" | #include "desktop_view_lock_menu.h" | ||||||
| 
 | 
 | ||||||
| #define LOCK_MENU_ITEMS_NB 3 | #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 <dolphin/dolphin.h> | ||||||
| 
 | 
 | ||||||
| #include "../desktop_i.h" | #include "../desktop_i.h" | ||||||
| #include "desktop_main.h" | #include "desktop_view_main.h" | ||||||
| 
 | 
 | ||||||
| struct DesktopMainView { | struct DesktopMainView { | ||||||
|     View* view; |     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->event_queue = osMessageQueueNew(8, sizeof(DolphinEvent), NULL); | ||||||
|     dolphin->pubsub = furi_pubsub_alloc(); |     dolphin->pubsub = furi_pubsub_alloc(); | ||||||
|     dolphin->butthurt_timer = xTimerCreate( |     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 = |     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( |     dolphin->clear_limits_timer = xTimerCreate( | ||||||
|         "Clear limits timer", |         NULL, HOURS_IN_TICKS(24), pdTRUE, dolphin, dolphin_clear_limits_timer_callback); | ||||||
|         HOURS_IN_TICKS(24), |  | ||||||
|         pdTRUE, |  | ||||||
|         dolphin, |  | ||||||
|         dolphin_clear_limits_timer_callback); |  | ||||||
| 
 | 
 | ||||||
|     return dolphin; |     return dolphin; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,4 +1,7 @@ | |||||||
| #include "elements.h" | #include "elements.h" | ||||||
|  | #include <assets_icons.h> | ||||||
|  | #include "furi_hal_resources.h" | ||||||
|  | #include <furi_hal.h> | ||||||
| #include "gui/canvas.h" | #include "gui/canvas.h" | ||||||
| 
 | 
 | ||||||
| #include <gui/icon_i.h> | #include <gui/icon_i.h> | ||||||
| @ -337,6 +340,47 @@ void elements_slightly_rounded_box( | |||||||
|     canvas_draw_rbox(canvas, x, y, width, height, 1); |     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) { | void elements_bubble(Canvas* canvas, uint8_t x, uint8_t y, uint8_t width, uint8_t height) { | ||||||
|     furi_assert(canvas); |     furi_assert(canvas); | ||||||
|     canvas_draw_rframe(canvas, x + 4, y, width, height, 3); |     canvas_draw_rframe(canvas, x + 4, y, width, height, 3); | ||||||
|  | |||||||
| @ -150,6 +150,19 @@ void elements_slightly_rounded_box( | |||||||
|     uint8_t width, |     uint8_t width, | ||||||
|     uint8_t height); |     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
 | /** Draw bubble frame for text
 | ||||||
|  * |  * | ||||||
|  * @param   canvas  Canvas instance |  * @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 <furi.h> | ||||||
| #include "loader/loader.h" | #include "loader/loader.h" | ||||||
| #include "loader_i.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)) { |     if(furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug)) { | ||||||
|         for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { |         for(size_t i = 0; i < FLIPPER_DEBUG_APPS_COUNT; i++) { | ||||||
|             if(strcmp(name, FLIPPER_DEBUG_APPS[i].name) == 0) { |             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_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_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_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}; | 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_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_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_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}; | 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_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_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_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_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_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}; | 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 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_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_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_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_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}; | 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_DoorLeft_70x55; | ||||||
| extern const Icon I_DoorLocked_10x56; | extern const Icon I_DoorLocked_10x56; | ||||||
| extern const Icon I_DoorRight_70x55; | extern const Icon I_DoorRight_70x55; | ||||||
| extern const Icon I_LockPopup_100x49; |  | ||||||
| extern const Icon I_PassportBottom_128x17; | extern const Icon I_PassportBottom_128x17; | ||||||
| extern const Icon I_PassportLeft_6x47; | extern const Icon I_PassportLeft_6x47; | ||||||
| extern const Icon I_WarningDolphin_45x42; | 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 A_iButton_14; | ||||||
| extern const Icon I_Detailed_chip_17x13; | extern const Icon I_Detailed_chip_17x13; | ||||||
| extern const Icon I_Medium_chip_22x21; | 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_bad1_46x49; | ||||||
| extern const Icon I_passport_bad2_46x49; | extern const Icon I_passport_bad2_46x49; | ||||||
| extern const Icon I_passport_bad3_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() { | void furi_hal_power_insomnia_enter() { | ||||||
|     vTaskSuspendAll(); |     FURI_CRITICAL_ENTER(); | ||||||
|     furi_assert(furi_hal_power.insomnia < UINT8_MAX); |     furi_assert(furi_hal_power.insomnia < UINT8_MAX); | ||||||
|     furi_hal_power.insomnia++; |     furi_hal_power.insomnia++; | ||||||
|     xTaskResumeAll(); |     FURI_CRITICAL_EXIT(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_insomnia_exit() { | void furi_hal_power_insomnia_exit() { | ||||||
|     vTaskSuspendAll(); |     FURI_CRITICAL_ENTER(); | ||||||
|     furi_assert(furi_hal_power.insomnia > 0); |     furi_assert(furi_hal_power.insomnia > 0); | ||||||
|     furi_hal_power.insomnia--; |     furi_hal_power.insomnia--; | ||||||
|     xTaskResumeAll(); |     FURI_CRITICAL_EXIT(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_power_sleep_available() { | 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() { | uint32_t furi_hal_rtc_get_fault_data() { | ||||||
|     return furi_hal_rtc_get_register(FuriHalRtcRegisterFaultData); |     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_version.h" | ||||||
| #include "furi_hal_usb_i.h" | #include "furi_hal_usb_i.h" | ||||||
| #include "furi_hal_usb.h" | #include "furi_hal_usb.h" | ||||||
|  | #include <furi_hal_power.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include "usb.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)) { |     if((usb_if_cur != NULL) && (usb_config.connected == true)) { | ||||||
|         usb_config.connected = false; |         usb_config.connected = false; | ||||||
|         usb_if_cur->suspend(&udev); |         usb_if_cur->suspend(&udev); | ||||||
|  | 
 | ||||||
|  |         furi_hal_power_insomnia_exit(); | ||||||
|     } |     } | ||||||
|     if(callback != NULL) { |     if(callback != NULL) { | ||||||
|         callback(FuriHalUsbStateEventSuspend, cb_ctx); |         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)) { |     if((usb_if_cur != NULL) && (usb_config.connected == false)) { | ||||||
|         usb_config.connected = true; |         usb_config.connected = true; | ||||||
|         usb_if_cur->wakeup(&udev); |         usb_if_cur->wakeup(&udev); | ||||||
|  | 
 | ||||||
|  |         furi_hal_power_insomnia_enter(); | ||||||
|     } |     } | ||||||
|     if(callback != NULL) { |     if(callback != NULL) { | ||||||
|         callback(FuriHalUsbStateEventWakeup, cb_ctx); |         callback(FuriHalUsbStateEventWakeup, cb_ctx); | ||||||
|  | |||||||
| @ -89,17 +89,17 @@ uint16_t furi_hal_power_insomnia_level() { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_insomnia_enter() { | void furi_hal_power_insomnia_enter() { | ||||||
|     vTaskSuspendAll(); |     FURI_CRITICAL_ENTER(); | ||||||
|     furi_assert(furi_hal_power.insomnia < UINT8_MAX); |     furi_assert(furi_hal_power.insomnia < UINT8_MAX); | ||||||
|     furi_hal_power.insomnia++; |     furi_hal_power.insomnia++; | ||||||
|     xTaskResumeAll(); |     FURI_CRITICAL_EXIT(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void furi_hal_power_insomnia_exit() { | void furi_hal_power_insomnia_exit() { | ||||||
|     vTaskSuspendAll(); |     FURI_CRITICAL_ENTER(); | ||||||
|     furi_assert(furi_hal_power.insomnia > 0); |     furi_assert(furi_hal_power.insomnia > 0); | ||||||
|     furi_hal_power.insomnia--; |     furi_hal_power.insomnia--; | ||||||
|     xTaskResumeAll(); |     FURI_CRITICAL_EXIT(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool furi_hal_power_sleep_available() { | 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() { | uint32_t furi_hal_rtc_get_fault_data() { | ||||||
|     return furi_hal_rtc_get_register(FuriHalRtcRegisterFaultData); |     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_version.h" | ||||||
| #include "furi_hal_usb_i.h" | #include "furi_hal_usb_i.h" | ||||||
| #include "furi_hal_usb.h" | #include "furi_hal_usb.h" | ||||||
|  | #include <furi_hal_power.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| #include "usb.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)) { |     if((usb_if_cur != NULL) && (usb_config.connected == true)) { | ||||||
|         usb_config.connected = false; |         usb_config.connected = false; | ||||||
|         usb_if_cur->suspend(&udev); |         usb_if_cur->suspend(&udev); | ||||||
|  | 
 | ||||||
|  |         furi_hal_power_insomnia_exit(); | ||||||
|     } |     } | ||||||
|     if(callback != NULL) { |     if(callback != NULL) { | ||||||
|         callback(FuriHalUsbStateEventSuspend, cb_ctx); |         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)) { |     if((usb_if_cur != NULL) && (usb_config.connected == false)) { | ||||||
|         usb_config.connected = true; |         usb_config.connected = true; | ||||||
|         usb_if_cur->wakeup(&udev); |         usb_if_cur->wakeup(&udev); | ||||||
|  | 
 | ||||||
|  |         furi_hal_power_insomnia_enter(); | ||||||
|     } |     } | ||||||
|     if(callback != NULL) { |     if(callback != NULL) { | ||||||
|         callback(FuriHalUsbStateEventWakeup, cb_ctx); |         callback(FuriHalUsbStateEventWakeup, cb_ctx); | ||||||
|  | |||||||
| @ -38,6 +38,7 @@ typedef enum { | |||||||
|     FuriHalRtcRegisterSystemVersion, |     FuriHalRtcRegisterSystemVersion, | ||||||
|     FuriHalRtcRegisterLfsFingerprint, |     FuriHalRtcRegisterLfsFingerprint, | ||||||
|     FuriHalRtcRegisterFaultData, |     FuriHalRtcRegisterFaultData, | ||||||
|  |     FuriHalRtcRegisterPinFails, | ||||||
| } FuriHalRtcRegister; | } FuriHalRtcRegister; | ||||||
| 
 | 
 | ||||||
| /** Initialize RTC subsystem */ | /** 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(); | 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 | #ifdef __cplusplus | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
|  | |||||||
 Albert Kharisov
						Albert Kharisov