Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"type": "font",
"name": "FONT_ICONS_28",
"file": "fonts/Lilex/LilexNerdFontMono-Regular.ttf",
"characterRegex": "[ ]"
"characterRegex": "[ ]"
},
{
"type": "font",
Expand All @@ -83,7 +83,7 @@
"targetPlatforms": [
"emery"
],
"characterRegex": "[ ]"
"characterRegex": "[ ]"
},
{
"type": "font",
Expand Down
21 changes: 17 additions & 4 deletions src/c/battery.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
static TextLayer *s_battery_layer_text;
static TextLayer *s_battery_layer_icon;

int BATTERY_ROW_MAX_WIDTH = 0;

/**
* Update battery icon and text.
*/
Expand Down Expand Up @@ -34,25 +36,36 @@ void battery_init() {
battery_state_service_subscribe(battery_update_handler);
}

// WARNING: Must be called before bluetooth loads.
void battery_load(Window *window, int row_height) {
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);

// Battery icon.
s_battery_layer_icon = font_render_icon_small(window_layer, ICON_BATTERY_50, PADDING_X, 0, true, false);
s_battery_layer_icon = font_render_icon_small(window_layer, ICON_BATTERY_100, PADDING_X, 0, true, false);
text_layer_set_text_color(s_battery_layer_icon, THEME.text_color);

// Battery percentage.
GRect battery_icon_bounds = layer_get_bounds(text_layer_get_layer(s_battery_layer_icon));
s_battery_layer_text =
text_layer_create(GRect(battery_icon_bounds.size.w - battery_icon_bounds.size.w, 0,
bounds.size.w - battery_icon_bounds.size.w - PADDING_X - 2, row_height));
s_battery_layer_text = text_layer_create(
GRect(battery_icon_bounds.size.w - battery_icon_bounds.size.w, 0,
bounds.size.w - battery_icon_bounds.size.w - PADDING_X - BATTERY_TEXT_RIGHT_INSET, row_height));

text_layer_set_text_alignment(s_battery_layer_text, GTextAlignmentRight);
text_layer_set_font(s_battery_layer_text, s_font_primary_small);
text_layer_set_text_color(s_battery_layer_text, THEME.text_color);
text_layer_set_background_color(s_battery_layer_text, GColorClear);
layer_add_child(window_layer, text_layer_get_layer(s_battery_layer_text));

// Set it to 100 so we can calculate the max width.
text_layer_set_text(s_battery_layer_text, "100");

// Before we call the update handler, calculate the max width of the
// battery text + icon.
GSize battery_icon_size = text_layer_get_content_size(s_battery_layer_icon);
GSize battery_text_size = text_layer_get_content_size(s_battery_layer_text);
BATTERY_ROW_MAX_WIDTH = battery_icon_size.w + battery_text_size.w;

battery_update_handler(battery_state_service_peek());
}

Expand Down
4 changes: 4 additions & 0 deletions src/c/battery.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <pebble.h>

#define BATTERY_TEXT_RIGHT_INSET 2

extern int BATTERY_ROW_MAX_WIDTH;

void battery_init();
void battery_load(Window *window, int row_height);
void battery_unload();
Expand Down
25 changes: 24 additions & 1 deletion src/c/bluetooth.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "bluetooth.h"
#include "battery.h"
#include "health.h"
#include "log.h"
#include "pebble.h"
#include "settings.h"
Expand Down Expand Up @@ -42,7 +44,8 @@ void bluetooth_deinit(void) {
connection_service_unsubscribe();
}

void bluetooth_load(Window *window) {
static void bluetooth_load_middle_right(Window *window) {

Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);

Expand All @@ -55,6 +58,26 @@ void bluetooth_load(Window *window) {
s_bluetooth_layer_icon =
font_render_icon_xsmall(window_layer, ICON_BLUETOOTH_CONNECTED, PADDING_X, icon_y, true, false);
text_layer_set_text_color(s_bluetooth_layer_icon, THEME.text_color);
}

static void bluetooth_load_top(Window *window) {
Layer *window_layer = window_get_root_layer(window);

int right_offset = PADDING_X + BATTERY_TEXT_RIGHT_INSET + BATTERY_ROW_MAX_WIDTH + 2;
int top_offset = 8;

s_bluetooth_layer_icon =
font_render_icon_xsmall(window_layer, ICON_BLUETOOTH_CONNECTED, right_offset, top_offset, true, false);
text_layer_set_text_color(s_bluetooth_layer_icon, THEME.text_color);
}

// WARNING: Must be called after battery loads.
void bluetooth_load(Window *window) {
#ifdef HEART_RATE_SUPPORTED
bluetooth_load_top(window);
#else
bluetooth_load_middle_right(window);
#endif

// Refresh state in case the initial peek happened before the service was ready.
bluetooth_refresh_connected_state();
Expand Down
1 change: 1 addition & 0 deletions src/c/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const char *ICON_BATTERY_50 = "";
const char *ICON_BATTERY_75 = "";
const char *ICON_BATTERY_100 = "";
const char *ICON_STEPS = "";
const char *ICON_HEART_RATE = "";
const char *ICON_UTC = "";
const char *ICON_BLUETOOTH_CONNECTED = "󰂯";
const char *ICON_SUNRISE = "";
Expand Down
1 change: 1 addition & 0 deletions src/c/font.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ extern const char *ICON_BATTERY_50;
extern const char *ICON_BATTERY_75;
extern const char *ICON_BATTERY_100;
extern const char *ICON_STEPS;
extern const char *ICON_HEART_RATE;
extern const char *ICON_UTC;
extern const char *ICON_BLUETOOTH_CONNECTED;
extern const char *ICON_SUNRISE;
Expand Down
131 changes: 114 additions & 17 deletions src/c/health.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
#include "health.h"
#include "common.h"
#include "font.h"
#include "settings.h"
#include "time.h"

TextLayer *s_steps_layer_text;
TextLayer *s_steps_layer_icon;
static TextLayer *s_steps_layer_text;
static TextLayer *s_steps_layer_icon;

#if defined(HEART_RATE_SUPPORTED)
static TextLayer *s_heart_rate_layer_text;
static TextLayer *s_heart_rate_layer_icon;

#if defined(PBL_PLATFORM_EMERY)
static const int HEART_RATE_Y_OFFSET = 9;
#else
static const int HEART_RATE_Y_OFFSET = 0;
#endif
#endif

static void health_update_steps(void) {
if (!s_steps_layer_text) {
return;
}

static void health_update(void) {
static char steps_buffer[16];

HealthServiceAccessibilityMask access =
Expand All @@ -20,9 +37,43 @@ static void health_update(void) {
text_layer_set_text(s_steps_layer_text, steps_buffer);
}

static void health_update_heart_rate(void) {
#if defined(HEART_RATE_SUPPORTED)
if (!s_heart_rate_layer_text) {
return;
}

static char heart_rate_buffer[16];

HealthServiceAccessibilityMask access = health_service_metric_aggregate_averaged_accessible(
HealthMetricHeartRateBPM, time(NULL), time(NULL), HealthAggregationAvg, HealthServiceTimeScopeOnce);
if (access & HealthServiceAccessibilityMaskAvailable) {
HealthValue heart_rate = health_service_peek_current_value(HealthMetricHeartRateBPM);
if (heart_rate > 0) {
snprintf(heart_rate_buffer, sizeof(heart_rate_buffer), "%ld", (long)heart_rate);
} else {
snprintf(heart_rate_buffer, sizeof(heart_rate_buffer), "--");
}
} else {
snprintf(heart_rate_buffer, sizeof(heart_rate_buffer), "--");
}

text_layer_set_text(s_heart_rate_layer_text, heart_rate_buffer);
#endif
}

static void health_update(void) {
health_update_steps();
health_update_heart_rate();
}

static void health_handler(HealthEventType event, void *context) {
if (event == HealthEventMovementUpdate || event == HealthEventSignificantUpdate) {
health_update();
health_update_steps();
}

if (event == HealthEventHeartRateUpdate || event == HealthEventSignificantUpdate) {
health_update_heart_rate();
}
}

Expand All @@ -35,23 +86,69 @@ void health_load(Window *window, int row_height) {
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);

int steps_y = row_height + 2;
s_steps_layer_icon = font_render_icon_small(window_layer, ICON_STEPS, PADDING_X, steps_y, true, false);
text_layer_set_text_color(s_steps_layer_icon, THEME.text_color);
GRect steps_icon_bounds = layer_get_bounds(text_layer_get_layer(s_steps_layer_icon));
// --- Steps ---

if (app_settings.show_steps) {
int steps_y = row_height + 2;
s_steps_layer_icon = font_render_icon_small(window_layer, ICON_STEPS, PADDING_X, steps_y, true, false);
text_layer_set_text_color(s_steps_layer_icon, THEME.text_color);
GRect steps_icon_bounds = layer_get_bounds(text_layer_get_layer(s_steps_layer_icon));

s_steps_layer_text =
text_layer_create(GRect(0, steps_y, bounds.size.w - steps_icon_bounds.size.w - PADDING_X - 2, row_height));
text_layer_set_text_alignment(s_steps_layer_text, GTextAlignmentRight);
text_layer_set_font(s_steps_layer_text, s_font_primary_small);
text_layer_set_text_color(s_steps_layer_text, THEME.text_color);
text_layer_set_background_color(s_steps_layer_text, GColorClear);
layer_add_child(window_layer, text_layer_get_layer(s_steps_layer_text));
}

// --- Heart Rate ---

#if defined(HEART_RATE_SUPPORTED)
#if defined(PBL_PLATFORM_EMERY)
int heart_rate_y = (bounds.size.h / 2) - (TIME_CONTAINER_HEIGHT / 2) - 20 - HEART_RATE_Y_OFFSET;
#else
int heart_rate_y = (bounds.size.h / 2) - (TIME_CONTAINER_HEIGHT / 2) - 14 - HEART_RATE_Y_OFFSET;
#endif
s_heart_rate_layer_icon =
font_render_icon_small(window_layer, ICON_HEART_RATE, PADDING_X, heart_rate_y, true, false);
text_layer_set_text_color(s_heart_rate_layer_icon, THEME.text_color);
GRect heart_rate_icon_bounds = layer_get_bounds(text_layer_get_layer(s_heart_rate_layer_icon));

s_steps_layer_text = text_layer_create(GRect(steps_icon_bounds.size.w - steps_icon_bounds.size.w, steps_y,
bounds.size.w - steps_icon_bounds.size.w - PADDING_X - 2, row_height));
text_layer_set_text_alignment(s_steps_layer_text, GTextAlignmentRight);
text_layer_set_font(s_steps_layer_text, s_font_primary_small);
text_layer_set_text_color(s_steps_layer_text, THEME.text_color);
text_layer_set_background_color(s_steps_layer_text, GColorClear);
layer_add_child(window_layer, text_layer_get_layer(s_steps_layer_text));
s_heart_rate_layer_text = text_layer_create(
GRect(0, heart_rate_y, bounds.size.w - heart_rate_icon_bounds.size.w - PADDING_X - 2, row_height));
text_layer_set_text_alignment(s_heart_rate_layer_text, GTextAlignmentRight);
text_layer_set_font(s_heart_rate_layer_text, s_font_primary_small);
text_layer_set_text_color(s_heart_rate_layer_text, THEME.text_color);
text_layer_set_background_color(s_heart_rate_layer_text, GColorClear);
layer_add_child(window_layer, text_layer_get_layer(s_heart_rate_layer_text));
#endif

health_update();
}

void health_unload() {
text_layer_destroy(s_steps_layer_icon);
text_layer_destroy(s_steps_layer_text);
if (s_steps_layer_icon) {
text_layer_destroy(s_steps_layer_icon);
s_steps_layer_icon = NULL;
}

if (s_steps_layer_text) {
text_layer_destroy(s_steps_layer_text);
s_steps_layer_text = NULL;
}
#if defined(HEART_RATE_SUPPORTED)
if (s_heart_rate_layer_icon) {
text_layer_destroy(s_heart_rate_layer_icon);
s_heart_rate_layer_icon = NULL;
}

if (s_heart_rate_layer_text) {
text_layer_destroy(s_heart_rate_layer_text);
s_heart_rate_layer_text = NULL;
}
#endif
}

void health_deinit() {
Expand Down
4 changes: 4 additions & 0 deletions src/c/health.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

#include <pebble.h>

#if defined(PBL_PLATFORM_DIORITE) || defined(PBL_PLATFORM_EMERY)
#define HEART_RATE_SUPPORTED
#endif

void health_init();
void health_load(Window *window, int row_height);
void health_unload();
Expand Down
18 changes: 14 additions & 4 deletions src/c/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,16 @@

static int s_last_vibrate_hour = -1;

#if defined(PBL_HEALTH)
static bool health_should_run(void) {
#if defined(HEART_RATE_SUPPORTED)
return true;
#else
return app_settings.show_steps;
#endif
}
#endif

static void tick_handler(struct tm *tick_time, TimeUnits units_changed) {
LOG_DEBUG("tick handler...");
time_update();
Expand All @@ -36,7 +46,7 @@ void load_top_right(Window *window) {
#endif
battery_load(window, row_height);
#if defined(PBL_HEALTH)
if (app_settings.show_steps) {
if (health_should_run()) {
health_load(window, row_height);
}
#endif
Expand All @@ -59,7 +69,7 @@ static void window_unload(Window *window) {
bluetooth_unload();
battery_unload();
#if defined(PBL_HEALTH)
if (app_settings.show_steps) {
if (health_should_run()) {
health_unload();
}
#endif
Expand All @@ -80,7 +90,7 @@ static void init(void) {
battery_init();
bluetooth_init();
#if defined(PBL_HEALTH)
if (app_settings.show_steps) {
if (health_should_run()) {
health_init();
}
#endif
Expand All @@ -92,7 +102,7 @@ static void deinit(void) {
bluetooth_deinit();
battery_deinit();
#if defined(PBL_HEALTH)
if (app_settings.show_steps) {
if (health_should_run()) {
health_deinit();
}
#endif
Expand Down