diff --git a/applications/plugins/calculator/calculator.c b/applications/plugins/calculator/calculator.c index b121641b0..1ca1d3a86 100644 --- a/applications/plugins/calculator/calculator.c +++ b/applications/plugins/calculator/calculator.c @@ -19,6 +19,7 @@ typedef struct { } selectedPosition; typedef struct { + FuriMutex* mutex; selectedPosition position; //string with the inputted calculator text char text[20]; @@ -201,8 +202,10 @@ void generate_calculator_layout(Canvas* canvas) { }; void calculator_draw_callback(Canvas* canvas, void* ctx) { - const Calculator* calculator_state = acquire_mutex((ValueMutex*)ctx, 25); - UNUSED(ctx); + furi_assert(ctx); + const Calculator* calculator_state = ctx; + furi_mutex_acquire(calculator_state->mutex, FuriWaitForever); + canvas_clear(canvas); //show selected button @@ -240,7 +243,7 @@ void calculator_draw_callback(Canvas* canvas, void* ctx) { //draw cursor canvas_draw_box(canvas, stringWidth + 5, 29, 5, 1); - release_mutex((ValueMutex*)ctx, calculator_state); + furi_mutex_release(calculator_state->mutex); } void calculator_input_callback(InputEvent* input_event, void* ctx) { @@ -315,8 +318,8 @@ int32_t calculator_app(void* p) { FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); Calculator* calculator_state = malloc(sizeof(Calculator)); - ValueMutex calculator_state_mutex; - if(!init_mutex(&calculator_state_mutex, calculator_state, sizeof(Calculator))) { + calculator_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(!calculator_state->mutex) { //FURI_LOG_E("calculator", "cannot create mutex\r\n"); free(calculator_state); return -1; @@ -324,7 +327,7 @@ int32_t calculator_app(void* p) { // Configure view port ViewPort* view_port = view_port_alloc(); - view_port_draw_callback_set(view_port, calculator_draw_callback, &calculator_state_mutex); + view_port_draw_callback_set(view_port, calculator_draw_callback, calculator_state); view_port_input_callback_set(view_port, calculator_input_callback, event_queue); view_port_set_orientation(view_port, ViewPortOrientationVertical); @@ -444,10 +447,12 @@ int32_t calculator_app(void* p) { } gui_remove_view_port(gui, view_port); view_port_free(view_port); + furi_mutex_free(calculator_state->mutex); furi_message_queue_free(event_queue); furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_GUI); + free(calculator_state); return 0; } diff --git a/applications/plugins/dice/application.fam b/applications/plugins/multi_dice/application.fam similarity index 90% rename from applications/plugins/dice/application.fam rename to applications/plugins/multi_dice/application.fam index bd836c48c..15f5fe820 100644 --- a/applications/plugins/dice/application.fam +++ b/applications/plugins/multi_dice/application.fam @@ -1,5 +1,5 @@ App( - appid="Dice", + appid="multi_dice", name="Multi-Dice", apptype=FlipperAppType.EXTERNAL, entry_point="dice_app", diff --git a/applications/plugins/dice/dice.c b/applications/plugins/multi_dice/dice.c similarity index 98% rename from applications/plugins/dice/dice.c rename to applications/plugins/multi_dice/dice.c index 0bf90a1c8..2de407cf0 100644 --- a/applications/plugins/dice/dice.c +++ b/applications/plugins/multi_dice/dice.c @@ -4,7 +4,6 @@ #include #include #include -#include #define TAG "Dice Roller" @@ -290,10 +289,6 @@ static void dice_render_callback(Canvas* const canvas, void* ctx) { state->diceQty, state->diceType[0], state->rollTime[0]); - // if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect) - // DOLPHIN_DEED(getRandomDeed()); - // if(state->diceSelect >= 20 && state->diceRoll == state->diceSelect - 1) - // DOLPHIN_DEED(getRandomDeed()); if(state->diceQty == 1) { snprintf(state->strings[1], sizeof(state->strings[1]), "%d", state->diceRoll); } else if(state->diceQty == 2) { diff --git a/applications/plugins/dice/dice.png b/applications/plugins/multi_dice/dice.png similarity index 100% rename from applications/plugins/dice/dice.png rename to applications/plugins/multi_dice/dice.png diff --git a/applications/plugins/nightstand/application.fam b/applications/plugins/nightstand/application.fam index 0b8cbf83a..ea28c7b77 100644 --- a/applications/plugins/nightstand/application.fam +++ b/applications/plugins/nightstand/application.fam @@ -1,12 +1,12 @@ App( - appid="Nightstand", + appid="nightstand", name="Nightstand Clock", apptype=FlipperAppType.EXTERNAL, entry_point="clock_app", requires=["gui"], icon="A_Clock_14", stack_size=2 * 1024, - fap_icon="ClockIcon.png", + fap_icon="clock.png", fap_category="Misc", order=81, ) diff --git a/applications/plugins/nightstand/ClockIcon.png b/applications/plugins/nightstand/clock.png similarity index 100% rename from applications/plugins/nightstand/ClockIcon.png rename to applications/plugins/nightstand/clock.png diff --git a/applications/plugins/nightstand/clock_app.c b/applications/plugins/nightstand/clock_app.c index d7a9f7faa..33dbb49a4 100644 --- a/applications/plugins/nightstand/clock_app.c +++ b/applications/plugins/nightstand/clock_app.c @@ -11,13 +11,16 @@ /* This is a modified version of the default clock app intended for use overnight - Up / Down control the displays brightness. Down at brightness 0 turns the notification LED on and off. + Up / Down controls the displays brightness. Down at brightness 0 turns the notification LED on and off. */ int brightness = 5; bool led = false; NotificationApp* notif = 0; +int dspBrightnessBarFrames = 0; +const int dspBrightnessBarDisplayFrames = 8; + const NotificationMessage message_red_dim = { .type = NotificationMessageTypeLedRed, .data.led.value = 0xFF / 16, @@ -51,6 +54,7 @@ void set_backlight_brightness(float brightness) { } void handle_up() { + dspBrightnessBarFrames = dspBrightnessBarDisplayFrames; if(brightness < 100) { led = false; notification_message(notif, &led_off); @@ -60,6 +64,7 @@ void handle_up() { } void handle_down() { + dspBrightnessBarFrames = dspBrightnessBarDisplayFrames; if(brightness > 0) { brightness -= 5; if(brightness == 0) { //trigger only on the first brightness 5 -> 0 transition @@ -83,6 +88,29 @@ static void clock_input_callback(InputEvent* input_event, FuriMessageQueue* even furi_message_queue_put(event_queue, &event, FuriWaitForever); } +//do you are have stupid? +void elements_progress_bar_vertical( + Canvas* canvas, + uint8_t x, + uint8_t y, + uint8_t height, + float progress) { + furi_assert(canvas); + furi_assert((progress >= 0) && (progress <= 1.0)); + uint8_t width = 9; + + uint8_t progress_length = roundf((1.f - progress) * (height - 2)); + + canvas_set_color(canvas, ColorBlack); + canvas_draw_box(canvas, x + 1, y + 1, width - 2, height - 2); + + canvas_set_color(canvas, ColorWhite); + canvas_draw_box(canvas, x + 1, y + 1, width - 2, progress_length); + + canvas_set_color(canvas, ColorBlack); + canvas_draw_rframe(canvas, x, y, width, height, 3); +} + static void clock_render_callback(Canvas* const canvas, void* ctx) { //canvas_clear(canvas); //canvas_set_color(canvas, ColorBlack); @@ -90,6 +118,11 @@ static void clock_render_callback(Canvas* const canvas, void* ctx) { //avoids a bug with the brightness being reverted after the backlight-off period set_backlight_brightness((float)(brightness / 100.f)); + if(dspBrightnessBarFrames > 0) { + elements_progress_bar_vertical(canvas, 119, 1, 62, (float)(brightness / 100.f)); + dspBrightnessBarFrames--; + } + ClockState* state = ctx; if(furi_mutex_acquire(state->mutex, 200) != FuriStatusOk) { //FURI_LOG_D(TAG, "Can't obtain mutex, requeue render"); @@ -270,7 +303,7 @@ int32_t clock_app(void* p) { notif = furi_record_open(RECORD_NOTIFICATION); float tmpBrightness = notif->settings.display_brightness; - brightness = tmpBrightness * 100; + brightness = tmpBrightness * 100; // Keep current brightness by default notification_message(notif, &sequence_display_backlight_enforce_on); notification_message(notif, &led_off); diff --git a/applications/plugins/orgasmotron/orgasmotron.c b/applications/plugins/orgasmotron/orgasmotron.c index 684fc3d95..80c7d9e42 100644 --- a/applications/plugins/orgasmotron/orgasmotron.c +++ b/applications/plugins/orgasmotron/orgasmotron.c @@ -6,6 +6,7 @@ #include typedef struct { + FuriMutex* mutex; int mode; } PluginState; @@ -39,8 +40,8 @@ int32_t orgasmotron_app(void* p) { FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent)); PluginState* plugin_state = malloc(sizeof(PluginState)); - ValueMutex state_mutex; - if(!init_mutex(&state_mutex, plugin_state, sizeof(PluginState))) { + plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal); + if(!plugin_state->mutex) { FURI_LOG_E("Orgasmatron", "cannot create mutex\r\n"); free(plugin_state); return 255; @@ -63,7 +64,7 @@ int32_t orgasmotron_app(void* p) { //while(furi_message_queue_get(event_queue, &event, FuriWaitForever) == FuriStatusOk) { while(processing) { FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100); - PluginState* plugin_state = (PluginState*)acquire_mutex_block(&state_mutex); + furi_mutex_acquire(plugin_state->mutex, FuriWaitForever); if(event_status == FuriStatusOk) { if(event.key == InputKeyBack && event.type == InputTypeShort) { //Exit Application @@ -132,15 +133,15 @@ int32_t orgasmotron_app(void* p) { delay(50); } } - release_mutex(&state_mutex, plugin_state); + furi_mutex_release(plugin_state->mutex); } gui_remove_view_port(gui, view_port); view_port_free(view_port); + furi_mutex_free(plugin_state->mutex); furi_message_queue_free(event_queue); furi_record_close(RECORD_NOTIFICATION); furi_record_close(RECORD_GUI); - delete_mutex(&state_mutex); return 0; -} \ No newline at end of file +} diff --git a/applications/plugins/pomodoro/LICENSE b/applications/plugins/pomodoro/LICENSE deleted file mode 100644 index 0e259d42c..000000000 --- a/applications/plugins/pomodoro/LICENSE +++ /dev/null @@ -1,121 +0,0 @@ -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. diff --git a/applications/plugins/pomodoro/application.fam b/applications/plugins/pomodoro/application.fam index e73427fc8..847d91606 100644 --- a/applications/plugins/pomodoro/application.fam +++ b/applications/plugins/pomodoro/application.fam @@ -1,15 +1,11 @@ App( - appid="Pomodoro_Timer", + appid="flipp_pomodoro", name="Pomodoro Timer", apptype=FlipperAppType.EXTERNAL, - entry_point="pomodoro_app", + entry_point="flipp_pomodoro_app", + requires=["gui", "notification", "dolphin"], stack_size=1 * 1024, - cdefines=["APP_POMODORO"], - requires=[ - "gui", - ], - order=10, - fap_icon="pomodoro_timer.png", fap_category="Tools", - fap_icon_assets="icons", + fap_icon_assets="images", + fap_icon="flipp_pomodoro_10.png", ) diff --git a/applications/plugins/pomodoro/flipp_pomodoro_10.png b/applications/plugins/pomodoro/flipp_pomodoro_10.png new file mode 100644 index 000000000..977d16a58 Binary files /dev/null and b/applications/plugins/pomodoro/flipp_pomodoro_10.png differ diff --git a/applications/plugins/pomodoro/flipp_pomodoro_app.c b/applications/plugins/pomodoro/flipp_pomodoro_app.c new file mode 100644 index 000000000..5adca1edb --- /dev/null +++ b/applications/plugins/pomodoro/flipp_pomodoro_app.c @@ -0,0 +1,95 @@ +#include "flipp_pomodoro_app_i.h" + +enum { + CustomEventConsumed = true, + CustomEventNotConsumed = false, +}; + +static bool flipp_pomodoro_app_back_event_callback(void* ctx) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + return scene_manager_handle_back_event(app->scene_manager); +}; + +static void flipp_pomodoro_app_tick_event_callback(void* ctx) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + + scene_manager_handle_custom_event(app->scene_manager, FlippPomodoroAppCustomEventTimerTick); +}; + +static bool flipp_pomodoro_app_custom_event_callback(void* ctx, uint32_t event) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + + switch(event) { + case FlippPomodoroAppCustomEventStageSkip: + flipp_pomodoro__toggle_stage(app->state); + view_dispatcher_send_custom_event( + app->view_dispatcher, FlippPomodoroAppCustomEventStateUpdated); + return CustomEventConsumed; + case FlippPomodoroAppCustomEventStageComplete: + flipp_pomodoro__toggle_stage(app->state); + notification_message( + app->notification_app, + stage_start_notification_sequence_map[flipp_pomodoro__get_stage(app->state)]); + view_dispatcher_send_custom_event( + app->view_dispatcher, FlippPomodoroAppCustomEventStateUpdated); + return CustomEventConsumed; + default: + break; + } + return scene_manager_handle_custom_event(app->scene_manager, event); +}; + +FlippPomodoroApp* flipp_pomodoro_app_alloc() { + FlippPomodoroApp* app = malloc(sizeof(FlippPomodoroApp)); + app->state = flipp_pomodoro__new(); + + app->scene_manager = scene_manager_alloc(&flipp_pomodoro_scene_handlers, app); + app->gui = furi_record_open(RECORD_GUI); + app->notification_app = furi_record_open(RECORD_NOTIFICATION); + + app->view_dispatcher = view_dispatcher_alloc(); + 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); + view_dispatcher_set_tick_event_callback( + app->view_dispatcher, flipp_pomodoro_app_tick_event_callback, 1000); + view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); + view_dispatcher_set_navigation_event_callback( + app->view_dispatcher, flipp_pomodoro_app_back_event_callback); + + app->timer_view = flipp_pomodoro_view_timer_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); + + return app; +}; + +void flipp_pomodoro_app_free(FlippPomodoroApp* app) { + view_dispatcher_remove_view(app->view_dispatcher, FlippPomodoroAppViewTimer); + view_dispatcher_free(app->view_dispatcher); + scene_manager_free(app->scene_manager); + flipp_pomodoro_view_timer_free(app->timer_view); + free(app); + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); +}; + +int32_t flipp_pomodoro_app(void* p) { + UNUSED(p); + FlippPomodoroApp* app = flipp_pomodoro_app_alloc(); + + view_dispatcher_run(app->view_dispatcher); + + flipp_pomodoro_app_free(app); + + return 0; +}; diff --git a/applications/plugins/pomodoro/flipp_pomodoro_app.h b/applications/plugins/pomodoro/flipp_pomodoro_app.h new file mode 100644 index 000000000..54102e1f3 --- /dev/null +++ b/applications/plugins/pomodoro/flipp_pomodoro_app.h @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "views/flipp_pomodoro_timer_view.h" + +#include "modules/flipp_pomodoro.h" + +typedef enum { + // Reserve first 100 events for button types and indexes, starting from 0 + FlippPomodoroAppCustomEventStageSkip = 100, + FlippPomodoroAppCustomEventStageComplete, // By Expiration + FlippPomodoroAppCustomEventTimerTick, + FlippPomodoroAppCustomEventStateUpdated, +} FlippPomodoroAppCustomEvent; + +typedef struct { + SceneManager* scene_manager; + ViewDispatcher* view_dispatcher; + Gui* gui; + NotificationApp* notification_app; + FlippPomodoroTimerView* timer_view; + FlippPomodoroState* state; +} FlippPomodoroApp; + +typedef enum { + FlippPomodoroAppViewTimer, +} FlippPomodoroAppView; \ No newline at end of file diff --git a/applications/plugins/pomodoro/flipp_pomodoro_app_i.h b/applications/plugins/pomodoro/flipp_pomodoro_app_i.h new file mode 100644 index 000000000..03c3dc894 --- /dev/null +++ b/applications/plugins/pomodoro/flipp_pomodoro_app_i.h @@ -0,0 +1,30 @@ +#pragma once + +#define FURI_DEBUG 1 + +/** + * Index of dependencies for the main app + */ + +// Platform Imports + +#include +#include +#include +#include +#include +#include +#include +#include + +// App resource imports + +#include "helpers/time.h" +#include "helpers/notifications.h" +#include "modules/flipp_pomodoro.h" +#include "flipp_pomodoro_app.h" +#include "scenes/flipp_pomodoro_scene.h" +#include "views/flipp_pomodoro_timer_view.h" + +// Auto-compiled icons +#include "flipp_pomodoro_icons.h" diff --git a/applications/plugins/pomodoro/helpers/debug.h b/applications/plugins/pomodoro/helpers/debug.h new file mode 100644 index 000000000..13b8f2998 --- /dev/null +++ b/applications/plugins/pomodoro/helpers/debug.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +#define TAG "FlippPomodoro" \ No newline at end of file diff --git a/applications/plugins/pomodoro/helpers/notifications.c b/applications/plugins/pomodoro/helpers/notifications.c new file mode 100644 index 000000000..388a3f11d --- /dev/null +++ b/applications/plugins/pomodoro/helpers/notifications.c @@ -0,0 +1,49 @@ +#include + +const NotificationSequence work_start_notification = { + &message_display_backlight_on, + + &message_vibro_on, + + &message_note_b5, + &message_delay_250, + + &message_note_d5, + &message_delay_250, + + &message_sound_off, + &message_vibro_off, + + &message_green_255, + &message_delay_1000, + &message_green_0, + &message_delay_250, + &message_green_255, + &message_delay_1000, + + NULL, +}; + +const NotificationSequence rest_start_notification = { + &message_display_backlight_on, + + &message_vibro_on, + + &message_note_d5, + &message_delay_250, + + &message_note_b5, + &message_delay_250, + + &message_sound_off, + &message_vibro_off, + + &message_red_255, + &message_delay_1000, + &message_red_0, + &message_delay_250, + &message_red_255, + &message_delay_1000, + + NULL, +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/helpers/notifications.h b/applications/plugins/pomodoro/helpers/notifications.h new file mode 100644 index 000000000..c6cd0428f --- /dev/null +++ b/applications/plugins/pomodoro/helpers/notifications.h @@ -0,0 +1,14 @@ +#pragma once + +#include "../modules/flipp_pomodoro.h" +#include + +extern const NotificationSequence work_start_notification; +extern const NotificationSequence rest_start_notification; + +/// @brief Defines a notification sequence that should indicate start of specific pomodoro stage. +const NotificationSequence* stage_start_notification_sequence_map[] = { + [FlippPomodoroStageFocus] = &work_start_notification, + [FlippPomodoroStageRest] = &rest_start_notification, + [FlippPomodoroStageLongBreak] = &rest_start_notification, +}; diff --git a/applications/plugins/pomodoro/helpers/time.c b/applications/plugins/pomodoro/helpers/time.c new file mode 100644 index 000000000..7fb0d13c2 --- /dev/null +++ b/applications/plugins/pomodoro/helpers/time.c @@ -0,0 +1,20 @@ +#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/applications/plugins/pomodoro/helpers/time.h b/applications/plugins/pomodoro/helpers/time.h new file mode 100644 index 000000000..7a7d90bf2 --- /dev/null +++ b/applications/plugins/pomodoro/helpers/time.h @@ -0,0 +1,24 @@ +#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); diff --git a/applications/plugins/pomodoro/icons/ButtonLeft_4x7.png b/applications/plugins/pomodoro/icons/ButtonLeft_4x7.png deleted file mode 100644 index 0b4655d43..000000000 Binary files a/applications/plugins/pomodoro/icons/ButtonLeft_4x7.png and /dev/null differ diff --git a/applications/plugins/pomodoro/icons/Ok_btn_9x9.png b/applications/plugins/pomodoro/icons/Ok_btn_9x9.png deleted file mode 100644 index 9a1539da2..000000000 Binary files a/applications/plugins/pomodoro/icons/Ok_btn_9x9.png and /dev/null differ diff --git a/applications/plugins/pomodoro/icons/Pin_back_arrow_10x8.png b/applications/plugins/pomodoro/icons/Pin_back_arrow_10x8.png deleted file mode 100644 index 3bafabd14..000000000 Binary files a/applications/plugins/pomodoro/icons/Pin_back_arrow_10x8.png and /dev/null differ diff --git a/applications/plugins/pomodoro/icons/Space_65x18.png b/applications/plugins/pomodoro/icons/Space_65x18.png deleted file mode 100644 index b60ae5097..000000000 Binary files a/applications/plugins/pomodoro/icons/Space_65x18.png and /dev/null differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png new file mode 100644 index 000000000..7ead27c4e Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png new file mode 100644 index 000000000..0e36886f2 Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png new file mode 100644 index 000000000..072affef3 Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png new file mode 100644 index 000000000..cf6358658 Binary files /dev/null and b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png differ diff --git a/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate new file mode 100644 index 000000000..56a6051ca --- /dev/null +++ b/applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/applications/plugins/pomodoro/modules/flipp_pomodoro.c b/applications/plugins/pomodoro/modules/flipp_pomodoro.c new file mode 100644 index 000000000..161e862f8 --- /dev/null +++ b/applications/plugins/pomodoro/modules/flipp_pomodoro.c @@ -0,0 +1,89 @@ +#include +#include +#include "../helpers/time.h" +#include "flipp_pomodoro.h" + +PomodoroStage stages_sequence[] = { + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + + FlippPomodoroStageFocus, + FlippPomodoroStageLongBreak, +}; + +char* current_stage_label[] = { + [FlippPomodoroStageFocus] = "Continue focus for:", + [FlippPomodoroStageRest] = "Keep rest for:", + [FlippPomodoroStageLongBreak] = "Long Break for:", +}; + +char* next_stage_label[] = { + [FlippPomodoroStageFocus] = "Focus", + [FlippPomodoroStageRest] = "Short Break", + [FlippPomodoroStageLongBreak] = "Long Break", +}; + +PomodoroStage flipp_pomodoro__stage_by_index(int index) { + const int one_loop_size = sizeof(stages_sequence); + return stages_sequence[index % one_loop_size]; +} + +void flipp_pomodoro__toggle_stage(FlippPomodoroState* state) { + furi_assert(state); + state->current_stage_index = state->current_stage_index + 1; + state->started_at_timestamp = time_now(); +}; + +PomodoroStage flipp_pomodoro__get_stage(FlippPomodoroState* state) { + furi_assert(state); + return flipp_pomodoro__stage_by_index(state->current_stage_index); +}; + +char* flipp_pomodoro__current_stage_label(FlippPomodoroState* state) { + furi_assert(state); + return current_stage_label[flipp_pomodoro__get_stage(state)]; +}; + +char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state) { + furi_assert(state); + return next_stage_label[flipp_pomodoro__stage_by_index(state->current_stage_index + 1)]; +}; + +uint32_t flipp_pomodoro__current_stage_total_duration(FlippPomodoroState* state) { + const int32_t stage_duration_seconds_map[] = { + [FlippPomodoroStageFocus] = 25 * TIME_SECONDS_IN_MINUTE, + [FlippPomodoroStageRest] = 5 * TIME_SECONDS_IN_MINUTE, + [FlippPomodoroStageLongBreak] = 30 * TIME_SECONDS_IN_MINUTE, + }; + + return stage_duration_seconds_map[flipp_pomodoro__get_stage(state)]; +}; + +uint32_t flipp_pomodoro__stage_expires_timestamp(FlippPomodoroState* state) { + return state->started_at_timestamp + flipp_pomodoro__current_stage_total_duration(state); +}; + +TimeDifference flipp_pomodoro__stage_remaining_duration(FlippPomodoroState* state) { + const uint32_t stage_ends_at = flipp_pomodoro__stage_expires_timestamp(state); + return time_difference_seconds(time_now(), stage_ends_at); +}; + +bool flipp_pomodoro__is_stage_expired(FlippPomodoroState* state) { + const uint32_t expired_by = flipp_pomodoro__stage_expires_timestamp(state); + const uint8_t seamless_change_span_seconds = 1; + return (time_now() - seamless_change_span_seconds) >= expired_by; +}; + +FlippPomodoroState* flipp_pomodoro__new() { + FlippPomodoroState* state = malloc(sizeof(FlippPomodoroState)); + const uint32_t now = time_now(); + state->started_at_timestamp = now; + state->current_stage_index = 0; + return state; +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/modules/flipp_pomodoro.h b/applications/plugins/pomodoro/modules/flipp_pomodoro.h new file mode 100644 index 000000000..251a77469 --- /dev/null +++ b/applications/plugins/pomodoro/modules/flipp_pomodoro.h @@ -0,0 +1,54 @@ +#pragma once + +#include +#include "../helpers/time.h" + +/// @brief Options of pomodoro stages +typedef enum { + FlippPomodoroStageFocus, + FlippPomodoroStageRest, + FlippPomodoroStageLongBreak, +} PomodoroStage; + +/// @brief State of the pomodoro timer +typedef struct { + PomodoroStage stage; + uint8_t current_stage_index; + uint32_t started_at_timestamp; +} FlippPomodoroState; + +/// @brief Generates initial state +/// @returns A new pre-populated state for pomodoro timer +FlippPomodoroState* flipp_pomodoro__new(); + +/// @brief Extract current stage of pomodoro +/// @param state - pointer to the state of pomorodo +/// @returns Current stage value +PomodoroStage flipp_pomodoro__get_stage(FlippPomodoroState* state); + +/// @brief Destroys state of timer and it's dependencies +void flipp_pomodoro__destroy(FlippPomodoroState* state); + +/// @brief Get remaining stage time. +/// @param state - pointer to the state of pomorodo +/// @returns Time difference to the end of current stage +TimeDifference flipp_pomodoro__stage_remaining_duration(FlippPomodoroState* state); + +/// @brief Label of currently active stage +/// @param state - pointer to the state of pomorodo +/// @returns A string that explains current stage +char* flipp_pomodoro__current_stage_label(FlippPomodoroState* state); + +/// @brief Label of transition to the next stage +/// @param state - pointer to the state of pomorodo. +/// @returns string with the label of the "skipp" button +char* flipp_pomodoro__next_stage_label(FlippPomodoroState* state); + +/// @brief Check if current stage is expired +/// @param state - pointer to the state of pomorodo. +/// @returns expriations status - true means stage is expired +bool flipp_pomodoro__is_stage_expired(FlippPomodoroState* state); + +/// @brief Rotate stage of the timer +/// @param state - pointer to the state of pomorodo. +void flipp_pomodoro__toggle_stage(FlippPomodoroState* state); diff --git a/applications/plugins/pomodoro/pomodoro.c b/applications/plugins/pomodoro/pomodoro.c deleted file mode 100644 index 5b1db1984..000000000 --- a/applications/plugins/pomodoro/pomodoro.c +++ /dev/null @@ -1,164 +0,0 @@ -#include "pomodoro.h" -#include - -#define TAG "PomodoroApp" - -enum PomodoroDebugSubmenuIndex { - PomodoroSubmenuIndex10, - PomodoroSubmenuIndex25, - PomodoroSubmenuIndex50, -}; - -void pomodoro_submenu_callback(void* context, uint32_t index) { - furi_assert(context); - Pomodoro* app = context; - if(index == PomodoroSubmenuIndex10) { - app->view_id = PomodoroView10; - view_dispatcher_switch_to_view(app->view_dispatcher, PomodoroView10); - } - if(index == PomodoroSubmenuIndex25) { - app->view_id = PomodoroView25; - view_dispatcher_switch_to_view(app->view_dispatcher, PomodoroView25); - } - if(index == PomodoroSubmenuIndex50) { - app->view_id = PomodoroView50; - view_dispatcher_switch_to_view(app->view_dispatcher, PomodoroView50); - } -} - -void pomodoro_dialog_callback(DialogExResult result, void* context) { - furi_assert(context); - Pomodoro* app = context; - if(result == DialogExResultLeft) { - view_dispatcher_stop(app->view_dispatcher); - } else if(result == DialogExResultRight) { - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); // Show last view - } else if(result == DialogExResultCenter) { - view_dispatcher_switch_to_view(app->view_dispatcher, PomodoroViewSubmenu); - } -} - -uint32_t pomodoro_exit_confirm_view(void* context) { - UNUSED(context); - return PomodoroViewExitConfirm; -} - -uint32_t pomodoro_exit(void* context) { - UNUSED(context); - return VIEW_NONE; -} - -Pomodoro* pomodoro_app_alloc() { - Pomodoro* app = malloc(sizeof(Pomodoro)); - - // Gui - app->gui = furi_record_open(RECORD_GUI); - - // Notifications - app->notifications = furi_record_open(RECORD_NOTIFICATION); - - // View dispatcher - app->view_dispatcher = view_dispatcher_alloc(); - view_dispatcher_enable_queue(app->view_dispatcher); - view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); - - // Submenu view - app->submenu = submenu_alloc(); - submenu_add_item( - app->submenu, - "Classic: 25 work 5 rest", - PomodoroSubmenuIndex25, - pomodoro_submenu_callback, - app); - submenu_add_item( - app->submenu, - "Long: 50 work 10 rest", - PomodoroSubmenuIndex50, - pomodoro_submenu_callback, - app); - submenu_add_item( - app->submenu, - "Sprint: 10 work 2 rest", - PomodoroSubmenuIndex10, - pomodoro_submenu_callback, - app); - view_set_previous_callback(submenu_get_view(app->submenu), pomodoro_exit); - view_dispatcher_add_view( - app->view_dispatcher, PomodoroViewSubmenu, submenu_get_view(app->submenu)); - - // Dialog view - app->dialog = dialog_ex_alloc(); - dialog_ex_set_result_callback(app->dialog, pomodoro_dialog_callback); - dialog_ex_set_context(app->dialog, app); - dialog_ex_set_left_button_text(app->dialog, "Exit"); - dialog_ex_set_right_button_text(app->dialog, "Stay"); - dialog_ex_set_center_button_text(app->dialog, "Menu"); - dialog_ex_set_header(app->dialog, "Close Current App?", 16, 12, AlignLeft, AlignTop); - view_dispatcher_add_view( - app->view_dispatcher, PomodoroViewExitConfirm, dialog_ex_get_view(app->dialog)); - - // 25 minutes view - app->pomodoro_25 = pomodoro_25_alloc(); - view_set_previous_callback(pomodoro_25_get_view(app->pomodoro_25), pomodoro_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, PomodoroView25, pomodoro_25_get_view(app->pomodoro_25)); - - // 50 minutes view - app->pomodoro_50 = pomodoro_50_alloc(); - view_set_previous_callback(pomodoro_50_get_view(app->pomodoro_50), pomodoro_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, PomodoroView50, pomodoro_50_get_view(app->pomodoro_50)); - - // 10 minutes view - app->pomodoro_10 = pomodoro_10_alloc(); - view_set_previous_callback(pomodoro_10_get_view(app->pomodoro_10), pomodoro_exit_confirm_view); - view_dispatcher_add_view( - app->view_dispatcher, PomodoroView10, pomodoro_10_get_view(app->pomodoro_10)); - - // TODO switch to menu after Media is done - app->view_id = PomodoroViewSubmenu; - view_dispatcher_switch_to_view(app->view_dispatcher, app->view_id); - - return app; -} - -void pomodoro_app_free(Pomodoro* app) { - furi_assert(app); - - // Reset notification - notification_internal_message(app->notifications, &sequence_reset_blue); - - // Free views - view_dispatcher_remove_view(app->view_dispatcher, PomodoroViewSubmenu); - submenu_free(app->submenu); - view_dispatcher_remove_view(app->view_dispatcher, PomodoroViewExitConfirm); - dialog_ex_free(app->dialog); - view_dispatcher_remove_view(app->view_dispatcher, PomodoroView25); - pomodoro_25_free(app->pomodoro_25); - view_dispatcher_remove_view(app->view_dispatcher, PomodoroView50); - pomodoro_50_free(app->pomodoro_50); - view_dispatcher_remove_view(app->view_dispatcher, PomodoroView10); - pomodoro_10_free(app->pomodoro_10); - view_dispatcher_free(app->view_dispatcher); - - // Close records - furi_record_close(RECORD_GUI); - app->gui = NULL; - furi_record_close(RECORD_NOTIFICATION); - app->notifications = NULL; - - // Free rest - free(app); -} - -int32_t pomodoro_app(void* p) { - UNUSED(p); - // Switch profile to Hid - Pomodoro* app = pomodoro_app_alloc(); - - view_dispatcher_run(app->view_dispatcher); - - pomodoro_app_free(app); - - return 0; -} diff --git a/applications/plugins/pomodoro/pomodoro.h b/applications/plugins/pomodoro/pomodoro.h deleted file mode 100644 index 53dedb8e3..000000000 --- a/applications/plugins/pomodoro/pomodoro.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include -#include -#include "pomodoro_timer.h" -#include "views/pomodoro_10.h" -#include "views/pomodoro_25.h" -#include "views/pomodoro_50.h" - -typedef struct { - Gui* gui; - NotificationApp* notifications; - ViewDispatcher* view_dispatcher; - Submenu* submenu; - DialogEx* dialog; - PomodoroTimer* pomodoro_10; - PomodoroTimer* pomodoro_25; - PomodoroTimer* pomodoro_50; - uint32_t view_id; -} Pomodoro; - -typedef enum { - PomodoroViewSubmenu, - PomodoroView10, - PomodoroView25, - PomodoroView50, - PomodoroViewExitConfirm, -} PomodoroView; diff --git a/applications/plugins/pomodoro/pomodoro_timer.c b/applications/plugins/pomodoro/pomodoro_timer.c deleted file mode 100644 index 0fba5db42..000000000 --- a/applications/plugins/pomodoro/pomodoro_timer.c +++ /dev/null @@ -1,242 +0,0 @@ -#include "pomodoro_timer.h" -#include -#include -#include -#include -#include - -const NotificationSequence sequence_finish = { - &message_display_backlight_on, - &message_green_255, - &message_vibro_on, - &message_note_c5, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_e5, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_g5, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_b5, - &message_delay_250, - &message_vibro_off, - &message_vibro_on, - &message_note_c6, - &message_delay_250, - &message_vibro_off, - &message_sound_off, - NULL, -}; - -const NotificationSequence sequence_rest = { - &message_display_backlight_on, - &message_red_255, - &message_vibro_on, - &message_note_c6, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_b5, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_g5, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_e5, - &message_delay_100, - &message_vibro_off, - &message_vibro_on, - &message_note_c5, - &message_delay_250, - &message_vibro_off, - &message_sound_off, - NULL, -}; - -void pomodoro_timer_process(PomodoroTimer* pomodoro_timer, InputEvent* event) { - with_view_model( - pomodoro_timer->view, - PomodoroTimerModel * model, - { - if(event->type == InputTypePress) { - if(event->key == InputKeyOk) { - model->ok_pressed = true; - } else if(event->key == InputKeyLeft) { - model->reset_pressed = true; - } else if(event->key == InputKeyBack) { - model->back_pressed = true; - } - } else if(event->type == InputTypeRelease) { - if(event->key == InputKeyOk) { - model->ok_pressed = false; - - // START/STOP TIMER - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - uint32_t current_timestamp = furi_hal_rtc_datetime_to_timestamp(&curr_dt); - - // STARTED -> PAUSED - if(model->timer_running) { - // Update stopped seconds - model->timer_stopped_seconds = - current_timestamp - model->timer_start_timestamp; - } else if(!model->time_passed) { - // INITIAL -> STARTED - model->timer_start_timestamp = current_timestamp; - model->rest_running = false; - } else { - // PAUSED -> STARTED - model->timer_start_timestamp = - current_timestamp - model->timer_stopped_seconds; - } - model->timer_running = !model->timer_running; - } else if(event->key == InputKeyLeft) { - if(!model->timer_running) { - furi_record_close(RECORD_NOTIFICATION); - model->timer_stopped_seconds = 0; - model->timer_start_timestamp = 0; - model->time_passed = 0; - model->timer_running = false; - } - model->reset_pressed = false; - } else if(event->key == InputKeyBack) { - model->back_pressed = false; - } - } - }, - true); -} - -void pomodoro_draw_callback(Canvas* canvas, void* context, int max_seconds, int max_seconds_rest) { - furi_assert(context); - PomodoroTimerModel* model = context; - FuriHalRtcDateTime curr_dt; - furi_hal_rtc_get_datetime(&curr_dt); - uint32_t current_timestamp = furi_hal_rtc_datetime_to_timestamp(&curr_dt); - - // Header - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Pomodoro"); - - canvas_draw_icon(canvas, 68, 1, &I_Pin_back_arrow_10x8); - canvas_set_font(canvas, FontSecondary); - elements_multiline_text_aligned(canvas, 127, 1, AlignRight, AlignTop, "Hold to exit"); - - // Start/Pause/Continue - int txt_main_y = 34; - canvas_draw_icon(canvas, 63, 23, &I_Space_65x18); // button - if(model->ok_pressed) { - elements_slightly_rounded_box(canvas, 66, 25, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - if(model->timer_running) { - model->time_passed = current_timestamp - model->timer_start_timestamp; - elements_multiline_text_aligned(canvas, 83, txt_main_y, AlignLeft, AlignBottom, "Pause"); - canvas_draw_box(canvas, 71, 27, 2, 8); - canvas_draw_box(canvas, 75, 27, 2, 8); - } else { - if(model->time_passed) { - elements_multiline_text_aligned( - canvas, 83, txt_main_y, AlignLeft, AlignBottom, "Continue"); - } else { - elements_multiline_text_aligned( - canvas, 83, txt_main_y, AlignLeft, AlignBottom, "Start"); - } - canvas_draw_icon(canvas, 70, 26, &I_Ok_btn_9x9); // OK icon - } - canvas_set_color(canvas, ColorBlack); - - // Reset - if(!model->timer_running && model->time_passed) { - canvas_draw_icon(canvas, 63, 46, &I_Space_65x18); - if(model->reset_pressed) { - elements_slightly_rounded_box(canvas, 66, 48, 60, 13); - canvas_set_color(canvas, ColorWhite); - } - canvas_draw_icon(canvas, 72, 50, &I_ButtonLeft_4x7); - elements_multiline_text_aligned(canvas, 83, 57, AlignLeft, AlignBottom, "Reset"); - canvas_set_color(canvas, ColorBlack); - } - - char buffer[64]; - - // Time to work - int total_time_left = (max_seconds - (uint32_t)model->time_passed); - int minutes_left = total_time_left / 60; - int seconds_left = total_time_left % 60; - canvas_set_font(canvas, FontBigNumbers); - - // Play sound - if(total_time_left == 0 && !model->sound_playing) { - model->sound_playing = true; - notification_message(furi_record_open(RECORD_NOTIFICATION), &sequence_finish); - } - if(total_time_left < 0) { - model->timer_running = false; - model->time_passed = 0; - model->sound_playing = false; - - model->rest_running = true; - model->rest_start_timestamp = current_timestamp; - seconds_left = 0; - model->counter += 1; - } - if(!model->rest_running) { - snprintf(buffer, sizeof(buffer), "%02d:%02d", minutes_left, seconds_left); - canvas_draw_str(canvas, 0, 39, buffer); - } - if(model->timer_running) { - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 0, 50, AlignLeft, AlignTop, "Time to work"); - } - - // Time to rest - if(model->rest_running && !model->timer_running) { - canvas_set_font(canvas, FontBigNumbers); - int rest_passed = current_timestamp - model->rest_start_timestamp; - int rest_total_time_left = (max_seconds_rest - rest_passed); - int rest_minutes_left = rest_total_time_left / 60; - int rest_seconds_left = rest_total_time_left % 60; - - // Play sound - if(rest_total_time_left == 0 && !model->sound_playing) { - model->sound_playing = true; - notification_message(furi_record_open(RECORD_NOTIFICATION), &sequence_rest); - } - if(rest_total_time_left < 0) { - rest_seconds_left = 0; - model->rest_running = false; - model->sound_playing = false; - } - snprintf(buffer, sizeof(buffer), "%02d:%02d", rest_minutes_left, rest_seconds_left); - canvas_draw_str(canvas, 0, 60, buffer); - - canvas_set_font(canvas, FontPrimary); - elements_multiline_text_aligned(canvas, 0, 27, AlignLeft, AlignTop, "Have a rest"); - } - - // Clocks - canvas_set_font(canvas, FontSecondary); - snprintf( - buffer, - sizeof(buffer), - "%02ld:%02ld:%02ld", - ((uint32_t)current_timestamp % (60 * 60 * 24)) / (60 * 60), - ((uint32_t)current_timestamp % (60 * 60)) / 60, - (uint32_t)current_timestamp % 60); - canvas_draw_str(canvas, 0, 20, buffer); - - // Tomato counter - if(model->counter > 5) { - model->counter = 1; - } - for(int i = 0; i < model->counter; ++i) { - canvas_draw_disc(canvas, 122 - i * 10, 15, 4); - } -} diff --git a/applications/plugins/pomodoro/pomodoro_timer.h b/applications/plugins/pomodoro/pomodoro_timer.h deleted file mode 100644 index 284f0a6c6..000000000 --- a/applications/plugins/pomodoro/pomodoro_timer.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -typedef struct PomodoroTimer PomodoroTimer; - -struct PomodoroTimer { - View* view; -}; - -typedef struct PomodoroTimerModel PomodoroTimerModel; - -struct PomodoroTimerModel { - bool ok_pressed; - bool reset_pressed; - bool back_pressed; - bool connected; - bool timer_running; - bool rest_running; - bool sound_playing; - uint32_t timer_start_timestamp; - uint32_t timer_stopped_seconds; - uint32_t time_passed; - uint32_t rest_start_timestamp; - int counter; -}; - -void pomodoro_timer_process(PomodoroTimer* pomodoro_timer, InputEvent* event); - -void pomodoro_draw_callback(Canvas* canvas, void* context, int max_seconds, int max_seconds_rest); diff --git a/applications/plugins/pomodoro/pomodoro_timer.png b/applications/plugins/pomodoro/pomodoro_timer.png deleted file mode 100644 index b25c2718e..000000000 Binary files a/applications/plugins/pomodoro/pomodoro_timer.png and /dev/null differ diff --git a/applications/plugins/pomodoro/scenes/.keep b/applications/plugins/pomodoro/scenes/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h b/applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h new file mode 100644 index 000000000..f95daeb30 --- /dev/null +++ b/applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h @@ -0,0 +1 @@ +ADD_SCENE(flipp_pomodoro, timer, Timer) \ No newline at end of file diff --git a/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c new file mode 100644 index 000000000..5856ac947 --- /dev/null +++ b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c @@ -0,0 +1,30 @@ +#include "flipp_pomodoro_scene.h" + +// Generate scene on_enter handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, +void (*const flipp_pomodoro_scene_on_enter_handlers[])(void*) = { +#include "config/flipp_pomodoro_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_event handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, +bool (*const flipp_pomodoro_scene_on_event_handlers[])(void* ctx, SceneManagerEvent event) = { +#include "config/flipp_pomodoro_scene_config.h" +}; +#undef ADD_SCENE + +// Generate scene on_exit handlers array +#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, +void (*const flipp_pomodoro_scene_on_exit_handlers[])(void* ctx) = { +#include "config/flipp_pomodoro_scene_config.h" +}; +#undef ADD_SCENE + +// Initialize scene handlers configuration structure +const SceneManagerHandlers flipp_pomodoro_scene_handlers = { + .on_enter_handlers = flipp_pomodoro_scene_on_enter_handlers, + .on_event_handlers = flipp_pomodoro_scene_on_event_handlers, + .on_exit_handlers = flipp_pomodoro_scene_on_exit_handlers, + .scene_num = FlippPomodoroSceneNum, +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h new file mode 100644 index 000000000..3b8a9052a --- /dev/null +++ b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h @@ -0,0 +1,27 @@ +#include + +// Generate scene id and total number +#define ADD_SCENE(prefix, name, id) FlippPomodoroScene##id, +typedef enum { +#include "config/flipp_pomodoro_scene_config.h" + FlippPomodoroSceneNum, +} FlippPomodoroScene; +#undef ADD_SCENE + +extern const SceneManagerHandlers flipp_pomodoro_scene_handlers; + +// Generate scene on_enter handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); +#include "config/flipp_pomodoro_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_event handlers declaration +#define ADD_SCENE(prefix, name, id) \ + bool prefix##_scene_##name##_on_event(void* ctx, SceneManagerEvent event); +#include "config/flipp_pomodoro_scene_config.h" +#undef ADD_SCENE + +// Generate scene on_exit handlers declaration +#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* ctx); +#include "config/flipp_pomodoro_scene_config.h" +#undef ADD_SCENE diff --git a/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c new file mode 100644 index 000000000..2190dbdb7 --- /dev/null +++ b/applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c @@ -0,0 +1,71 @@ +#include +#include +#include +#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); + + FlippPomodoroApp* app = ctx; + + flipp_pomodoro_view_timer_set_state( + flipp_pomodoro_view_timer_get_view(app->timer_view), app->state); +}; + +void flipp_pomodoro_scene_timer_on_next_stage(void* ctx) { + furi_assert(ctx); + + FlippPomodoroApp* app = ctx; + + view_dispatcher_send_custom_event(app->view_dispatcher, FlippPomodoroAppCustomEventStageSkip); +}; + +void flipp_pomodoro_scene_timer_on_enter(void* ctx) { + furi_assert(ctx); + + FlippPomodoroApp* app = ctx; + + 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( + app->timer_view, flipp_pomodoro_scene_timer_on_next_stage, app); +}; + +void flipp_pomodoro_scene_timer_handle_custom_event( + FlippPomodoroApp* app, + FlippPomodoroAppCustomEvent custom_event) { + if(custom_event == FlippPomodoroAppCustomEventTimerTick && + flipp_pomodoro__is_stage_expired(app->state)) { + view_dispatcher_send_custom_event( + app->view_dispatcher, FlippPomodoroAppCustomEventStageComplete); + } + + if(custom_event == FlippPomodoroAppCustomEventStateUpdated) { + flipp_pomodoro_scene_timer_sync_view_state(app); + } +}; + +bool flipp_pomodoro_scene_timer_on_event(void* ctx, SceneManagerEvent event) { + furi_assert(ctx); + FlippPomodoroApp* app = ctx; + + switch(event.type) { + case SceneManagerEventTypeCustom: + flipp_pomodoro_scene_timer_handle_custom_event(app, event.event); + return SceneEventConusmed; + case SceneManagerEventTypeBack: + return ExitSignal; + default: + break; + }; + return SceneEventNotConusmed; +}; + +void flipp_pomodoro_scene_timer_on_exit(void* ctx) { + UNUSED(ctx); +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/views/.keep b/applications/plugins/pomodoro/views/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c new file mode 100644 index 000000000..e8e0383b7 --- /dev/null +++ b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c @@ -0,0 +1,195 @@ +#include "flipp_pomodoro_timer_view.h" +#include +#include +#include +#include +#include "../helpers/debug.h" +#include "../flipp_pomodoro_app.h" +#include "../modules/flipp_pomodoro.h" + +// Auto-compiled icons +#include "flipp_pomodoro_icons.h" + +enum { + ViewInputConsumed = true, + ViewInputNotConusmed = false, +}; + +struct FlippPomodoroTimerView { + View* view; + FlippPomodoroTimerViewInputCb right_cb; + void* right_cb_ctx; +}; + +typedef struct { + IconAnimation* icon; + FlippPomodoroState* state; +} FlippPomodoroTimerViewModel; + +static const Icon* stage_background_image[] = { + [FlippPomodoroStageFocus] = &A_flipp_pomodoro_focus_64, + [FlippPomodoroStageRest] = &A_flipp_pomodoro_rest_64, + [FlippPomodoroStageLongBreak] = &A_flipp_pomodoro_rest_64, +}; + +static void + flipp_pomodoro_view_timer_draw_countdown(Canvas* canvas, TimeDifference remaining_time) { + canvas_set_font(canvas, FontBigNumbers); + const uint8_t right_border_margin = 1; + + const uint8_t countdown_box_height = canvas_height(canvas) * 0.4; + const uint8_t countdown_box_width = canvas_width(canvas) * 0.5; + const uint8_t countdown_box_x = + canvas_width(canvas) - countdown_box_width - right_border_margin; + const uint8_t countdown_box_y = 15; + + elements_bold_rounded_frame( + canvas, countdown_box_x, countdown_box_y, countdown_box_width, countdown_box_height); + + FuriString* timer_string = furi_string_alloc(); + furi_string_printf(timer_string, "%02u:%02u", remaining_time.minutes, remaining_time.seconds); + const char* remaining_stage_time_string = furi_string_get_cstr(timer_string); + canvas_draw_str_aligned( + canvas, + countdown_box_x + (countdown_box_width / 2), + countdown_box_y + (countdown_box_height / 2), + AlignCenter, + AlignCenter, + remaining_stage_time_string); + + furi_string_free(timer_string); +}; + +static void draw_str_with_drop_shadow( + 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++) { + for(int y_off = -2; y_off <= 2; y_off++) { + 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); +} + +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, + canvas_width(canvas), + 0, + AlignRight, + AlignTop, + flipp_pomodoro__current_stage_label(state)); +} + +static void flipp_pomodoro_view_timer_draw_callback(Canvas* canvas, void* _model) { + if(!_model) { + return; + }; + + FlippPomodoroTimerViewModel* model = _model; + + canvas_clear(canvas); + if(model->icon) { + canvas_draw_icon_animation(canvas, 0, 0, model->icon); + } + + flipp_pomodoro_view_timer_draw_countdown( + canvas, flipp_pomodoro__stage_remaining_duration(model->state)); + + flipp_pomodoro_view_timer_draw_current_stage_label(canvas, model->state); + canvas_set_color(canvas, ColorBlack); + + canvas_set_font(canvas, FontSecondary); + elements_button_right(canvas, flipp_pomodoro__next_stage_label(model->state)); +}; + +bool flipp_pomodoro_view_timer_input_callback(InputEvent* event, void* ctx) { + furi_assert(ctx); + furi_assert(event); + FlippPomodoroTimerView* timer = ctx; + + const bool should_trigger_right_event_cb = (event->type == InputTypePress) && + (event->key == InputKeyRight) && + (timer->right_cb != NULL); + + if(should_trigger_right_event_cb) { + furi_assert(timer->right_cb); + furi_assert(timer->right_cb_ctx); + timer->right_cb(timer->right_cb_ctx); + return ViewInputConsumed; + }; + + return ViewInputNotConusmed; +}; + +View* flipp_pomodoro_view_timer_get_view(FlippPomodoroTimerView* timer) { + furi_assert(timer); + return timer->view; +}; + +void flipp_pomodoro_view_timer_assign_animation(View* view) { + with_view_model( + view, + FlippPomodoroTimerViewModel * model, + { + furi_assert(model->state); + if(model->icon) { + icon_animation_free(model->icon); + } + model->icon = icon_animation_alloc( + stage_background_image[flipp_pomodoro__get_stage(model->state)]); + view_tie_icon_animation(view, model->icon); + icon_animation_start(model->icon); + }, + true); +} + +FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc() { + FlippPomodoroTimerView* timer = malloc(sizeof(FlippPomodoroTimerView)); + timer->view = view_alloc(); + + view_allocate_model(timer->view, 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); + + return timer; +}; + +void flipp_pomodoro_view_timer_set_on_right_cb( + FlippPomodoroTimerView* timer, + FlippPomodoroTimerViewInputCb right_cb, + void* right_cb_ctx) { + furi_assert(right_cb); + furi_assert(right_cb_ctx); + timer->right_cb = right_cb; + timer->right_cb_ctx = right_cb_ctx; +}; + +void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state) { + furi_assert(view); + furi_assert(state); + with_view_model( + view, FlippPomodoroTimerViewModel * model, { model->state = state; }, false); + flipp_pomodoro_view_timer_assign_animation(view); +}; + +void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer) { + furi_assert(timer); + with_view_model( + timer->view, + FlippPomodoroTimerViewModel * model, + { icon_animation_free(model->icon); }, + false); + view_free(timer->view); + + free(timer); +}; \ No newline at end of file diff --git a/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h new file mode 100644 index 000000000..929a0eba3 --- /dev/null +++ b/applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include "../modules/flipp_pomodoro.h" + +typedef struct FlippPomodoroTimerView FlippPomodoroTimerView; + +typedef void (*FlippPomodoroTimerViewInputCb)(void* ctx); + +FlippPomodoroTimerView* flipp_pomodoro_view_timer_alloc(); + +View* flipp_pomodoro_view_timer_get_view(FlippPomodoroTimerView* timer); + +void flipp_pomodoro_view_timer_free(FlippPomodoroTimerView* timer); + +void flipp_pomodoro_view_timer_set_state(View* view, FlippPomodoroState* state); + +void flipp_pomodoro_view_timer_set_on_right_cb( + FlippPomodoroTimerView* timer, + FlippPomodoroTimerViewInputCb right_cb, + void* right_cb_ctx); diff --git a/applications/plugins/pomodoro/views/pomodoro_10.c b/applications/plugins/pomodoro/views/pomodoro_10.c deleted file mode 100644 index f11f96d9f..000000000 --- a/applications/plugins/pomodoro/views/pomodoro_10.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../pomodoro_timer.h" -#include "pomodoro_10.h" -#include -#include -#include -#include - -static void pomodoro_10_draw_callback(Canvas* canvas, void* context) { - int max_seconds = 60 * 10; - int max_seconds_rest = 60 * 2; - pomodoro_draw_callback(canvas, context, max_seconds, max_seconds_rest); -} - -static bool pomodoro_10_input_callback(InputEvent* event, void* context) { - furi_assert(context); - PomodoroTimer* pomodoro_10 = context; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - return false; - } else { - pomodoro_timer_process(pomodoro_10, event); - return true; - } -} - -PomodoroTimer* pomodoro_10_alloc() { - PomodoroTimer* pomodoro_10 = malloc(sizeof(PomodoroTimer)); - pomodoro_10->view = view_alloc(); - view_set_context(pomodoro_10->view, pomodoro_10); - view_allocate_model(pomodoro_10->view, ViewModelTypeLocking, sizeof(PomodoroTimerModel)); - view_set_draw_callback(pomodoro_10->view, pomodoro_10_draw_callback); - view_set_input_callback(pomodoro_10->view, pomodoro_10_input_callback); - - return pomodoro_10; -} - -void pomodoro_10_free(PomodoroTimer* pomodoro_10) { - furi_assert(pomodoro_10); - view_free(pomodoro_10->view); - free(pomodoro_10); -} - -View* pomodoro_10_get_view(PomodoroTimer* pomodoro_10) { - furi_assert(pomodoro_10); - return pomodoro_10->view; -} diff --git a/applications/plugins/pomodoro/views/pomodoro_10.h b/applications/plugins/pomodoro/views/pomodoro_10.h deleted file mode 100644 index 8f27e6bd6..000000000 --- a/applications/plugins/pomodoro/views/pomodoro_10.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include "../pomodoro_timer.h" - -PomodoroTimer* pomodoro_10_alloc(); - -void pomodoro_10_free(PomodoroTimer* pomodoro_10); - -View* pomodoro_10_get_view(PomodoroTimer* pomodoro_10); diff --git a/applications/plugins/pomodoro/views/pomodoro_25.c b/applications/plugins/pomodoro/views/pomodoro_25.c deleted file mode 100644 index 01c5a7125..000000000 --- a/applications/plugins/pomodoro/views/pomodoro_25.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../pomodoro_timer.h" -#include "pomodoro_25.h" -#include -#include -#include -#include - -static void pomodoro_25_draw_callback(Canvas* canvas, void* context) { - int max_seconds = 60 * 25; - int max_seconds_rest = 60 * 5; - pomodoro_draw_callback(canvas, context, max_seconds, max_seconds_rest); -} - -static bool pomodoro_25_input_callback(InputEvent* event, void* context) { - furi_assert(context); - PomodoroTimer* pomodoro_25 = context; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - return false; - } else { - pomodoro_timer_process(pomodoro_25, event); - return true; - } -} - -PomodoroTimer* pomodoro_25_alloc() { - PomodoroTimer* pomodoro_25 = malloc(sizeof(PomodoroTimer)); - pomodoro_25->view = view_alloc(); - view_set_context(pomodoro_25->view, pomodoro_25); - view_allocate_model(pomodoro_25->view, ViewModelTypeLocking, sizeof(PomodoroTimerModel)); - view_set_draw_callback(pomodoro_25->view, pomodoro_25_draw_callback); - view_set_input_callback(pomodoro_25->view, pomodoro_25_input_callback); - - return pomodoro_25; -} - -void pomodoro_25_free(PomodoroTimer* pomodoro_25) { - furi_assert(pomodoro_25); - view_free(pomodoro_25->view); - free(pomodoro_25); -} - -View* pomodoro_25_get_view(PomodoroTimer* pomodoro_25) { - furi_assert(pomodoro_25); - return pomodoro_25->view; -} diff --git a/applications/plugins/pomodoro/views/pomodoro_25.h b/applications/plugins/pomodoro/views/pomodoro_25.h deleted file mode 100644 index c3eb43976..000000000 --- a/applications/plugins/pomodoro/views/pomodoro_25.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include "../pomodoro_timer.h" - -PomodoroTimer* pomodoro_25_alloc(); - -void pomodoro_25_free(PomodoroTimer* pomodoro_25); - -View* pomodoro_25_get_view(PomodoroTimer* pomodoro_25); diff --git a/applications/plugins/pomodoro/views/pomodoro_50.c b/applications/plugins/pomodoro/views/pomodoro_50.c deleted file mode 100644 index 74f89122a..000000000 --- a/applications/plugins/pomodoro/views/pomodoro_50.c +++ /dev/null @@ -1,46 +0,0 @@ -#include "../pomodoro_timer.h" -#include "pomodoro_50.h" -#include -#include -#include -#include - -static void pomodoro_50_draw_callback(Canvas* canvas, void* context) { - int max_seconds = 60 * 50; - int max_seconds_rest = 60 * 10; - pomodoro_draw_callback(canvas, context, max_seconds, max_seconds_rest); -} - -static bool pomodoro_50_input_callback(InputEvent* event, void* context) { - furi_assert(context); - PomodoroTimer* pomodoro_50 = context; - - if(event->type == InputTypeLong && event->key == InputKeyBack) { - return false; - } else { - pomodoro_timer_process(pomodoro_50, event); - return true; - } -} - -PomodoroTimer* pomodoro_50_alloc() { - PomodoroTimer* pomodoro_50 = malloc(sizeof(PomodoroTimer)); - pomodoro_50->view = view_alloc(); - view_set_context(pomodoro_50->view, pomodoro_50); - view_allocate_model(pomodoro_50->view, ViewModelTypeLocking, sizeof(PomodoroTimerModel)); - view_set_draw_callback(pomodoro_50->view, pomodoro_50_draw_callback); - view_set_input_callback(pomodoro_50->view, pomodoro_50_input_callback); - - return pomodoro_50; -} - -void pomodoro_50_free(PomodoroTimer* pomodoro_50) { - furi_assert(pomodoro_50); - view_free(pomodoro_50->view); - free(pomodoro_50); -} - -View* pomodoro_50_get_view(PomodoroTimer* pomodoro_50) { - furi_assert(pomodoro_50); - return pomodoro_50->view; -} diff --git a/applications/plugins/pomodoro/views/pomodoro_50.h b/applications/plugins/pomodoro/views/pomodoro_50.h deleted file mode 100644 index e0246d2d2..000000000 --- a/applications/plugins/pomodoro/views/pomodoro_50.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include -#include "../pomodoro_timer.h" - -PomodoroTimer* pomodoro_50_alloc(); - -void pomodoro_50_free(PomodoroTimer* pomodoro_50); - -View* pomodoro_50_get_view(PomodoroTimer* pomodoro_50);