Add awareness alarm tutorial status page

This commit is contained in:
2026-08-14 01:26:26 -04:00
parent f97e18ac48
commit 96a9f26814
4 changed files with 56 additions and 31 deletions
+7
View File
@@ -14,3 +14,10 @@ Because it requires the perfect amount of thought to activate your brain in the
- The vibration pattern is randomized. It derives the length of the three pulses from the angles in the generated triangle. Neat!
- 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 (1.1 and beyond)
- [Pavlok](https://pavlok.com/pages/how-it-works) integration to shock the user on failure to complete secondary (awareness) alarm and when force-exiting alarm
- Timeline integration
- Speaker support
- Full touch navigation
- Draw measurements based on triangle side locations, rather than in fixed positions
+1 -1
View File
@@ -68,7 +68,7 @@
]
},
{
"characterRegex": "[°ntype:θ=acuobsrigh¯¹0123456789]",
"characterRegex": "[sincostaeθ=¯¹0123456789hldSELECTubm]",
"file": "mansalva_regular.ttf",
"name": "FONT_MANSALVA_REGULAR_22",
"type": "font"
+43 -27
View File
@@ -84,61 +84,72 @@ static char *s_options_under[2];
////////////////////// STATUS //////////////////////
static void status_0_1_back_click_handler(void *recognizer, void *ctx) {
static void click_handler_disable_tutorial(void *recognizer, void *ctx) {
persist_write_bool(STORAGE_KEY_DISABLE_TUTORIAL, true);
window_stack_pop_all(true);
}
static void click_handler_push_setter(void *recognizer, void *ctx) {
s_highlight_pos = 0;
window_stack_pop_all(true);
push_setter_window();
}
static void status_0_select_click_handler(void *recognizer, void *ctx) {
static void click_handler_exit(void *recognizer, void *ctx) {
window_stack_pop_all(true);
}
static void status_2_select_click_handler(void *recognizer, void *ctx) {
static void click_handler_retry(void *recognizer, void *ctx) {
window_stack_pop(true);
}
static void status_0_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_UP, scroll_layer_scroll_up_click_handler);
window_single_click_subscribe(BUTTON_ID_DOWN, scroll_layer_scroll_down_click_handler);
window_single_click_subscribe(BUTTON_ID_BACK, status_0_1_back_click_handler);
window_single_click_subscribe(BUTTON_ID_SELECT, status_0_select_click_handler);
static void status_main_tutorial_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_SELECT, click_handler_exit);
window_single_click_subscribe(BUTTON_ID_BACK, click_handler_disable_tutorial);
}
static void status_1_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_BACK, status_0_1_back_click_handler);
window_single_click_subscribe(BUTTON_ID_SELECT, status_0_1_back_click_handler);
window_single_click_subscribe(BUTTON_ID_UP, status_0_1_back_click_handler);
window_single_click_subscribe(BUTTON_ID_DOWN, status_0_1_back_click_handler);
static void status_confirmation_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_BACK, click_handler_push_setter);
window_single_click_subscribe(BUTTON_ID_SELECT, click_handler_exit);
}
static void status_2_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_SELECT, status_2_select_click_handler);
static void status_set_failure_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_BACK, click_handler_push_setter);
window_single_click_subscribe(BUTTON_ID_SELECT, click_handler_push_setter);
window_single_click_subscribe(BUTTON_ID_UP, click_handler_push_setter);
window_single_click_subscribe(BUTTON_ID_DOWN, click_handler_push_setter);
}
static void status_math_failure_click_config_provider(void *ctx) {
window_single_click_subscribe(BUTTON_ID_SELECT, click_handler_retry);
}
static void status_window_load(StatusWindowPurpose purpose) {
Layer *window_layer = window_get_root_layer(s_status_window);
s_status_txt_layer = text_layer_create(GRect(0, 0, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT));
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24));
switch (purpose) {
case STATUS_MAIN_TUTORIAL:
// don't disable ticks to ensure vibrations remain till the tutorial is closed
text_layer_set_text(s_status_txt_layer, "Congrats! To ensure you're awake, I'll re-open without vibrating in 9 minutes. Complete the equation within 60 seconds to disarm me. Take too long and I'll vibrate and re-schedule another alarm.\n\nPress SELECT to exit or BACK to disable this tutorial in the future (and exit).");
window_set_click_config_provider(s_status_window, status_main_tutorial_click_config_provider);
break;
case STATUS_CONFIRMATION:
tick_timer_service_unsubscribe();
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24));
static char s_status_confirmed_buffer[105];
static char s_status_confirmed_buffer[106];
snprintf(s_status_confirmed_buffer, sizeof(s_status_confirmed_buffer), "Alarm disarmed and re-set (%02u:%02u) successfully.\n\nPress SELECT to exit or BACK to change the alarm time.", the_time.HourSet, the_time.MinuteSet);
text_layer_set_text(s_status_txt_layer, s_status_confirmed_buffer);
window_set_click_config_provider(s_status_window, status_0_click_config_provider);
window_set_click_config_provider(s_status_window, status_confirmation_click_config_provider);
break;
case STATUS_SET_FAILURE:
tick_timer_service_unsubscribe();
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
text_layer_set_text(s_status_txt_layer, "Failed to set an alarm.\nPress any button to return to alarm setter.");
window_set_click_config_provider(s_status_window, status_1_click_config_provider);
window_set_click_config_provider(s_status_window, status_set_failure_click_config_provider);
break;
case 2:
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
case STATUS_MATH_FAILURE:
text_layer_set_text(s_status_txt_layer, "Incorrect equation.\nTry again!");
window_set_click_config_provider(s_status_window, status_2_click_config_provider);
window_set_click_config_provider(s_status_window, status_math_failure_click_config_provider);
}
text_layer_set_background_color(s_status_txt_layer, GColorClear);
layer_set_frame(text_layer_get_layer(s_status_txt_layer), GRect(0, (PBL_DISPLAY_HEIGHT / 2) - (text_layer_get_content_size(s_status_txt_layer).h / 2), PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT));
@@ -201,7 +212,7 @@ static bool schedule_alarm(WakeupReason schedule_reason) {
}
}
if (status < 0) {
push_status_window(1);
push_status_window(STATUS_SET_FAILURE);
return false;
}
return true;
@@ -647,7 +658,7 @@ static void alarm_select_hold_handler(void *recognizer, void *ctx) {
// check solution
for (int i = 0; i < 3; ++i) {
if (s_selected_indices[i] != s_solution_indices[i]) {
push_status_window(2);
push_status_window(STATUS_MATH_FAILURE);
return;
}
}
@@ -655,12 +666,17 @@ static void alarm_select_hold_handler(void *recognizer, void *ctx) {
if (s_alarming_for_awareness) {
// set main alarm if the awareness alarm was solved
if (schedule_alarm(MAIN_ALARM)) {
push_status_window(0);
push_status_window(STATUS_CONFIRMATION);
}
} else {
// otherwise, set awareness alarm and exit
if (schedule_alarm(AWARENESS_ALARM)) {
window_stack_pop_all(true);
if (persist_read_bool(STORAGE_KEY_DISABLE_TUTORIAL)) {
window_stack_pop_all(true);
} else {
// show tutorial if it has not yet been disabled
push_status_window(STATUS_MAIN_TUTORIAL);
}
}
}
}
+5 -3
View File
@@ -3,12 +3,14 @@
#define STORAGE_KEY_ALARM_HOUR 0
#define STORAGE_KEY_ALARM_MINUTE 1
#define STORAGE_KEY_ALARMING_FOR_AWARENESS 2
#define STORAGE_KEY_DISABLE_TUTORIAL 3
typedef enum
{
STATUS_CONFIRMATION = 0,
STATUS_SET_FAILURE = 1,
STATUS_MATH_FAILURE = 2
STATUS_MAIN_TUTORIAL = 0,
STATUS_CONFIRMATION = 1,
STATUS_SET_FAILURE = 2,
STATUS_MATH_FAILURE = 3
} StatusWindowPurpose;
static void push_setter_window();