desktop_locked.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #include "desktop/desktop_settings/desktop_settings.h"
  2. #include "furi/check.h"
  3. #include "gui/view.h"
  4. #include "portmacro.h"
  5. #include <furi.h>
  6. #include <gui/gui_i.h>
  7. #include <gui/elements.h>
  8. #include "../desktop_i.h"
  9. #include "desktop_locked.h"
  10. #include <stdint.h>
  11. #define DOOR_MOVING_INTERVAL_MS (1000 / 16)
  12. #define UNLOCKED_HINT_TIMEOUT_MS (2000)
  13. struct DesktopLockedView {
  14. View* view;
  15. DesktopLockedViewCallback callback;
  16. void* context;
  17. TimerHandle_t timer;
  18. uint8_t lock_count;
  19. uint32_t lock_lastpress;
  20. PinCode pincode;
  21. PinCode pincode_input;
  22. };
  23. typedef struct {
  24. uint32_t hint_icon_expire_at;
  25. bool unlocked_hint;
  26. bool locked;
  27. bool pin_locked;
  28. int8_t door_left_x;
  29. int8_t door_right_x;
  30. bool animation_seq_end;
  31. } DesktopLockedViewModel;
  32. static void desktop_locked_unlock(DesktopLockedView* locked_view);
  33. void desktop_locked_set_callback(
  34. DesktopLockedView* locked_view,
  35. DesktopLockedViewCallback callback,
  36. void* context) {
  37. furi_assert(locked_view);
  38. furi_assert(callback);
  39. locked_view->callback = callback;
  40. locked_view->context = context;
  41. }
  42. void locked_view_timer_callback(TimerHandle_t timer) {
  43. DesktopLockedView* locked_view = pvTimerGetTimerID(timer);
  44. locked_view->callback(DesktopMainEventUpdate, locked_view->context);
  45. }
  46. static void desktop_locked_update_hint_icon_timeout(DesktopLockedView* locked_view) {
  47. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  48. model->hint_icon_expire_at = osKernelGetTickCount() + osKernelGetTickFreq();
  49. view_commit_model(locked_view->view, true);
  50. }
  51. static void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) {
  52. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  53. model->animation_seq_end = false;
  54. model->door_left_x = DOOR_L_POS;
  55. model->door_right_x = DOOR_R_POS;
  56. view_commit_model(locked_view->view, true);
  57. }
  58. void desktop_locked_update(DesktopLockedView* locked_view) {
  59. bool stop_timer = false;
  60. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  61. if(model->locked) {
  62. if(model->door_left_x != DOOR_L_POS_MAX) {
  63. model->door_left_x = CLAMP(model->door_left_x + 5, DOOR_L_POS_MAX, DOOR_L_POS);
  64. model->door_right_x = CLAMP(model->door_right_x - 5, DOOR_R_POS, DOOR_R_POS_MIN);
  65. } else {
  66. model->animation_seq_end = true;
  67. }
  68. stop_timer = model->animation_seq_end;
  69. } else {
  70. model->unlocked_hint = false;
  71. stop_timer = true;
  72. }
  73. view_commit_model(locked_view->view, true);
  74. if(stop_timer) {
  75. xTimerStop(locked_view->timer, portMAX_DELAY);
  76. }
  77. }
  78. void desktop_locked_draw(Canvas* canvas, void* model) {
  79. DesktopLockedViewModel* m = model;
  80. uint32_t now = osKernelGetTickCount();
  81. canvas_set_color(canvas, ColorBlack);
  82. if(m->locked) {
  83. if(!m->animation_seq_end) {
  84. canvas_draw_icon(canvas, m->door_left_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorLeft_70x55);
  85. canvas_draw_icon(canvas, m->door_right_x, 0 + STATUS_BAR_Y_SHIFT, &I_DoorRight_70x55);
  86. canvas_set_font(canvas, FontPrimary);
  87. elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Locked");
  88. } else if((now < m->hint_icon_expire_at) && !m->pin_locked) {
  89. canvas_set_font(canvas, FontSecondary);
  90. canvas_draw_icon(canvas, 13, 2 + STATUS_BAR_Y_SHIFT, &I_LockPopup_100x49);
  91. elements_multiline_text(canvas, 65, 20 + STATUS_BAR_Y_SHIFT, "To unlock\npress:");
  92. }
  93. } else {
  94. if(m->unlocked_hint) {
  95. canvas_set_font(canvas, FontPrimary);
  96. elements_multiline_text_framed(canvas, 42, 30 + STATUS_BAR_Y_SHIFT, "Unlocked");
  97. }
  98. }
  99. }
  100. View* desktop_locked_get_view(DesktopLockedView* locked_view) {
  101. furi_assert(locked_view);
  102. return locked_view->view;
  103. }
  104. bool desktop_locked_input(InputEvent* event, void* context) {
  105. furi_assert(event);
  106. furi_assert(context);
  107. DesktopLockedView* locked_view = context;
  108. bool locked = false;
  109. bool locked_with_pin = false;
  110. uint32_t press_time = xTaskGetTickCount();
  111. {
  112. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  113. bool changed = false;
  114. locked = model->locked;
  115. locked_with_pin = model->pin_locked;
  116. if(!locked && model->unlocked_hint && event->type == InputTypePress) {
  117. model->unlocked_hint = false;
  118. changed = true;
  119. }
  120. view_commit_model(locked_view->view, changed);
  121. }
  122. if(!locked || (event->type != InputTypeShort)) {
  123. return locked;
  124. }
  125. if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) {
  126. locked_view->lock_lastpress = press_time;
  127. locked_view->lock_count = 0;
  128. locked_view->pincode_input.length = 0;
  129. }
  130. if(locked_with_pin) {
  131. locked_view->pincode_input.length = code_input_push(
  132. locked_view->pincode_input.data, locked_view->pincode_input.length, event->key);
  133. bool match = code_input_compare(
  134. locked_view->pincode_input.data,
  135. locked_view->pincode_input.length,
  136. locked_view->pincode.data,
  137. locked_view->pincode.length);
  138. if(match) {
  139. desktop_locked_unlock(locked_view);
  140. }
  141. } else {
  142. if(event->key == InputKeyBack) {
  143. locked_view->lock_lastpress = press_time;
  144. locked_view->lock_count++;
  145. if(locked_view->lock_count == UNLOCK_CNT) {
  146. desktop_locked_unlock(locked_view);
  147. }
  148. } else {
  149. desktop_locked_update_hint_icon_timeout(locked_view);
  150. locked_view->lock_count = 0;
  151. }
  152. }
  153. locked_view->lock_lastpress = press_time;
  154. return locked;
  155. }
  156. DesktopLockedView* desktop_locked_alloc() {
  157. DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView));
  158. locked_view->view = view_alloc();
  159. locked_view->timer =
  160. xTimerCreate("Locked view", 1000 / 16, pdTRUE, locked_view, locked_view_timer_callback);
  161. view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopLockedViewModel));
  162. view_set_context(locked_view->view, locked_view);
  163. view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_draw);
  164. view_set_input_callback(locked_view->view, desktop_locked_input);
  165. return locked_view;
  166. }
  167. void desktop_locked_free(DesktopLockedView* locked_view) {
  168. furi_assert(locked_view);
  169. osTimerDelete(locked_view->timer);
  170. view_free(locked_view->view);
  171. free(locked_view);
  172. }
  173. void desktop_locked_lock(DesktopLockedView* locked_view) {
  174. locked_view->pincode.length = 0;
  175. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  176. model->locked = true;
  177. model->pin_locked = false;
  178. view_commit_model(locked_view->view, true);
  179. desktop_locked_reset_door_pos(locked_view);
  180. xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY);
  181. Gui* gui = furi_record_open("gui");
  182. gui_set_lockdown(gui, true);
  183. furi_record_close("gui");
  184. }
  185. void desktop_locked_lock_pincode(DesktopLockedView* locked_view, PinCode pincode) {
  186. locked_view->pincode = pincode;
  187. locked_view->pincode_input.length = 0;
  188. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  189. model->locked = true;
  190. model->pin_locked = true;
  191. view_commit_model(locked_view->view, true);
  192. desktop_locked_reset_door_pos(locked_view);
  193. xTimerChangePeriod(locked_view->timer, DOOR_MOVING_INTERVAL_MS, portMAX_DELAY);
  194. Gui* gui = furi_record_open("gui");
  195. gui_set_lockdown(gui, true);
  196. furi_record_close("gui");
  197. }
  198. static void desktop_locked_unlock(DesktopLockedView* locked_view) {
  199. furi_assert(locked_view);
  200. locked_view->lock_count = 0;
  201. DesktopLockedViewModel* model = view_get_model(locked_view->view);
  202. model->locked = false;
  203. model->pin_locked = false;
  204. model->unlocked_hint = true;
  205. view_commit_model(locked_view->view, true);
  206. locked_view->callback(DesktopMainEventUnlocked, locked_view->context);
  207. xTimerChangePeriod(locked_view->timer, UNLOCKED_HINT_TIMEOUT_MS, portMAX_DELAY);
  208. Gui* gui = furi_record_open("gui");
  209. gui_set_lockdown(gui, false);
  210. furi_record_close("gui");
  211. }