[FL-1178] Idle screen improvements (#444)
* Dolphin idle screen: Cleanup of debug views; Hold [down] to open debug view; Sequential input for unlocking; * Lock screen popup, WIP * Fix reverse modulus * Lock popup added * Dolphin: timer for handling UI animation sequences * Allow tick events to be discarded on queue overflow and prevent timer service from crash Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									469e2dffec
								
							
						
					
					
						commit
						920b3c3dee
					
				| @ -2,8 +2,7 @@ | |||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include "applications.h" | #include "applications.h" | ||||||
| 
 | 
 | ||||||
| static void | static void dolphin_switch_to_app(Dolphin* dolphin, const FlipperApplication* flipper_app) { | ||||||
| dolphin_switch_to_interactive_scene(Dolphin* dolphin, const FlipperApplication* flipper_app) { |  | ||||||
|     furi_assert(dolphin); |     furi_assert(dolphin); | ||||||
|     furi_assert(flipper_app); |     furi_assert(flipper_app); | ||||||
|     furi_assert(flipper_app->app); |     furi_assert(flipper_app->app); | ||||||
| @ -42,98 +41,126 @@ bool dolphin_view_first_start_input(InputEvent* event, void* context) { | |||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Dolphin* dolphin = context; |     Dolphin* dolphin = context; | ||||||
|     if(event->type == InputTypeShort) { |     if(event->type == InputTypeShort) { | ||||||
|  |         DolphinViewFirstStartModel* model = view_get_model(dolphin->idle_view_first_start); | ||||||
|         if(event->key == InputKeyLeft) { |         if(event->key == InputKeyLeft) { | ||||||
|             with_view_model( |  | ||||||
|                 dolphin->idle_view_first_start, (DolphinViewFirstStartModel * model) { |  | ||||||
|             if(model->page > 0) model->page--; |             if(model->page > 0) model->page--; | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(event->key == InputKeyRight) { |         } else if(event->key == InputKeyRight) { | ||||||
|             uint32_t page; |             uint32_t page = ++model->page; | ||||||
|             with_view_model( |  | ||||||
|                 dolphin->idle_view_first_start, (DolphinViewFirstStartModel * model) { |  | ||||||
|                     page = ++model->page; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|             if(page > 8) { |             if(page > 8) { | ||||||
|                 dolphin_save(dolphin); |                 dolphin_save(dolphin); | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         view_commit_model(dolphin->idle_view_first_start, true); | ||||||
|     } |     } | ||||||
|     // All events consumed
 |     // All evennts cosumed
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void dolphin_lock_handler(InputEvent* event, Dolphin* dolphin) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(dolphin); | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         uint32_t press_time = HAL_GetTick(); | ||||||
|  | 
 | ||||||
|  |         // check if pressed sequentially
 | ||||||
|  |         if(press_time - dolphin->lock_lastpress < 200) { | ||||||
|  |             dolphin->lock_lastpress = press_time; | ||||||
|  |             dolphin->lock_count++; | ||||||
|  |         } else if(press_time - dolphin->lock_lastpress > 200) { | ||||||
|  |             dolphin->lock_lastpress = press_time; | ||||||
|  |             dolphin->lock_count = 0; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(dolphin->lock_count == 3) { | ||||||
|  |             dolphin->locked = false; | ||||||
|  |             dolphin->lock_count = 0; | ||||||
|  | 
 | ||||||
|  |             with_view_model( | ||||||
|  |                 dolphin->view_lockmenu, (DolphinViewLockMenuModel * model) { | ||||||
|  |                     model->locked = false; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |             with_view_model( | ||||||
|  |                 dolphin->idle_view_main, (DolphinViewMainModel * model) { | ||||||
|  |                     model->hint_timeout = 0; | ||||||
|  |                     return true; | ||||||
|  |                 }); | ||||||
|  | 
 | ||||||
|  |             view_port_enabled_set(dolphin->lock_viewport, false); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| bool dolphin_view_idle_main_input(InputEvent* event, void* context) { | bool dolphin_view_idle_main_input(InputEvent* event, void* context) { | ||||||
|     furi_assert(event); |     furi_assert(event); | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Dolphin* dolphin = context; |     Dolphin* dolphin = context; | ||||||
| 
 |     // unlocked
 | ||||||
|     if(event->type == InputTypeShort) { |  | ||||||
|     if(!dolphin->locked) { |     if(!dolphin->locked) { | ||||||
|             if(event->key == InputKeyOk) { |         if(event->key == InputKeyOk && event->type == InputTypeShort) { | ||||||
|             with_value_mutex( |             with_value_mutex( | ||||||
|                 dolphin->menu_vm, (Menu * menu) { menu_ok(menu); }); |                 dolphin->menu_vm, (Menu * menu) { menu_ok(menu); }); | ||||||
|             } else if(event->key == InputKeyUp) { |         } else if(event->key == InputKeyUp && event->type == InputTypeShort) { | ||||||
|  |             osTimerStart(dolphin->timeout_timer, 40); | ||||||
|             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewLockMenu); |             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewLockMenu); | ||||||
|             } else if(event->key == InputKeyLeft) { |         } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleUp); | #if 0 | ||||||
|             } else if(event->key == InputKeyRight) { |             dolphin_switch_to_app(dolphin, &FAV_APP); | ||||||
|                 dolphin_switch_to_interactive_scene(dolphin, &FLIPPER_SCENE); | #endif | ||||||
|             } else if(event->key == InputKeyDown) { |         } else if(event->key == InputKeyRight && event->type == InputTypeShort) { | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleDown); |             dolphin_switch_to_app(dolphin, &FLIPPER_SCENE); | ||||||
|             } |         } else if(event->key == InputKeyDown && event->type == InputTypeShort) { | ||||||
|             if(event->key == InputKeyBack) { | #if 0 | ||||||
|  |             dolphin_switch_to_app(dolphin, &ARCHIVE_APP); | ||||||
|  | #endif | ||||||
|  |         } else if(event->key == InputKeyDown && event->type == InputTypeLong) { | ||||||
|  |             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewStats); | ||||||
|  |         } else if(event->key == InputKeyBack && event->type == InputTypeShort) { | ||||||
|             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|             if(event->key == InputKeyBack) { |         // locked
 | ||||||
|                 dolphin->lock_count++; | 
 | ||||||
|                 if(dolphin->lock_count == 3) { |         with_view_model( | ||||||
|                     dolphin->locked = false; |             dolphin->idle_view_main, (DolphinViewMainModel * model) { | ||||||
|                     dolphin->lock_count = 0; |                 model->hint_timeout = 3; | ||||||
|                     view_dispatcher_switch_to_view( |                 return true; | ||||||
|                         dolphin->idle_view_dispatcher, DolphinViewIdleMain); |             }); | ||||||
|                     view_port_enabled_set(dolphin->lock_viewport, false); | 
 | ||||||
|                 } |         dolphin_lock_handler(event, dolphin); | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         dolphin_scene_handler_switch_scene(dolphin); |         dolphin_scene_handler_switch_scene(dolphin); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     // All events consumed
 |     // All events consumed
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool dolphin_view_idle_up_input(InputEvent* event, void* context) { | void lock_menu_refresh_handler(void* p) { | ||||||
|     furi_assert(event); |     osMessageQueueId_t event_queue = p; | ||||||
|     furi_assert(context); |     DolphinEvent event; | ||||||
|     Dolphin* dolphin = context; |     event.type = DolphinEventTypeTick; | ||||||
| 
 |     // Some tick events may lost and we don't care.
 | ||||||
|     if(event->type != InputTypeShort) return false; |     osMessageQueuePut(event_queue, &event, 0, 0); | ||||||
| 
 |  | ||||||
|     if(event->key == InputKeyLeft) { |  | ||||||
|         dolphin_deed(dolphin, DolphinDeedWrong); |  | ||||||
|     } else if(event->key == InputKeyRight) { |  | ||||||
|         dolphin_deed(dolphin, DolphinDeedIButtonRead); |  | ||||||
|     } else if(event->key == InputKeyOk) { |  | ||||||
|         dolphin_save(dolphin); |  | ||||||
|     } else { |  | ||||||
|         return false; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void lock_menu_callback(void* context, uint8_t index) { | static void lock_menu_callback(void* context, uint8_t index) { | ||||||
|  |     furi_assert(context); | ||||||
|     Dolphin* dolphin = context; |     Dolphin* dolphin = context; | ||||||
|     switch(index) { |     switch(index) { | ||||||
|  |     // lock
 | ||||||
|     case 0: |     case 0: | ||||||
|         dolphin->locked = true; |         dolphin->locked = true; | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |         DolphinViewLockMenuModel* model = view_get_model(dolphin->view_lockmenu); | ||||||
|         view_port_enabled_set(dolphin->lock_viewport, true); | 
 | ||||||
|  |         model->locked = true; | ||||||
|  |         model->exit_timeout = 20; | ||||||
|  | 
 | ||||||
|  |         view_port_enabled_set(dolphin->lock_viewport, dolphin->locked); | ||||||
|  |         view_commit_model(dolphin->view_lockmenu, true); | ||||||
|  | 
 | ||||||
|         break; |         break; | ||||||
|  | 
 | ||||||
|     default: |     default: | ||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
| @ -152,42 +179,24 @@ bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { | |||||||
| 
 | 
 | ||||||
|     if(event->type != InputTypeShort) return false; |     if(event->type != InputTypeShort) return false; | ||||||
| 
 | 
 | ||||||
|  |     DolphinViewLockMenuModel* model = view_get_model(dolphin->view_lockmenu); | ||||||
|  | 
 | ||||||
|     if(event->key == InputKeyUp) { |     if(event->key == InputKeyUp) { | ||||||
|         with_view_model( |         model->idx = CLAMP(model->idx - 1, 2, 0); | ||||||
|             dolphin->view_lockmenu, (DolphinViewMenuModel * model) { |  | ||||||
|                 if(model->idx <= 0) |  | ||||||
|                     model->idx = 0; |  | ||||||
|                 else |  | ||||||
|                     --model->idx; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|     } else if(event->key == InputKeyDown) { |     } else if(event->key == InputKeyDown) { | ||||||
|         with_view_model( |         model->idx = CLAMP(model->idx + 1, 2, 0); | ||||||
|             dolphin->view_lockmenu, (DolphinViewMenuModel * model) { |  | ||||||
|                 if(model->idx >= 2) |  | ||||||
|                     model->idx = 2; |  | ||||||
|                 else |  | ||||||
|                     ++model->idx; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|     } else if(event->key == InputKeyOk) { |     } else if(event->key == InputKeyOk) { | ||||||
|         with_view_model( |  | ||||||
|             dolphin->view_lockmenu, (DolphinViewMenuModel * model) { |  | ||||||
|         lock_menu_callback(context, model->idx); |         lock_menu_callback(context, model->idx); | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|     } else if(event->key == InputKeyBack) { |     } else if(event->key == InputKeyBack) { | ||||||
|         with_view_model( |  | ||||||
|             dolphin->view_lockmenu, (DolphinViewMenuModel * model) { |  | ||||||
|         model->idx = 0; |         model->idx = 0; | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
| 
 | 
 | ||||||
|         if(random() % 100 > 50) |         if(random() % 100 > 50) | ||||||
|             dolphin_scene_handler_set_scene(dolphin, idle_scenes[random() % sizeof(idle_scenes)]); |             dolphin_scene_handler_set_scene(dolphin, idle_scenes[random() % sizeof(idle_scenes)]); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     view_commit_model(dolphin->view_lockmenu, true); | ||||||
|  | 
 | ||||||
|     return true; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -195,27 +204,40 @@ bool dolphin_view_idle_down_input(InputEvent* event, void* context) { | |||||||
|     furi_assert(event); |     furi_assert(event); | ||||||
|     furi_assert(context); |     furi_assert(context); | ||||||
|     Dolphin* dolphin = context; |     Dolphin* dolphin = context; | ||||||
|  |     DolphinViewStatsScreens current; | ||||||
| 
 | 
 | ||||||
|     if(event->type != InputTypeShort) return false; |     if(event->type != InputTypeShort) return false; | ||||||
| 
 | 
 | ||||||
|     if((event->key == InputKeyLeft) || (event->key == InputKeyRight)) { |     DolphinViewStatsModel* model = view_get_model(dolphin->idle_view_dolphin_stats); | ||||||
|         with_view_model( | 
 | ||||||
|             dolphin->idle_view_down, (DolphinViewIdleDownModel * model) { |     current = model->screen; | ||||||
|                 model->show_fw_or_boot = !model->show_fw_or_boot; | 
 | ||||||
|                 return true; |     if(event->key == InputKeyDown) { | ||||||
|             }); |         model->screen = (model->screen + 1) % DolphinViewStatsTotalCount; | ||||||
|  |     } else if(event->key == InputKeyUp) { | ||||||
|  |         model->screen = | ||||||
|  |             ((model->screen - 1) + DolphinViewStatsTotalCount) % DolphinViewStatsTotalCount; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     view_commit_model(dolphin->idle_view_dolphin_stats, true); | ||||||
|  | 
 | ||||||
|  |     if(current == DolphinViewStatsMeta) { | ||||||
|  |         if(event->key == InputKeyLeft) { | ||||||
|  |             dolphin_deed(dolphin, DolphinDeedWrong); | ||||||
|  |         } else if(event->key == InputKeyRight) { | ||||||
|  |             dolphin_deed(dolphin, DolphinDeedIButtonRead); | ||||||
|  |         } else if(event->key == InputKeyOk) { | ||||||
|  |             dolphin_save(dolphin); | ||||||
|  |         } else { | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if(event->key == InputKeyBack) { |     if(event->key == InputKeyBack) { | ||||||
|         with_view_model( |  | ||||||
|             dolphin->idle_view_down, (DolphinViewIdleDownModel * model) { |  | ||||||
|                 model->show_fw_or_boot = 0; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     return false; |     return true; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| Dolphin* dolphin_alloc() { | Dolphin* dolphin_alloc() { | ||||||
| @ -229,10 +251,8 @@ Dolphin* dolphin_alloc() { | |||||||
|     dolphin->menu_vm = furi_record_open("menu"); |     dolphin->menu_vm = furi_record_open("menu"); | ||||||
|     // Scene thread
 |     // Scene thread
 | ||||||
|     dolphin->scene_thread = furi_thread_alloc(); |     dolphin->scene_thread = furi_thread_alloc(); | ||||||
| 
 |  | ||||||
|     // GUI
 |     // GUI
 | ||||||
|     dolphin->gui = furi_record_open("gui"); |     dolphin->gui = furi_record_open("gui"); | ||||||
| 
 |  | ||||||
|     // Dispatcher
 |     // Dispatcher
 | ||||||
|     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); |     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); | ||||||
| 
 | 
 | ||||||
| @ -250,46 +270,45 @@ Dolphin* dolphin_alloc() { | |||||||
|     dolphin->idle_view_main = view_alloc(); |     dolphin->idle_view_main = view_alloc(); | ||||||
|     view_set_context(dolphin->idle_view_main, dolphin); |     view_set_context(dolphin->idle_view_main, dolphin); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         dolphin->idle_view_main, ViewModelTypeLockFree, sizeof(DolphinViewIdleUpModel)); |         dolphin->idle_view_main, ViewModelTypeLockFree, sizeof(DolphinViewMainModel)); | ||||||
| 
 | 
 | ||||||
|     view_set_draw_callback(dolphin->idle_view_main, dolphin_view_idle_main_draw); |     view_set_draw_callback(dolphin->idle_view_main, dolphin_view_idle_main_draw); | ||||||
|     view_set_input_callback(dolphin->idle_view_main, dolphin_view_idle_main_input); |     view_set_input_callback(dolphin->idle_view_main, dolphin_view_idle_main_input); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main); |         dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main); | ||||||
| 
 | 
 | ||||||
|     // Stats Idle View
 |  | ||||||
|     dolphin->idle_view_up = view_alloc(); |  | ||||||
|     view_set_context(dolphin->idle_view_up, dolphin); |  | ||||||
| 
 |  | ||||||
|     view_allocate_model( |  | ||||||
|         dolphin->idle_view_up, ViewModelTypeLockFree, sizeof(DolphinViewMainModel)); |  | ||||||
|     view_set_draw_callback(dolphin->idle_view_up, dolphin_view_idle_up_draw); |  | ||||||
|     view_set_input_callback(dolphin->idle_view_up, dolphin_view_idle_up_input); |  | ||||||
|     view_set_previous_callback(dolphin->idle_view_up, dolphin_view_idle_back); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleUp, dolphin->idle_view_up); |  | ||||||
| 
 |  | ||||||
|     // Lock Menu View
 |     // Lock Menu View
 | ||||||
|     dolphin->view_lockmenu = view_alloc(); |     dolphin->view_lockmenu = view_alloc(); | ||||||
|     view_set_context(dolphin->view_lockmenu, dolphin); |     view_set_context(dolphin->view_lockmenu, dolphin); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         dolphin->view_lockmenu, ViewModelTypeLockFree, sizeof(DolphinViewMenuModel)); |         dolphin->view_lockmenu, ViewModelTypeLockFree, sizeof(DolphinViewLockMenuModel)); | ||||||
|     view_set_draw_callback(dolphin->view_lockmenu, dolphin_view_lockmenu_draw); |     view_set_draw_callback(dolphin->view_lockmenu, dolphin_view_lockmenu_draw); | ||||||
|     view_set_input_callback(dolphin->view_lockmenu, dolphin_view_lockmenu_input); |     view_set_input_callback(dolphin->view_lockmenu, dolphin_view_lockmenu_input); | ||||||
|     view_set_previous_callback(dolphin->view_lockmenu, dolphin_view_idle_back); |     view_set_previous_callback(dolphin->view_lockmenu, dolphin_view_idle_back); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewLockMenu, dolphin->view_lockmenu); |         dolphin->idle_view_dispatcher, DolphinViewLockMenu, dolphin->view_lockmenu); | ||||||
| 
 | 
 | ||||||
|     // Down Idle View
 |     // default doors xpos
 | ||||||
|     dolphin->idle_view_down = view_alloc(); |     with_view_model( | ||||||
|     view_set_context(dolphin->idle_view_down, dolphin); |         dolphin->view_lockmenu, (DolphinViewLockMenuModel * model) { | ||||||
|  |             model->door_left_x = -57; // defaults
 | ||||||
|  |             model->door_right_x = 115; // defaults
 | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     dolphin->timeout_timer = | ||||||
|  |         osTimerNew(lock_menu_refresh_handler, osTimerPeriodic, dolphin->event_queue, NULL); | ||||||
|  | 
 | ||||||
|  |     // Stats Idle View
 | ||||||
|  |     dolphin->idle_view_dolphin_stats = view_alloc(); | ||||||
|  |     view_set_context(dolphin->idle_view_dolphin_stats, dolphin); | ||||||
|     view_allocate_model( |     view_allocate_model( | ||||||
|         dolphin->idle_view_down, ViewModelTypeLockFree, sizeof(DolphinViewIdleDownModel)); |         dolphin->idle_view_dolphin_stats, ViewModelTypeLockFree, sizeof(DolphinViewStatsModel)); | ||||||
|     view_set_draw_callback(dolphin->idle_view_down, dolphin_view_idle_down_draw); |     view_set_draw_callback(dolphin->idle_view_dolphin_stats, dolphin_view_idle_down_draw); | ||||||
|     view_set_input_callback(dolphin->idle_view_down, dolphin_view_idle_down_input); |     view_set_input_callback(dolphin->idle_view_dolphin_stats, dolphin_view_idle_down_input); | ||||||
|     view_set_previous_callback(dolphin->idle_view_down, dolphin_view_idle_back); |     view_set_previous_callback(dolphin->idle_view_dolphin_stats, dolphin_view_idle_back); | ||||||
|     view_dispatcher_add_view( |     view_dispatcher_add_view( | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleDown, dolphin->idle_view_down); |         dolphin->idle_view_dispatcher, DolphinViewStats, dolphin->idle_view_dolphin_stats); | ||||||
|     // HW Mismatch
 |     // HW Mismatch
 | ||||||
|     dolphin->view_hw_mismatch = view_alloc(); |     dolphin->view_hw_mismatch = view_alloc(); | ||||||
|     view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw); |     view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw); | ||||||
| @ -321,6 +340,8 @@ void dolphin_free(Dolphin* dolphin) { | |||||||
|     view_port_free(dolphin->lock_viewport); |     view_port_free(dolphin->lock_viewport); | ||||||
|     icon_free(dolphin->lock_icon); |     icon_free(dolphin->lock_icon); | ||||||
| 
 | 
 | ||||||
|  |     osTimerDelete(dolphin->timeout_timer); | ||||||
|  | 
 | ||||||
|     view_dispatcher_free(dolphin->idle_view_dispatcher); |     view_dispatcher_free(dolphin->idle_view_dispatcher); | ||||||
| 
 | 
 | ||||||
|     furi_record_close("gui"); |     furi_record_close("gui"); | ||||||
| @ -361,8 +382,9 @@ int32_t dolphin_task() { | |||||||
|     } else { |     } else { | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewFirstStart); |         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewFirstStart); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     with_view_model( |     with_view_model( | ||||||
|         dolphin->idle_view_up, (DolphinViewIdleUpModel * model) { |         dolphin->idle_view_dolphin_stats, (DolphinViewStatsModel * model) { | ||||||
|             model->icounter = dolphin_state_get_icounter(dolphin->state); |             model->icounter = dolphin_state_get_icounter(dolphin->state); | ||||||
|             model->butthurt = dolphin_state_get_butthurt(dolphin->state); |             model->butthurt = dolphin_state_get_butthurt(dolphin->state); | ||||||
|             return true; |             return true; | ||||||
| @ -373,13 +395,27 @@ int32_t dolphin_task() { | |||||||
|     if(!api_hal_version_do_i_belong_here()) { |     if(!api_hal_version_do_i_belong_here()) { | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewHwMismatch); |         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewHwMismatch); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     DolphinEvent event; |     DolphinEvent event; | ||||||
|     while(1) { |     while(1) { | ||||||
|         furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK); |         furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK); | ||||||
|         if(event.type == DolphinEventTypeDeed) { | 
 | ||||||
|  |         DolphinViewLockMenuModel* lock_model = view_get_model(dolphin->view_lockmenu); | ||||||
|  | 
 | ||||||
|  |         if(lock_model->locked && lock_model->exit_timeout == 0 && | ||||||
|  |            osTimerIsRunning(dolphin->timeout_timer)) { | ||||||
|  |             osTimerStop(dolphin->timeout_timer); | ||||||
|  |             osDelay(1); // smol enterprise delay
 | ||||||
|  |             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if(event.type == DolphinEventTypeTick) { | ||||||
|  |             view_commit_model(dolphin->view_lockmenu, true); | ||||||
|  | 
 | ||||||
|  |         } else if(event.type == DolphinEventTypeDeed) { | ||||||
|             dolphin_state_on_deed(dolphin->state, event.deed); |             dolphin_state_on_deed(dolphin->state, event.deed); | ||||||
|             with_view_model( |             with_view_model( | ||||||
|                 dolphin->idle_view_up, (DolphinViewIdleUpModel * model) { |                 dolphin->idle_view_dolphin_stats, (DolphinViewStatsModel * model) { | ||||||
|                     model->icounter = dolphin_state_get_icounter(dolphin->state); |                     model->icounter = dolphin_state_get_icounter(dolphin->state); | ||||||
|                     model->butthurt = dolphin_state_get_butthurt(dolphin->state); |                     model->butthurt = dolphin_state_get_butthurt(dolphin->state); | ||||||
|                     return true; |                     return true; | ||||||
|  | |||||||
| @ -17,6 +17,7 @@ | |||||||
| typedef enum { | typedef enum { | ||||||
|     DolphinEventTypeDeed, |     DolphinEventTypeDeed, | ||||||
|     DolphinEventTypeSave, |     DolphinEventTypeSave, | ||||||
|  |     DolphinEventTypeTick, | ||||||
| } DolphinEventType; | } DolphinEventType; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| @ -40,7 +41,7 @@ struct Dolphin { | |||||||
|     ViewDispatcher* idle_view_dispatcher; |     ViewDispatcher* idle_view_dispatcher; | ||||||
|     View* idle_view_first_start; |     View* idle_view_first_start; | ||||||
|     View* idle_view_main; |     View* idle_view_main; | ||||||
|     View* idle_view_up; |     View* idle_view_dolphin_stats; | ||||||
|     View* idle_view_down; |     View* idle_view_down; | ||||||
|     View* idle_view_meta; |     View* idle_view_meta; | ||||||
|     View* view_hw_mismatch; |     View* view_hw_mismatch; | ||||||
| @ -50,6 +51,8 @@ struct Dolphin { | |||||||
| 
 | 
 | ||||||
|     bool locked; |     bool locked; | ||||||
|     uint8_t lock_count; |     uint8_t lock_count; | ||||||
|  |     uint32_t lock_lastpress; | ||||||
|  |     osTimerId_t timeout_timer; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Temporary
 | // Temporary
 | ||||||
|  | |||||||
| @ -59,50 +59,63 @@ void dolphin_view_first_start_draw(Canvas* canvas, void* model) { | |||||||
| void dolphin_view_idle_main_draw(Canvas* canvas, void* model) { | void dolphin_view_idle_main_draw(Canvas* canvas, void* model) { | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     DolphinViewMainModel* m = model; |     DolphinViewMainModel* m = model; | ||||||
|     if(m->animation) canvas_draw_icon(canvas, 0, -3, m->animation); |     if(m->animation) { | ||||||
| } |         canvas_draw_icon(canvas, 0, -3, m->animation); | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
| void dolphin_view_idle_up_draw(Canvas* canvas, void* model) { |     if(m->hint_timeout > 0) { | ||||||
|     DolphinViewIdleUpModel* m = model; |         m->hint_timeout--; | ||||||
|     canvas_clear(canvas); |         canvas_draw_icon_name(canvas, 13, 5, I_LockPopup_100x49); | ||||||
| 
 |         elements_multiline_text(canvas, 65, 20, "To unlock\npress:"); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     } | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     canvas_draw_str(canvas, 2, 15, "Dolphin stats:"); |  | ||||||
| 
 |  | ||||||
|     char buffer[64]; |  | ||||||
|     canvas_set_font(canvas, FontSecondary); |  | ||||||
|     snprintf(buffer, 64, "Icounter: %ld", m->icounter); |  | ||||||
|     canvas_draw_str(canvas, 5, 30, buffer); |  | ||||||
|     snprintf(buffer, 64, "Butthurt: %ld", m->butthurt); |  | ||||||
|     canvas_draw_str(canvas, 5, 40, buffer); |  | ||||||
|     canvas_draw_str(canvas, 0, 53, "[< >] icounter value   [ok] save"); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dolphin_view_lockmenu_draw(Canvas* canvas, void* model) { | void dolphin_view_lockmenu_draw(Canvas* canvas, void* model) { | ||||||
|     DolphinViewMenuModel* m = model; |     DolphinViewLockMenuModel* m = model; | ||||||
|     canvas_clear(canvas); |     canvas_clear(canvas); | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_draw_icon_name(canvas, 5, 0, I_DoorLeft_8x56); |     canvas_draw_icon_name(canvas, m->door_left_x, 0, I_DoorLeft_70x55); | ||||||
|     canvas_draw_icon_name(canvas, 115, 0, I_DoorRight_8x56); |     canvas_draw_icon_name(canvas, m->door_right_x, 0, I_DoorRight_70x55); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     if(m->locked) { | ||||||
|  |         m->exit_timeout--; | ||||||
|  | 
 | ||||||
|  |         m->door_left_x = CLAMP(m->door_left_x + 10, 0, -57); | ||||||
|  |         m->door_right_x = CLAMP(m->door_right_x - 10, 115, 60); | ||||||
|  | 
 | ||||||
|  |         if(m->door_left_x > -10) { | ||||||
|  |             canvas_set_font(canvas, FontPrimary); | ||||||
|  |             elements_multiline_text_framed(canvas, 42, 30, "Locked"); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |     } else { | ||||||
|  |         m->door_left_x = CLAMP(m->door_left_x - 10, 0, -57); | ||||||
|  |         m->door_right_x = CLAMP(m->door_right_x + 10, 115, 60); | ||||||
|  | 
 | ||||||
|  |         if(m->door_left_x == -57) { | ||||||
|             for(uint8_t i = 0; i < 3; ++i) { |             for(uint8_t i = 0; i < 3; ++i) { | ||||||
|                 canvas_draw_str_aligned( |                 canvas_draw_str_aligned( | ||||||
|                     canvas, 64, 13 + (i * 17), AlignCenter, AlignCenter, Lockmenu_Items[i]); |                     canvas, 64, 13 + (i * 17), AlignCenter, AlignCenter, Lockmenu_Items[i]); | ||||||
|                 if(m->idx == i) elements_frame(canvas, 15, 5 + (i * 17), 98, 15); |                 if(m->idx == i) elements_frame(canvas, 15, 5 + (i * 17), 98, 15); | ||||||
|             } |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { | void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { | ||||||
|     DolphinViewIdleDownModel* m = model; |     DolphinViewStatsModel* m = model; | ||||||
|     const Version* ver; |     const Version* ver; | ||||||
|     char buffer[64]; |     char buffer[64]; | ||||||
| 
 | 
 | ||||||
|  |     static const char* headers[] = {"Boot Version info:", "FW Version info:", "Dolphin info:"}; | ||||||
|  | 
 | ||||||
|     canvas_set_color(canvas, ColorBlack); |     canvas_set_color(canvas, ColorBlack); | ||||||
|     canvas_set_font(canvas, FontPrimary); |     canvas_set_font(canvas, FontPrimary); | ||||||
|     canvas_draw_str(canvas, 2, 13, m->show_fw_or_boot ? "Boot Version info:" : "FW Version info:"); |     canvas_draw_str(canvas, 2, 13, headers[m->screen]); | ||||||
|     canvas_set_font(canvas, FontSecondary); |     canvas_set_font(canvas, FontSecondary); | ||||||
| 
 | 
 | ||||||
|  |     if(m->screen != DolphinViewStatsMeta) { | ||||||
|         // Hardware version
 |         // Hardware version
 | ||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, |             buffer, | ||||||
| @ -115,7 +128,7 @@ void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { | |||||||
|             api_hal_version_get_name_ptr()); |             api_hal_version_get_name_ptr()); | ||||||
|         canvas_draw_str(canvas, 5, 23, buffer); |         canvas_draw_str(canvas, 5, 23, buffer); | ||||||
| 
 | 
 | ||||||
|     ver = m->show_fw_or_boot ? api_hal_version_get_boot_version() : |         ver = m->screen == DolphinViewStatsBoot ? api_hal_version_get_boot_version() : | ||||||
|                                                   api_hal_version_get_fw_version(); |                                                   api_hal_version_get_fw_version(); | ||||||
| 
 | 
 | ||||||
|         if(!ver) { |         if(!ver) { | ||||||
| @ -124,16 +137,34 @@ void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         snprintf( |         snprintf( | ||||||
|         buffer, sizeof(buffer), "%s [%s]", version_get_version(ver), version_get_builddate(ver)); |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "%s [%s]", | ||||||
|  |             version_get_version(ver), | ||||||
|  |             version_get_builddate(ver)); | ||||||
|         canvas_draw_str(canvas, 5, 33, buffer); |         canvas_draw_str(canvas, 5, 33, buffer); | ||||||
| 
 | 
 | ||||||
|         snprintf( |         snprintf( | ||||||
|         buffer, sizeof(buffer), "%s [%s]", version_get_githash(ver), version_get_gitbranchnum(ver)); |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "%s [%s]", | ||||||
|  |             version_get_githash(ver), | ||||||
|  |             version_get_gitbranchnum(ver)); | ||||||
|         canvas_draw_str(canvas, 5, 43, buffer); |         canvas_draw_str(canvas, 5, 43, buffer); | ||||||
| 
 | 
 | ||||||
|         snprintf( |         snprintf( | ||||||
|             buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver)); |             buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver)); | ||||||
|         canvas_draw_str(canvas, 5, 53, buffer); |         canvas_draw_str(canvas, 5, 53, buffer); | ||||||
|  | 
 | ||||||
|  |     } else { | ||||||
|  |         char buffer[64]; | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         snprintf(buffer, 64, "Icounter: %ld", m->icounter); | ||||||
|  |         canvas_draw_str(canvas, 5, 30, buffer); | ||||||
|  |         snprintf(buffer, 64, "Butthurt: %ld", m->butthurt); | ||||||
|  |         canvas_draw_str(canvas, 5, 40, buffer); | ||||||
|  |         canvas_draw_str(canvas, 0, 53, "[< >] icounter value   [ok] save"); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model) { | void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model) { | ||||||
|  | |||||||
| @ -6,16 +6,35 @@ | |||||||
| #include <input/input.h> | #include <input/input.h> | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| 
 | 
 | ||||||
| // Idle scree
 | #ifndef MAX | ||||||
|  | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef MIN | ||||||
|  | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #ifndef CLAMP | ||||||
|  | #define CLAMP(x, upper, lower) (MIN(upper, MAX(x, lower))) | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | // Idle screen
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DolphinViewIdleMain, |     DolphinViewIdleMain, | ||||||
|     DolphinViewFirstStart, |     DolphinViewFirstStart, | ||||||
|     DolphinViewIdleUp, |     DolphinViewStats, | ||||||
|     DolphinViewIdleDown, |  | ||||||
|     DolphinViewHwMismatch, |     DolphinViewHwMismatch, | ||||||
|     DolphinViewLockMenu, |     DolphinViewLockMenu, | ||||||
| } DolphinViewIdle; | } DolphinViewIdle; | ||||||
| 
 | 
 | ||||||
|  | // Debug info
 | ||||||
|  | typedef enum { | ||||||
|  |     DolphinViewStatsFw, | ||||||
|  |     DolphinViewStatsBoot, | ||||||
|  |     DolphinViewStatsMeta, | ||||||
|  |     DolphinViewStatsTotalCount, | ||||||
|  | } DolphinViewStatsScreens; | ||||||
|  | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t page; |     uint32_t page; | ||||||
| } DolphinViewFirstStartModel; | } DolphinViewFirstStartModel; | ||||||
| @ -26,20 +45,21 @@ bool dolphin_view_first_start_input(InputEvent* event, void* context); | |||||||
| typedef struct { | typedef struct { | ||||||
|     uint32_t icounter; |     uint32_t icounter; | ||||||
|     uint32_t butthurt; |     uint32_t butthurt; | ||||||
| } DolphinViewIdleUpModel; |     DolphinViewStatsScreens screen; | ||||||
| 
 | } DolphinViewStatsModel; | ||||||
| typedef struct { |  | ||||||
|     bool show_fw_or_boot; |  | ||||||
| } DolphinViewIdleDownModel; |  | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     uint8_t idx; |     uint8_t idx; | ||||||
| } DolphinViewMenuModel; |     int8_t door_left_x; | ||||||
|  |     int8_t door_right_x; | ||||||
|  |     uint8_t exit_timeout; | ||||||
|  |     bool locked; | ||||||
|  | } DolphinViewLockMenuModel; | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     Icon* animation; |     Icon* animation; | ||||||
|     uint8_t scene_num; |     uint8_t scene_num; | ||||||
| 
 |     uint8_t hint_timeout; | ||||||
| } DolphinViewMainModel; | } DolphinViewMainModel; | ||||||
| 
 | 
 | ||||||
| void dolphin_view_idle_main_draw(Canvas* canvas, void* model); | void dolphin_view_idle_main_draw(Canvas* canvas, void* model); | ||||||
|  | |||||||
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Interface/DoorLeft_70x55.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/Interface/DoorLeft_70x55.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 564 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Interface/DoorRight_70x55.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/Interface/DoorRight_70x55.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 570 B | 
							
								
								
									
										
											BIN
										
									
								
								assets/icons/Interface/LockPopup_100x49.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								assets/icons/Interface/LockPopup_100x49.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 577 B | 
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 its your bedtime
						its your bedtime