1
+ #include "flipp_pomodoro_app_i.h"
1
2
#include <furi.h>
2
- #include <furi_hal.h>
3
3
4
4
#include <notification/notification_messages.h>
5
5
#include <gui/gui.h>
6
+ #include <dolphin/dolphin.h>
6
7
#include <gui/elements.h>
7
8
#include <input/input.h>
8
9
9
10
/* Magic happens here -- this file is generated by fbt.
10
11
* Just set fap_icon_assets in application.fam and #include {APPID}_icons.h */
11
12
#include "flipp_pomodoro_icons.h"
12
13
13
- const int SECONDS_IN_MINUTE = 60 ;
14
-
15
14
/// @brief Actions to be processed in a queue
16
15
typedef enum {
17
16
TimerTickType = 42 ,
@@ -97,42 +96,17 @@ static const PomodoroStage stage_rotaion_map[] = {
97
96
[Rest ] = Work ,
98
97
};
99
98
100
- static const int32_t stage_duration_seconds_map [] = {
101
- [Work ] = 25 * SECONDS_IN_MINUTE ,
102
- [Rest ] = 5 * SECONDS_IN_MINUTE ,
103
- };
104
-
105
99
const PomodoroStage default_stage = Work ;
106
100
107
- /// @brief Container for a time period
108
- typedef struct {
109
- uint8_t seconds ;
110
- uint8_t minutes ;
111
- uint32_t total_seconds ;
112
- } TimeDifference ;
113
-
114
101
typedef struct {
115
102
PomodoroStage stage ;
116
103
uint32_t started_at_timestamp ;
117
104
} FlippPomodoroState ;
118
105
119
- /// @brief Calculates difference between two provided timestamps
120
- /// @param begin - start timestamp of the period
121
- /// @param end - end timestamp of the period to measure
122
- /// @return TimeDifference struct
123
- static TimeDifference get_timestamp_difference_seconds (uint32_t begin , uint32_t end ) {
124
- const uint32_t duration_seconds = end - begin ;
125
-
126
- uint32_t minutes = (duration_seconds / SECONDS_IN_MINUTE ) % SECONDS_IN_MINUTE ;
127
- uint32_t seconds = duration_seconds % SECONDS_IN_MINUTE ;
128
-
129
- return (TimeDifference ){.total_seconds = duration_seconds , .minutes = minutes , .seconds = seconds };
130
- }
131
-
132
106
static void flipp_pomodoro__toggle_stage (FlippPomodoroState * state ) {
133
107
furi_assert (state );
134
108
state -> stage = stage_rotaion_map [state -> stage ];
135
- state -> started_at_timestamp = furi_hal_rtc_get_timestamp ();
109
+ state -> started_at_timestamp = time_now ();
136
110
}
137
111
138
112
static char * flipp_pomodoro__next_stage_label (FlippPomodoroState * state ) {
@@ -146,25 +120,32 @@ static void flipp_pomodoro__destroy(FlippPomodoroState* state) {
146
120
free (state );
147
121
}
148
122
123
+ static uint32_t flipp_pomodoro__current_stage_total_duration (FlippPomodoroState * state ) {
124
+ const int32_t stage_duration_seconds_map [] = {
125
+ [Work ] = 25 * TIME_SECONDS_IN_MINUTE ,
126
+ [Rest ] = 5 * TIME_SECONDS_IN_MINUTE ,
127
+ };
128
+
129
+ return stage_duration_seconds_map [state -> stage ];
130
+ }
131
+
149
132
static uint32_t flipp_pomodoro__stage_expires_timestamp (FlippPomodoroState * state ) {
150
- return state -> started_at_timestamp + stage_duration_seconds_map [ state -> stage ] ;
133
+ return state -> started_at_timestamp + flipp_pomodoro__current_stage_total_duration ( state ) ;
151
134
}
152
135
153
136
static TimeDifference flipp_pomodoro__stage_remaining_duration (FlippPomodoroState * state ) {
154
- const uint32_t now = furi_hal_rtc_get_timestamp ();
155
137
const uint32_t stage_ends_at = flipp_pomodoro__stage_expires_timestamp (state );
156
- return get_timestamp_difference_seconds ( now , stage_ends_at );
138
+ return time_difference_seconds ( time_now () , stage_ends_at );
157
139
}
158
140
159
141
static bool flipp_pomodoro__is_stage_expired (FlippPomodoroState * state ) {
160
- const uint32_t now = furi_hal_rtc_get_timestamp ();
161
142
const uint32_t expired_by = flipp_pomodoro__stage_expires_timestamp (state );
162
143
const uint8_t seamless_change_span_seconds = 1 ;
163
- return (now - seamless_change_span_seconds ) >= expired_by ;
144
+ return (time_now () - seamless_change_span_seconds ) >= expired_by ;
164
145
}
165
146
166
147
static FlippPomodoroState flipp_pomodoro__new () {
167
- const uint32_t now = furi_hal_rtc_get_timestamp ();
148
+ const uint32_t now = time_now ();
168
149
const FlippPomodoroState new_state = {.stage = default_stage , .started_at_timestamp = now };
169
150
return new_state ;
170
151
}
@@ -238,23 +219,30 @@ static void app_input_callback(InputEvent* input_event, void* ctx) {
238
219
furi_message_queue_put (event_queue , & action , FuriWaitForever );
239
220
};
240
221
241
- static bool input_events_reducer (FlippPomodoroState * state , InputEvent * input_event ) {
242
- bool keep_running = true;
243
- if ((input_event -> type == InputTypePress ) || (input_event -> type == InputTypeRepeat )) {
244
- switch (input_event -> key ) {
245
- case InputKeyRight :
246
- flipp_pomodoro__toggle_stage (state );
247
- break ;
248
- case InputKeyBack :
249
- keep_running = false;
250
- break ;
251
- default :
252
- break ;
253
- }
254
- }
255
- return keep_running ;
222
+ static bool is_input_event (Action action ) {
223
+ return action .type == InputEventType ;
224
+ }
225
+
226
+ static bool is_press_or_repeat (InputEvent * input_event ) {
227
+ return (input_event -> type == InputTypePress ) || (input_event -> type == InputTypeRepeat );
228
+ }
229
+
230
+ static bool is_button_back_pressed (Action action ) {
231
+ return is_input_event (action )
232
+ && is_press_or_repeat (action .payload )
233
+ && ((InputEvent * )action .payload )-> key == InputKeyBack ;
234
+ }
235
+
236
+ static bool is_button_right_pressed (Action action ) {
237
+ return is_input_event (action )
238
+ && is_press_or_repeat (action .payload )
239
+ && ((InputEvent * )action .payload )-> key == InputKeyRight ;
256
240
}
257
241
242
+ static bool is_timer_tick (Action action ) {
243
+ return action .type == TimerTickType ;
244
+ };
245
+
258
246
int32_t flipp_pomodoro_main (void * p ) {
259
247
UNUSED (p );
260
248
FuriMessageQueue * event_queue = furi_message_queue_alloc (8 , sizeof (Action ));
@@ -279,29 +267,45 @@ int32_t flipp_pomodoro_main(void* p) {
279
267
280
268
281
269
bool running = true;
270
+
271
+ const int queue_reading_window_tics = 200 ;
272
+
282
273
while (running ) {
283
274
Action action ;
284
- if (furi_message_queue_get (event_queue , & action , 200 ) != FuriStatusOk ) {
275
+ if (furi_message_queue_get (event_queue , & action , queue_reading_window_tics ) != FuriStatusOk ) {
276
+ // Queue read is failed
285
277
continue ;
286
278
};
287
279
288
280
if (!action .type ) {
281
+ // No item in queue
289
282
continue ;
290
283
}
291
-
292
- switch (action .type ) {
293
- case InputEventType :
294
- running = input_events_reducer (& state , action .payload );
295
- break ;
296
- case TimerTickType :
284
+
285
+ if (is_button_back_pressed (action )) {
286
+ running = false;
287
+ continue ;
288
+ };
289
+
290
+ if (is_timer_tick (action )) {
297
291
if (flipp_pomodoro__is_stage_expired (& state )) {
292
+ if (state .stage == Work ) {
293
+ // REGISTER a deed on work stage complete to get an acheivement
294
+ DOLPHIN_DEED (DolphinDeedPluginGameWin );
295
+ };
296
+
298
297
flipp_pomodoro__toggle_stage (& state );
298
+
299
+
300
+
299
301
notification_message (notification_app , stage_start_notification_sequence_map [state .stage ]);
300
302
};
301
- break ;
302
- default :
303
- break ;
304
303
}
304
+
305
+ if (is_button_right_pressed (action )) {
306
+ flipp_pomodoro__toggle_stage (& state );
307
+ };
308
+
305
309
view_port_update (view_port ); // Only re-draw on event
306
310
}
307
311
0 commit comments