diff --git a/application.fam b/application.fam index 22d1a365a99..914f0c94e7f 100644 --- a/application.fam +++ b/application.fam @@ -3,9 +3,9 @@ App( name="Flipp Pomodoro", apptype=FlipperAppType.EXTERNAL, entry_point="flipp_pomodoro_main", - requires=["gui", "notification"], + requires=["gui", "notification", "dolphin"], stack_size=1 * 1024, fap_category="Productivity", fap_icon_assets="images", fap_icon="flipp_pomodoro_10.png", -) \ No newline at end of file +) diff --git a/flipp_pomodoro.c b/flipp_pomodoro_app.c similarity index 76% rename from flipp_pomodoro.c rename to flipp_pomodoro_app.c index 8d1397114ae..6fec8f8606c 100644 --- a/flipp_pomodoro.c +++ b/flipp_pomodoro_app.c @@ -1,8 +1,9 @@ +#include "flipp_pomodoro_app_i.h" #include -#include #include #include +#include #include #include @@ -10,8 +11,6 @@ * Just set fap_icon_assets in application.fam and #include {APPID}_icons.h */ #include "flipp_pomodoro_icons.h" -const int SECONDS_IN_MINUTE = 60; - /// @brief Actions to be processed in a queue typedef enum { TimerTickType = 42, @@ -97,42 +96,17 @@ static const PomodoroStage stage_rotaion_map[] = { [Rest] = Work, }; -static const int32_t stage_duration_seconds_map[] = { - [Work] = 25 * SECONDS_IN_MINUTE, - [Rest] = 5 * SECONDS_IN_MINUTE, -}; - const PomodoroStage default_stage = Work; -/// @brief Container for a time period -typedef struct { - uint8_t seconds; - uint8_t minutes; - uint32_t total_seconds; -} TimeDifference; - typedef struct { PomodoroStage stage; uint32_t started_at_timestamp; } FlippPomodoroState; -/// @brief Calculates difference between two provided timestamps -/// @param begin - start timestamp of the period -/// @param end - end timestamp of the period to measure -/// @return TimeDifference struct -static TimeDifference get_timestamp_difference_seconds(uint32_t begin, uint32_t end) { - const uint32_t duration_seconds = end - begin; - - uint32_t minutes = (duration_seconds / SECONDS_IN_MINUTE) % SECONDS_IN_MINUTE; - uint32_t seconds = duration_seconds % SECONDS_IN_MINUTE; - - return (TimeDifference){.total_seconds=duration_seconds, .minutes=minutes, .seconds=seconds}; -} - static void flipp_pomodoro__toggle_stage(FlippPomodoroState* state) { furi_assert(state); state->stage = stage_rotaion_map[state->stage]; - state->started_at_timestamp = furi_hal_rtc_get_timestamp(); + state->started_at_timestamp = time_now(); } static char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state) { @@ -146,25 +120,32 @@ static void flipp_pomodoro__destroy(FlippPomodoroState* state) { free(state); } +static uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) { + const int32_t stage_duration_seconds_map[] = { + [Work] = 25 * TIME_SECONDS_IN_MINUTE, + [Rest] = 5 * TIME_SECONDS_IN_MINUTE, + }; + + return stage_duration_seconds_map[state->stage]; +} + static uint32_t flipp_pomodoro__stage_expires_timestamp(FlippPomodoroState* state) { - return state->started_at_timestamp + stage_duration_seconds_map[state->stage]; + return state->started_at_timestamp + flipp_pomodoro__current_stage_total_duration(state); } static TimeDifference flipp_pomodoro__stage_remaining_duration(FlippPomodoroState* state) { - const uint32_t now = furi_hal_rtc_get_timestamp(); const uint32_t stage_ends_at = flipp_pomodoro__stage_expires_timestamp(state); - return get_timestamp_difference_seconds(now, stage_ends_at); + return time_difference_seconds(time_now(), stage_ends_at); } static bool flipp_pomodoro__is_stage_expired(FlippPomodoroState* state) { - const uint32_t now = furi_hal_rtc_get_timestamp(); const uint32_t expired_by = flipp_pomodoro__stage_expires_timestamp(state); const uint8_t seamless_change_span_seconds = 1; - return (now - seamless_change_span_seconds) >= expired_by; + return (time_now() - seamless_change_span_seconds) >= expired_by; } static FlippPomodoroState flipp_pomodoro__new() { - const uint32_t now = furi_hal_rtc_get_timestamp(); + const uint32_t now = time_now(); const FlippPomodoroState new_state = {.stage=default_stage, .started_at_timestamp=now}; return new_state; } @@ -238,23 +219,30 @@ static void app_input_callback(InputEvent* input_event, void* ctx) { furi_message_queue_put(event_queue, &action, FuriWaitForever); }; -static bool input_events_reducer (FlippPomodoroState* state, InputEvent* input_event) { - bool keep_running = true; - if((input_event->type == InputTypePress) || (input_event->type == InputTypeRepeat)) { - switch(input_event->key) { - case InputKeyRight: - flipp_pomodoro__toggle_stage(state); - break; - case InputKeyBack: - keep_running = false; - break; - default: - break; - } - } - return keep_running; +static bool is_input_event(Action action) { + return action.type == InputEventType; +} + +static bool is_press_or_repeat(InputEvent* input_event) { + return (input_event->type == InputTypePress) || (input_event->type == InputTypeRepeat); +} + +static bool is_button_back_pressed(Action action) { + return is_input_event(action) + && is_press_or_repeat(action.payload) + && ((InputEvent*)action.payload)->key == InputKeyBack; +} + +static bool is_button_right_pressed(Action action) { + return is_input_event(action) + && is_press_or_repeat(action.payload) + && ((InputEvent*)action.payload)->key == InputKeyRight; } +static bool is_timer_tick(Action action) { + return action.type == TimerTickType; +}; + int32_t flipp_pomodoro_main(void* p) { UNUSED(p); FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(Action)); @@ -279,29 +267,45 @@ int32_t flipp_pomodoro_main(void* p) { bool running = true; + + const int queue_reading_window_tics = 200; + while(running) { Action action; - if(furi_message_queue_get(event_queue, &action, 200) != FuriStatusOk) { + if(furi_message_queue_get(event_queue, &action, queue_reading_window_tics) != FuriStatusOk) { + // Queue read is failed continue; }; if(!action.type) { + // No item in queue continue; } - - switch (action.type) { - case InputEventType: - running = input_events_reducer(&state, action.payload); - break; - case TimerTickType: + + if(is_button_back_pressed(action)) { + running = false; + continue; + }; + + if(is_timer_tick(action)) { if(flipp_pomodoro__is_stage_expired(&state)) { + if(state.stage == Work) { + // REGISTER a deed on work stage complete to get an acheivement + DOLPHIN_DEED(DolphinDeedPluginGameWin); + }; + flipp_pomodoro__toggle_stage(&state); + + + notification_message(notification_app, stage_start_notification_sequence_map[state.stage]); }; - break; - default: - break; } + + if(is_button_right_pressed(action)) { + flipp_pomodoro__toggle_stage(&state); + }; + view_port_update(view_port); // Only re-draw on event } diff --git a/flipp_pomodoro_app_i.h b/flipp_pomodoro_app_i.h new file mode 100644 index 00000000000..40d4fbf7091 --- /dev/null +++ b/flipp_pomodoro_app_i.h @@ -0,0 +1,9 @@ +#pragma once + +/** + * Index of dependencies for the main app +*/ + +#include +#include +#include "helpers/time.h" \ No newline at end of file diff --git a/helpers/time.c b/helpers/time.c new file mode 100644 index 00000000000..fd6d7c262ba --- /dev/null +++ b/helpers/time.c @@ -0,0 +1,21 @@ +#include +#include +#include "time.h" + +const int TIME_SECONDS_IN_MINUTE = 60; +const int TIME_MINUTES_IN_HOUR = 60; + +uint32_t time_now() { + return furi_hal_rtc_get_timestamp(); +}; + +TimeDifference time_difference_seconds(uint32_t begin, uint32_t end) { + const uint32_t duration_seconds = end - begin; + + uint32_t minutes = (duration_seconds / TIME_MINUTES_IN_HOUR) % TIME_MINUTES_IN_HOUR; + uint32_t seconds = duration_seconds % TIME_SECONDS_IN_MINUTE; + + return (TimeDifference){.total_seconds=duration_seconds, .minutes=minutes, .seconds=seconds}; +} + + diff --git a/helpers/time.h b/helpers/time.h new file mode 100644 index 00000000000..f77b35e7698 --- /dev/null +++ b/helpers/time.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +extern const int TIME_SECONDS_IN_MINUTE; +extern const int TIME_MINUTES_IN_HOUR; + +/// @brief Container for a time period +typedef struct { + uint8_t seconds; + uint8_t minutes; + uint32_t total_seconds; +} TimeDifference; + +/// @brief Time by the moment of calling +/// @return A timestamp(seconds percision) +uint32_t time_now(); + +/// @brief Calculates difference between two provided timestamps +/// @param begin - start timestamp of the period +/// @param end - end timestamp of the period to measure +/// @return TimeDifference struct +TimeDifference time_difference_seconds(uint32_t begin, uint32_t end); +