countdown_view.c 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. #include "countdown_view.h"
  2. #include "../utils/utils.h"
  3. // internal
  4. static void handle_cmd(CountDownTimView* hw, CountDownViewCmd cmd);
  5. static void handle_time_setting_updown(CountDownTimView* hwv, CountDownViewCmd cmd);
  6. static void handle_time_setting_select(InputKey key, CountDownTimView* hwv);
  7. static void draw_selection(Canvas* canvas, CountDownViewSelect selection);
  8. // callbacks
  9. static void countdown_timer_view_on_enter(void* ctx);
  10. static void countdown_timer_view_on_draw(Canvas* canvas, void* ctx);
  11. static bool countdown_timer_view_on_input(InputEvent* event, void* ctx);
  12. static void timer_cb(void* ctx);
  13. CountDownTimView* helloworld_view_new() {
  14. CountDownTimView* hwv = (CountDownTimView*)(malloc(sizeof(CountDownTimView)));
  15. hwv->view = view_alloc();
  16. hwv->timer = furi_timer_alloc(timer_cb, FuriTimerTypePeriodic, hwv);
  17. hwv->counting = false;
  18. view_set_context(hwv->view, hwv);
  19. view_allocate_model(hwv->view, ViewModelTypeLocking, sizeof(CountDownModel));
  20. view_set_draw_callback(hwv->view, countdown_timer_view_on_draw);
  21. view_set_input_callback(hwv->view, countdown_timer_view_on_input);
  22. view_set_enter_callback(hwv->view, countdown_timer_view_on_enter);
  23. return hwv;
  24. }
  25. void countdown_timer_view_delete(CountDownTimView* hwv) {
  26. furi_assert(hwv);
  27. view_free(hwv->view);
  28. furi_timer_stop(hwv->timer);
  29. furi_timer_free(hwv->timer);
  30. free(hwv);
  31. }
  32. View* countdown_timer_view_get_view(CountDownTimView* hwv) {
  33. return hwv->view;
  34. }
  35. void countdown_timer_view_state_reset(CountDownTimView* hwv) {
  36. hwv->counting = false;
  37. with_view_model(
  38. hwv->view, CountDownModel * model, { model->sec_expected = 10; }, true);
  39. }
  40. void countdown_timer_state_toggle(CountDownTimView* hwv) {
  41. bool on = hwv->counting;
  42. if(!on) {
  43. furi_timer_start(hwv->timer, furi_kernel_get_tick_frequency() * 1); // 1s
  44. } else {
  45. furi_timer_stop(hwv->timer);
  46. notification_off();
  47. }
  48. hwv->counting = !on;
  49. }
  50. // on enter callback, CountDownTimView as ctx
  51. static void countdown_timer_view_on_enter(void* ctx) {
  52. furi_assert(ctx);
  53. CountDownTimView* hwv = (CountDownTimView*)ctx;
  54. countdown_timer_view_state_reset(hwv);
  55. }
  56. // view draw callback, CountDownModel as ctx
  57. static void countdown_timer_view_on_draw(Canvas* canvas, void* ctx) {
  58. furi_assert(ctx);
  59. CountDownModel* model = (CountDownModel*)ctx;
  60. char buffer[64];
  61. int32_t sec = model->sec_expected;
  62. CountDownViewSelect select = model->select;
  63. elements_frame(canvas, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
  64. canvas_set_font(canvas, FontBigNumbers);
  65. draw_selection(canvas, select);
  66. snprintf(
  67. buffer,
  68. sizeof(buffer),
  69. "%02ld:%02ld:%02ld",
  70. (sec % (60 * 60 * 24)) / (60 * 60), // hour
  71. (sec % (60 * 60)) / 60, // minute
  72. sec % 60); // second
  73. canvas_draw_str_aligned(
  74. canvas, SCREEN_CENTER_X, SCREEN_CENTER_Y, AlignCenter, AlignCenter, buffer);
  75. }
  76. // keys input event callback, CountDownTimView as ctx
  77. static bool countdown_timer_view_on_input(InputEvent* event, void* ctx) {
  78. furi_assert(ctx);
  79. CountDownTimView* hw = (CountDownTimView*)ctx;
  80. if(event->type == InputTypeShort || event->type == InputTypeRepeat) {
  81. switch(event->key) {
  82. case InputKeyUp:
  83. case InputKeyDown:
  84. case InputKeyRight:
  85. case InputKeyLeft:
  86. handle_time_setting_select(event->key, hw);
  87. break;
  88. case InputKeyOk:
  89. if(event->type == InputTypeShort) {
  90. handle_cmd(hw, CountDownTimerToggleCounting);
  91. }
  92. break;
  93. default:
  94. break;
  95. }
  96. return true;
  97. }
  98. if(event->type == InputTypeLong) {
  99. switch(event->key) {
  100. case InputKeyOk:
  101. handle_cmd(hw, CountDownTimerReset);
  102. break;
  103. case InputKeyBack:
  104. return false;
  105. break;
  106. default:
  107. break;
  108. }
  109. return true;
  110. }
  111. return false;
  112. }
  113. static void timer_cb(void* ctx) {
  114. furi_assert(ctx);
  115. CountDownTimView* hwv = (CountDownTimView*)ctx;
  116. int32_t sec;
  117. bool timeup = false;
  118. // decrement counter
  119. with_view_model(
  120. hwv->view,
  121. CountDownModel * model,
  122. {
  123. sec = model->sec_expected;
  124. sec--;
  125. // check timeup
  126. if(sec <= 0) {
  127. sec = 0;
  128. timeup = true;
  129. }
  130. model->sec_expected = sec;
  131. },
  132. true);
  133. if(timeup) {
  134. handle_cmd(hwv, CountDownTimerTimeUp);
  135. }
  136. }
  137. static void handle_time_setting_updown(CountDownTimView* hwv, CountDownViewCmd cmd) {
  138. int32_t sec_expected;
  139. with_view_model(
  140. hwv->view,
  141. CountDownModel * model,
  142. {
  143. sec_expected = model->sec_expected;
  144. switch(cmd) {
  145. case CountDownTimerMinuteUp:
  146. sec_expected += 60;
  147. break;
  148. case CountDownTimerMinuteDown:
  149. sec_expected -= 60;
  150. break;
  151. case CountDownTimerHourDown:
  152. sec_expected -= 3600;
  153. break;
  154. case CountDownTimerHourUp:
  155. sec_expected += 3600;
  156. break;
  157. case CountDownTimerSecUp:
  158. sec_expected++;
  159. break;
  160. case CountDownTimerSecDown:
  161. sec_expected--;
  162. break;
  163. default:
  164. break;
  165. }
  166. if(sec_expected < 0) {
  167. sec_expected = 0;
  168. }
  169. model->sec_expected = sec_expected;
  170. },
  171. true);
  172. }
  173. static void handle_cmd(CountDownTimView* hw, CountDownViewCmd cmd) {
  174. switch(cmd) {
  175. case CountDownTimerTimeUp:
  176. notification_timeup();
  177. break;
  178. case CountDownTimerReset:
  179. furi_timer_stop(hw->timer);
  180. countdown_timer_view_state_reset(hw);
  181. notification_off();
  182. break;
  183. case CountDownTimerToggleCounting:
  184. countdown_timer_state_toggle(hw);
  185. break;
  186. default:
  187. break;
  188. }
  189. return;
  190. }
  191. static void handle_time_setting_select(InputKey key, CountDownTimView* hwv) {
  192. bool counting = hwv->counting;
  193. CountDownViewCmd setting_cmd = CountDownTimerSecUp;
  194. CountDownViewSelect selection;
  195. if(counting) {
  196. return;
  197. }
  198. // load current selection from model context
  199. with_view_model(
  200. hwv->view, CountDownModel * model, { selection = model->select; }, false);
  201. // select
  202. switch(key) {
  203. case InputKeyUp:
  204. switch(selection) {
  205. case CountDownTimerSelectSec:
  206. setting_cmd = CountDownTimerSecUp;
  207. break;
  208. case CountDownTimerSelectMinute:
  209. setting_cmd = CountDownTimerMinuteUp;
  210. break;
  211. case CountDownTimerSelectHour:
  212. setting_cmd = CountDownTimerHourUp;
  213. break;
  214. }
  215. handle_time_setting_updown(hwv, setting_cmd);
  216. break;
  217. case InputKeyDown:
  218. switch(selection) {
  219. case CountDownTimerSelectSec:
  220. setting_cmd = CountDownTimerSecDown;
  221. break;
  222. case CountDownTimerSelectMinute:
  223. setting_cmd = CountDownTimerMinuteDown;
  224. break;
  225. case CountDownTimerSelectHour:
  226. setting_cmd = CountDownTimerHourDown;
  227. break;
  228. }
  229. handle_time_setting_updown(hwv, setting_cmd);
  230. break;
  231. case InputKeyRight:
  232. selection--;
  233. selection = selection % 3;
  234. break;
  235. case InputKeyLeft:
  236. selection++;
  237. selection = selection % 3;
  238. break;
  239. default:
  240. break;
  241. }
  242. // save selection to model context
  243. with_view_model(
  244. hwv->view, CountDownModel * model, { model->select = selection; }, false);
  245. }
  246. static void draw_selection(Canvas* canvas, CountDownViewSelect selection) {
  247. switch(selection) {
  248. case CountDownTimerSelectSec:
  249. elements_slightly_rounded_box(canvas, SCREEN_CENTER_X + 25, SCREEN_CENTER_Y + 11, 21, 2);
  250. break;
  251. case CountDownTimerSelectMinute:
  252. elements_slightly_rounded_box(canvas, SCREEN_CENTER_X - 10, SCREEN_CENTER_Y + 11, 21, 2);
  253. break;
  254. case CountDownTimerSelectHour:
  255. elements_slightly_rounded_box(canvas, SCREEN_CENTER_X - 47, SCREEN_CENTER_Y + 11, 21, 2);
  256. break;
  257. }
  258. }