flipp_pomodoro_timer_view.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #include "flipp_pomodoro_timer_view.h"
  2. #include <furi.h>
  3. #include <gui/gui.h>
  4. #include <gui/elements.h>
  5. #include <gui/view.h>
  6. #include "../helpers/debug.h"
  7. #include "../flipp_pomodoro_app.h"
  8. #include "../modules/flipp_pomodoro.h"
  9. // Auto-compiled icons
  10. #include "flipp_pomodoro_icons.h"
  11. enum {
  12. ViewInputConsumed = true,
  13. ViewInputNotConusmed = false,
  14. };
  15. struct FlippPomodoroTimerView {
  16. View* view;
  17. FlippPomodoroTimerViewInputCb right_cb;
  18. void* right_cb_ctx;
  19. };
  20. typedef struct {
  21. IconAnimation* icon;
  22. FlippPomodoroState* state;
  23. } FlippPomodoroTimerViewModel;
  24. static const Icon* stage_background_image[] = {
  25. [FlippPomodoroStageFocus] = &A_flipp_pomodoro_focus_64,
  26. [FlippPomodoroStageRest] = &A_flipp_pomodoro_rest_64,
  27. [FlippPomodoroStageLongBreak] = &A_flipp_pomodoro_rest_64,
  28. };
  29. static void
  30. flipp_pomodoro_view_timer_draw_countdown(Canvas* canvas, TimeDifference remaining_time) {
  31. canvas_set_font(canvas, FontBigNumbers);
  32. const uint8_t right_border_margin = 1;
  33. const uint8_t countdown_box_height = canvas_height(canvas) * 0.4;
  34. const uint8_t countdown_box_width = canvas_width(canvas) * 0.5;
  35. const uint8_t countdown_box_x =
  36. canvas_width(canvas) - countdown_box_width - right_border_margin;
  37. const uint8_t countdown_box_y = 15;
  38. elements_bold_rounded_frame(
  39. canvas, countdown_box_x, countdown_box_y, countdown_box_width, countdown_box_height);
  40. FuriString* timer_string = furi_string_alloc();
  41. furi_string_printf(timer_string, "%02u:%02u", remaining_time.minutes, remaining_time.seconds);
  42. const char* remaining_stage_time_string = furi_string_get_cstr(timer_string);
  43. canvas_draw_str_aligned(
  44. canvas,
  45. countdown_box_x + (countdown_box_width / 2),
  46. countdown_box_y + (countdown_box_height / 2),
  47. AlignCenter,
  48. AlignCenter,
  49. remaining_stage_time_string);
  50. furi_string_free(timer_string);
  51. };
  52. static void draw_str_with_drop_shadow(
  53. Canvas* canvas,
  54. uint8_t x,
  55. uint8_t y,
  56. Align horizontal,
  57. Align vertical,
  58. const char* str) {
  59. canvas_set_color(canvas, ColorWhite);
  60. for(int x_off = -2; x_off <= 2; x_off++) {
  61. for(int y_off = -2; y_off <= 2; y_off++) {
  62. canvas_draw_str_aligned(canvas, x + x_off, y + y_off, horizontal, vertical, str);
  63. }
  64. }
  65. canvas_set_color(canvas, ColorBlack);
  66. canvas_draw_str_aligned(canvas, x, y, horizontal, vertical, str);
  67. }
  68. static void
  69. flipp_pomodoro_view_timer_draw_current_stage_label(Canvas* canvas, FlippPomodoroState* state) {
  70. canvas_set_font(canvas, FontPrimary);
  71. draw_str_with_drop_shadow(
  72. canvas,
  73. canvas_width(canvas),
  74. 0,
  75. AlignRight,
  76. AlignTop,
  77. flipp_pomodoro__current_stage_label(state));
  78. }
  79. static void flipp_pomodoro_view_timer_draw_callback(Canvas* canvas, void* _model) {
  80. if(!_model) {
  81. return;
  82. };
  83. FlippPomodoroTimerViewModel* model = _model;
  84. canvas_clear(canvas);
  85. if(model->icon) {
  86. canvas_draw_icon_animation(canvas, 0, 0, model->icon);
  87. }
  88. flipp_pomodoro_view_timer_draw_countdown(
  89. canvas, flipp_pomodoro__stage_remaining_duration(model->state));
  90. flipp_pomodoro_view_timer_draw_current_stage_label(canvas, model->state);
  91. canvas_set_color(canvas, ColorBlack);
  92. canvas_set_font(canvas, FontSecondary);
  93. elements_button_right(canvas, flipp_pomodoro__next_stage_label(model->state));
  94. };
  95. bool flipp_pomodoro_view_timer_input_callback(InputEvent* event, void* ctx) {
  96. furi_assert(ctx);
  97. furi_assert(event);
  98. FlippPomodoroTimerView* timer = ctx;
  99. const bool should_trigger_right_event_cb = (event->type == InputTypePress) &&
  100. (event->key == InputKeyRight) &&
  101. (timer->right_cb != NULL);
  102. if(should_trigger_right_event_cb) {
  103. furi_assert(timer->right_cb);
  104. furi_assert(timer->right_cb_ctx);
  105. timer->right_cb(timer->right_cb_ctx);
  106. return ViewInputConsumed;
  107. };
  108. return ViewInputNotConusmed;
  109. };
  110. View* flipp_pomodoro_view_timer_get_view(FlippPomodoroTimerView* timer) {
  111. furi_assert(timer);
  112. return timer->view;
  113. };
  114. void flipp_pomodoro_view_timer_assign_animation(View* view) {
  115. with_view_model(
  116. view,
  117. FlippPomodoroTimerViewModel * model,
  118. {
  119. furi_assert(model->state);
  120. if(model->icon) {
  121. icon_animation_free(model->icon);
  122. }
  123. model->icon = icon_animation_alloc(
  124. stage_background_image[flipp_pomodoro__get_stage(model->state)]);
  125. view_tie_icon_animation(view, model->icon);
  126. icon_animation_start(model->icon);
  127. },
  128. true);
  129. }
  130. FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc() {
  131. FlippPomodoroTimerView* timer = malloc(sizeof(FlippPomodoroTimerView));
  132. timer->view = view_alloc();
  133. view_allocate_model(
  134. flipp_pomodoro_view_timer_get_view(timer),
  135. ViewModelTypeLockFree,
  136. sizeof(FlippPomodoroTimerViewModel));
  137. view_set_context(flipp_pomodoro_view_timer_get_view(timer), timer);
  138. view_set_draw_callback(timer->view, flipp_pomodoro_view_timer_draw_callback);
  139. view_set_input_callback(timer->view, flipp_pomodoro_view_timer_input_callback);
  140. return timer;
  141. };
  142. void flipp_pomodoro_view_timer_set_on_right_cb(
  143. FlippPomodoroTimerView* timer,
  144. FlippPomodoroTimerViewInputCb right_cb,
  145. void* right_cb_ctx) {
  146. furi_assert(right_cb);
  147. furi_assert(right_cb_ctx);
  148. timer->right_cb = right_cb;
  149. timer->right_cb_ctx = right_cb_ctx;
  150. };
  151. void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state) {
  152. furi_assert(view);
  153. furi_assert(state);
  154. with_view_model(
  155. view, FlippPomodoroTimerViewModel * model, { model->state = state; }, false);
  156. flipp_pomodoro_view_timer_assign_animation(view);
  157. };
  158. void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer) {
  159. furi_assert(timer);
  160. with_view_model(
  161. timer->view,
  162. FlippPomodoroTimerViewModel * model,
  163. { icon_animation_free(model->icon); },
  164. false);
  165. view_free(timer->view);
  166. free(timer);
  167. };