Fix edge-cases where an incorrect setter countdown could be displayed

This commit is contained in:
RandyTheSilly committed 2026-11-10 19:57:38 -05:00
1 parent 67d6468c02
commit 26dc5f9505
4 files changed
+50 -24

No files matched your search

+1 -4
View File
@@ -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)
+35 -6
View File
@@ -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);
+13 -14
View File
@@ -1,4 +1,5 @@
#include "scheduler.h"
#include "settings.h"
#include <pebble.h>
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;
}
+1
View File
@@ -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;