From 26dc5f9505833cbcef16a317879075791958b263 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Tue, 10 Nov 2026 19:57:38 -0500 Subject: [PATCH] Fix edge-cases where an incorrect setter countdown could be displayed --- README.md | 5 +---- src/c/main.c | 41 +++++++++++++++++++++++++++++++++++------ src/c/scheduler.c | 27 +++++++++++++-------------- src/c/settings.h | 1 + 4 files changed, 50 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 20a71a4..88dca5a 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,10 @@ Trigalarm is meant to be adapted to your needs with as little confusion as possi - Punishes the user via mild electrocution if they... - ...take too long to respond to the first triangle - ...force quit the app by holding the back button (the app re-opens and sends a zap) + ## Tips & Tricks - When you successfully disarm the alarm, you are prompted with the options to either exit and keep the same alarm time for tomorrow, or to select a new time. If choosing the latter, whatever time you select will assume you mean tomorrow. This avoids situations where you wake up at 6 on a Friday, set an alarm intended for 9 on Saturday, and end up with your wrist buzzing in three hours! - There is a "Reset Alarm" button in the phone-side settings to help if you make an unsolvable alarm configuration by mistake. -## Some Neat Stuff -- Some of the alarm scheduling code was taken from [Gentle Wake](https://github.com/SeaPea/GentleWake). It seems trusted by the community, so... I stole it! The beauty of open source, no AI needed! -- A custom font was made to satisfy the need for something that looks like LECO but is monospaced. The version I made contains only numbers, period, and colon, but if you want to build off of it, [it's public](https://git.wetfence.xyz/RandyTheSilly/pebble-misc/src/branch/main/fonts) and easy to modify! - ## Future Goals (v2.1 and beyond) - Custom, self-hosted Pavlok API support (going to try some Bluetooth reverse engineering) diff --git a/src/c/main.c b/src/c/main.c index 7d6ce3f..3cf46a3 100644 --- a/src/c/main.c +++ b/src/c/main.c @@ -65,6 +65,8 @@ static WakeupReason s_alarm_reason; static GColor s_setter_highlight_color; static uint8_t s_highlight_pos = 0; static bool s_skip_current_day = false; +static bool s_skip_current_day_from_confirmation = false; +static uint8_t s_skip_current_day_set_on_mday; // day the flag was set on //// alarm static uint8_t s_current_triangle_num; static uint8_t s_solution_indices[3]; @@ -120,6 +122,15 @@ typedef enum { static void push_setter_window(); +static void set_skip_current_day(bool from_confirmation) { + time_t now = time(NULL); + struct tm now_tm = *localtime(&now); + + s_skip_current_day = true; + s_skip_current_day_from_confirmation = from_confirmation; + s_skip_current_day_set_on_mday = now_tm.tm_mday; +} + static void click_handler_push_setter(void *recognizer, void *ctx) { s_highlight_pos = 0; window_stack_pop_all(true); @@ -133,7 +144,7 @@ static void click_handler_disable_tutorial_and_push_setter(void *recognizer, voi } static void click_handler_push_setter_skip_current_day(void *recognizer, void *ctx) { - s_skip_current_day = true; // setting the next alarm should assume the user meant tomorrow + set_skip_current_day(true); // setting the next alarm should assume the user meant tomorrow click_handler_push_setter(recognizer, ctx); } @@ -245,13 +256,11 @@ static bool schedule_alarm(WakeupReason schedule_reason) { switch (schedule_reason) { case WAKE_ALARM: { target = compute_alarm_time(the_time.HourWIP, the_time.MinuteWIP); - wakeup_cancel_all(); status = wakeup_schedule_simple_robust(target, schedule_reason); break; } case WAKE_RECOVERY_ALARM: target = time(NULL) + 15; - // no need to cancel alarms, as recovery alarms are short-lived and are expired by the time another is being scheduled status = wakeup_schedule_simple_robust(target, schedule_reason); } if (status < 0) { @@ -913,8 +922,13 @@ static void push_alarm_window() { ////////////////////// SETTER ////////////////////// static void setter_seconds_handler(struct tm *tick_time, TimeUnits units_changed) { - struct tm now_tm = *tick_time; + // unset s_skip_current_day if the day changes while the setter is open + if (s_skip_current_day && tick_time->tm_mday != s_skip_current_day_set_on_mday) { + s_skip_current_day = false; + s_skip_current_day_from_confirmation = false; + } + struct tm now_tm = *tick_time; time_t now = mktime(&now_tm); time_t target = compute_alarm_time(the_time.HourSet, the_time.MinuteSet); @@ -1001,6 +1015,11 @@ static void setter_down_click_handler(void *recognizer, void *ctx) { static void setter_select_click_handler(void *recognizer, void *ctx) { if (s_highlight_pos == 2) { + // do not skip a day if the setter was opened directly + if (s_skip_current_day && !s_skip_current_day_from_confirmation) { + s_skip_current_day = false; + } + bool success = schedule_alarm(WAKE_ALARM); if (!success) { return; // early return to avoid indicating alarm was set when it was not @@ -1045,6 +1064,7 @@ static void live_wakeup_handler_for_setter(WakeupId id, int32_t reason) { // reset values potentially set by prior alarm s_skip_current_day = false; + s_skip_current_day_from_confirmation = false; s_selected_indices[0] = 9; s_selected_indices[1] = 9; s_selected_indices[2] = 9; @@ -1084,10 +1104,19 @@ static void setter_window_load() { text_layer_set_background_color(s_countdown_txt_layer, GColorClear); text_layer_set_font(s_countdown_txt_layer, s_font_lecoish_small); layer_add_child(window_layer, text_layer_get_layer(s_countdown_txt_layer)); + if (!s_skip_current_day) { + WakeupId wakeup_id = persist_read_int(STORAGE_KEY_ALARM_WAKEUP_ID); + if (wakeup_id > 0) { + time_t now = time(NULL); + time_t scheduled_time = now; + bool scheduled = wakeup_query(wakeup_id, &scheduled_time); + if (scheduled && (scheduled_time - now) > SECONDS_PER_DAY) { + set_skip_current_day(false); + } + } + } update_countdown_display(); - // progress - // highlighter s_setter_highlight_layer = layer_create(GRect(0, s_top_bar_grect.size.h, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT - (2 * s_top_bar_grect.size.h))); layer_set_update_proc(s_setter_highlight_layer, setter_highlight_layer_update_proc); diff --git a/src/c/scheduler.c b/src/c/scheduler.c index 3207e77..1b76da9 100644 --- a/src/c/scheduler.c +++ b/src/c/scheduler.c @@ -1,4 +1,5 @@ #include "scheduler.h" +#include "settings.h" #include struct TheTime the_time; @@ -16,26 +17,24 @@ static void glance_reload_callback(AppGlanceReloadSession *session, size_t limit app_glance_add_slice(session, slice); } -// Originally stolen from https://github.com/SeaPea/GentleWake (simplified by me for SDK 4.44+); -// A slightly more robust wakeup scheduler that retries on errors WakeupId wakeup_schedule_simple_robust(time_t wakeup_time, WakeupReason wakeup_reason) { - WakeupId result = 0; - result = wakeup_schedule(wakeup_time, wakeup_reason, true); + wakeup_cancel_all(); // only 1 wakeup should be scheduled for this app at any time + WakeupId result = wakeup_schedule(wakeup_time, wakeup_reason, true); - if (result < 0) { - // If result is negative, something went wrong, so make sure all wakeups for this app are cancelled and try again - wakeup_cancel_all(); - result = wakeup_schedule(wakeup_time, wakeup_reason, true); - - // As of SDK 4.44, E_RANGE result no longer needs handled, as it now only reports wakeups scheduled by THIS app; - // we call wakeup_cancel_all() above, so E_RANGE will never be encountered - } - - if (result >= 0) { + if (result >= 0) { // positive result code is a wakeup ID the_time.HourSet = the_time.HourWIP; the_time.MinuteSet = the_time.MinuteWIP; app_glance_reload(glance_reload_callback, (void *)(uintptr_t)wakeup_time); + if (wakeup_reason == WAKE_ALARM) { + // store wakeup ID for regular alarms so the setter can reference + // it later to generate the initial countdown + persist_write_int(STORAGE_KEY_ALARM_WAKEUP_ID, result); + } } + // As of SDK 4.44, E_RANGE result no longer needs handled, as it now only reports wakeups scheduled by THIS app; + // we call wakeup_cancel_all() above, so E_RANGE will never be encountered, thus any failure + // that occurs here cannot be remedied, so we just return the result code. + return result; } diff --git a/src/c/settings.h b/src/c/settings.h index 7b8316d..688921a 100644 --- a/src/c/settings.h +++ b/src/c/settings.h @@ -6,6 +6,7 @@ #define STORAGE_KEY_ALARM_HOUR 0 #define STORAGE_KEY_ALARM_MINUTE 1 #define STORAGE_KEY_ALARM_REASON 2 +#define STORAGE_KEY_ALARM_WAKEUP_ID 3 typedef struct AppSettings { bool TutorialEnabled;