Skip to content
This repository has been archived by the owner on Apr 27, 2020. It is now read-only.

Commit

Permalink
Optimized Chalk, Emery display
Browse files Browse the repository at this point in the history
The Pebble Round interface now actually fits on the round screen rather than having some text cut off. Emery also now has larger fonts to account for the increased pixel density.

There is also now an option to remember the duration of the last session and have that be the default breathing duration.
  • Loading branch information
aaronhktan committed Nov 19, 2016
1 parent b5cd3d2 commit a5bdd79
Show file tree
Hide file tree
Showing 17 changed files with 235 additions and 86 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"circleColor",
"vibrationEnabled",
"heartRateEnabled",
"reminderHours"
"reminderHours",
"rememberDuration"
],
"projectType": "native",
"resources": {
Expand Down Expand Up @@ -51,5 +52,5 @@
"watchface": false
}
},
"version": "0.23.0"
"version": "0.24.0"
}
63 changes: 45 additions & 18 deletions src/c/breathe_window.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ static uint8_t s_radius_final, s_radius = 0;
static int s_min_to_breathe = 1, s_min_breathed_today = 0, s_times_played = 0;
static bool s_animation_completed = false, s_animating = false;
static GPoint s_center;
static char s_min_to_breathe_text[3] = "1", s_instruct_text[9], s_min_text[5], s_min_today[25], s_greet_text[27], *s_start_time, *s_end_time;
static char s_min_to_breathe_text[3] = "1", s_instruct_text[27], s_min_text[25], s_min_today[25], s_greet_text[27], *s_start_time, *s_end_time;
static time_t t;

// ******************************************************************************************* Layer Update Procedures
Expand All @@ -24,7 +24,7 @@ static void canvas_update_proc(Layer *s_drawing_layer, GContext *ctx) {

// Updates text inside circle, side semicircle, and triangles
static void inside_text_layer_update_proc(Layer *s_inside_text_layer, GContext *ctx) {
graphics_draw_inner_text(ctx, bounds, s_min_to_breathe, settings_get_textColor(), s_min_to_breathe_text, s_instruct_text, s_min_text);
graphics_draw_inner_text(ctx, bounds, s_animating, s_min_to_breathe, settings_get_textColor(), s_min_to_breathe_text, s_instruct_text, s_min_text);
}

// Draws text at top of screen
Expand Down Expand Up @@ -80,6 +80,16 @@ static void finish_setup_callback(void *context) {
layer_mark_dirty(s_lower_text_layer);
}

// ******************************************************************************************* Other stuff
// Changes text in circle if singular or plural
static void set_min_text(int minutes, void *string) {
if (minutes == 1) {
snprintf(string, 5, "%s", "MIN");
} else {
snprintf(string, 5, "%s", "MINS");
}
}

// ******************************************************************************************* Animation Sequence Creator
// Animation while breathing
static void radius_contract_update(Animation *anim, AnimationProgress dist_normalized) {
Expand Down Expand Up @@ -139,6 +149,10 @@ static void main_animation_end() {
// Sets up and schedules circle contract and expand
static void main_animation() {
// Hides text layers
#ifdef PBL_ROUND
layer_set_hidden(s_inside_text_layer, true);
#endif

layer_set_hidden(s_upper_text_layer, true);
layer_set_hidden(s_lower_text_layer, true);

Expand Down Expand Up @@ -190,6 +204,9 @@ static void main_animation_callback () {
static void first_breath_in_callback(void *context) {
snprintf(s_greet_text, sizeof(s_greet_text), localize_get_inhale_text());
layer_set_hidden(s_upper_text_layer, false);
#ifdef PBL_ROUND
layer_set_hidden(s_inside_text_layer, true);
#endif
}

// Shows instructions to exhale; first hides the top text and then shows the bottom text
Expand Down Expand Up @@ -224,15 +241,14 @@ static void animation_start_callback(void *context) {
int random_number = rand() % 9;
APP_LOG(APP_LOG_LEVEL_DEBUG, "The random_number is %d", random_number);
APP_LOG(APP_LOG_LEVEL_DEBUG, "The string is %s", &*strings[random_number]);
snprintf(s_greet_text, sizeof(s_greet_text), "%s", &*strings[random_number]);

// Same thing as above but for bottom text
char* bottom_text[4] = {"BREATHE.", "EXHALE.", "CONCENTRATE.", "FOCUS."};
if (strncmp(localize_get_locale(), "fr", 2) == 0) {
char* french_bottom_text[4] = {"RESPIREZ.", "EXHALEZ.", "RESPIREZ.", "EXHALEZ."};
for (int i = 0; i <= 3; i++) {
bottom_text[i] = french_bottom_text[i];
}
}
} else if (strncmp(localize_get_locale(), "es", 2) == 0) {
char* spanish_bottom_text[4] = {"RESPIRA.", "EXHALA.", "RESPIRA.", "EXHALA."};
for (int i = 0; i <= 8; i++) {
Expand All @@ -243,11 +259,19 @@ static void animation_start_callback(void *context) {
int random_number_2 = rand() % 4;
APP_LOG(APP_LOG_LEVEL_DEBUG, "The random_number #2 is %d", random_number_2);
APP_LOG(APP_LOG_LEVEL_DEBUG, "The string is %s", &*bottom_text[random_number_2]);
snprintf(s_min_today, sizeof(s_min_today), "%s", &*bottom_text[random_number_2]);

// Shows the text at top and bottom
layer_set_hidden(s_upper_text_layer, false);
layer_set_hidden(s_lower_text_layer, false);

#ifdef PBL_RECT
// Shows the text at top and bottom
snprintf(s_greet_text, sizeof(s_greet_text), "%s", &*strings[random_number]);
snprintf(s_min_today, sizeof(s_min_today), "%s", &*bottom_text[random_number_2]);
layer_set_hidden(s_upper_text_layer, false);
layer_set_hidden(s_lower_text_layer, false);
#else
// Shows the text near the center of the screen
snprintf(s_instruct_text, sizeof(s_instruct_text), "%s", &*strings[random_number]);
snprintf(s_min_text, sizeof(s_min_text), "%s", &*bottom_text[random_number_2]);
layer_set_hidden(s_inside_text_layer, false);
#endif
}

// End animation show text
Expand Down Expand Up @@ -277,6 +301,12 @@ static void animation_end_callback(void *context) {
data_write_breathe_persist_data(s_min_breathed_today);
data_write_date_persist_data();

// Persist the duration of minutes
if (settings_get_rememberDuration()) {
APP_LOG(APP_LOG_LEVEL_DEBUG, "rememberDuration is enabled and duration has been saved.");
data_write_last_duration_data(s_min_to_breathe);
}

// Sets different number of digits for one digit or two digits
if (s_min_to_breathe == 10) {
snprintf(s_min_to_breathe_text, 3, "%dd", s_min_to_breathe);
Expand All @@ -285,20 +315,15 @@ static void animation_end_callback(void *context) {
}

// Shows all the layers because breathing is done
#ifdef PBL_ROUND
set_min_text(s_min_to_breathe, s_min_text);
snprintf(s_instruct_text, sizeof(s_instruct_text), localize_get_breathe_text());
#endif
layer_set_hidden(s_inside_text_layer, false);
layer_set_hidden(s_upper_text_layer, false);
layer_set_hidden(s_lower_text_layer, false);
}

// Changes text in circle if singular or plural
static void set_min_text(int minutes, void *string) {
if (minutes == 1) {
snprintf(string, 5, "%s", "MIN");
} else {
snprintf(string, 5, "%s", "MINS");
}
}

// ******************************************************************************************* Click Handlers
static void up_click_handler(ClickRecognizerRef recognizer, void *context) {
// Increments number, displays number.
Expand Down Expand Up @@ -452,6 +477,8 @@ void breathe_window_push(int min) {
snprintf(s_min_to_breathe_text, sizeof(s_min_to_breathe_text), "%d", s_min_to_breathe);
set_min_text(s_min_to_breathe, s_min_text);

snprintf(s_greet_text, sizeof(s_greet_text), localize_get_greet_text());

// Show window on the watch, with animated = true
window_stack_push(s_main_window, true);
}
16 changes: 16 additions & 0 deletions src/c/data.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,20 @@ int data_read_breathe_persist_data() {
return min_breathed_today;
}
return 0;
}

void data_write_last_duration_data(int last_duration) {
persist_write_int(LAST_DURATION_KEY, last_duration);
}

int data_read_last_duration_data() {
int last_duration = 1;
if (persist_exists(LAST_DURATION_KEY)) {
last_duration = persist_read_int(LAST_DURATION_KEY);
APP_LOG(APP_LOG_LEVEL_DEBUG, "The last duration was %d.", last_duration);
} else {
APP_LOG(APP_LOG_LEVEL_DEBUG, "User has not breathed before; created data.");
data_write_last_duration_data(last_duration);
}
return last_duration;
}
5 changes: 4 additions & 1 deletion src/c/data.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#define MIN_BREATHED_TODAY_KEY 0
#define DATE_STORED_KEY 1
#define LAST_DURATION_KEY 2

void data_init();

Expand All @@ -21,4 +22,6 @@ char* data_get_current_heart_rate_buffer();
char* data_get_date_today();
void data_write_breathe_persist_data(int min_to_breathe);
void data_write_date_persist_data();
int data_read_breathe_persist_data();
int data_read_breathe_persist_data();
void data_write_last_duration_data(int last_duration);
int data_read_last_duration_data();
72 changes: 42 additions & 30 deletions src/c/graphics.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ void graphics_draw_upper_text(GContext *ctx, GRect bounds, bool is_animating, bo
#endif

graphics_context_set_text_color(ctx, (is_animating) ? textColor : PBL_IF_COLOR_ELSE(GColorDarkGray, textColor)); // Set text color to dark gray on main menu, but white for other sections
GSize greet_text_bounds = graphics_text_layout_get_content_size("THAT IS A LOT OF STEPS TO TAKE IN JUST ONE DAY, INNIT?", fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
GSize greet_text_bounds = graphics_text_layout_get_content_size("THAT IS A LOT OF STEPS TO TAKE IN JUST ONE DAY, INNIT?", fonts_get_system_font(FONT_KEY),
GRect(0, 0, bounds.size.w, bounds.size.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter); // Random string for size purposes
if (is_animating) { // If animating, shows the normal text
graphics_draw_text(ctx, greet_text, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
graphics_draw_text(ctx, greet_text, fonts_get_system_font(FONT_KEY),
GRect((bounds.size.w - greet_text_bounds.w) / 2, PBL_IF_RECT_ELSE(5, 15), greet_text_bounds.w, greet_text_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
} else {
if (heart_rate && data_get_current_heart_rate() > 0) { // If heart rate monitor is enabled in configuration and is available, show heart rate
const char *heart_rate_buffer = data_get_current_heart_rate_buffer();
graphics_draw_text(ctx, heart_rate_buffer, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
graphics_draw_text(ctx, heart_rate_buffer, fonts_get_system_font(FONT_KEY),
GRect((bounds.size.w - greet_text_bounds.w) / 2, PBL_IF_RECT_ELSE(5, 15), greet_text_bounds.w, greet_text_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
} else { // Otherwise, show step counts if Pebble Health, and string if not.
graphics_draw_text(ctx, PBL_IF_HEALTH_ELSE(steps_buffer, greet_text), fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
graphics_draw_text(ctx, PBL_IF_HEALTH_ELSE(steps_buffer, greet_text), fonts_get_system_font(FONT_KEY),
GRect((bounds.size.w - greet_text_bounds.w) / 2, PBL_IF_RECT_ELSE(5, 15), greet_text_bounds.w, greet_text_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}
Expand All @@ -64,54 +64,66 @@ void graphics_draw_upper_text(GContext *ctx, GRect bounds, bool is_animating, bo
// Method for updating the lower text layer
void graphics_draw_lower_text(GContext *ctx, GRect bounds, bool is_animating, GColor textColor, char *min_today) {
graphics_context_set_text_color(ctx, (is_animating) ? textColor : PBL_IF_COLOR_ELSE(GColorDarkGray, textColor)); // Like above, sets text color to dark gray on main menu, but white for other sections
GSize today_text_bounds = graphics_text_layout_get_content_size("TODAY: 10,000 MINUTES", fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
GSize today_text_bounds = graphics_text_layout_get_content_size("TODAY: 10,000 MINUTES", fonts_get_system_font(FONT_KEY),
GRect(0, 0, bounds.size.w, bounds.size.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter);

graphics_draw_text(ctx, min_today, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
graphics_draw_text(ctx, min_today, fonts_get_system_font(FONT_KEY),
GRect((bounds.size.w - today_text_bounds.w) / 2, bounds.size.h - today_text_bounds.h - PBL_IF_RECT_ELSE(8, 20), today_text_bounds.w, today_text_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}

// Method for updating the inner text, triangles, and the semicircle on the right center of the screen
void graphics_draw_inner_text(GContext *ctx, GRect bounds, int min_to_breathe, GColor textColor, char *min_to_breathe_text, char *instruct_text, char *min_text) {
void graphics_draw_inner_text(GContext *ctx, GRect bounds, bool is_animating, int min_to_breathe, GColor textColor, char *min_to_breathe_text, char *instruct_text, char *min_text) {
// Draw side circle
graphics_context_set_fill_color(ctx, textColor);
graphics_fill_circle(ctx, GPoint(bounds.size.w + 5, bounds.size.h / 2), 10);
#ifdef PBL_PLATFORM_EMERY
graphics_fill_circle(ctx, GPoint(bounds.size.w + 7, bounds.size.h / 2), 12);
#elif PBL_PLATFORM_CHALK
if (!is_animating) {
graphics_fill_circle(ctx, GPoint(bounds.size.w + 1, bounds.size.h / 2), 12);
}
#else
graphics_fill_circle(ctx, GPoint(bounds.size.w + 5, bounds.size.h / 2), 10);
#endif

// Draw triangles
switch(min_to_breathe) {
case 1 :
gpath_draw_filled(ctx, s_up_triangle); // Only draw the upper triangle because user cannot set a time lower than 1
break;
case 10 :
gpath_draw_filled(ctx, s_down_triangle); // Only draw the lower triangle because the user cannot set a time higher than 10
break;
default:
gpath_draw_filled(ctx, s_up_triangle);
gpath_draw_filled(ctx, s_down_triangle);
if (!is_animating) {
// Draw triangles
switch(min_to_breathe) {
case 1 :
gpath_draw_filled(ctx, s_up_triangle); // Only draw the upper triangle because user cannot set a time lower than 1
break;
case 10 :
gpath_draw_filled(ctx, s_down_triangle); // Only draw the lower triangle because the user cannot set a time higher than 10
break;
default:
gpath_draw_filled(ctx, s_up_triangle);
gpath_draw_filled(ctx, s_down_triangle);
}
}

// Draw text in circle
graphics_context_set_text_color(ctx, textColor);
GSize min_to_breathe_bounds = graphics_text_layout_get_content_size("10", fonts_get_system_font(FONT_KEY_LECO_42_NUMBERS),
GRect(0, 0, bounds.size.w, bounds.size.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter);
graphics_draw_text(ctx, min_to_breathe_text, fonts_get_system_font(FONT_KEY_LECO_42_NUMBERS),
GRect((bounds.size.w - min_to_breathe_bounds.w) / 2, (bounds.size.h - min_to_breathe_bounds.h) / 2 - 6, min_to_breathe_bounds.w, min_to_breathe_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);

GSize instruct_text_bounds = graphics_text_layout_get_content_size("RESPIRAR", fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
if (!is_animating) {
GSize min_to_breathe_bounds = graphics_text_layout_get_content_size("10", fonts_get_system_font(FONT_KEY_LECO_42_NUMBERS),
GRect(0, 0, bounds.size.w, bounds.size.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter);
graphics_draw_text(ctx, min_to_breathe_text, fonts_get_system_font(FONT_KEY_LECO_42_NUMBERS),
GRect((bounds.size.w - min_to_breathe_bounds.w) / 2, (bounds.size.h - min_to_breathe_bounds.h) / 2 - 6, min_to_breathe_bounds.w, min_to_breathe_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}

GSize instruct_text_bounds = graphics_text_layout_get_content_size(PBL_IF_ROUND_ELSE("DONNEZ_VOUS DE L'ESPACE;", "BREATHE"), fonts_get_system_font(FONT_KEY),
GRect(0, 0, bounds.size.w, bounds.size.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter);
graphics_draw_text(ctx, instruct_text, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
graphics_draw_text(ctx, instruct_text, fonts_get_system_font(FONT_KEY),
GRect((bounds.size.w - instruct_text_bounds.w) / 2, (bounds.size.h - instruct_text_bounds.h) / 2 - 29, instruct_text_bounds.w, instruct_text_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);

GSize min_text_bounds = graphics_text_layout_get_content_size("MINS", fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
GSize min_text_bounds = graphics_text_layout_get_content_size("CONCENTRATE.", fonts_get_system_font(FONT_KEY),
GRect(0, 0, bounds.size.w, bounds.size.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter);
graphics_draw_text(ctx, min_text, fonts_get_system_font(FONT_KEY_GOTHIC_14_BOLD),
graphics_draw_text(ctx, min_text, fonts_get_system_font(FONT_KEY),
GRect((bounds.size.w - min_text_bounds.w) / 2, (bounds.size.h - min_text_bounds.h) / 2 + 25, min_text_bounds.w, min_text_bounds.h),
GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL);
}
Expand Down
8 changes: 7 additions & 1 deletion src/c/graphics.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@
#include <pebble.h>
#include "src/c/data.h"

#ifdef PBL_PLATFORM_EMERY
#define FONT_KEY FONT_KEY_GOTHIC_18_BOLD
#else
#define FONT_KEY FONT_KEY_GOTHIC_14_BOLD
#endif

void graphics_draw_upper_text(GContext *ctx, GRect bounds, bool is_animating, bool heart_rate, GColor textColor, char *);

void graphics_draw_lower_text(GContext *ctx, GRect bounds, bool is_animating, GColor textColor, char *);

void graphics_draw_inner_text(GContext *ctx, GRect bounds, int min_to_breathe, GColor textColor, char *, char *, char *);
void graphics_draw_inner_text(GContext *ctx, GRect bounds, bool is_animating, int min_to_breathe, GColor textColor, char *, char *, char *);

void graphics_draw_main_circle(GContext *ctx, GColor circleColor, GPoint center, int radius);

Expand Down
22 changes: 16 additions & 6 deletions src/c/localize.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ char * localize_get_app_glance_text(int minutes) {
switch (minutes) {
case 1:
if (strncmp(localize_get_locale(), "fr", 2) == 0) {
return "La journée plus récente: %d minute. Respirez maintenant!";
return "Dernière session: %d minute. Respirez maintenant!";
} else if (strncmp(localize_get_locale(), "es", 2) == 0) {
return "El día más reciente: %d minuto. ¡Respira ahora!";
return "Última sesión: %d minuto. ¡Respira ahora!";
} else {
return "Most recent day: %d minute. Breathe now!";
return "Last session: %d minute. Breathe now!";
}
default:
if (strncmp(localize_get_locale(), "fr", 2) == 0) {
return "La journée plus récente: %d minutes. Respirez maintenant!";
return "Dernière session: %d minutes. Respirez maintenant!";
} else if (strncmp(localize_get_locale(), "es", 2) == 0) {
return "El día más reciente: %d minutos. ¡Respira ahora!";
return "Última sesión: %d minutos. ¡Respira ahora!";
} else {
return "Most recent day: %d minutes. Breathe now!";
return "Last session: %d minutes. Breathe now!";
}
}
}
Expand Down Expand Up @@ -142,4 +142,14 @@ char * localize_get_reminder_text() {
} else {
return "Time to breathe!";
}
}

char * localize_get_greet_text() {
if (strncmp(localize_get_locale(), "fr", 2) == 0) {
return "BONJOUR!";
} else if (strncmp(localize_get_locale(), "es", 2) == 0) {
return "¡HOLA!";
} else {
return "HELLO!";
}
}
3 changes: 2 additions & 1 deletion src/c/localize.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ char * localize_get_min_breathed_today_text();
char * localize_get_steps_today_text(int thousands);
char * localize_get_heart_rate_text();
char * localize_get_reminder_action_menu_text();
char * localize_get_reminder_text();
char * localize_get_reminder_text();
char * localize_get_greet_text();
Loading

0 comments on commit a5bdd79

Please sign in to comment.