Просмотр исходного кода

feat: display stats (#97)

1. A new feature to display statistics has been added. This includes the creation of new files `flipp_pomodoro_statistics.c` and `flipp_pomodoro_statistics.h` in the `modules` directory, and changes to `flipp_pomodoro_app.c` and `flipp_pomodoro_app.h` to incorporate the statistics functionality.

2. The `.vscode/settings.json` file has been updated with new entries.

3. The `flipp_pomodoro_app.c` file has been updated with new functions and modifications to existing ones to accommodate the new statistics feature.

4. New scenes have been added for displaying information and statistics, as seen in the `flipp_pomodoro_scene_info.c` and `flipp_pomodoro_scene_timer.c` files.

5. A new view `flipp_pomodoro_info_view.c` has been created to display the statistics and information.

6. An image file `flipp_pomodoro_learn_50x128.png` has been added to the `images` directory.

7. A new shell script `files-list.sh` has been added to the `tools` directory.
Mikhail Gubenko 2 лет назад
Родитель
Сommit
52cc11a8c1

+ 19 - 1
flipp_pomodoro_app.c

@@ -1,5 +1,7 @@
 #include "flipp_pomodoro_app_i.h"
 
+#define TAG "FlippPomodoro"
+
 enum
 {
     CustomEventConsumed = true,
@@ -39,6 +41,9 @@ static bool flipp_pomodoro_app_custom_event_callback(void *ctx, uint32_t event)
         {
             // 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);
@@ -63,6 +68,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(app->view_dispatcher, flipp_pomodoro_app_custom_event_callback);
@@ -71,23 +78,32 @@ FlippPomodoroApp *flipp_pomodoro_app_alloc()
     view_dispatcher_set_navigation_event_callback(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);
@@ -97,8 +113,10 @@ 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);

+ 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
 {
@@ -17,6 +19,7 @@ typedef enum
     FlippPomodoroAppCustomEventStageComplete, // By Expiration
     FlippPomodoroAppCustomEventTimerTick,
     FlippPomodoroAppCustomEventStateUpdated,
+    FlippPomodoroAppCustomEventResumeTimer,
 } FlippPomodoroAppCustomEvent;
 
 typedef struct
@@ -26,10 +29,13 @@ 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


+ 0 - 1
modules/flipp_pomodoro.h

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

+ 28 - 0
modules/flipp_pomodoro_statistics.c

@@ -0,0 +1,28 @@
+#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

+ 67 - 0
scenes/flipp_pomodoro_scene_info.c

@@ -0,0 +1,67 @@
+#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);
+};

+ 10 - 3
scenes/flipp_pomodoro_scene_timer.c

@@ -1,6 +1,8 @@
 #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"
 
@@ -10,8 +12,6 @@ enum
     SceneEventNotConusmed = false
 };
 
-uint8_t ExitSignal = 0;
-
 void flipp_pomodoro_scene_timer_sync_view_state(void *ctx)
 {
     furi_assert(ctx);
@@ -40,6 +40,12 @@ 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(
@@ -76,7 +82,8 @@ bool flipp_pomodoro_scene_timer_on_event(void *ctx, SceneManagerEvent event)
             event.event);
         return SceneEventConusmed;
     case SceneManagerEventTypeBack:
-        return ExitSignal;
+        scene_manager_next_scene(app->scene_manager, FlippPomodoroSceneInfo);
+        return SceneEventConusmed;
     default:
         break;
     };

+ 167 - 0
views/flipp_pomodoro_info_view.c

@@ -0,0 +1,167 @@
+
+#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;
+}

+ 69 - 0
views/flipp_pomodoro_info_view.h

@@ -0,0 +1,69 @@
+#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);

+ 20 - 19
views/flipp_pomodoro_timer_view.c

@@ -66,37 +66,38 @@ static void flipp_pomodoro_view_timer_draw_countdown(Canvas *canvas, TimeDiffere
 };
 
 static void draw_str_with_drop_shadow(
-    Canvas *canvas,  uint8_t x,
+    Canvas *canvas, uint8_t x,
     uint8_t y,
     Align horizontal,
     Align vertical,
-    const char* str
-    ) {
-        canvas_set_color(canvas, ColorWhite);
-        for (int x_off = -2; x_off <= 2; x_off++)
+    const char *str)
+{
+    canvas_set_color(canvas, ColorWhite);
+    for (int x_off = -2; x_off <= 2; x_off++)
+    {
+        for (int y_off = -2; y_off <= 2; y_off++)
         {
-            for (int y_off = -2; y_off <= 2; y_off++)
-            {
-               canvas_draw_str_aligned(
+            canvas_draw_str_aligned(
                 canvas,
                 x + x_off,
                 y + y_off,
                 horizontal,
                 vertical,
                 str);
-            }
         }
-        canvas_set_color(canvas, ColorBlack);
-        canvas_draw_str_aligned(
-            canvas,
-            x,
-            y,
-            horizontal,
-            vertical,
-            str);
     }
+    canvas_set_color(canvas, ColorBlack);
+    canvas_draw_str_aligned(
+        canvas,
+        x,
+        y,
+        horizontal,
+        vertical,
+        str);
+}
 
-static void flipp_pomodoro_view_timer_draw_current_stage_label(Canvas *canvas, FlippPomodoroState *state) {
+static void flipp_pomodoro_view_timer_draw_current_stage_label(Canvas *canvas, FlippPomodoroState *state)
+{
     canvas_set_font(canvas, FontPrimary);
     draw_str_with_drop_shadow(
         canvas,
@@ -184,7 +185,7 @@ 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);