From 04a7c41a1a75d7f45a0934b8dcd7de93a8dba220 Mon Sep 17 00:00:00 2001 From: alanacheff Date: Sun, 6 Oct 2024 21:21:14 +0000 Subject: [PATCH] Upload files to "src/c" --- src/c/basic.c | 625 +++++++++++++++++++++++++++++++++++++++++++ src/c/basic.h | 50 ++++ src/c/constants.c | 40 +++ src/c/constants.h | 58 ++++ src/c/digital_time.c | 66 +++++ 5 files changed, 839 insertions(+) create mode 100644 src/c/basic.c create mode 100644 src/c/basic.h create mode 100644 src/c/constants.c create mode 100644 src/c/constants.h create mode 100644 src/c/digital_time.c diff --git a/src/c/basic.c b/src/c/basic.c new file mode 100644 index 0000000..c3a4333 --- /dev/null +++ b/src/c/basic.c @@ -0,0 +1,625 @@ +#include +#include "basic.h" +#include "constants.h" +#include "options.h" +#include "weather.h" +#include "messaging.h" +#include "digital_time.h" +#include + +#define DEBUG_DATE "Sat 02 Jul" +#define DEBUG_DAY "Sunday" +#define SCREEN_SHOT_HR 20 +#define SCREEN_SHOT_MIN 38 + +Options s_options; + +//stores weather retry counts (incremented in second tick handler). +//Stop retry count at DEFAULT_MAX_WEATHER_RETRY_COUNT +int g_weather_retry_count = 0; + +static TextLayer *s_hr_layer, *s_min_layer; + +static GFont s_time_font; +static GFont s_time_thin_font; +static GFont s_time_bold_font; +static BitmapLayer *s_background_layer; +static GBitmap *s_background_bitmap; + +static BluetoothLayer *s_bluetooth_layer; +//static TextLayer *s_bluetooth_battery_text_layer; +//static BatteryBarLayer *s_battery_layer; + +static GFont s_date_font; +TextLayer *s_date_layer; +TextLayer *s_steps_layer; + +AppTimer *temp_display_timer; + +void set_hr_layer_color(GColor textColor) { + text_layer_set_text_color(s_hr_layer, textColor); +} + +void set_min_layer_color(GColor textColor) { + text_layer_set_text_color(s_min_layer, textColor); +} + +void set_wsd_layers_color(GColor textColor) { + text_layer_set_text_color(weather_layer1, textColor); + text_layer_set_text_color(weather_layer2, textColor); + text_layer_set_text_color(weather_layer_center, textColor); + text_layer_set_text_color(s_steps_layer, textColor); + text_layer_set_text_color(s_date_layer, textColor); +} + +static void init_window_background_color(){ + + window_set_background_color(s_main_window, GColorBlack); + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorBlack); + + #ifdef PBL_COLOR // If on basalt + window_set_background_color(s_main_window, GColorFromHEX(s_options.background_color)); + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorFromHEX(s_options.background_color)); + battery_bar_set_colors(GColorGreen, GColorYellow, GColorRed, GColorWhite); + #else + if (s_options.background_color == 0xFFFFFF) { + window_set_background_color(s_main_window, GColorWhite);//white + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorWhite);//white + battery_bar_set_colors(GColorBlack, GColorBlack, GColorBlack, GColorBlack); + } + else if (s_options.background_color == 0x000000) {//black + window_set_background_color(s_main_window, GColorBlack); + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorBlack); + battery_bar_set_colors(GColorWhite, GColorWhite, GColorWhite, GColorWhite); + } + else { //didn't select white or black, default to white + window_set_background_color(s_main_window, GColorBlack); + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorBlack); + battery_bar_set_colors(GColorWhite, GColorWhite, GColorWhite, GColorWhite); + } + #endif + + layer_mark_dirty(text_layer_get_layer(s_bluetooth_battery_text_layer)); +} + +void init_static_row(TextLayer *label, GFont font) { + text_layer_set_background_color(label, GColorClear); + text_layer_set_text_color(label, GColorWhite); + text_layer_set_text_color(label, GColorFromHEX(s_options.wsd_color)); + + if (font) { + text_layer_set_font(label, font); + } +} + +static void bt_handler(bool isConnected) { + + int current_bluetooth_state = 0; //default bluetooth disconnected + if (isConnected) { + current_bluetooth_state = 1; //bluetooth connected + } + + //if bluetooth was previously disconnected and is now connected + if (s_options.bluetooth_state == 0 && + current_bluetooth_state == 1) { + + //clear weather conditions and reset weather retry count to force weather update + memset(s_options.conditions, 0,sizeof(s_options.conditions)); + s_options.condition_code = DEFAULT_CONDITION_CODE; + g_weather_retry_count = 0; + } + + //store bluetooth state + s_options.bluetooth_state = current_bluetooth_state; +} + +void on_animation_stopped(Animation *anim, bool finished, void *context) { + //Free the memory used by the Animation + property_animation_destroy((PropertyAnimation*) anim); +} + +void animate_grect_layer(Layer *layer, GRect *start, GRect *finish, int duration, int delay) { + //Declare animation + PropertyAnimation *anim = property_animation_create_layer_frame(layer, start, finish); + + //Set characteristics + animation_set_duration((Animation*) anim, duration); + animation_set_delay((Animation*) anim, delay); + + //Set stopped handler to free memory + AnimationHandlers handlers = { + //The reference to the stopped handler is the only one in the array + .stopped = (AnimationStoppedHandler) on_animation_stopped + }; + animation_set_handlers((Animation*) anim, handlers, NULL); + + //Start animation! + animation_schedule((Animation*) anim); +} + +static void animate_text_layers_round() { + + // Steps moves in from bottom + GRect sins = GRect(20, 180, 60, 24); + GRect sinf = GRect(20, 122, 60, 24); + animate_grect_layer(text_layer_get_layer(s_steps_layer), &sins, &sinf, 1000, 0); + + GRect souts = GRect(20, 122, 60, 24); + GRect soutf = GRect(20, 180, 60, 24); + animate_grect_layer(text_layer_get_layer(s_steps_layer), &souts, &soutf, 1000, 5000); + + // Date moves in from bottom + GRect dins = GRect(100, 180, 60, 24); + GRect dinf = GRect(100, 122, 60, 24); + animate_grect_layer(text_layer_get_layer(s_date_layer), &dins, &dinf, 1000, 0); + + GRect douts = GRect(100, 122, 60, 24); + GRect doutf = GRect(100, 180, 60, 24); + animate_grect_layer(text_layer_get_layer(s_date_layer), &douts, &doutf, 1000, 5000); + + // Bluetooth & battery layers revealed at top + GRect bbins = GRect(0, 5, 200, 47); + GRect bbinf = GRect(0, -47, 200, 47); + animate_grect_layer(text_layer_get_layer(s_bluetooth_battery_text_layer), &bbins, &bbinf, 1000, 0); + + GRect bbouts = GRect(0, -47, 200, 47); + GRect bboutf = GRect(0, 5, 200, 47); + animate_grect_layer(text_layer_get_layer(s_bluetooth_battery_text_layer), &bbouts, &bboutf, 1000, 5000); +} + +static void animate_text_layers() { + + // Steps moves in from bottom + GRect sins = GRect(2, 180, 80, 24); + GRect sinf = GRect(2, 151, 80, 24); + animate_grect_layer(text_layer_get_layer(s_steps_layer), &sins, &sinf, 1000, 0); + + GRect souts = GRect(2, 151, 80, 24); + GRect soutf = GRect(2, 180, 80, 24); + animate_grect_layer(text_layer_get_layer(s_steps_layer), &souts, &soutf, 1000, 5000); + + // Date moves in from bottom + GRect dins = GRect(82, 180, 60, 24); + GRect dinf = GRect(82, 151, 60, 24); + animate_grect_layer(text_layer_get_layer(s_date_layer), &dins, &dinf, 1000, 0); + + GRect douts = GRect(82, 151, 60, 24); + GRect doutf = GRect(82, 180, 60, 24); + animate_grect_layer(text_layer_get_layer(s_date_layer), &douts, &doutf, 1000, 5000); + + // Bluetooth & battery layers revealed at top + GRect bbins = GRect(0, 0, 200, 35); + GRect bbinf = GRect(0, -35, 200, 35); + animate_grect_layer(text_layer_get_layer(s_bluetooth_battery_text_layer), &bbins, &bbinf, 1000, 0); + + GRect bbouts = GRect(0, -35, 200, 35); + GRect bboutf = GRect(0, 0, 200, 35); + animate_grect_layer(text_layer_get_layer(s_bluetooth_battery_text_layer), &bbouts, &bboutf, 1000, 5000); +} + +static void update_time(struct tm *tick_time, TimeUnits units_changed) { + static char date_buffer[16]; + const char *current_date_layer; + + // Create a long-lived buffer + static char hr_buffer[] = "00"; + static char min_buffer[] = "00"; + + // Write the current hours and minutes into the buffer + if(clock_is_24h_style() == true) { + //Use 2h hour format + strftime(hr_buffer, sizeof("00"), "%H", tick_time); + } else { + //Use 12 hour format + strftime(hr_buffer, sizeof("00"), "%I", tick_time); + } + strftime(min_buffer, sizeof("00"), "%M", tick_time); + + // Display this time on the TextLayer + text_layer_set_text(s_hr_layer, hr_buffer); + + // Display the seconds on the TextLayer + text_layer_set_text(s_min_layer, min_buffer); + + //add date layer + current_date_layer = text_layer_get_text(s_date_layer); + + if (current_date_layer != date_buffer) { + //get current date + strftime(date_buffer, sizeof(date_buffer), "%a %d %b", tick_time); + #if DEBUG + strftime(date_buffer, sizeof(date_buffer), DEBUG_DATE, tick_time); //for screen shots + #endif + text_layer_set_text(s_date_layer, date_buffer); + } +} + +//every five seconds +static void handle_5second_tick(struct tm *tick_time, TimeUnits units_changed) { + + //if conditions blank (no current weather info) + if(strlen(s_options.conditions) == 0 && + g_weather_retry_count < DEFAULT_MAX_WEATHER_RETRY_COUNT) { + + //add one to weather retry count - stop trying this app session at DEFAULT_MAX_WEATHER_RETRY_COUNT + ++g_weather_retry_count; + + //reset time since last forecast timer + s_options.min_since_last_forecast = 0; + + //get updated weather + send(KEY_GET_WEATHER, 1, KEY_WEATHER_USE_GPS, s_options.weather_use_GPS, KEY_WEATHER_LOCATION, s_options.weather_location); + + //update weather layer + update_weather_layer(); + } + //APP_LOG(APP_LOG_LEVEL_DEBUG, "heap_bytes_free:heap_bytes_used %zu: %zu", heap_bytes_free(), heap_bytes_used()); +} + +static void update_steps() { + HealthMetric metric = HealthMetricStepCount; + time_t start = time_start_of_today(); + time_t end = time(NULL); + static char steps_buffer[32]; + + // Check the metric has data available for today + HealthServiceAccessibilityMask mask = health_service_metric_accessible(metric, + start, end); + + if(mask & HealthServiceAccessibilityMaskAvailable) { + // Data is available! + snprintf(steps_buffer, sizeof(steps_buffer), "s: %d", (int)health_service_sum_today(metric)); + + #if DEBUG + snprintf(steps_buffer, sizeof(steps_buffer), "s: 1%d", (int)health_service_sum_today(metric)); + #endif + + APP_LOG(APP_LOG_LEVEL_INFO, "Steps today: %d", + (int)health_service_sum_today(metric)); + // Display to user in correct units + text_layer_set_text(s_steps_layer, steps_buffer); + } else { + // No data recorded yet today + APP_LOG(APP_LOG_LEVEL_ERROR, "Data unavailable!"); + } +} + +static void timer_callback(void *context) { + APP_LOG(APP_LOG_LEVEL_INFO, "Timer elapsed!"); + + if (s_options.shake_for_lohi == 1) { + //Display Lo Hi temp info; + display_lohi_weather_info(); + } +} + +static void tap_handler(AccelAxisType axis, int32_t direction) { + update_steps(); + #if defined(PBL_ROUND) + animate_text_layers_round(); + #else + animate_text_layers(); + #endif + + // Schedule the timer + app_timer_register(2500, timer_callback, NULL); +} + +static void main_window_load(Window *window) { + + //set-retrieve watchface options + init_options(); + + //add weather and date layers + GRect layer_frame = layer_get_frame(window_get_root_layer(s_main_window)); + const int16_t width = layer_frame.size.w; + const int16_t height = layer_frame.size.h; + + //Create GFont + + s_time_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_ROBOTO_REGULAR_48)); + s_time_thin_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_ROBOTO_LIGHT_48)); + s_time_bold_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_ROBOTO_BOLD_48)); + + // Create time TextLayer + #if defined(PBL_ROUND) + s_hr_layer = text_layer_create(GRect(35, 57, 57, 48)); + #else + s_hr_layer = text_layer_create(GRect(15, 50, 57, 48)); + #endif + text_layer_set_background_color(s_hr_layer, GColorClear); + text_layer_set_text_color(s_hr_layer, GColorFromHEX(s_options.hr_color)); + text_layer_set_text_alignment(s_hr_layer, GTextAlignmentRight); + text_layer_set_text(s_hr_layer, "00"); + + if (s_options.hourFont == 2) { + text_layer_set_font(s_hr_layer, s_time_bold_font); + } + else if(s_options.hourFont == 0) { + text_layer_set_font(s_hr_layer, s_time_thin_font); + } + else { + text_layer_set_font(s_hr_layer, s_time_font); + } + + // Add it as a child layer to the Window's root layer + layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_hr_layer)); + + #if defined(PBL_ROUND) + s_min_layer = text_layer_create(GRect(95, 57, 57, 48)); + #else + s_min_layer = text_layer_create(GRect(75, 50, 57, 48)); + #endif + text_layer_set_background_color(s_min_layer, GColorClear); + text_layer_set_text_alignment(s_min_layer, GTextAlignmentLeft); + text_layer_set_text_color(s_min_layer, GColorFromHEX(s_options.min_color)); + + if (s_options.minutesFont == 2) { + text_layer_set_font(s_min_layer, s_time_bold_font); + } + else if(s_options.minutesFont == 0) { + text_layer_set_font(s_min_layer, s_time_thin_font); + } + else { + text_layer_set_font(s_min_layer, s_time_font); + } + + // Add it as a child layer to the Window's root layer + layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_min_layer)); + + //add Bluetooth layer + s_bluetooth_layer = bluetooth_layer_create(); + #if defined(PBL_ROUND) + bluetooth_set_position(GPoint(42, 31)); + #else + bluetooth_set_position(GPoint(2, 2)); + #endif + layer_add_child(window_get_root_layer(window), s_bluetooth_layer); + + //add battery layer + s_battery_layer = battery_bar_layer_create(); + battery_bar_set_percent_hidden(true); + battery_bar_set_icon_hidden(false); + #ifdef PBL_COLOR // If on basalt + battery_bar_set_colors(GColorGreen, GColorYellow, GColorRed, GColorWhite); + #endif + #if defined(PBL_ROUND) + battery_bar_set_position(GPoint(102, 32)); + #else + battery_bar_set_position(GPoint(102, 3)); + #endif + layer_add_child(window_get_root_layer(window), s_battery_layer); + + //add weather and digital layers + add_weather_layers(window_get_root_layer(s_main_window), width, height); + add_digital_time_layer(window_get_root_layer(s_main_window), width, height); + + #if defined(PBL_ROUND) + s_bluetooth_battery_text_layer = text_layer_create(GRect(0, 5, 200, 45)); + #else + s_bluetooth_battery_text_layer = text_layer_create(GRect(0, 0, 200, 35)); + #endif + + #if defined(PBL_ROUND) + s_bluetooth_battery_text_layer = text_layer_create(GRect(0, 5, 200, 45)); + #else + s_bluetooth_battery_text_layer = text_layer_create(GRect(0, 0, 200, 35)); + #endif + + init_window_background_color(); + layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_bluetooth_battery_text_layer)); + + /* + //text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorClear); + #ifdef PBL_COLOR // If on basalt + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorFromHEX(s_options.background_color)); + #else + if (s_options.background_color == 0xFFFFFF) { + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorWhite);//white + } + else if (s_options.background_color == 0x000000) {//black + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorBlack); + } + else { //didn't select white or black, default to white + text_layer_set_background_color(s_bluetooth_battery_text_layer, GColorBlack); + } + #endif + */ + + //date layer + #if defined(PBL_ROUND) + s_date_layer = text_layer_create(GRect(100, 180, 60, 24)); + #else + s_date_layer = text_layer_create(GRect(82, 180, 60, 24)); + #endif + text_layer_set_background_color(s_date_layer, GColorClear); + text_layer_set_text_color(s_date_layer, GColorFromHEX(s_options.wsd_color)); + text_layer_set_text_alignment(s_date_layer, GTextAlignmentRight); + s_date_font = fonts_get_system_font(FONT_KEY_GOTHIC_14); + //s_date_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_DIGITAL_SEVEN_14)); + + //Apply to TextLayer + text_layer_set_font(s_date_layer, s_date_font); + layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_date_layer)); + + //steps layer + #if defined(PBL_ROUND) + s_steps_layer = text_layer_create(GRect(20, 180, 60, 24)); + #else + s_steps_layer = text_layer_create(GRect(2, 180, 80, 24)); + #endif + text_layer_set_background_color(s_steps_layer, GColorClear); + text_layer_set_text_color(s_steps_layer, GColorFromHEX(s_options.wsd_color)); + text_layer_set_text_alignment(s_steps_layer, GTextAlignmentLeft); + s_date_font = fonts_get_system_font(FONT_KEY_GOTHIC_14); + //s_steps_font = fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_DIGITAL_SEVEN_14)); + + //Apply to TextLayer + text_layer_set_font(s_steps_layer, s_date_font); + layer_add_child(window_get_root_layer(window), text_layer_get_layer(s_steps_layer)); +} + +static void main_window_unload(Window *window) { + + //Destroy Bluetooth layer + bluetooth_layer_destroy(s_bluetooth_layer); + + //Destroy battery layer + battery_bar_layer_destroy(s_battery_layer); + + //Destroy GBitmap + gbitmap_destroy(s_background_bitmap); + + //Destroy BitmapLayer + bitmap_layer_destroy(s_background_layer); + + // Destroy TextLayers + text_layer_destroy(s_hr_layer); + text_layer_destroy(s_min_layer); + text_layer_destroy(s_bluetooth_battery_text_layer); + + text_layer_destroy(weather_layer1); + text_layer_destroy(weather_layer_center); + text_layer_destroy(weather_layer2); + text_layer_destroy(digital_time_layer); + +} + +static void health_handler(HealthEventType event, void *context) { + // Which type of event occurred? + switch(event) { + case HealthEventSignificantUpdate: + //update_steps(); + APP_LOG(APP_LOG_LEVEL_INFO, + "New HealthService HealthEventSignificantUpdate event"); + break; + case HealthEventMovementUpdate: + //update_steps(); + APP_LOG(APP_LOG_LEVEL_INFO, + "New HealthService HealthEventMovementUpdate event"); + break; + + case HealthEventMetricAlert: + APP_LOG(APP_LOG_LEVEL_INFO, + "New HealthService HealthEventMetricAlert event"); + break; + + case HealthEventHeartRateUpdate: + APP_LOG(APP_LOG_LEVEL_INFO, + "New HealthService HealthEventHeartRateUpdate event"); + break; + + case HealthEventSleepUpdate: + APP_LOG(APP_LOG_LEVEL_INFO, + "New HealthService HealthEventSleepUpdate event"); + break; + } +} + +static void handle_minute_tick(struct tm *tick_time, TimeUnits units_changed) { + update_time(tick_time, units_changed); + + //get minutes since last weather update + time_t t = time(NULL); + int min_since_last_update = (difftime(t, s_options.last_update) / 60) + 1; + + APP_LOG(APP_LOG_LEVEL_DEBUG, " (Last update %s) min_since_last_update:weather_frequency - %d:%d", s_options.last_weather_update24hr, min_since_last_update, s_options.weather_frequency); + //APP_LOG(APP_LOG_LEVEL_DEBUG, "handle_minute_tick strlen(s_options.conditions): %zu", strlen(s_options.conditions)); + //if min_since_last_forecast greater than or equal to weatherUpdateFrequency + if(min_since_last_update >= s_options.weather_frequency || + strlen(s_options.conditions) == 0) { + + s_options.min_since_last_forecast = 0; + + //get updated weather + send(KEY_GET_WEATHER, 1, KEY_WEATHER_USE_GPS, s_options.weather_use_GPS, KEY_WEATHER_LOCATION, s_options.weather_location); + + //update weather layer + update_weather_layer(); + } +} + +void handle_tick(struct tm *tick_time, TimeUnits units_changed) { + + if (units_changed & SECOND_UNIT) { + if (tick_time->tm_sec % 5 == 0) { + handle_5second_tick(tick_time, units_changed); + } + } + if (units_changed & MINUTE_UNIT) { + handle_minute_tick(tick_time, units_changed); + } +} + +static void init() { + // Create main Window element and assign to pointer + s_main_window = window_create(); + + // Set handlers to manage the elements inside the Window + window_set_window_handlers(s_main_window, (WindowHandlers) { + .load = main_window_load, + .unload = main_window_unload + }); + + // Show the Window on the watch, with animated=true + window_stack_push(s_main_window, true); + + app_message_register_inbox_received(inbox_received_callback); + app_message_register_inbox_dropped(message_dropped); + app_message_register_outbox_sent(message_out_success); + app_message_register_outbox_failed(message_out_failed); + + #if defined(PBL_BW) + app_message_open(175, 250); + #else + app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum()); + #endif + + update_digital_time_layer(); //update digital_time_layer + update_weather_layer(); //update weather layer + + time_t t = time(NULL); + struct tm *time_now = localtime(&t); + #if DEBUG + time_now->tm_hour = SCREEN_SHOT_HR; //for screen shots + time_now->tm_min = SCREEN_SHOT_MIN; + #endif + handle_tick(time_now, MINUTE_UNIT); + + // Subscribe to Bluetooth updates + connection_service_subscribe((ConnectionHandlers) { + .pebble_app_connection_handler = bt_handler + }); + + // Check current bluetooth connection state + bt_handler(connection_service_peek_pebble_app_connection()); + + #if defined(PBL_HEALTH) + // Attempt to subscribe + if(!health_service_events_subscribe(health_handler, NULL)) { + APP_LOG(APP_LOG_LEVEL_ERROR, "Health not available!"); + } + #else + APP_LOG(APP_LOG_LEVEL_ERROR, "Health not available!"); + #endif + + accel_tap_service_subscribe(tap_handler); + + // Register with TickTimerService + tick_timer_service_subscribe(MINUTE_UNIT | SECOND_UNIT, handle_tick); +} + +static void deinit() { + //save watchface options + persist_write_data(KEY_OPTIONS, &s_options, sizeof(s_options)); + + + // Destroy Window + window_destroy(s_main_window); +} + +int main(void) { + init(); + app_event_loop(); + deinit(); +} \ No newline at end of file diff --git a/src/c/basic.h b/src/c/basic.h new file mode 100644 index 0000000..b1d1d61 --- /dev/null +++ b/src/c/basic.h @@ -0,0 +1,50 @@ +#include +#include + +TextLayer *weather_layer1, *weather_layer2, *weather_layer_center; +TextLayer *s_bluetooth_battery_text_layer; +TextLayer *date_layer1, *date_layer2, *date_layer_center; +TextLayer *digital_time_layer; +TextLayer *battery_layer; +AppTimer *lohi_display_timer; +BatteryBarLayer *s_battery_layer; + +void init_static_row(TextLayer *label, GFont font); //creates/configures static (weather/date) display lines +void set_text_layers_color(GColor textColor); //sets color for text (weather, date, digital time) elements + +void set_hr_layer_color(GColor textColor); +void set_min_layer_color(GColor textColor); +void set_wsd_layers_color(GColor textColor); + +typedef struct { + int shake_for_lohi; + int tempF; + int tempFLo; + int tempFHi; + int tempC; + int tempCLo; + int tempCHi; + int display_weather; + int weather_use_GPS; + char weather_location[64]; + int use_celsius; + int weather_frequency; + int min_since_last_forecast; + int condition_code; + int display_digital_time; + int pebble_js_ready; + int hr_color; + int min_color; + int wsd_color; + int background_color; + int hourFont; + int minutesFont; + bool bluetooth_state; + time_t last_update; + char conditions[32]; + char last_weather_update12hr[16]; + char last_weather_update24hr[16]; +} Options; + +Window *s_main_window; +Layer *s_canvas_layer; \ No newline at end of file diff --git a/src/c/constants.c b/src/c/constants.c new file mode 100644 index 0000000..6d315bc --- /dev/null +++ b/src/c/constants.c @@ -0,0 +1,40 @@ +#include +#include "constants.h" + +const int DEFAULT_SHAKE_FOR_LOHI = 1; //True - shake to show Lo Hi Temps +const int DEFAULT_DISPLAY_LOHI_TIMER = 5000; //length time (milliseconds) to display Lo Hi Temps +const int DEFAULT_MIN_SINCE_WEATHER_UPDATE = 0; //weather just updated +const char DEFAULT_LAST_WEATHER_UPDATE[16] = "--:--"; //default last update "time" display +const char DEFAULT_ERROR_WEATHER_UPDATE[16] = "---"; //default text display upon weather update error +const int DEFAULT_CONDITION_CODE = -99; //Invalid condition code to force weather update +const int DEFAULT_DISPLAY_WEATHER = 1; //true +const int DEFAULT_WEATHER_FREQUENCY = 30; //minutes +const int DEFAULT_WEATHER_USE_GPS = 1; //true +const int DEFAULT_USE_CELSIUS = 0; //false +const int DEFAULT_DISPLAY_DIGITAL_TIME = 0; //false +const int DEFAULT_HR_COLOR = 0xFFFFFF; //white +const int DEFAULT_MIN_COLOR = 0xFF5500; //orange +const int DEFAULT_WSD_COLOR = 0xFFFFFF; //white +const int DEFAULT_BACKGROUND_COLOR = 0x000000; //black +const int DEFAULT_HOUR_FONT = 1; //regular +const int DEFAULT_MINUTES_FONT = 1; //regular + +const int DEFAULT_MAX_WEATHER_RETRY_COUNT = 5; //max (seconds) weather retry counts +const uint MAX_CHALK_SINGLE_LINE_CONDITIONS_LEN = 6; //max length for weather conditions to display on single line. longer split to two lines + +const int DEFAULT_CHALK_TIME_X_OFFSET = 20; //X-axis adjustment for time display on Chalk (Pebble Time Round) +const int DEFAULT_CHALK_TIME_Y_OFFSET = 10; //Y-axis adjustment for time display on Chalk (Pebble Time Round) +const int DEFAULT_MARKERS_X_OFFSET = 7; //X-axix adjustment for when displaying hour/minute markers + +const int DEFAULT_CHALK_WEATHER1_Y_OFFSET = 5; //Y-axis adjustment for weather display on Chalk (Pebble Time Round) +const int DEFAULT_CHALK_WEATHER2_Y_OFFSET = 5; //Y-axis adjustment for weather display on Chalk (Pebble Time Round) +const int DEFAULT_CHALK_WEATHER_CENTER_Y_OFFSET = 10; //Y-axis adjustment for weather display on Chalk (Pebble Time Round) + +const int DEFAULT_DATE_Y_OFFSET_READABILITY = 4; //Y-axis adjustment for increased readability font options + +const int DEFAULT_DIGITAL_TIME_Y_OFFSET_READABILITY = 5; //Y-axis adjustment for increased readability font options +const int DEFAULT_MARKERS_Y_OFFSET = 12; //Y-axix adjustment for when displaying hour/minute markers +const int DEFAULT_CHALK_DIGITAL_TIME_Y_OFFSET = 12; //Y-axis adjustment for digital time display on Chalk (Pebble Time Round) + +const int DEFAULT_CHALK_BATTERY_X_OFFSET = 5; //X-axis adjustment for battery display on Chalk (Pebble Time Round) +const int DEFAULT_BATTERY_OFFSET_READABILITY = 5; //Y-axis adjustment for increased readability font options diff --git a/src/c/constants.h b/src/c/constants.h new file mode 100644 index 0000000..1129428 --- /dev/null +++ b/src/c/constants.h @@ -0,0 +1,58 @@ +#pragma once + + #define DEBUG 0 + + #define KEY_TEMPERATURE_IN_C 1 + #define KEY_CONDITIONS 2 + #define KEY_WEATHER_FREQUENCY 3 + #define KEY_USE_CELSIUS 4 + #define KEY_DISPLAY_WEATHER 5 + #define KEY_MIN_SINCE_WEATHER_UPDATE 6 + #define KEY_GET_WEATHER 7 + #define KEY_TEMPERATURE 8 + #define KEY_TEMPERATURE_LO 9 + #define KEY_TEMPERATURE_HI 10 + #define KEY_TEMPERATURE_IN_C_LO 11 + #define KEY_TEMPERATURE_IN_C_HI 12 + #define KEY_CONDITION_CODE 13 + #define KEY_SHAKE_FOR_LOHI 14 + #define KEY_DISPLAY_DIGITAL_TIME 15 + #define KEY_WEATHER_USE_GPS 16 + #define KEY_WEATHER_LOCATION 17 + #define KEY_JS_READY 18 + #define KEY_HR_COLOR 19 + #define KEY_MIN_COLOR 20 + #define KEY_WSD_COLOR 21 + #define KEY_BACKGROUND_COLOR 22 + #define KEY_HOUR_FONT 23 + #define KEY_MINUTES_FONT 24 + #define KEY_OPTIONS 99 + + extern const int DEFAULT_SHAKE_FOR_LOHI; + extern const int DEFAULT_DISPLAY_LOHI_TIMER; + extern const int DEFAULT_MIN_SINCE_WEATHER_UPDATE; + extern const char DEFAULT_LAST_WEATHER_UPDATE[16]; + extern const char DEFAULT_ERROR_WEATHER_UPDATE[16]; + extern const int DEFAULT_CONDITION_CODE; + extern const int DEFAULT_DISPLAY_WEATHER; + extern const int DEFAULT_WEATHER_FREQUENCY; + extern const int DEFAULT_WEATHER_USE_GPS; + extern const int DEFAULT_USE_CELSIUS; + extern const int DEFAULT_DISPLAY_DIGITAL_TIME; + extern const int DEFAULT_HR_COLOR; + extern const int DEFAULT_MIN_COLOR; + extern const int DEFAULT_WSD_COLOR; + extern const int DEFAULT_BACKGROUND_COLOR; + extern const int DEFAULT_HOUR_FONT; + extern const int DEFAULT_MINUTES_FONT; + extern const int DEFAULT_MAX_WEATHER_RETRY_COUNT; + extern const uint MAX_CHALK_SINGLE_LINE_CONDITIONS_LEN; + extern const int DEFAULT_CHALK_TIME_X_OFFSET; + extern const int DEFAULT_CHALK_WEATHER1_Y_OFFSET; + extern const int DEFAULT_CHALK_WEATHER2_Y_OFFSET; + extern const int DEFAULT_CHALK_WEATHER_CENTER_Y_OFFSET; + extern const int DEFAULT_CHALK_TIME_Y_OFFSET; + extern const int DEFAULT_CHALK_DIGITAL_TIME_Y_OFFSET; + extern const int DEFAULT_MARKERS_Y_OFFSET; + extern const int DEFAULT_MARKERS_X_OFFSET; + extern const int DEFAULT_CHALK_BATTERY_X_OFFSET; diff --git a/src/c/digital_time.c b/src/c/digital_time.c new file mode 100644 index 0000000..cfb11d0 --- /dev/null +++ b/src/c/digital_time.c @@ -0,0 +1,66 @@ +#include +#include "digital_time.h" +#include "constants.h" +#include "basic.h" + +#define SCREEN_SHOT_HR 10 +#define SCREEN_SHOT_MIN 22 + +extern Options s_options; + +//checks/updates date display line +void update_digital_time_layer() { + static char digital_time_buffer[16]; + const char *current_digital_time_layer; + + //if displaying digital time + if (s_options.display_digital_time) { + + //get current date_layer text + current_digital_time_layer = text_layer_get_text(digital_time_layer); + + //get digital time + time_t temp = time(NULL); + struct tm *tick_time = localtime(&temp); + #if DEBUG + tick_time->tm_hour = SCREEN_SHOT_HR; //for screen shots + tick_time->tm_min = SCREEN_SHOT_MIN; + #endif + if (clock_is_24h_style()) { + strftime(digital_time_buffer, sizeof(digital_time_buffer), "%H:%M", tick_time); + } else { + strftime(digital_time_buffer, sizeof(digital_time_buffer), "%l:%M %P", tick_time); + } + + if (current_digital_time_layer != digital_time_buffer) { + text_layer_set_text(digital_time_layer, digital_time_buffer); + } + } + else { + text_layer_set_text(digital_time_layer, ""); + } + #if DEBUG + APP_LOG(APP_LOG_LEVEL_DEBUG, "update_digital_time_layer: text_layer_set_text digital_time_layer: %s", digital_time_buffer); + #endif +} + +//adds/configures display digital time line +void add_digital_time_layer(Layer *window_layer, int16_t width, int16_t height) { + + GFont digital_time_font; + int chalk_digital_time_y_offset = 0; + + #if defined(PBL_ROUND) + chalk_digital_time_y_offset = DEFAULT_CHALK_DIGITAL_TIME_Y_OFFSET; + #else + chalk_digital_time_y_offset = 0; + #endif + + digital_time_font = fonts_get_system_font(FONT_KEY_GOTHIC_14); + + digital_time_layer = text_layer_create(GRect(0, 15 + chalk_digital_time_y_offset, width, 20)); + text_layer_set_text_alignment(digital_time_layer, GTextAlignmentCenter); + text_layer_set_background_color(digital_time_layer, GColorWhite); + init_static_row(digital_time_layer, digital_time_font); + layer_add_child(window_layer, text_layer_get_layer(digital_time_layer)); +} \ No newline at end of file