@@ -18,12 +18,15 @@ enum {
1818struct FlippPomodoroTimerView {
1919 View * view ;
2020 FlippPomodoroTimerViewInputCb right_cb ;
21- void * right_cb_ctx ;
21+ FlippPomodoroTimerViewInputCb ok_cb ;
22+ void * callback_context ;
2223};
2324
2425typedef struct {
2526 IconAnimation * icon ;
2627 FlippPomodoroState * state ;
28+ size_t scroll_counter ;
29+ char * current_hint ;
2730} FlippPomodoroTimerViewModel ;
2831
2932static const Icon * stage_background_image [] = {
@@ -89,6 +92,55 @@ static void
8992 flipp_pomodoro__current_stage_label (state ));
9093}
9194
95+ static void
96+ flipp_pomodoro_view_timer_draw_hint (Canvas * canvas , FlippPomodoroTimerViewModel * model ) {
97+ size_t MAX_SCROLL_COUNTER = 300 ;
98+ uint8_t SCROLL_DELAY_FRAMES = 3 ;
99+
100+ if (model -> scroll_counter >= MAX_SCROLL_COUNTER || model -> current_hint == NULL ) {
101+ return ;
102+ }
103+
104+ uint8_t hint_width = 90 ;
105+ uint8_t hint_height = 18 ;
106+
107+ uint8_t hint_x = canvas_width (canvas ) - hint_width - 6 ;
108+ uint8_t hint_y = 35 ;
109+
110+ FuriString * displayed_hint_string = furi_string_alloc ();
111+
112+ furi_string_printf (displayed_hint_string , "%s" , model -> current_hint );
113+
114+ size_t perfect_duration = furi_string_size (displayed_hint_string ) * 1.5 ;
115+
116+ if (model -> scroll_counter > perfect_duration ) {
117+ model -> scroll_counter = MAX_SCROLL_COUNTER ;
118+ furi_string_free (displayed_hint_string );
119+ return ;
120+ }
121+
122+ size_t scroll_offset = (model -> scroll_counter < SCROLL_DELAY_FRAMES ) ?
123+ 0 :
124+ model -> scroll_counter - SCROLL_DELAY_FRAMES ;
125+
126+ canvas_set_color (canvas , ColorWhite );
127+ canvas_draw_box (canvas , hint_x , hint_y , hint_width + 3 , hint_height );
128+ canvas_set_color (canvas , ColorBlack );
129+
130+ elements_bubble (canvas , hint_x , hint_y , hint_width , hint_height );
131+
132+ elements_scrollable_text_line (
133+ canvas ,
134+ hint_x + 6 ,
135+ hint_y + 12 ,
136+ hint_width - 4 ,
137+ displayed_hint_string ,
138+ scroll_offset ,
139+ true);
140+ furi_string_free (displayed_hint_string );
141+ model -> scroll_counter ++ ;
142+ }
143+
92144static void flipp_pomodoro_view_timer_draw_callback (Canvas * canvas , void * _model ) {
93145 if (!_model ) {
94146 return ;
@@ -105,42 +157,58 @@ static void flipp_pomodoro_view_timer_draw_callback(Canvas* canvas, void* _model
105157 canvas , flipp_pomodoro__stage_remaining_duration (model -> state ));
106158
107159 flipp_pomodoro_view_timer_draw_current_stage_label (canvas , model -> state );
160+
108161 canvas_set_color (canvas , ColorBlack );
109162
110163 canvas_set_font (canvas , FontSecondary );
111164 elements_button_right (canvas , flipp_pomodoro__next_stage_label (model -> state ));
165+ flipp_pomodoro_view_timer_draw_hint (canvas , model );
112166};
113167
114168bool flipp_pomodoro_view_timer_input_callback (InputEvent * event , void * ctx ) {
115169 furi_assert (ctx );
116170 furi_assert (event );
117171 FlippPomodoroTimerView * timer = ctx ;
118172
119- const bool should_trigger_right_event_cb = (event -> type == InputTypePress ) &&
120- (event -> key == InputKeyRight ) &&
121- (timer -> right_cb != NULL );
173+ const bool is_press_event = event -> type == InputTypePress ;
122174
123- if (should_trigger_right_event_cb ) {
124- furi_assert (timer -> right_cb );
125- furi_assert (timer -> right_cb_ctx );
126- timer -> right_cb (timer -> right_cb_ctx );
127- return ViewInputConsumed ;
128- };
175+ if (!is_press_event ) {
176+ return ViewInputNotConusmed ;
177+ }
129178
130- return ViewInputNotConusmed ;
179+ switch (event -> key ) {
180+ case InputKeyRight :
181+ timer -> right_cb (timer -> callback_context );
182+ return ViewInputConsumed ;
183+ case InputKeyOk :
184+ timer -> ok_cb (timer -> callback_context );
185+ return ViewInputConsumed ;
186+ default :
187+ return ViewInputNotConusmed ;
188+ }
131189};
132190
133191View * flipp_pomodoro_view_timer_get_view (FlippPomodoroTimerView * timer ) {
134192 furi_assert (timer );
135193 return timer -> view ;
136194};
137195
196+ void flipp_pomodoro_view_timer_display_hint (View * view , char * hint ) {
197+ with_view_model (
198+ view ,
199+ FlippPomodoroTimerViewModel * model ,
200+ {
201+ model -> scroll_counter = 0 ;
202+ model -> current_hint = hint ;
203+ },
204+ true);
205+ }
206+
138207void flipp_pomodoro_view_timer_assign_animation (View * view ) {
139208 with_view_model (
140209 view ,
141210 FlippPomodoroTimerViewModel * model ,
142211 {
143- furi_assert (model -> state );
144212 if (model -> icon ) {
145213 icon_animation_free (model -> icon );
146214 }
@@ -160,28 +228,55 @@ FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc() {
160228 flipp_pomodoro_view_timer_get_view (timer ),
161229 ViewModelTypeLockFree ,
162230 sizeof (FlippPomodoroTimerViewModel ));
231+
163232 view_set_context (flipp_pomodoro_view_timer_get_view (timer ), timer );
164233 view_set_draw_callback (timer -> view , flipp_pomodoro_view_timer_draw_callback );
165234 view_set_input_callback (timer -> view , flipp_pomodoro_view_timer_input_callback );
166235
236+ with_view_model (
237+ flipp_pomodoro_view_timer_get_view (timer ),
238+ FlippPomodoroTimerViewModel * model ,
239+ { model -> scroll_counter = 0 ; },
240+ false);
241+
167242 return timer ;
168243};
169244
245+ void flipp_pomodoro_view_timer_set_callback_context (
246+ FlippPomodoroTimerView * timer ,
247+ void * callback_ctx ) {
248+ furi_assert (timer );
249+ furi_assert (callback_ctx );
250+ timer -> callback_context = callback_ctx ;
251+ }
252+
170253void flipp_pomodoro_view_timer_set_on_right_cb (
171254 FlippPomodoroTimerView * timer ,
172- FlippPomodoroTimerViewInputCb right_cb ,
173- void * right_cb_ctx ) {
255+ FlippPomodoroTimerViewInputCb right_cb ) {
256+ furi_assert ( timer );
174257 furi_assert (right_cb );
175- furi_assert (right_cb_ctx );
176258 timer -> right_cb = right_cb ;
177- timer -> right_cb_ctx = right_cb_ctx ;
178259};
179260
261+ void flipp_pomodoro_view_timer_set_on_ok_cb (
262+ FlippPomodoroTimerView * timer ,
263+ FlippPomodoroTimerViewInputCb ok_kb ) {
264+ furi_assert (ok_kb );
265+ furi_assert (timer );
266+ timer -> ok_cb = ok_kb ;
267+ }
268+
180269void flipp_pomodoro_view_timer_set_state (View * view , FlippPomodoroState * state ) {
181270 furi_assert (view );
182271 furi_assert (state );
183272 with_view_model (
184- view , FlippPomodoroTimerViewModel * model , { model -> state = state ; }, false);
273+ view ,
274+ FlippPomodoroTimerViewModel * model ,
275+ {
276+ model -> state = state ;
277+ model -> current_hint = NULL ;
278+ },
279+ false);
185280 flipp_pomodoro_view_timer_assign_animation (view );
186281};
187282
0 commit comments