Initial awareness alarm implementation
This commit is contained in:
+56
-34
@@ -12,7 +12,6 @@ static Window *s_drop_window;
|
|||||||
static Layer *s_top_bar_layer;
|
static Layer *s_top_bar_layer;
|
||||||
static Layer *s_bottom_bar_layer;
|
static Layer *s_bottom_bar_layer;
|
||||||
static TextLayer *s_counter_txt_layer;
|
static TextLayer *s_counter_txt_layer;
|
||||||
static ScrollLayer *s_status_scroll_layer;
|
|
||||||
static TextLayer *s_status_txt_layer;
|
static TextLayer *s_status_txt_layer;
|
||||||
//// setter
|
//// setter
|
||||||
static BitmapLayer *s_clock_bmp_layer;
|
static BitmapLayer *s_clock_bmp_layer;
|
||||||
@@ -54,6 +53,7 @@ static GBitmap *s_check_bmp;
|
|||||||
static GColor s_setter_highlight_color;
|
static GColor s_setter_highlight_color;
|
||||||
static uint8_t s_highlight_pos = 0;
|
static uint8_t s_highlight_pos = 0;
|
||||||
//// alarm
|
//// alarm
|
||||||
|
static bool s_alarming_for_awareness;
|
||||||
static uint8_t s_solution_indices[3] = {8, 8, 8};
|
static uint8_t s_solution_indices[3] = {8, 8, 8};
|
||||||
static uint8_t s_selected_indices[3] = {9, 9, 9};
|
static uint8_t s_selected_indices[3] = {9, 9, 9};
|
||||||
static uint8_t s_stopwatch_time[2] = {0, 0};
|
static uint8_t s_stopwatch_time[2] = {0, 0};
|
||||||
@@ -65,8 +65,6 @@ static const uint8_t s_edge_bar_height = ((PBL_DISPLAY_HEIGHT / 7) * 2);
|
|||||||
static const GRect s_top_bar_grect = GRect(0, 0, PBL_DISPLAY_WIDTH, s_edge_bar_height);
|
static const GRect s_top_bar_grect = GRect(0, 0, PBL_DISPLAY_WIDTH, s_edge_bar_height);
|
||||||
static const GRect s_bottom_bar_grect = GRect(0, PBL_DISPLAY_HEIGHT - s_edge_bar_height, PBL_DISPLAY_WIDTH, s_edge_bar_height);
|
static const GRect s_bottom_bar_grect = GRect(0, PBL_DISPLAY_HEIGHT - s_edge_bar_height, PBL_DISPLAY_WIDTH, s_edge_bar_height);
|
||||||
static const GColor s_primary_color = GColorJaegerGreen;
|
static const GColor s_primary_color = GColorJaegerGreen;
|
||||||
#define STORAGE_KEY_ALARM_HOUR 0
|
|
||||||
#define STORAGE_KEY_ALARM_MINUTE 1
|
|
||||||
//// alarm
|
//// alarm
|
||||||
static const uint8_t s_drop_height = 22;
|
static const uint8_t s_drop_height = 22;
|
||||||
static const GRect s_drop_function_grect = GRect(PBL_IF_ROUND_ELSE(55, 45), s_bottom_bar_grect.origin.y + ((s_bottom_bar_grect.size.h / 2) - PBL_IF_ROUND_ELSE(s_drop_height - 1, s_drop_height / 2)), 50, s_drop_height);
|
static const GRect s_drop_function_grect = GRect(PBL_IF_ROUND_ELSE(55, 45), s_bottom_bar_grect.origin.y + ((s_bottom_bar_grect.size.h / 2) - PBL_IF_ROUND_ELSE(s_drop_height - 1, s_drop_height / 2)), 50, s_drop_height);
|
||||||
@@ -118,24 +116,22 @@ static void status_2_click_config_provider(void *ctx) {
|
|||||||
window_single_click_subscribe(BUTTON_ID_SELECT, status_2_select_click_handler);
|
window_single_click_subscribe(BUTTON_ID_SELECT, status_2_select_click_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void status_window_load(uint8_t reason) {
|
static void status_window_load(StatusWindowPurpose purpose) {
|
||||||
Layer *window_layer = window_get_root_layer(s_status_window);
|
Layer *window_layer = window_get_root_layer(s_status_window);
|
||||||
|
|
||||||
s_status_scroll_layer = scroll_layer_create(GRect(0, 0, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT));
|
switch (purpose) {
|
||||||
|
case STATUS_CONFIRMATION:
|
||||||
switch (reason) {
|
|
||||||
case 0:
|
|
||||||
tick_timer_service_unsubscribe();
|
tick_timer_service_unsubscribe();
|
||||||
s_status_txt_layer = text_layer_create(GRect(0, 8, PBL_DISPLAY_WIDTH, 500));
|
s_status_txt_layer = text_layer_create(GRect(0, 8, PBL_DISPLAY_WIDTH, 500));
|
||||||
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24));
|
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24));
|
||||||
text_layer_set_text(s_status_txt_layer, "Alarm disarmed and re-set successfully.\n\nLast seven times:\n1. 00:00\n2. 00:00\n3. 00:00\n4. 00:00\n5. 00:00\n6. 00:00\n7. 00:00");
|
text_layer_set_text(s_status_txt_layer, "Alarm disarmed and re-set successfully.");
|
||||||
window_set_click_config_provider_with_context(s_status_window, status_0_click_config_provider, s_status_scroll_layer);
|
window_set_click_config_provider(s_status_window, status_0_click_config_provider);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case STATUS_SET_FAILURE:
|
||||||
tick_timer_service_unsubscribe();
|
tick_timer_service_unsubscribe();
|
||||||
s_status_txt_layer = text_layer_create(GRect(0, PBL_DISPLAY_HEIGHT / 2, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT));
|
s_status_txt_layer = text_layer_create(GRect(0, PBL_DISPLAY_HEIGHT / 2, PBL_DISPLAY_WIDTH, PBL_DISPLAY_HEIGHT));
|
||||||
text_layer_set_font(s_status_txt_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
|
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 primary alarm.\nPress any button to return to alarm setter.");
|
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_1_click_config_provider);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
@@ -147,38 +143,48 @@ static void status_window_load(uint8_t reason) {
|
|||||||
text_layer_set_background_color(s_status_txt_layer, GColorClear);
|
text_layer_set_background_color(s_status_txt_layer, GColorClear);
|
||||||
text_layer_set_text_alignment(s_status_txt_layer, GTextAlignmentCenter);
|
text_layer_set_text_alignment(s_status_txt_layer, GTextAlignmentCenter);
|
||||||
|
|
||||||
scroll_layer_add_child(s_status_scroll_layer, text_layer_get_layer(s_status_txt_layer));
|
layer_add_child(window_layer, text_layer_get_layer(s_status_txt_layer));
|
||||||
layer_add_child(window_layer, scroll_layer_get_layer(s_status_scroll_layer));
|
|
||||||
GSize max_size = text_layer_get_content_size(s_status_txt_layer);
|
|
||||||
max_size.h += 10;
|
|
||||||
scroll_layer_set_content_size(s_status_scroll_layer, max_size);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void status_window_unload() {
|
static void status_window_unload() {
|
||||||
text_layer_destroy(s_status_txt_layer);
|
text_layer_destroy(s_status_txt_layer);
|
||||||
scroll_layer_destroy(s_status_scroll_layer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// reasons: 0 = confirmation, 1 = failure to set alarm, 2 = user sucks at math
|
static void push_status_window(StatusWindowPurpose purpose) {
|
||||||
static void push_status_window(uint8_t reason) {
|
|
||||||
s_status_window = window_create();
|
s_status_window = window_create();
|
||||||
window_set_window_handlers(
|
window_set_window_handlers(
|
||||||
s_status_window,
|
s_status_window,
|
||||||
(WindowHandlers){.unload = status_window_unload});
|
(WindowHandlers){.unload = status_window_unload});
|
||||||
status_window_load(reason);
|
status_window_load(purpose);
|
||||||
window_stack_push(s_status_window, true);
|
window_stack_push(s_status_window, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////// MISC //////////////////////
|
////////////////////// MISC //////////////////////
|
||||||
|
|
||||||
static bool schedule_alarm(bool is_fallback) {
|
static bool schedule_alarm(WakeupReason schedule_reason) {
|
||||||
time_t target;
|
time_t target;
|
||||||
WakeupId status;
|
WakeupId status;
|
||||||
|
|
||||||
if (is_fallback) {
|
switch (schedule_reason) {
|
||||||
|
case RECOVERY_ALARM:
|
||||||
target = time(NULL) + 15;
|
target = time(NULL) + 15;
|
||||||
status = wakeup_schedule_simple_robust(target, 15, true);
|
// no need to cancel alarms, as RECOVERY_ALARM is short-lived and is expired by the time another is being scheduled
|
||||||
} else {
|
status = wakeup_schedule_simple_robust(target, 15, schedule_reason);
|
||||||
|
if (s_alarming_for_awareness) {
|
||||||
|
persist_write_bool(STORAGE_KEY_ALARMING_FOR_AWARENESS, false);
|
||||||
|
s_alarming_for_awareness = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case AWARENESS_ALARM:
|
||||||
|
target = time(NULL) + 9 * SECONDS_PER_MINUTE;
|
||||||
|
wakeup_cancel_all();
|
||||||
|
status = wakeup_schedule_simple_robust(target, SECONDS_PER_MINUTE, schedule_reason);
|
||||||
|
if (!s_alarming_for_awareness) {
|
||||||
|
persist_write_bool(STORAGE_KEY_ALARMING_FOR_AWARENESS, true);
|
||||||
|
s_alarming_for_awareness = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MAIN_ALARM: {
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
struct tm target_tm = *localtime(&now);
|
struct tm target_tm = *localtime(&now);
|
||||||
target_tm.tm_hour = the_time.HourWIP;
|
target_tm.tm_hour = the_time.HourWIP;
|
||||||
@@ -188,8 +194,13 @@ static bool schedule_alarm(bool is_fallback) {
|
|||||||
if (target <= now) {
|
if (target <= now) {
|
||||||
target += SECONDS_PER_DAY;
|
target += SECONDS_PER_DAY;
|
||||||
}
|
}
|
||||||
wakeup_cancel_all(); // only cancel for main alarm (fallback alarm has short lifetime)
|
wakeup_cancel_all();
|
||||||
status = wakeup_schedule_simple_robust(target, SECONDS_PER_MINUTE, is_fallback);
|
status = wakeup_schedule_simple_robust(target, SECONDS_PER_MINUTE, schedule_reason);
|
||||||
|
if (s_alarming_for_awareness) {
|
||||||
|
persist_write_bool(STORAGE_KEY_ALARMING_FOR_AWARENESS, false);
|
||||||
|
s_alarming_for_awareness = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (status < 0) {
|
if (status < 0) {
|
||||||
push_status_window(1);
|
push_status_window(1);
|
||||||
@@ -234,7 +245,9 @@ static void alarm_seconds_handler(struct tm *tick_time, TimeUnits units_changed)
|
|||||||
static char s_stopwatch_buffer[9];
|
static char s_stopwatch_buffer[9];
|
||||||
snprintf(s_stopwatch_buffer, sizeof(s_stopwatch_buffer), "%02u:%02u", s_stopwatch_time[0], s_stopwatch_time[1]);
|
snprintf(s_stopwatch_buffer, sizeof(s_stopwatch_buffer), "%02u:%02u", s_stopwatch_time[0], s_stopwatch_time[1]);
|
||||||
text_layer_set_text(s_counter_txt_layer, s_stopwatch_buffer);
|
text_layer_set_text(s_counter_txt_layer, s_stopwatch_buffer);
|
||||||
|
if (!s_alarming_for_awareness) {
|
||||||
vibes_enqueue_custom_pattern(s_vibe_pattern);
|
vibes_enqueue_custom_pattern(s_vibe_pattern);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void graph_layer_update_proc(Layer *layer, GContext *ctx) {
|
static void graph_layer_update_proc(Layer *layer, GContext *ctx) {
|
||||||
@@ -320,9 +333,9 @@ static void drop_menu_window_unload(Window *window) {
|
|||||||
s_drop_menu_layer = NULL;
|
s_drop_menu_layer = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void live_wakeup_handler_for_alarm(WakeupId id, int32_t reason) {
|
static void live_wakeup_handler_for_alarm(WakeupId id, int32_t wakeup_reason) {
|
||||||
if (reason == 1) { // if fallback alarm, re-schedule it
|
if (wakeup_reason == RECOVERY_ALARM) { // if recovery alarm, re-schedule it
|
||||||
schedule_alarm(true); // output is not captured, as it is not actionable
|
schedule_alarm(RECOVERY_ALARM); // output is not captured, as it is not actionable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,7 +576,7 @@ static void alarm_window_load() {
|
|||||||
.num_segments = ARRAY_LENGTH(s_vibe_segments),
|
.num_segments = ARRAY_LENGTH(s_vibe_segments),
|
||||||
};
|
};
|
||||||
|
|
||||||
schedule_alarm(true); // output is not captured, as it is not actionable
|
schedule_alarm(RECOVERY_ALARM); // output is not captured, as it is not actionable
|
||||||
tick_timer_service_subscribe(SECOND_UNIT, alarm_seconds_handler);
|
tick_timer_service_subscribe(SECOND_UNIT, alarm_seconds_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,10 +649,17 @@ static void alarm_select_hold_handler(void *recognizer, void *ctx) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool success = schedule_alarm(false);
|
if (s_alarming_for_awareness) {
|
||||||
if (success) {
|
// set main alarm if the awareness alarm was solved
|
||||||
|
if (schedule_alarm(MAIN_ALARM)) {
|
||||||
push_status_window(0);
|
push_status_window(0);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// otherwise, set awareness alarm
|
||||||
|
if (schedule_alarm(AWARENESS_ALARM)) {
|
||||||
|
window_stack_pop_all(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void alarm_click_config_provider(void *ctx) {
|
static void alarm_click_config_provider(void *ctx) {
|
||||||
@@ -759,7 +779,7 @@ static void setter_down_click_handler(void *recognizer, void *ctx) {
|
|||||||
|
|
||||||
static void setter_select_click_handler(void *recognizer, void *ctx) {
|
static void setter_select_click_handler(void *recognizer, void *ctx) {
|
||||||
if (s_highlight_pos == 2) {
|
if (s_highlight_pos == 2) {
|
||||||
bool success = schedule_alarm(false);
|
bool success = schedule_alarm(MAIN_ALARM);
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return; // early return to avoid indicating alarm was set when it was not
|
return; // early return to avoid indicating alarm was set when it was not
|
||||||
}
|
}
|
||||||
@@ -798,6 +818,7 @@ static void setter_click_config_provider(void *ctx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void live_wakeup_handler_for_setter(WakeupId id, int32_t reason) {
|
static void live_wakeup_handler_for_setter(WakeupId id, int32_t reason) {
|
||||||
|
s_alarming_for_awareness = persist_read_bool(STORAGE_KEY_ALARMING_FOR_AWARENESS);
|
||||||
s_highlight_pos = 0;
|
s_highlight_pos = 0;
|
||||||
window_stack_pop_all(false);
|
window_stack_pop_all(false);
|
||||||
push_alarm_window();
|
push_alarm_window();
|
||||||
@@ -886,6 +907,7 @@ static void init() {
|
|||||||
switch (launch_reason()) {
|
switch (launch_reason()) {
|
||||||
case APP_LAUNCH_PHONE: // DEBUG, REMOVE PRIOR TO RELEASE!
|
case APP_LAUNCH_PHONE: // DEBUG, REMOVE PRIOR TO RELEASE!
|
||||||
case APP_LAUNCH_WAKEUP:
|
case APP_LAUNCH_WAKEUP:
|
||||||
|
s_alarming_for_awareness = persist_read_bool(STORAGE_KEY_ALARMING_FOR_AWARENESS);
|
||||||
push_alarm_window();
|
push_alarm_window();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define STORAGE_KEY_ALARM_HOUR 0
|
||||||
|
#define STORAGE_KEY_ALARM_MINUTE 1
|
||||||
|
#define STORAGE_KEY_ALARMING_FOR_AWARENESS 2
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
STATUS_CONFIRMATION = 0,
|
||||||
|
STATUS_SET_FAILURE = 1,
|
||||||
|
STATUS_MATH_FAILURE = 2
|
||||||
|
} StatusWindowPurpose;
|
||||||
|
|
||||||
static void push_setter_window();
|
static void push_setter_window();
|
||||||
|
|||||||
+4
-4
@@ -17,24 +17,24 @@ static void glance_reload_callback(AppGlanceReloadSession *session, size_t limit
|
|||||||
// Mostly stolen from https://github.com/SeaPea/GentleWake;
|
// Mostly stolen from https://github.com/SeaPea/GentleWake;
|
||||||
// A slightly more robust wakeup scheduler that retries on certain errors and
|
// A slightly more robust wakeup scheduler that retries on certain errors and
|
||||||
// can retry for a different wakeup time offset by retry_diff up to retry_max times
|
// can retry for a different wakeup time offset by retry_diff up to retry_max times
|
||||||
WakeupId wakeup_schedule_simple_robust(time_t wakeup_time, int8_t retry_diff, bool is_fallback) {
|
WakeupId wakeup_schedule_simple_robust(time_t wakeup_time, int8_t retry_diff, WakeupReason wakeup_reason) {
|
||||||
WakeupId result = 0;
|
WakeupId result = 0;
|
||||||
uint8_t try_count = 0;
|
uint8_t try_count = 0;
|
||||||
|
|
||||||
result = wakeup_schedule(wakeup_time, is_fallback, true);
|
result = wakeup_schedule(wakeup_time, wakeup_reason, true);
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0) {
|
||||||
// If result is negative, something went wrong, so make sure all wakeups for this app are cancelled and try again
|
// If result is negative, something went wrong, so make sure all wakeups for this app are cancelled and try again
|
||||||
wakeup_cancel_all();
|
wakeup_cancel_all();
|
||||||
|
|
||||||
result = wakeup_schedule(wakeup_time, is_fallback, true);
|
result = wakeup_schedule(wakeup_time, wakeup_reason, true);
|
||||||
|
|
||||||
if (result == E_RANGE) {
|
if (result == E_RANGE) {
|
||||||
// E_RANGE means some other app has the same wakeup time +/- 1 minute, so try to set
|
// E_RANGE means some other app has the same wakeup time +/- 1 minute, so try to set
|
||||||
// the wakeup for a time up to (retry_diff * 8) minutes before/after.
|
// the wakeup for a time up to (retry_diff * 8) minutes before/after.
|
||||||
while (result == E_RANGE && try_count++ < 8) {
|
while (result == E_RANGE && try_count++ < 8) {
|
||||||
wakeup_time += retry_diff;
|
wakeup_time += retry_diff;
|
||||||
result = wakeup_schedule(wakeup_time, is_fallback, true);
|
result = wakeup_schedule(wakeup_time, wakeup_reason, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -1,6 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <pebble.h>
|
#include <pebble.h>
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
MAIN_ALARM = 0,
|
||||||
|
AWARENESS_ALARM = 1,
|
||||||
|
RECOVERY_ALARM = 2
|
||||||
|
} WakeupReason;
|
||||||
|
|
||||||
typedef struct TheTime {
|
typedef struct TheTime {
|
||||||
uint8_t HourWIP;
|
uint8_t HourWIP;
|
||||||
uint8_t MinuteWIP;
|
uint8_t MinuteWIP;
|
||||||
@@ -10,4 +17,4 @@ typedef struct TheTime {
|
|||||||
|
|
||||||
struct TheTime the_time;
|
struct TheTime the_time;
|
||||||
|
|
||||||
WakeupId wakeup_schedule_simple_robust(time_t wakeup_time, int8_t retry_diff, bool is_fallback);
|
WakeupId wakeup_schedule_simple_robust(time_t wakeup_time, int8_t retry_diff, WakeupReason wakeup_reason);
|
||||||
|
|||||||
Reference in New Issue
Block a user