From 4c78f0f81e233f6775d62191d0f3f3a829878c6f Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Sun, 3 May 2026 13:34:31 -0400 Subject: [PATCH] Animate pin button --- src/c/main.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 7 deletions(-) diff --git a/src/c/main.c b/src/c/main.c index 5d62a90..a32d727 100644 --- a/src/c/main.c +++ b/src/c/main.c @@ -22,6 +22,8 @@ static GDrawCommandImage *s_pin_icon; // declare animation statics static GRect s_sleep_bar_start = GRect(0, 0, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT); static GRect s_sleep_icon_start = GRect((PBL_DISPLAY_WIDTH / 2) - 13, (PBL_DISPLAY_HEIGHT / 2) - 12, 25, 25); +static uint8_t s_pin_stroke_width = 1; +static Animation *s_pin_stroke_anim; // declare time tracking statics static time_t s_sleep_timestamp; @@ -54,30 +56,69 @@ static void sleep_icon_update_proc(Layer *layer, GContext *ctx) { gdraw_command_image_draw(ctx, s_sleep_icon, GPoint(0, 0)); } -#if PBL_ROUND -static void format_pin_for_round(uint8_t stroke_width) { +static void draw_pin() { GDrawCommandList *command_list = gdraw_command_image_get_command_list(s_pin_icon); const uint32_t command_count = gdraw_command_list_get_num_commands(command_list); for (uint32_t i = 0; i < command_count; ++i) { GDrawCommand *command = gdraw_command_list_get_command(command_list, i); if (command) { +#if PBL_ROUND if (s_is_jellyfin == 1) { gdraw_command_set_stroke_color(command, GColorPictonBlue); } else { gdraw_command_set_stroke_color(command, GColorLightGray); } gdraw_command_set_fill_color(command, GColorClear); - gdraw_command_set_stroke_width(command, stroke_width); +#endif + gdraw_command_set_stroke_width(command, s_pin_stroke_width); } } } -#endif + +static uint8_t get_stroke_width_for_progress(AnimationProgress progress) { + const uint8_t min_width = 1; + const uint8_t max_width = 3; + const uint8_t delta = max_width - min_width; + const AnimationProgress half = ANIMATION_NORMALIZED_MAX / 2; + + if (progress <= half) { + return min_width + (uint8_t)(delta * progress * 2 / ANIMATION_NORMALIZED_MAX); + } + return max_width - (uint8_t)(delta * (progress - half) * 2 / ANIMATION_NORMALIZED_MAX); +} + +static void pin_stroke_anim_update(Animation *animation, const AnimationProgress progress) { + s_pin_stroke_width = get_stroke_width_for_progress(progress); + layer_mark_dirty(s_pin_icon_layer); +} + +static void pin_stroke_anim_stopped(Animation *animation, bool finished, void *context) { + s_pin_stroke_anim = NULL; + animation_destroy(animation); +} + +static void pin_stroke_anim_start(void) { + if (s_pin_stroke_anim) { + animation_unschedule(s_pin_stroke_anim); + animation_destroy(s_pin_stroke_anim); + s_pin_stroke_anim = NULL; + } + + static const AnimationImplementation s_pin_stroke_anim_impl = { + .update = pin_stroke_anim_update, + }; + + s_pin_stroke_anim = animation_create(); + animation_set_implementation(s_pin_stroke_anim, &s_pin_stroke_anim_impl); + animation_set_duration(s_pin_stroke_anim, 400); + animation_set_curve(s_pin_stroke_anim, AnimationCurveEaseInOut); + animation_set_handlers(s_pin_stroke_anim, (AnimationHandlers){.stopped = pin_stroke_anim_stopped}, NULL); + animation_schedule(s_pin_stroke_anim); +} static void pin_icon_update_proc(Layer *layer, GContext *ctx) { graphics_context_set_antialiased(ctx, false); -#if PBL_ROUND - format_pin_for_round(2); -#endif + draw_pin(); gdraw_command_image_draw(ctx, s_pin_icon, GPoint(0, 0)); } @@ -101,6 +142,7 @@ static void main_window_load(Window *window) { } // pin icon + s_pin_stroke_width = 1; s_pin_icon_layer = layer_create(GRect(PBL_DISPLAY_WIDTH - PBL_IF_ROUND_ELSE(27, 25), (PBL_DISPLAY_HEIGHT / 2) - 13, 25, 25)); layer_set_update_proc(s_pin_icon_layer, pin_icon_update_proc); @@ -163,6 +205,11 @@ static void main_window_load(Window *window) { } static void main_window_unload(Window *window) { + if (s_pin_stroke_anim) { + animation_unschedule(s_pin_stroke_anim); + animation_destroy(s_pin_stroke_anim); + s_pin_stroke_anim = NULL; + } text_layer_destroy(s_last_watched_layer); text_layer_destroy(s_sleep_time_layer); layer_destroy(s_sleep_icon_layer); @@ -212,6 +259,7 @@ static void send_pin_to_pkjs() { } static void select_single_click_handler(ClickRecognizerRef recognizer, void *context) { + pin_stroke_anim_start(); send_pin_to_pkjs(); }