mirror of
https://github.com/joeycastillo/second-movement.git
synced 2025-10-29 03:24:59 +00:00
Port the interval_face complication to Second Movement (#66)
* Port the interval_face complication to Second Movement - Compile inside Second Movement - Support custom display * Refactor display buffer name, enlarge index buffer Also removed now unused _blink_idx array * Fix Clear setting not showing, and its formatting * Rename work interval label to make it unique * Skip empty interval timers while cycling through
This commit is contained in:
parent
9121c0cfb8
commit
4eee544762
@ -63,6 +63,7 @@
|
||||
#include "tally_face.h"
|
||||
#include "probability_face.h"
|
||||
#include "ke_decimal_time_face.h"
|
||||
#include "interval_face.h"
|
||||
#include "timer_face.h"
|
||||
#include "simple_coin_flip_face.h"
|
||||
#include "lis2dw_monitor_face.h"
|
||||
|
||||
@ -38,6 +38,7 @@ SRCS += \
|
||||
./watch-faces/complication/kitchen_conversions_face.c \
|
||||
./watch-faces/complication/periodic_table_face.c \
|
||||
./watch-faces/clock/ke_decimal_time_face.c \
|
||||
./watch-faces/complication/interval_face.c \
|
||||
./watch-faces/complication/timer_face.c \
|
||||
./watch-faces/complication/simple_coin_flip_face.c \
|
||||
./watch-faces/sensor/lis2dw_monitor_face.c \
|
||||
|
||||
@ -28,8 +28,6 @@
|
||||
#include "interval_face.h"
|
||||
#include "watch.h"
|
||||
#include "watch_utility.h"
|
||||
#include "watch_private_display.h"
|
||||
#include "watch_buzzer.h"
|
||||
|
||||
typedef enum {
|
||||
interval_setting_0_timer_idx,
|
||||
@ -48,10 +46,15 @@ typedef enum {
|
||||
} interval_setting_idx_t;
|
||||
|
||||
#define INTERVAL_FACE_STATE_DEFAULT "IT" // Interval Timer
|
||||
#define INTERVAL_FACE_STATE_DEFAULT_CD "INT"
|
||||
#define INTERVAL_FACE_STATE_WARMUP "PR" // PRepare / warm up
|
||||
#define INTERVAL_FACE_STATE_WARMUP_CD "PRE"
|
||||
#define INTERVAL_FACE_STATE_WORK "WO" // WOrk
|
||||
#define INTERVAL_FACE_STATE_WORK_CD "WOR"
|
||||
#define INTERVAL_FACE_STATE_BREAK "BR" // BReak
|
||||
#define INTERVAL_FACE_STATE_BREAK_CD "BRK"
|
||||
#define INTERVAL_FACE_STATE_COOLDOWN "CD" // CoolDown
|
||||
#define INTERVAL_FACE_STATE_COOLDOWN_CD "CLD"
|
||||
|
||||
// Define some default timer settings. Each timer is described in an array like this:
|
||||
// 1. warm-up seconds,
|
||||
@ -68,7 +71,7 @@ static const int8_t _default_timers[6][5] = {{0, 40, 20, 0, 0},
|
||||
{0, -20, -5, 0, 0}};
|
||||
|
||||
static const uint8_t _intro_segdata[4][2] = {{1, 8}, {0, 8}, {0, 7}, {1, 7}};
|
||||
static const uint8_t _blink_idx[] = {3, 9, 4, 6, 4, 6, 8, 4, 6, 8, 4, 6};
|
||||
static const uint8_t _intro_segdata_cd[4][2] = {{1, 8}, {1, 9}, {0, 9}, {0, 8}};
|
||||
static const uint8_t _setting_page_idx[] = {1, 0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4};
|
||||
static const int8_t _sound_seq_warmup[] = {BUZZER_NOTE_F6, 8, BUZZER_NOTE_REST, 1, -2, 3, 0};
|
||||
static const int8_t _sound_seq_work[] = {BUZZER_NOTE_F6, 8, BUZZER_NOTE_REST, 1, -2, 2, BUZZER_NOTE_C7, 24, 0};
|
||||
@ -102,41 +105,56 @@ static inline void _button_beep() {
|
||||
if (movement_button_should_sound()) watch_buzzer_play_note(BUZZER_NOTE_C7, 50);
|
||||
}
|
||||
|
||||
static void _timer_write_info(interval_face_state_t *state, char *buf, uint8_t timer_page) {
|
||||
static void _timer_write_info(interval_face_state_t *state, char* bottom_row, char state_str[2][4], char* index_str, uint8_t timer_page) {
|
||||
// fill display string with requested timer information
|
||||
switch (timer_page) {
|
||||
case 0:
|
||||
// clear timer?
|
||||
sprintf(buf, "%2s %1dCLEARn", INTERVAL_FACE_STATE_DEFAULT, state->timer_idx + 1);
|
||||
if (_erase_timer_flag) buf[9] = 'y';
|
||||
sprintf(bottom_row, "CLEARn");
|
||||
sprintf(state_str[0], "%2s", INTERVAL_FACE_STATE_DEFAULT);
|
||||
sprintf(state_str[1], "%3s", INTERVAL_FACE_STATE_DEFAULT_CD);
|
||||
sprintf(index_str, " %1d", state->timer_idx + 1);
|
||||
if (_erase_timer_flag) bottom_row[5] = 'y';
|
||||
watch_clear_colon();
|
||||
break;
|
||||
case 1:
|
||||
// warmup time info
|
||||
sprintf(buf, "%2s %1d%02d%02d ", INTERVAL_FACE_STATE_WARMUP, state->timer_idx + 1,
|
||||
sprintf(bottom_row, "%02d%02d ",
|
||||
state->timer[state->timer_idx].warmup_minutes,
|
||||
state->timer[state->timer_idx].warmup_seconds);
|
||||
sprintf(state_str[0], "%2s", INTERVAL_FACE_STATE_WARMUP);
|
||||
sprintf(state_str[1], "%3s", INTERVAL_FACE_STATE_WARMUP_CD);
|
||||
sprintf(index_str, " %1d", state->timer_idx + 1);
|
||||
break;
|
||||
case 2:
|
||||
// work interval info
|
||||
sprintf(buf, "%2s %1d%02d%02d%2d", INTERVAL_FACE_STATE_WORK, state->timer_idx + 1,
|
||||
sprintf(bottom_row, "%02d%02d%2d",
|
||||
state->timer[state->timer_idx].work_minutes,
|
||||
state->timer[state->timer_idx].work_seconds,
|
||||
state->timer[state->timer_idx].work_rounds);
|
||||
sprintf(state_str[0], "%2s", INTERVAL_FACE_STATE_WORK);
|
||||
sprintf(state_str[1], "%3s", INTERVAL_FACE_STATE_WORK_CD);
|
||||
sprintf(index_str, " %1d", state->timer_idx + 1);
|
||||
break;
|
||||
case 3:
|
||||
// break interval info
|
||||
sprintf(buf, "%2s %1d%02d%02d%2d", INTERVAL_FACE_STATE_BREAK, state->timer_idx + 1,
|
||||
sprintf(bottom_row, "%02d%02d%2d",
|
||||
state->timer[state->timer_idx].break_minutes,
|
||||
state->timer[state->timer_idx].break_seconds,
|
||||
state->timer[state->timer_idx].full_rounds);
|
||||
if (!state->timer[state->timer_idx].full_rounds) buf[9] = '-';
|
||||
if (!state->timer[state->timer_idx].full_rounds) bottom_row[5] = '-';
|
||||
sprintf(state_str[0], "%2s", INTERVAL_FACE_STATE_BREAK);
|
||||
sprintf(state_str[1], "%3s", INTERVAL_FACE_STATE_BREAK_CD);
|
||||
sprintf(index_str, " %1d", state->timer_idx + 1);
|
||||
break;
|
||||
case 4:
|
||||
// cooldown time info
|
||||
sprintf(buf, "%2s %1d%02d%02d ", INTERVAL_FACE_STATE_COOLDOWN ,state->timer_idx + 1,
|
||||
sprintf(bottom_row, "%02d%02d ",
|
||||
state->timer[state->timer_idx].cooldown_minutes,
|
||||
state->timer[state->timer_idx].cooldown_seconds);
|
||||
sprintf(state_str[0], "%2s", INTERVAL_FACE_STATE_COOLDOWN);
|
||||
sprintf(state_str[1], "%3s", INTERVAL_FACE_STATE_COOLDOWN_CD);
|
||||
sprintf(index_str, " %1d", state->timer_idx + 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -146,8 +164,10 @@ static void _timer_write_info(interval_face_state_t *state, char *buf, uint8_t t
|
||||
static void _face_draw(interval_face_state_t *state, uint8_t subsecond) {
|
||||
// draws current face state
|
||||
if (!state->is_active) return;
|
||||
char buf[14];
|
||||
buf[0] = 0;
|
||||
char bottom_row[10];
|
||||
char int_state_str[2][4];
|
||||
char int_index_str[5];
|
||||
bottom_row[0] = 0;
|
||||
uint8_t tmp;
|
||||
if (state->face_state == interval_state_waiting && _ticks >= 0) {
|
||||
// play info slideshow for current timer
|
||||
@ -160,9 +180,9 @@ static void _face_draw(interval_face_state_t *state, uint8_t subsecond) {
|
||||
}
|
||||
}
|
||||
tmp = ticks / 3 + 1;
|
||||
_timer_write_info(state, buf, tmp);
|
||||
_timer_write_info(state, bottom_row, int_state_str, int_index_str, tmp);
|
||||
// don't show '1 round' when displaying workout time to avoid detail overload
|
||||
if (tmp == 2 && state->timer[state->timer_idx].work_rounds == 1) buf[9] = ' ';
|
||||
if (tmp == 2 && state->timer[state->timer_idx].work_rounds == 1) bottom_row[5] = ' ';
|
||||
// blink colon
|
||||
if (subsecond % 2 == 0 && _ticks < 24) watch_clear_colon();
|
||||
else watch_set_colon();
|
||||
@ -175,38 +195,66 @@ static void _face_draw(interval_face_state_t *state, uint8_t subsecond) {
|
||||
} else {
|
||||
tmp = _setting_page_idx[_setting_idx];
|
||||
}
|
||||
_timer_write_info(state, buf, tmp);
|
||||
_timer_write_info(state, bottom_row, int_state_str, int_index_str, tmp);
|
||||
// blink at cursor position
|
||||
if (subsecond % 2 && _ticks != -2) {
|
||||
buf[_blink_idx[_setting_idx]] = ' ';
|
||||
if (_blink_idx[_setting_idx] % 2 == 0) buf[_blink_idx[_setting_idx] + 1] = ' ';
|
||||
switch (_setting_idx) {
|
||||
case interval_setting_0_timer_idx:
|
||||
int_index_str[0] = int_index_str[1] = ' ';
|
||||
break;
|
||||
case interval_setting_1_clear_yn:
|
||||
bottom_row[5] = ' ';
|
||||
break;
|
||||
case interval_setting_2_warmup_minutes:
|
||||
case interval_setting_4_work_minutes:
|
||||
case interval_setting_7_break_minutes:
|
||||
case interval_setting_10_cooldown_minutes:
|
||||
bottom_row[0] = bottom_row[1] = ' ';
|
||||
break;
|
||||
case interval_setting_3_warmup_seconds:
|
||||
case interval_setting_5_work_seconds:
|
||||
case interval_setting_8_break_seconds:
|
||||
case interval_setting_11_cooldown_seconds:
|
||||
bottom_row[2] = bottom_row[3] = ' ';
|
||||
break;
|
||||
case interval_setting_6_work_rounds:
|
||||
case interval_setting_9_full_rounds:
|
||||
bottom_row[4] = bottom_row[5] = ' ';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
// show lap indicator only when rounds are set
|
||||
if (_setting_idx == interval_setting_6_work_rounds || _setting_idx == interval_setting_9_full_rounds)
|
||||
watch_set_indicator(WATCH_INDICATOR_LAP);
|
||||
else
|
||||
else
|
||||
watch_clear_indicator(WATCH_INDICATOR_LAP);
|
||||
} else if (state->face_state == interval_state_running || state->face_state == interval_state_pausing) {
|
||||
tmp = _timer_full_round;
|
||||
switch (_timer_run_state) {
|
||||
case 0:
|
||||
sprintf(buf, INTERVAL_FACE_STATE_WARMUP);
|
||||
sprintf(int_state_str[0], "%2s", INTERVAL_FACE_STATE_WARMUP);
|
||||
sprintf(int_state_str[1], "%3s", INTERVAL_FACE_STATE_WARMUP_CD);
|
||||
break;
|
||||
case 1:
|
||||
sprintf(buf, INTERVAL_FACE_STATE_WORK);
|
||||
sprintf(int_state_str[0], "%2s", INTERVAL_FACE_STATE_WORK);
|
||||
sprintf(int_state_str[1], "%3s", INTERVAL_FACE_STATE_WORK_CD);
|
||||
if (state->timer[state->timer_idx].work_rounds > 1) tmp = _timer_work_round;
|
||||
break;
|
||||
case 2:
|
||||
sprintf(buf, INTERVAL_FACE_STATE_BREAK);
|
||||
sprintf(int_state_str[0], "%2s", INTERVAL_FACE_STATE_BREAK);
|
||||
sprintf(int_state_str[1], "%3s", INTERVAL_FACE_STATE_BREAK_CD);
|
||||
break;
|
||||
case 3:
|
||||
sprintf(buf, INTERVAL_FACE_STATE_COOLDOWN);
|
||||
sprintf(int_state_str[0], "%2s", INTERVAL_FACE_STATE_COOLDOWN);
|
||||
sprintf(int_state_str[1], "%3s", INTERVAL_FACE_STATE_COOLDOWN_CD);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
div_t delta;
|
||||
|
||||
|
||||
if (state->face_state == interval_state_pausing) {
|
||||
// pausing
|
||||
delta = div(_target_ts - _paused_ts, 60);
|
||||
@ -216,16 +264,21 @@ static void _face_draw(interval_face_state_t *state, uint8_t subsecond) {
|
||||
} else
|
||||
// running
|
||||
delta = div(_target_ts - _now_ts, 60);
|
||||
sprintf(&buf[2], " %1d%02d%02d%2d", state->timer_idx + 1, delta.quot, delta.rem, tmp + 1);
|
||||
sprintf(bottom_row, "%02d%02d%2d", delta.quot, delta.rem, tmp + 1);
|
||||
sprintf(int_index_str, " %1d", state->timer_idx + 1);
|
||||
}
|
||||
// write out to lcd
|
||||
if (buf[0]) {
|
||||
watch_display_character(buf[0], 0);
|
||||
watch_display_character(buf[1], 1);
|
||||
if (int_state_str[0][0]) {
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, int_state_str[1], int_state_str[0]);
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP_RIGHT, int_index_str, int_index_str);
|
||||
// set the bar for the i-like symbol on position 2
|
||||
watch_set_pixel(2, 9);
|
||||
if (watch_get_lcd_type() == WATCH_LCD_TYPE_CLASSIC) {
|
||||
watch_set_pixel(2, 9);
|
||||
} else {
|
||||
watch_set_pixel(2, 10);
|
||||
}
|
||||
// display the rest of the string
|
||||
watch_display_string(&buf[3], 3);
|
||||
watch_display_text_with_fallback(WATCH_POSITION_BOTTOM, bottom_row, bottom_row);
|
||||
}
|
||||
}
|
||||
|
||||
@ -427,8 +480,12 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
_init_timer_info(state);
|
||||
_face_draw(state, event.subsecond);
|
||||
break;
|
||||
}
|
||||
watch_set_pixel(_intro_segdata[_ticks][0], _intro_segdata[_ticks][1]);
|
||||
}
|
||||
if (watch_get_lcd_type() == WATCH_LCD_TYPE_CLASSIC) {
|
||||
watch_set_pixel(_intro_segdata[_ticks][0], _intro_segdata[_ticks][1]);
|
||||
} else {
|
||||
watch_set_pixel(_intro_segdata_cd[_ticks][0], _intro_segdata_cd[_ticks][1]);
|
||||
}
|
||||
_ticks++;
|
||||
} else if (state->face_state == interval_state_waiting && _ticks >= 0) {
|
||||
// play information slideshow for current interval timer
|
||||
@ -448,7 +505,7 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
}
|
||||
break;
|
||||
case EVENT_ACTIVATE:
|
||||
watch_display_string(INTERVAL_FACE_STATE_DEFAULT, 0);
|
||||
watch_display_text_with_fallback(WATCH_POSITION_TOP_LEFT, INTERVAL_FACE_STATE_DEFAULT_CD, INTERVAL_FACE_STATE_DEFAULT);
|
||||
if (state->face_state) _face_draw(state, event.subsecond);
|
||||
break;
|
||||
case EVENT_LIGHT_BUTTON_UP:
|
||||
@ -479,7 +536,7 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
}
|
||||
break;
|
||||
case EVENT_LIGHT_LONG_PRESS:
|
||||
_button_beep(settings);
|
||||
_button_beep();
|
||||
if (state->face_state == interval_state_setting) {
|
||||
_resume_setting(state, event.subsecond);
|
||||
} else {
|
||||
@ -490,8 +547,10 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
case EVENT_ALARM_BUTTON_UP:
|
||||
switch (state->face_state) {
|
||||
case interval_state_waiting:
|
||||
// cycle through timers
|
||||
_inc_uint8(&state->timer_idx, 1, INTERVAL_TIMERS);
|
||||
// cycle through timers, skipping empty ones
|
||||
do {
|
||||
_inc_uint8(&state->timer_idx, 1, INTERVAL_TIMERS);
|
||||
} while (_is_timer_empty(&state->timer[state->timer_idx]) && state->timer_idx != 0);
|
||||
_ticks = 0;
|
||||
_face_draw(state, event.subsecond);
|
||||
break;
|
||||
@ -502,7 +561,7 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
break;
|
||||
case interval_state_running:
|
||||
// pause timer
|
||||
_button_beep(settings);
|
||||
_button_beep();
|
||||
_paused_ts = _get_now_ts();
|
||||
state->face_state = interval_state_pausing;
|
||||
movement_cancel_background_task();
|
||||
@ -510,7 +569,7 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
break;
|
||||
case interval_state_pausing:
|
||||
// resume paused timer
|
||||
_button_beep(settings);
|
||||
_button_beep();
|
||||
_resume_paused_timer(state);
|
||||
_face_draw(state, event.subsecond);
|
||||
break;
|
||||
@ -527,7 +586,7 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
} else if (state->face_state <= interval_state_waiting) {
|
||||
if (_is_timer_empty(timer)) {
|
||||
// jump back to timer #1
|
||||
_button_beep(settings);
|
||||
_button_beep();
|
||||
state->timer_idx = 0;
|
||||
_init_timer_info(state);
|
||||
} else {
|
||||
@ -551,7 +610,7 @@ bool interval_face_loop(movement_event_t event, void *context) {
|
||||
_init_timer_info(state);
|
||||
} else if (state->face_state == interval_state_pausing) {
|
||||
// resume paused timer
|
||||
_button_beep(settings);
|
||||
_button_beep();
|
||||
_resume_paused_timer(state);
|
||||
}
|
||||
_face_draw(state, event.subsecond);
|
||||
Loading…
x
Reference in New Issue
Block a user