Parcourir la source

fix cnt down timer & update pomodoro

MX il y a 2 ans
Parent
commit
5cee3bd7c4

+ 22 - 1
flipp_pomodoro_app.c

@@ -1,5 +1,7 @@
 #include "flipp_pomodoro_app_i.h"
 
+#define TAG "FlippPomodoro"
+
 enum {
     CustomEventConsumed = true,
     CustomEventNotConsumed = false,
@@ -32,6 +34,9 @@ static bool flipp_pomodoro_app_custom_event_callback(void* ctx, uint32_t event)
         if(flipp_pomodoro__get_stage(app->state) == FlippPomodoroStageFocus) {
             // REGISTER a deed on work stage complete to get an acheivement
             dolphin_deed(DolphinDeedPluginGameWin);
+            FURI_LOG_I(TAG, "Focus stage reward added");
+
+            flipp_pomodoro_statistics__increase_focus_stages_completed(app->statistics);
         };
 
         flipp_pomodoro__toggle_stage(app->state);
@@ -56,6 +61,8 @@ FlippPomodoroApp* flipp_pomodoro_app_alloc() {
     app->notification_app = furi_record_open(RECORD_NOTIFICATION);
 
     app->view_dispatcher = view_dispatcher_alloc();
+    app->statistics = flipp_pomodoro_statistics__new();
+
     view_dispatcher_enable_queue(app->view_dispatcher);
     view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
     view_dispatcher_set_custom_event_callback(
@@ -67,22 +74,32 @@ FlippPomodoroApp* flipp_pomodoro_app_alloc() {
         app->view_dispatcher, flipp_pomodoro_app_back_event_callback);
 
     app->timer_view = flipp_pomodoro_view_timer_alloc();
+    app->info_view = flipp_pomodoro_info_view_alloc();
 
     view_dispatcher_add_view(
         app->view_dispatcher,
         FlippPomodoroAppViewTimer,
         flipp_pomodoro_view_timer_get_view(app->timer_view));
 
-    scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneTimer);
+    view_dispatcher_add_view(
+        app->view_dispatcher,
+        FlippPomodoroAppViewInfo,
+        flipp_pomodoro_info_view_get_view(app->info_view));
 
+    scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneTimer);
+    FURI_LOG_I(TAG, "Alloc complete");
     return app;
 };
 
 void flipp_pomodoro_app_free(FlippPomodoroApp* app) {
     view_dispatcher_remove_view(app->view_dispatcher, FlippPomodoroAppViewTimer);
+    view_dispatcher_remove_view(app->view_dispatcher, FlippPomodoroAppViewInfo);
     view_dispatcher_free(app->view_dispatcher);
     scene_manager_free(app->scene_manager);
     flipp_pomodoro_view_timer_free(app->timer_view);
+    flipp_pomodoro_info_view_free(app->info_view);
+    flipp_pomodoro_statistics__destroy(app->statistics);
+    flipp_pomodoro__destroy(app->state);
     free(app);
     furi_record_close(RECORD_GUI);
     furi_record_close(RECORD_NOTIFICATION);
@@ -90,8 +107,12 @@ void flipp_pomodoro_app_free(FlippPomodoroApp* app) {
 
 int32_t flipp_pomodoro_app(void* p) {
     UNUSED(p);
+    FURI_LOG_I(TAG, "Initial");
     FlippPomodoroApp* app = flipp_pomodoro_app_alloc();
 
+    FURI_LOG_I(TAG, "Run deed added");
+    dolphin_deed(DolphinDeedPluginGameStart);
+
     view_dispatcher_run(app->view_dispatcher);
 
     flipp_pomodoro_app_free(app);

+ 6 - 0
flipp_pomodoro_app.h

@@ -7,8 +7,10 @@
 #include <gui/scene_manager.h>
 #include <notification/notification_messages.h>
 #include "views/flipp_pomodoro_timer_view.h"
+#include "views/flipp_pomodoro_info_view.h"
 
 #include "modules/flipp_pomodoro.h"
+#include "modules/flipp_pomodoro_statistics.h"
 
 typedef enum {
     // Reserve first 100 events for button types and indexes, starting from 0
@@ -16,6 +18,7 @@ typedef enum {
     FlippPomodoroAppCustomEventStageComplete, // By Expiration
     FlippPomodoroAppCustomEventTimerTick,
     FlippPomodoroAppCustomEventStateUpdated,
+    FlippPomodoroAppCustomEventResumeTimer,
 } FlippPomodoroAppCustomEvent;
 
 typedef struct {
@@ -24,9 +27,12 @@ typedef struct {
     Gui* gui;
     NotificationApp* notification_app;
     FlippPomodoroTimerView* timer_view;
+    FlippPomodoroInfoView* info_view;
     FlippPomodoroState* state;
+    FlippPomodoroStatistics* statistics;
 } FlippPomodoroApp;
 
 typedef enum {
     FlippPomodoroAppViewTimer,
+    FlippPomodoroAppViewInfo,
 } FlippPomodoroAppView;

+ 1 - 1
flipp_pomodoro_app_i.h

@@ -1,6 +1,6 @@
 #pragma once
 
-#define FURI_DEBUG 1
+// #define FURI_DEBUG 1
 
 /**
  * Index of dependencies for the main app

BIN
images/flipp_pomodoro_learn_50x128.png


+ 5 - 0
modules/flipp_pomodoro.c

@@ -55,6 +55,11 @@ char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state) {
     return next_stage_label[flipp_pomodoro__stage_by_index(state->current_stage_index + 1)];
 };
 
+void flipp_pomodoro__destroy(FlippPomodoroState* state) {
+    furi_assert(state);
+    free(state);
+};
+
 uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) {
     const int32_t stage_duration_seconds_map[] = {
         [FlippPomodoroStageFocus] = 25 * TIME_SECONDS_IN_MINUTE,

+ 0 - 1
modules/flipp_pomodoro.h

@@ -12,7 +12,6 @@ typedef enum {
 
 /// @brief State of the pomodoro timer
 typedef struct {
-    PomodoroStage stage;
     uint8_t current_stage_index;
     uint32_t started_at_timestamp;
 } FlippPomodoroState;

+ 26 - 0
modules/flipp_pomodoro_statistics.c

@@ -0,0 +1,26 @@
+#include "flipp_pomodoro_statistics.h"
+
+FlippPomodoroStatistics* flipp_pomodoro_statistics__new() {
+    FlippPomodoroStatistics* statistics = malloc(sizeof(FlippPomodoroStatistics));
+
+    statistics->focus_stages_completed = 0;
+
+    return statistics;
+}
+
+// Return the number of completed focus stages
+uint8_t
+    flipp_pomodoro_statistics__get_focus_stages_completed(FlippPomodoroStatistics* statistics) {
+    return statistics->focus_stages_completed;
+}
+
+// Increase the number of completed focus stages by one
+void flipp_pomodoro_statistics__increase_focus_stages_completed(
+    FlippPomodoroStatistics* statistics) {
+    statistics->focus_stages_completed++;
+}
+
+void flipp_pomodoro_statistics__destroy(FlippPomodoroStatistics* statistics) {
+    furi_assert(statistics);
+    free(statistics);
+};

+ 45 - 0
modules/flipp_pomodoro_statistics.h

@@ -0,0 +1,45 @@
+#pragma once
+#include <furi_hal.h>
+
+/** @brief FlippPomodoroStatistics structure
+ *
+ *  This structure is used to keep track of completed focus stages.
+ */
+typedef struct {
+    uint8_t focus_stages_completed;
+} FlippPomodoroStatistics;
+
+/** @brief Allocate and initialize a new FlippPomodoroStatistics
+ *
+ *  This function allocates a new FlippPomodoroStatistics structure, initializes its members
+ *  and returns a pointer to it.
+ *
+ *  @return A pointer to a new FlippPomodoroStatistics structure
+ */
+FlippPomodoroStatistics* flipp_pomodoro_statistics__new();
+
+/** @brief Get the number of completed focus stages
+ *
+ *  This function retrieves the number of completed focus stages in a FlippPomodoroStatistics structure.
+ *
+ *  @param statistics A pointer to a FlippPomodoroStatistics structure
+ *  @return The number of completed focus stages
+ */
+uint8_t flipp_pomodoro_statistics__get_focus_stages_completed(FlippPomodoroStatistics* statistics);
+
+/** @brief Increase the number of completed focus stages
+ *
+ *  This function increases the count of the completed focus stages by one in a FlippPomodoroStatistics structure.
+ *
+ *  @param statistics A pointer to a FlippPomodoroStatistics structure
+ */
+void flipp_pomodoro_statistics__increase_focus_stages_completed(
+    FlippPomodoroStatistics* statistics);
+
+/** @brief Free a FlippPomodoroStatistics structure
+ *
+ *  This function frees the memory used by a FlippPomodoroStatistics structure.
+ *
+ *  @param statistics A pointer to a FlippPomodoroStatistics structure
+ */
+void flipp_pomodoro_statistics__destroy(FlippPomodoroStatistics* state);

+ 1 - 0
scenes/config/flipp_pomodoro_scene_config.h

@@ -1 +1,2 @@
+ADD_SCENE(flipp_pomodoro, info, Info)
 ADD_SCENE(flipp_pomodoro, timer, Timer)

+ 1 - 0
scenes/flipp_pomodoro_scene.h

@@ -1,3 +1,4 @@
+#pragma once
 #include <gui/scene_manager.h>
 
 // Generate scene id and total number

+ 59 - 0
scenes/flipp_pomodoro_scene_info.c

@@ -0,0 +1,59 @@
+#include <furi.h>
+#include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+#include "flipp_pomodoro_scene.h"
+#include "../flipp_pomodoro_app.h"
+#include "../views/flipp_pomodoro_info_view.h"
+
+enum { SceneEventConusmed = true, SceneEventNotConusmed = false };
+
+void flipp_pomodoro_scene_info_on_back_to_timer(void* ctx) {
+    furi_assert(ctx);
+    FlippPomodoroApp* app = ctx;
+
+    view_dispatcher_send_custom_event(
+        app->view_dispatcher, FlippPomodoroAppCustomEventResumeTimer);
+};
+
+void flipp_pomodoro_scene_info_on_enter(void* ctx) {
+    furi_assert(ctx);
+    FlippPomodoroApp* app = ctx;
+
+    view_dispatcher_switch_to_view(app->view_dispatcher, FlippPomodoroAppViewInfo);
+    flipp_pomodoro_info_view_set_pomodoros_completed(
+        flipp_pomodoro_info_view_get_view(app->info_view),
+        flipp_pomodoro_statistics__get_focus_stages_completed(app->statistics));
+    flipp_pomodoro_info_view_set_mode(
+        flipp_pomodoro_info_view_get_view(app->info_view), FlippPomodoroInfoViewModeStats);
+    flipp_pomodoro_info_view_set_resume_timer_cb(
+        app->info_view, flipp_pomodoro_scene_info_on_back_to_timer, app);
+};
+
+void flipp_pomodoro_scene_info_handle_custom_event(
+    FlippPomodoroApp* app,
+    FlippPomodoroAppCustomEvent custom_event) {
+    if(custom_event == FlippPomodoroAppCustomEventResumeTimer) {
+        scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneTimer);
+    }
+};
+
+bool flipp_pomodoro_scene_info_on_event(void* ctx, SceneManagerEvent event) {
+    furi_assert(ctx);
+    FlippPomodoroApp* app = ctx;
+
+    switch(event.type) {
+    case SceneManagerEventTypeBack:
+        view_dispatcher_stop(app->view_dispatcher);
+        return SceneEventConusmed;
+    case SceneManagerEventTypeCustom:
+        flipp_pomodoro_scene_info_handle_custom_event(app, event.event);
+        return SceneEventConusmed;
+    default:
+        break;
+    };
+    return SceneEventNotConusmed;
+};
+
+void flipp_pomodoro_scene_info_on_exit(void* ctx) {
+    UNUSED(ctx);
+};

+ 9 - 3
scenes/flipp_pomodoro_scene_timer.c

@@ -1,13 +1,13 @@
 #include <furi.h>
 #include <gui/scene_manager.h>
 #include <gui/view_dispatcher.h>
+#include <gui/scene_manager.h>
+#include "flipp_pomodoro_scene.h"
 #include "../flipp_pomodoro_app.h"
 #include "../views/flipp_pomodoro_timer_view.h"
 
 enum { SceneEventConusmed = true, SceneEventNotConusmed = false };
 
-uint8_t ExitSignal = 0;
-
 void flipp_pomodoro_scene_timer_sync_view_state(void* ctx) {
     furi_assert(ctx);
 
@@ -30,6 +30,11 @@ void flipp_pomodoro_scene_timer_on_enter(void* ctx) {
 
     FlippPomodoroApp* app = ctx;
 
+    if(flipp_pomodoro__is_stage_expired(app->state)) {
+        flipp_pomodoro__destroy(app->state);
+        app->state = flipp_pomodoro__new();
+    }
+
     view_dispatcher_switch_to_view(app->view_dispatcher, FlippPomodoroAppViewTimer);
     flipp_pomodoro_scene_timer_sync_view_state(app);
     flipp_pomodoro_view_timer_set_on_right_cb(
@@ -59,7 +64,8 @@ bool flipp_pomodoro_scene_timer_on_event(void* ctx, SceneManagerEvent event) {
         flipp_pomodoro_scene_timer_handle_custom_event(app, event.event);
         return SceneEventConusmed;
     case SceneManagerEventTypeBack:
-        return ExitSignal;
+        scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneInfo);
+        return SceneEventConusmed;
     default:
         break;
     };

+ 152 - 0
views/flipp_pomodoro_info_view.c

@@ -0,0 +1,152 @@
+
+#include <furi.h>
+#include <gui/gui.h>
+#include <gui/elements.h>
+#include <gui/view.h>
+#include "flipp_pomodoro_info_view.h"
+// Auto-compiled icons
+#include "flipp_pomodoro_icons.h"
+
+enum {
+    ViewInputConsumed = true,
+    ViewInputNotConusmed = false,
+};
+
+struct FlippPomodoroInfoView {
+    View* view;
+    FlippPomodoroInfoViewUserActionCb resume_timer_cb;
+    void* user_action_cb_ctx;
+};
+
+typedef struct {
+    uint8_t pomodoros_completed;
+    FlippPomodoroInfoViewMode mode;
+} FlippPomodoroInfoViewModel;
+
+static void
+    flipp_pomodoro_info_view_draw_statistics(Canvas* canvas, FlippPomodoroInfoViewModel* model) {
+    FuriString* stats_string = furi_string_alloc();
+
+    furi_string_printf(
+        stats_string,
+        "So Long,\nand Thanks for All the Focus...\nand for completing\n%i pomodoro(s)",
+        model->pomodoros_completed);
+    const char* stats_string_formatted = furi_string_get_cstr(stats_string);
+
+    elements_text_box(
+        canvas,
+        0,
+        0,
+        canvas_width(canvas),
+        canvas_height(canvas) - 10,
+        AlignCenter,
+        AlignCenter,
+        stats_string_formatted,
+        true);
+
+    furi_string_free(stats_string);
+
+    elements_button_left(canvas, "Guide");
+}
+
+static void
+    flipp_pomodoro_info_view_draw_about(Canvas* canvas, FlippPomodoroInfoViewModel* model) {
+    UNUSED(model);
+    canvas_draw_icon(canvas, 0, 0, &I_flipp_pomodoro_learn_50x128);
+    elements_button_left(canvas, "Stats");
+}
+
+static void flipp_pomodoro_info_view_draw_callback(Canvas* canvas, void* _model) {
+    if(!_model) {
+        return;
+    };
+
+    FlippPomodoroInfoViewModel* model = _model;
+
+    canvas_clear(canvas);
+
+    if(model->mode == FlippPomodoroInfoViewModeStats) {
+        flipp_pomodoro_info_view_draw_statistics(canvas, model);
+    } else {
+        flipp_pomodoro_info_view_draw_about(canvas, model);
+    }
+
+    elements_button_right(canvas, "Resume");
+}
+
+void flipp_pomodoro_info_view_set_mode(View* view, FlippPomodoroInfoViewMode desired_mode) {
+    with_view_model(
+        view, FlippPomodoroInfoViewModel * model, { model->mode = desired_mode; }, false);
+}
+
+void flipp_pomodoro_info_view_toggle_mode(FlippPomodoroInfoView* info_view) {
+    with_view_model(
+        flipp_pomodoro_info_view_get_view(info_view),
+        FlippPomodoroInfoViewModel * model,
+        {
+            flipp_pomodoro_info_view_set_mode(
+                flipp_pomodoro_info_view_get_view(info_view),
+                (model->mode == FlippPomodoroInfoViewModeStats) ? FlippPomodoroInfoViewModeAbout :
+                                                                  FlippPomodoroInfoViewModeStats);
+        },
+        true);
+}
+
+bool flipp_pomodoro_info_view_input_callback(InputEvent* event, void* ctx) {
+    FlippPomodoroInfoView* info_view = ctx;
+
+    if(event->type == InputTypePress) {
+        if(event->key == InputKeyRight && info_view->resume_timer_cb != NULL) {
+            info_view->resume_timer_cb(info_view->user_action_cb_ctx);
+            return ViewInputConsumed;
+        } else if(event->key == InputKeyLeft) {
+            flipp_pomodoro_info_view_toggle_mode(info_view);
+            return ViewInputConsumed;
+        }
+    }
+
+    return ViewInputNotConusmed;
+}
+
+FlippPomodoroInfoView* flipp_pomodoro_info_view_alloc() {
+    FlippPomodoroInfoView* info_view = malloc(sizeof(FlippPomodoroInfoView));
+    info_view->view = view_alloc();
+
+    view_allocate_model(
+        flipp_pomodoro_info_view_get_view(info_view),
+        ViewModelTypeLockFree,
+        sizeof(FlippPomodoroInfoViewModel));
+    view_set_context(flipp_pomodoro_info_view_get_view(info_view), info_view);
+    view_set_draw_callback(
+        flipp_pomodoro_info_view_get_view(info_view), flipp_pomodoro_info_view_draw_callback);
+    view_set_input_callback(
+        flipp_pomodoro_info_view_get_view(info_view), flipp_pomodoro_info_view_input_callback);
+
+    return info_view;
+}
+
+View* flipp_pomodoro_info_view_get_view(FlippPomodoroInfoView* info_view) {
+    return info_view->view;
+}
+
+void flipp_pomodoro_info_view_free(FlippPomodoroInfoView* info_view) {
+    furi_assert(info_view);
+    view_free(info_view->view);
+    free(info_view);
+}
+
+void flipp_pomodoro_info_view_set_pomodoros_completed(View* view, uint8_t pomodoros_completed) {
+    with_view_model(
+        view,
+        FlippPomodoroInfoViewModel * model,
+        { model->pomodoros_completed = pomodoros_completed; },
+        false);
+}
+
+void flipp_pomodoro_info_view_set_resume_timer_cb(
+    FlippPomodoroInfoView* info_view,
+    FlippPomodoroInfoViewUserActionCb user_action_cb,
+    void* user_action_cb_ctx) {
+    info_view->resume_timer_cb = user_action_cb;
+    info_view->user_action_cb_ctx = user_action_cb_ctx;
+}

+ 71 - 0
views/flipp_pomodoro_info_view.h

@@ -0,0 +1,71 @@
+#pragma once
+
+#include <gui/view.h>
+
+/** @brief Mode types for FlippPomodoroInfoView
+ *
+ *  These are the modes that can be used in the FlippPomodoroInfoView
+ */
+typedef enum {
+    FlippPomodoroInfoViewModeStats,
+    FlippPomodoroInfoViewModeAbout,
+} FlippPomodoroInfoViewMode;
+
+/** @brief Forward declaration of the FlippPomodoroInfoView struct */
+typedef struct FlippPomodoroInfoView FlippPomodoroInfoView;
+
+/** @brief User action callback function type
+ *
+ *  Callback functions of this type are called when a user action is performed.
+ */
+typedef void (*FlippPomodoroInfoViewUserActionCb)(void* ctx);
+
+/** @brief Allocate a new FlippPomodoroInfoView
+ *
+ *  Allocates a new FlippPomodoroInfoView and returns a pointer to it.
+ *  @return A pointer to a new FlippPomodoroInfoView
+ */
+FlippPomodoroInfoView* flipp_pomodoro_info_view_alloc();
+
+/** @brief Get the view from a FlippPomodoroInfoView
+ *
+ *  Returns a pointer to the view associated with a FlippPomodoroInfoView.
+ *  @param info_view A pointer to a FlippPomodoroInfoView
+ *  @return A pointer to the view of the FlippPomodoroInfoView
+ */
+View* flipp_pomodoro_info_view_get_view(FlippPomodoroInfoView* info_view);
+
+/** @brief Free a FlippPomodoroInfoView
+ *
+ *  Frees the memory used by a FlippPomodoroInfoView.
+ *  @param info_view A pointer to a FlippPomodoroInfoView
+ */
+void flipp_pomodoro_info_view_free(FlippPomodoroInfoView* info_view);
+
+/** @brief Set the number of completed pomodoros in the view
+ *
+ *  Sets the number of completed pomodoros that should be displayed in the view.
+ *  @param info_view A pointer to the view
+ *  @param pomodoros_completed The number of completed pomodoros
+ */
+void flipp_pomodoro_info_view_set_pomodoros_completed(View* info_view, uint8_t pomodoros_completed);
+
+/** @brief Set the callback function to be called when the timer should be resumed
+ *
+ *  Sets the callback function that will be called when the timer should be resumed.
+ *  @param info_view A pointer to the FlippPomodoroInfoView
+ *  @param user_action_cb The callback function
+ *  @param user_action_cb_ctx The context to be passed to the callback function
+ */
+void flipp_pomodoro_info_view_set_resume_timer_cb(
+    FlippPomodoroInfoView* info_view,
+    FlippPomodoroInfoViewUserActionCb user_action_cb,
+    void* user_action_cb_ctx);
+
+/** @brief Set the mode of the view
+ *
+ *  Sets the mode that should be used in the view.
+ *  @param view A pointer to the view
+ *  @param desired_mode The desired mode
+ */
+void flipp_pomodoro_info_view_set_mode(View* view, FlippPomodoroInfoViewMode desired_mode);

+ 4 - 1
views/flipp_pomodoro_timer_view.c

@@ -156,7 +156,10 @@ FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc() {
     FlippPomodoroTimerView* timer = malloc(sizeof(FlippPomodoroTimerView));
     timer->view = view_alloc();
 
-    view_allocate_model(timer->view, ViewModelTypeLockFree, sizeof(FlippPomodoroTimerViewModel));
+    view_allocate_model(
+        flipp_pomodoro_view_timer_get_view(timer),
+        ViewModelTypeLockFree,
+        sizeof(FlippPomodoroTimerViewModel));
     view_set_context(flipp_pomodoro_view_timer_get_view(timer), timer);
     view_set_draw_callback(timer->view, flipp_pomodoro_view_timer_draw_callback);
     view_set_input_callback(timer->view, flipp_pomodoro_view_timer_input_callback);