From c84c74e7609627385c9b70723ff11451c6c8baa8 Mon Sep 17 00:00:00 2001 From: Willy-JL Date: Thu, 9 Mar 2023 02:47:41 +0000 Subject: [PATCH] Update apps pt3 --- applications/plugins/calculator/calculator.c | 17 +- .../{dice => multi_dice}/application.fam | 2 +- .../plugins/{dice => multi_dice}/dice.c | 5 - .../plugins/{dice => multi_dice}/dice.png | Bin .../plugins/nightstand/application.fam | 4 +- .../nightstand/{ClockIcon.png => clock.png} | Bin applications/plugins/nightstand/clock_app.c | 37 ++- .../plugins/orgasmotron/orgasmotron.c | 13 +- applications/plugins/pomodoro/LICENSE | 121 --------- applications/plugins/pomodoro/application.fam | 14 +- .../plugins/pomodoro/flipp_pomodoro_10.png | Bin 0 -> 157 bytes .../plugins/pomodoro/flipp_pomodoro_app.c | 95 +++++++ .../plugins/pomodoro/flipp_pomodoro_app.h | 32 +++ .../plugins/pomodoro/flipp_pomodoro_app_i.h | 30 +++ applications/plugins/pomodoro/helpers/debug.h | 5 + .../plugins/pomodoro/helpers/notifications.c | 49 ++++ .../plugins/pomodoro/helpers/notifications.h | 14 + applications/plugins/pomodoro/helpers/time.c | 20 ++ applications/plugins/pomodoro/helpers/time.h | 24 ++ .../plugins/pomodoro/icons/ButtonLeft_4x7.png | Bin 1415 -> 0 bytes .../plugins/pomodoro/icons/Ok_btn_9x9.png | Bin 3605 -> 0 bytes .../pomodoro/icons/Pin_back_arrow_10x8.png | Bin 3606 -> 0 bytes .../plugins/pomodoro/icons/Space_65x18.png | Bin 3619 -> 0 bytes .../flipp_pomodoro_focus_64/frame_00.png | Bin 0 -> 1242 bytes .../flipp_pomodoro_focus_64/frame_01.png | Bin 0 -> 1215 bytes .../images/flipp_pomodoro_focus_64/frame_rate | 1 + .../flipp_pomodoro_rest_64/frame_00.png | Bin 0 -> 1083 bytes .../flipp_pomodoro_rest_64/frame_01.png | Bin 0 -> 1080 bytes .../images/flipp_pomodoro_rest_64/frame_rate | 1 + .../plugins/pomodoro/modules/flipp_pomodoro.c | 89 +++++++ .../plugins/pomodoro/modules/flipp_pomodoro.h | 54 ++++ applications/plugins/pomodoro/pomodoro.c | 164 ------------ applications/plugins/pomodoro/pomodoro.h | 34 --- .../plugins/pomodoro/pomodoro_timer.c | 242 ------------------ .../plugins/pomodoro/pomodoro_timer.h | 33 --- .../plugins/pomodoro/pomodoro_timer.png | Bin 306 -> 0 bytes applications/plugins/pomodoro/scenes/.keep | 0 .../config/flipp_pomodoro_scene_config.h | 1 + .../pomodoro/scenes/flipp_pomodoro_scene.c | 30 +++ .../pomodoro/scenes/flipp_pomodoro_scene.h | 27 ++ .../scenes/flipp_pomodoro_scene_timer.c | 71 +++++ applications/plugins/pomodoro/views/.keep | 0 .../views/flipp_pomodoro_timer_view.c | 195 ++++++++++++++ .../views/flipp_pomodoro_timer_view.h | 21 ++ .../plugins/pomodoro/views/pomodoro_10.c | 46 ---- .../plugins/pomodoro/views/pomodoro_10.h | 10 - .../plugins/pomodoro/views/pomodoro_25.c | 46 ---- .../plugins/pomodoro/views/pomodoro_25.h | 10 - .../plugins/pomodoro/views/pomodoro_50.c | 46 ---- .../plugins/pomodoro/views/pomodoro_50.h | 10 - 50 files changed, 820 insertions(+), 793 deletions(-) rename applications/plugins/{dice => multi_dice}/application.fam (90%) rename applications/plugins/{dice => multi_dice}/dice.c (98%) rename applications/plugins/{dice => multi_dice}/dice.png (100%) rename applications/plugins/nightstand/{ClockIcon.png => clock.png} (100%) delete mode 100644 applications/plugins/pomodoro/LICENSE create mode 100644 applications/plugins/pomodoro/flipp_pomodoro_10.png create mode 100644 applications/plugins/pomodoro/flipp_pomodoro_app.c create mode 100644 applications/plugins/pomodoro/flipp_pomodoro_app.h create mode 100644 applications/plugins/pomodoro/flipp_pomodoro_app_i.h create mode 100644 applications/plugins/pomodoro/helpers/debug.h create mode 100644 applications/plugins/pomodoro/helpers/notifications.c create mode 100644 applications/plugins/pomodoro/helpers/notifications.h create mode 100644 applications/plugins/pomodoro/helpers/time.c create mode 100644 applications/plugins/pomodoro/helpers/time.h delete mode 100644 applications/plugins/pomodoro/icons/ButtonLeft_4x7.png delete mode 100644 applications/plugins/pomodoro/icons/Ok_btn_9x9.png delete mode 100644 applications/plugins/pomodoro/icons/Pin_back_arrow_10x8.png delete mode 100644 applications/plugins/pomodoro/icons/Space_65x18.png create mode 100644 applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_00.png create mode 100644 applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_01.png create mode 100644 applications/plugins/pomodoro/images/flipp_pomodoro_focus_64/frame_rate create mode 100644 applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_00.png create mode 100644 applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_01.png create mode 100644 applications/plugins/pomodoro/images/flipp_pomodoro_rest_64/frame_rate create mode 100644 applications/plugins/pomodoro/modules/flipp_pomodoro.c create mode 100644 applications/plugins/pomodoro/modules/flipp_pomodoro.h delete mode 100644 applications/plugins/pomodoro/pomodoro.c delete mode 100644 applications/plugins/pomodoro/pomodoro.h delete mode 100644 applications/plugins/pomodoro/pomodoro_timer.c delete mode 100644 applications/plugins/pomodoro/pomodoro_timer.h delete mode 100644 applications/plugins/pomodoro/pomodoro_timer.png create mode 100644 applications/plugins/pomodoro/scenes/.keep create mode 100644 applications/plugins/pomodoro/scenes/config/flipp_pomodoro_scene_config.h create mode 100644 applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.c create mode 100644 applications/plugins/pomodoro/scenes/flipp_pomodoro_scene.h create mode 100644 applications/plugins/pomodoro/scenes/flipp_pomodoro_scene_timer.c create mode 100644 applications/plugins/pomodoro/views/.keep create mode 100644 applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.c create mode 100644 applications/plugins/pomodoro/views/flipp_pomodoro_timer_view.h delete mode 100644 applications/plugins/pomodoro/views/pomodoro_10.c delete mode 100644 applications/plugins/pomodoro/views/pomodoro_10.h delete mode 100644 applications/plugins/pomodoro/views/pomodoro_25.c delete mode 100644 applications/plugins/pomodoro/views/pomodoro_25.h delete mode 100644 applications/plugins/pomodoro/views/pomodoro_50.c delete mode 100644 applications/plugins/pomodoro/views/pomodoro_50.h 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 0000000000000000000000000000000000000000..977d16a584f63307ceb028a48f57713402abc520 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>3HNky4ABT~ zo#4oKK!Jm0_y2m6v$J|4wU)(+%sJ4oYSlc8Nnua6+`q%bGDG3H*bnyJge())*BAQu z?-*^XlzwJ?r0uexhV_H}+Gscene_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 0b4655d43247083aa705620e9836ac415b42ca46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1415 zcmbVM+iKK67*5rq)>aU2M7$VM1Vxif;vTv~W2u`S7ED{V3s&&L*<`XiG|9wd+THd> z5CnY!sdyuJtrvQyAo>KpiLcV|{Tkc)riAbluXfwSZCApL`ztB&p zx6LGKvks4K_4~)qD&oGa-YdJlW)hAKMNJd7<=t?6c^RI1>c$ifyjaM>^|&8!ey zB4!nh9u>5uen6Ve@<H5rru6h<2Ef#GQdQ*CmZOlQi~N!?9H`Rp;C% zU}CB21#?;r`&0|6C0}b-=jODa5|nEJ#ntxQ&{~jpgtwDta4hftr~G=#p@V36e4Zjh zq%J~{y26Jjn=1Nw-l*3%QW5YFE*v4z3gt0$&(*xf2en34c?JpH8+FYldo+Alvg8af-pG4(=!fyUi-Wsg z`g#n9VUcf(DFr{poMSNzw-lz>w+HV+n1ELr&SLA#LHUb0p(xWQ(1*vJ-i+1!`swxZ Z!O7;c$;lT_->m1Ovaz)0yuI`A$q$F8u*d)a 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 9a1539da2049f12f7b25f96b11a9c40cd8227302..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3605 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 TFC+3}9cE|kU{!4CefEC<&8td2 diff --git a/applications/plugins/pomodoro/icons/Space_65x18.png b/applications/plugins/pomodoro/icons/Space_65x18.png deleted file mode 100644 index b60ae50970b8be827ae32ddbd9e1b0d28c8b3a9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3619 zcmaJ@c{r5q+kR|?vSeS9G2*Q(Gqz$f_GOf18r!JE7=ytq%?xHFO-U))vSm#u)X=6# zwu*&|8!^APw~9?k(a6Vz_{`1J?VwO%hlm80mweJ_2Ll%+w5Jal|B#ZToHj zkX!A1wWV(yKRGcrJmE7L$o^5EyA?1;0vjpK4{lZ7;N}HH?K{|g9^>OZJmdzhM?p0K zMW=v17r<|D)m^7wAm^muyU^8WhW>`hzU({5Mni?Yg1dIjs(9V0f{sQT{n8mG4Mm49 zbG~l%ht2_K(@oNfYx5#D&tizdC8*fR7G5(g;>x7*Rzu{4&DevTBf5`It4m&=M_(&P zg6$d@FHi{BFL>ue9`qCWpjMUz{dO z@9>n#el1gZMS$0|kzX961dH0^726AL=a){4^e8+sFE>V1@t?G01xkRvR~uHtV6d@Jy=*+_LjJ^<;I%HkfZ+ zJ{WS&*3q1L--qRs;FC3Rwv9{p?cw*6_FMFK^@Q9yZ8!?f0Ei>znMIVlCNa;%nYvD_=OIcyvaxrpYxGcGRWZCqbo>reG^tc8h zWbb>x%$fc-l1kK>Pg=_9^WFC8k{QaNGP~oK)fB= zk~}W=y`t;c`=z{$ml*@ap9mj5x5DesKUlZZ%#d$#e*hBLJ2$e|kFK?B#{H}rW-Lg}+w*yHz2X|@s=6q5@hMLLk0Ngx@77A0z{8^GG<=3FCsOHJ6w{_pD*!j4k8!wLb`#+}y`?CB4 zQGwW*jB;lA{ql?St3NI0Q^jcF`vqpNjn(zm!LN-{xhDhDbu!1&ol`GQ%#aWnhw%cUor3tn<%~!N%j(>i+!K$>%8wb|oXB!X zUe^D7^t}0+-xUX|ptm{#4k$H7g6z!~%8Pa`7Cm2B9iPsA(lAKMOv=nd3E@*p)jmSY z4wO0gsHr6ijWH$&&GLy?n^(q^SE-Brl7W%7oq46G5~Q${Eu>J5eoE#Py&O@6IQcl%pM`Lo~JAQ5D{F{9M=h7QdD!DVxX< zG|G9wpE0lyi;C#Fd)Hj;lB;fVQBqS2vE;|e7g$M5vbQtaKehXm%Y{SI$sQ~+tFYwf zBdhX>5m$SU?yw~Wp|9`Dv9jjbX~cB?G?BI9R`c*!mA`5CyDM`-#q#qpezqJMP@wb32zU+0*_sQsBVDnwlp9 z1k~Y}eFzwNJcCK<%a~0Mc}6~YNcgqs_^ZDL?}eQkMSi{0{$}7!+hE#-vL*g$1VgP0 zRujb1$Rp&y?^LnB-pI>RIHO=)UG^)Stu=}bYS4>w&Cba>0H0qSyOcOu;9ZcNWp51s zkT$?rvE4`ua6jQ*ND(zN(xGR}RjlKca_;?=KGcDxu~0=Et)Zw@0K zo+3@-R$69V4NGW0?52-)vfp1=^RMlue*F1S)BQH1iv4y*zKp2)d2hK&#nR8<o8NY>iF~_Iy7d@WOBnj;S?k&H#!ZAREO0e@E9uw!tHWK^t=8Sj zR?0DPS&EACLUL6L-tCFQ1y2gZJDS5?ele!04<-jUN7j#bpf`HwcCAKt)RZua7Afop zMGs*O$_4u!*bGtM^Q3;}>g74L+mq3vv8SQ0@K zvyIWD6UZDk02mt6$rx+^jt26=`QnLiF#BZ<7=-tRgI)FPpmt<)oF5($O2IjX+B;!G z1F#0(U}GbYAsxmMAmC^i5S7-)K9yf9cVFLjVMR9g!I)rDy3YCxed9RrxIF6f^D=D4GH`@m2ZR{uET z?BHNO8jTEtKte)7G(&VWNfcj*mVto*1gZ_u*4E%4G^h+B4MW!;Qk8!zSm3Bw3Z6{E zlZc>gMT{3Ihz199LjBJf2;_fdiPV4c#K{#)rmpIK~Oj6!<%hNIw#dMD-()LE1W+P|yK8 z3>Ht^wjBJMVrK`lAyR1=A{J+30S9wLH1T+En5mAg1yo=Eh@P&MzLu7yxtX4op5xA}2IPRCO?t!+X9zvoGZ%D;b1(Y*s+gO-7(fhnSIU^r{GM99afXqQXz`L$cAW!v1IOaB9=s#hui 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 0000000000000000000000000000000000000000..7ead27c4e2d36b8155c088954b50e87cfc2a7e0c GIT binary patch literal 1242 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 +#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 b25c2718e0e6e84fa1c074e48b432c16cd0215f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^AT}2V8<6ZZI=>f4F%}28J29*~C-V}>aY>EvO!M_+ z&;qhK7#Q0#8CXC{fLIEM85o!sFfuR$X-1IP0w%aD*8*k)8>G;>V#ik?C6npm9|EMA zKw?0^3d9;v8pKX5;9)5Q(uSTcjv*SNNk95oBqSvMDJQF}{Lf>+=fP;@AjW)p5yyhe zhLen$A(JosRETy+a?u94>i_?)x=pWv40Dj?*gi%s1_KVJzyFs@d$Dg*I295!Y1!!= zx9>dC&JnI|v9S1ec~ORfMT2wLn$P8%C# + +// 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);