From dc2b1a129cc00d22ff31ae153b224a301f8b1619 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Sat, 2 May 2026 14:52:29 -0400 Subject: [PATCH] Add soft-reload after changing settings --- src/c/main.c | 190 +++++++++++++++++++++++++--------------------- src/pkjs/index.js | 28 ++++--- 2 files changed, 118 insertions(+), 100 deletions(-) diff --git a/src/c/main.c b/src/c/main.c index 46c4d17..0b33097 100644 --- a/src/c/main.c +++ b/src/c/main.c @@ -7,7 +7,7 @@ static uint8_t s_is_jellyfin; static GColor s_color_primary = GColorWhite; static GColor s_color_secondary = GColorWhite; -// declare window statics +// declare window/layer statics static Window *s_main_window; static TextLayer *s_config_app_layer; static TextLayer *s_sleep_time_layer; @@ -28,91 +28,6 @@ static time_t s_sleep_timestamp; static bool s_sleep_session_found; static bool s_sleep_data_accessible; -static void load_complete_animation_handler(Animation *animation, bool finished, void *context) { - layer_set_hidden(text_layer_get_layer(s_sleep_time_layer), false); - animation_destroy(animation); -} - -static void send_sleep_time_to_pkjs() { - DictionaryIterator *out; - AppMessageResult result = app_message_outbox_begin(&out); - if (result != APP_MSG_OK) { - text_layer_set_text(s_last_watched_layer, "outbox_begin failure"); - return; - } - if (s_sleep_session_found) { - dict_write_uint32(out, MESSAGE_KEY_PKJS_SLEEP_TIMESTAMP, s_sleep_timestamp); - } else { - // send current UNIX timestamp to fetch the last thing played - dict_write_uint32(out, MESSAGE_KEY_PKJS_SLEEP_TIMESTAMP, time(NULL)); - } - result = app_message_outbox_send(); - if (result != APP_MSG_OK) { - text_layer_set_text(s_last_watched_layer, "outbox_send failure"); - return; - } -} - -static void inbox_received_handler(DictionaryIterator *iter, void *context) { - Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY); - if (ready_tuple) { - // APP_LOG(APP_LOG_LEVEL_INFO, "Received PKJS_READY, calling PKJS..."); - send_sleep_time_to_pkjs(); - } - - Tuple *clay_tuple = dict_find(iter, MESSAGE_KEY_CLAY_API_IS_JELLYFIN); - if (clay_tuple) { - // APP_LOG(APP_LOG_LEVEL_INFO, "Received CLAY_API_IS_JELLYFIN, updating UI..."); - bool is_jellyfin = clay_tuple->value->int32 == 1; - if (is_jellyfin) { - persist_write_int(0, 1); - s_color_primary = GColorVividViolet; - s_color_secondary = GColorPictonBlue; -#if PBL_ROUND - s_pin_icon = gdraw_command_image_create_with_resource(RESOURCE_ID_PIN_ROUND_JELLYFIN_ICON); -#endif - } else { - persist_write_int(0, 2); - s_color_primary = GColorChromeYellow; - s_color_secondary = GColorLightGray; -#if PBL_ROUND - s_pin_icon = gdraw_command_image_create_with_resource(RESOURCE_ID_PIN_ROUND_PLEX_ICON); -#endif - } - layer_mark_dirty(s_sleep_bar_layer); -#if PBL_ROUND - layer_mark_dirty(s_pin_icon_layer); -#else - layer_mark_dirty(s_button_bar_layer); -#endif - } - - Tuple *watched_tuple = dict_find(iter, MESSAGE_KEY_PKJS_LAST_WATCHED); - if (watched_tuple) { - // APP_LOG(APP_LOG_LEVEL_INFO, "Received PKJS_LAST_WATCHED, displaying..."); - if (s_sleep_session_found) { - text_layer_set_text(s_last_watched_layer, watched_tuple->value->cstring); - } else { - static char last_watched_buffer[1024]; - snprintf(last_watched_buffer, sizeof(last_watched_buffer), "Last item played:\n%s", watched_tuple->value->cstring); - text_layer_set_text(s_last_watched_layer, last_watched_buffer); - } -#if PBL_DISPLAY_WIDTH >= 200 - PropertyAnimation *sleep_bar_prop = property_animation_create_layer_frame(s_sleep_bar_layer, &s_sleep_bar_start, &GRect(0, -PBL_DISPLAY_HEIGHT + PBL_IF_ROUND_ELSE(53, 31), PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT)); -#else - PropertyAnimation *sleep_bar_prop = property_animation_create_layer_frame(s_sleep_bar_layer, &s_sleep_bar_start, &GRect(0, -PBL_DISPLAY_HEIGHT + PBL_IF_ROUND_ELSE(49, 31), PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT)); -#endif - Animation *sleep_bar_anim = property_animation_get_animation(sleep_bar_prop); - animation_set_duration(sleep_bar_anim, 512); - PropertyAnimation *sleep_icon_prop = property_animation_create_layer_frame(s_sleep_icon_layer, &s_sleep_icon_start, &GRect(PBL_IF_ROUND_ELSE((PBL_DISPLAY_WIDTH / 2) - 13, 4), 4, 25, 25)); - Animation *sleep_icon_anim = property_animation_get_animation(sleep_icon_prop); - animation_set_duration(sleep_icon_anim, 512); - Animation *load_spawn_anim = animation_spawn_create(sleep_bar_anim, sleep_icon_anim, NULL); - animation_set_handlers(load_spawn_anim, (AnimationHandlers){.stopped = load_complete_animation_handler}, NULL); - animation_schedule(load_spawn_anim); - } -} - static bool cb_update_sleep_time(HealthActivity activity, time_t start_time, time_t end_time, void *context) { s_sleep_timestamp = start_time; return false; @@ -226,11 +141,110 @@ static void main_window_load(Window *window) { } static void main_window_unload(Window *window) { + text_layer_destroy(s_last_watched_layer); + text_layer_destroy(s_sleep_time_layer); layer_destroy(s_sleep_icon_layer); layer_destroy(s_sleep_bar_layer); + layer_destroy(s_pin_icon_layer); layer_destroy(s_button_bar_layer); - text_layer_destroy(s_sleep_time_layer); - text_layer_destroy(s_last_watched_layer); +} + +static void send_sleep_time_to_pkjs() { + DictionaryIterator *out; + AppMessageResult result = app_message_outbox_begin(&out); + if (result != APP_MSG_OK) { + text_layer_set_text(s_last_watched_layer, "outbox_begin failure"); + return; + } + if (s_sleep_session_found) { + dict_write_uint32(out, MESSAGE_KEY_PKJS_SLEEP_TIMESTAMP, s_sleep_timestamp); + } else { + // send current UNIX timestamp to fetch the last thing played + dict_write_uint32(out, MESSAGE_KEY_PKJS_SLEEP_TIMESTAMP, time(NULL)); + } + result = app_message_outbox_send(); + if (result != APP_MSG_OK) { + text_layer_set_text(s_last_watched_layer, "outbox_send failure"); + return; + } +} + +static void soft_reload() { + window_stack_remove(s_main_window, false); + window_destroy(s_main_window); + s_main_window = window_create(); + window_set_background_color(s_main_window, GColorBlack); + window_set_window_handlers( + s_main_window, + (WindowHandlers){.load = main_window_load, .unload = main_window_unload}); + window_stack_push(s_main_window, false); + send_sleep_time_to_pkjs(); +} + +static void load_complete_animation_handler(Animation *animation, bool finished, void *context) { + layer_set_hidden(text_layer_get_layer(s_sleep_time_layer), false); + animation_destroy(animation); +} + +static void inbox_received_handler(DictionaryIterator *iter, void *context) { + Tuple *ready_tuple = dict_find(iter, MESSAGE_KEY_PKJS_READY); + if (ready_tuple) { + send_sleep_time_to_pkjs(); + return; + } + + Tuple *clay_tuple = dict_find(iter, MESSAGE_KEY_CLAY_API_IS_JELLYFIN); + if (clay_tuple) { + bool is_jellyfin = clay_tuple->value->int32 == 1; + if (is_jellyfin) { + persist_write_int(0, 1); + s_color_primary = GColorVividViolet; + s_color_secondary = GColorPictonBlue; +#if PBL_ROUND + s_pin_icon = gdraw_command_image_create_with_resource(RESOURCE_ID_PIN_ROUND_JELLYFIN_ICON); +#endif + } else { + persist_write_int(0, 2); + s_color_primary = GColorChromeYellow; + s_color_secondary = GColorLightGray; +#if PBL_ROUND + s_pin_icon = gdraw_command_image_create_with_resource(RESOURCE_ID_PIN_ROUND_PLEX_ICON); +#endif + } + layer_mark_dirty(s_sleep_bar_layer); +#if PBL_ROUND + layer_mark_dirty(s_pin_icon_layer); +#else + layer_mark_dirty(s_button_bar_layer); +#endif + soft_reload(); // app needs "restarted" when settings are changed + return; + } + + Tuple *watched_tuple = dict_find(iter, MESSAGE_KEY_PKJS_LAST_WATCHED); + if (watched_tuple) { + if (s_sleep_session_found) { + text_layer_set_text(s_last_watched_layer, watched_tuple->value->cstring); + } else { + static char last_watched_buffer[1024]; + snprintf(last_watched_buffer, sizeof(last_watched_buffer), "Last item played:\n%s", watched_tuple->value->cstring); + text_layer_set_text(s_last_watched_layer, last_watched_buffer); + } +#if PBL_DISPLAY_WIDTH >= 200 + PropertyAnimation *sleep_bar_prop = property_animation_create_layer_frame(s_sleep_bar_layer, &s_sleep_bar_start, &GRect(0, -PBL_DISPLAY_HEIGHT + PBL_IF_ROUND_ELSE(53, 31), PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT)); +#else + PropertyAnimation *sleep_bar_prop = property_animation_create_layer_frame(s_sleep_bar_layer, &s_sleep_bar_start, &GRect(0, -PBL_DISPLAY_HEIGHT + PBL_IF_ROUND_ELSE(49, 31), PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT)); +#endif + Animation *sleep_bar_anim = property_animation_get_animation(sleep_bar_prop); + animation_set_duration(sleep_bar_anim, 512); + PropertyAnimation *sleep_icon_prop = property_animation_create_layer_frame(s_sleep_icon_layer, &s_sleep_icon_start, &GRect(PBL_IF_ROUND_ELSE((PBL_DISPLAY_WIDTH / 2) - 13, 4), 4, 25, 25)); + Animation *sleep_icon_anim = property_animation_get_animation(sleep_icon_prop); + animation_set_duration(sleep_icon_anim, 512); + Animation *load_spawn_anim = animation_spawn_create(sleep_bar_anim, sleep_icon_anim, NULL); + animation_set_handlers(load_spawn_anim, (AnimationHandlers){.stopped = load_complete_animation_handler}, NULL); + animation_schedule(load_spawn_anim); + return; + } } static void init() { diff --git a/src/pkjs/index.js b/src/pkjs/index.js index 9621569..78ff3e0 100644 --- a/src/pkjs/index.js +++ b/src/pkjs/index.js @@ -31,7 +31,7 @@ Pebble.addEventListener("appmessage", function (dict) { function callAPI(fullURL, apiKey, isJellyfin, trackedUser, sleepTimestamp) { const xhr = new XMLHttpRequest(); - + let didReportError = false; function reportApiError(message) { if (didReportError) { @@ -51,17 +51,22 @@ function callAPI(fullURL, apiKey, isJellyfin, trackedUser, sleepTimestamp) { xhr.onreadystatechange = function () { if (xhr.readyState === 4) { - if (xhr.status === 0) { - reportApiError("API UNREACHABLE"); - return; - } - if (xhr.status < 200 || xhr.status >= 300) { - if (xhr.status == 401) { + switch (xhr.status) { + case 200: + break; + case 0: + reportApiError("API UNREACHABLE"); + return; + case 401: + case 403: reportApiError("API ERROR: " + xhr.status + " (CHECK API KEY)"); - } else { + return; + case 404: + case 405: + reportApiError("API ERROR: " + xhr.status + " (INVALID ENDPOINT?)"); + return; + default: reportApiError("API ERROR: " + xhr.status); - } - return; } if (!xhr.responseText) { reportApiError("API EMPTY RESPONSE"); @@ -111,9 +116,8 @@ function callAPI(fullURL, apiKey, isJellyfin, trackedUser, sleepTimestamp) { }); } if (lastWatched != "") { - //console.log("Last watched: " + lastWatched); Pebble.sendAppMessage({ PKJS_LAST_WATCHED: lastWatched }); - } else { + } else { Pebble.sendAppMessage({ PKJS_LAST_WATCHED: "NO WATCH HISTORY FOUND FOR USER " + trackedUser }); } }