Upload files to "src/c"
This commit is contained in:
7
src/c/num2words.h
Normal file
7
src/c/num2words.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void time_to_common_words(int hours, int minutes, char *words);
|
||||||
|
void fuzzy_time_to_words(int hours, int minutes, char* words);
|
||||||
|
void minute_to_formal_words(int minutes, int displayPrefix, char *first_word, char *second_word);
|
||||||
|
void hour_to_12h_word(int hours, char *word);
|
||||||
|
void hour_to_24h_word(int hours, char *words);
|
||||||
72
src/c/options.c
Normal file
72
src/c/options.c
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
#include <pebble.h>
|
||||||
|
#include "options.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "sliding_time_wd.h"
|
||||||
|
|
||||||
|
extern Options s_options;
|
||||||
|
|
||||||
|
void init_options() {
|
||||||
|
|
||||||
|
if (persist_exists(KEY_OPTIONS)) {
|
||||||
|
persist_read_data(KEY_OPTIONS, &s_options, sizeof(s_options));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s_options.shake_for_lohi = DEFAULT_SHAKE_FOR_LOHI;
|
||||||
|
s_options.weatherdate_alignment = DEFAULT_WEATHERDATE_ALIGNMENT;
|
||||||
|
s_options.hourminute_alignment = DEFAULT_HOURMINUTES_ALIGNMENT;
|
||||||
|
s_options.display_weather = DEFAULT_DISPLAY_WEATHER;
|
||||||
|
s_options.use_celsius = DEFAULT_USE_CELSIUS;
|
||||||
|
s_options.weather_use_GPS = DEFAULT_WEATHER_USE_GPS;
|
||||||
|
memset(s_options.weather_location, 0,sizeof(s_options.weather_location));
|
||||||
|
s_options.weather_frequency = DEFAULT_WEATHER_FREQUENCY;
|
||||||
|
s_options.min_since_last_forecast = DEFAULT_MIN_SINCE_WEATHER_UPDATE;
|
||||||
|
s_options.display_prefix = DEFAULT_DISPLAY_O_PREFIX;
|
||||||
|
s_options.time_color = DEFAULT_TIME_COLOR;
|
||||||
|
s_options.hr_color = DEFAULT_HR_COLOR;
|
||||||
|
s_options.min_color = DEFAULT_MIN_COLOR;
|
||||||
|
s_options.wd_color = DEFAULT_WD_COLOR;
|
||||||
|
s_options.background_color = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
s_options.weatherdate_readability = DEFAULT_WEATHERDATE_READABILITY;
|
||||||
|
s_options.minutes_readability = DEFAULT_MINUTES_READABILITY;
|
||||||
|
s_options.condition_code = DEFAULT_CONDITION_CODE;
|
||||||
|
s_options.vibrate_bt_status = DEFAULT_VIBRATE_BT_STATUS;
|
||||||
|
s_options.display_date = DEFAULT_DISPLAY_DATE;
|
||||||
|
memset(s_options.conditions, 0,sizeof(s_options.conditions));
|
||||||
|
snprintf(s_options.last_weather_update12hr, sizeof(s_options.last_weather_update12hr), DEFAULT_LAST_WEATHER_UPDATE);
|
||||||
|
snprintf(s_options.last_weather_update24hr, sizeof(s_options.last_weather_update24hr), DEFAULT_LAST_WEATHER_UPDATE);
|
||||||
|
//persist_write_data(KEY_OPTIONS, &s_options, sizeof(s_options));
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.shake_for_lohi: %d", s_options.shake_for_lohi);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.tempF: %d", s_options.tempF);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.tempFLo: %d", s_options.tempFLo);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.tempFHi: %d", s_options.tempFHi);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.tempC: %d", s_options.tempC);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.tempCLo: %d", s_options.tempCLo);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.tempCHi: %d", s_options.tempCHi);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.weatherdate_alignment: %d", s_options.weatherdate_alignment);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.hourminute_alignment: %d", s_options.hourminute_alignment);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.display_weather: %d", s_options.display_weather);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.display_date: %d", s_options.display_date);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.use_celsius: %d", s_options.use_celsius);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.weather_use_GPS: %d", s_options.weather_use_GPS);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.weather_location: %s", s_options.weather_location);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.weather_frequency: %d", s_options.weather_frequency);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.min_since_last_forecast: %d", s_options.min_since_last_forecast);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.display_prefix: %d", s_options.display_prefix);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.time_color: %d", s_options.time_color);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.hr_color: %d", s_options.hr_color);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.min_color: %d", s_options.min_color);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.wd_color: %d", s_options.wd_color);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.background_color: %d", s_options.background_color);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.weatherdate_readability: %d", s_options.weatherdate_readability);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.minutes_readability: %d", s_options.minutes_readability);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.condition_code: %d", s_options.condition_code);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.bluetooth_state: %d", s_options.bluetooth_state);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.vibrate_bt_status: %d", s_options.vibrate_bt_status);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.conditions: %s", s_options.conditions);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.last_weather_update12hr: %s", s_options.last_weather_update12hr);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: s_options.last_weather_update24hr: %s", s_options.last_weather_update24hr);
|
||||||
|
APP_LOG(APP_LOG_LEVEL_DEBUG, "init_options: options sizeof(s_options) %zu", sizeof(s_options));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
5
src/c/options.h
Normal file
5
src/c/options.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define KEY_OPTIONS 99
|
||||||
|
|
||||||
|
void init_options();
|
||||||
477
src/c/sliding_time_wd.c
Normal file
477
src/c/sliding_time_wd.c
Normal file
@@ -0,0 +1,477 @@
|
|||||||
|
#include <pebble.h>
|
||||||
|
#include "sliding_time_wd.h"
|
||||||
|
#include "constants.h"
|
||||||
|
#include "num2words.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "weather_date.h"
|
||||||
|
#include "messaging.h"
|
||||||
|
|
||||||
|
Options s_options;
|
||||||
|
SlidingTextData *s_data;
|
||||||
|
|
||||||
|
//stores weather retry counts (incremented in second tick handler).
|
||||||
|
//Stop retry count at DEFAULT_MAX_WEATHER_RETRY_COUNT
|
||||||
|
int g_weather_retry_count = 0;
|
||||||
|
|
||||||
|
GTextAlignment row_alignment(int alignment) {
|
||||||
|
switch (alignment) {
|
||||||
|
case 0: return GTextAlignmentLeft;
|
||||||
|
case 1: return GTextAlignmentCenter;
|
||||||
|
case 2: return GTextAlignmentRight;
|
||||||
|
default: return GTextAlignmentLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_time_layers_color(GColor textColor) {
|
||||||
|
SlidingTextData *data = s_data;
|
||||||
|
SlidingRow *row;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ARRAY_LENGTH(data->rows); ++i) {
|
||||||
|
row = &data->rows[i];
|
||||||
|
text_layer_set_text_color(row->label, textColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_hr_layer_color(GColor textColor) {
|
||||||
|
SlidingTextData *data = s_data;
|
||||||
|
SlidingRow *row;
|
||||||
|
|
||||||
|
row = &data->rows[HOUR_ROW];
|
||||||
|
text_layer_set_text_color(row->label, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_min_layers_color(GColor textColor) {
|
||||||
|
SlidingTextData *data = s_data;
|
||||||
|
SlidingRow *row;
|
||||||
|
|
||||||
|
row = &data->rows[MINUTE_ROW1];
|
||||||
|
text_layer_set_text_color(row->label, textColor);
|
||||||
|
|
||||||
|
row = &data->rows[MINUTE_ROW2];
|
||||||
|
text_layer_set_text_color(row->label, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_wd_layers_color(GColor textColor) {
|
||||||
|
text_layer_set_text_color(weather_layer1, textColor);
|
||||||
|
#if defined(PBL_ROUND)
|
||||||
|
text_layer_set_text_color(weather_layer2, textColor);
|
||||||
|
text_layer_set_text_color(weather_layer_center, textColor);
|
||||||
|
#endif
|
||||||
|
text_layer_set_text_color(date_layer, textColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_window_background_color(){
|
||||||
|
SlidingTextData *data = s_data;
|
||||||
|
|
||||||
|
window_set_background_color(data->window, GColorBlack);
|
||||||
|
#ifdef PBL_COLOR // If on basalt
|
||||||
|
window_set_background_color(data->window, GColorFromHEX(s_options.background_color));
|
||||||
|
#else
|
||||||
|
if (s_options.background_color == 0xFFFFFF) {
|
||||||
|
window_set_background_color(data->window, GColorWhite);//white
|
||||||
|
}
|
||||||
|
else if (s_options.background_color == 0x000000) {//black
|
||||||
|
window_set_background_color(data->window, GColorBlack);
|
||||||
|
}
|
||||||
|
else { //didn't select white or black, default to white
|
||||||
|
window_set_background_color(data->window, GColorBlack);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static void init_sliding_row(SlidingTextData *data, SlidingRow *row, GRect pos, GFont font,
|
||||||
|
int delay, int layerColor) {
|
||||||
|
row->label = text_layer_create(pos);
|
||||||
|
|
||||||
|
//set row alignment
|
||||||
|
text_layer_set_text_alignment(row->label, row_alignment(s_options.hourminute_alignment));
|
||||||
|
|
||||||
|
text_layer_set_background_color(row->label, GColorClear);
|
||||||
|
text_layer_set_text_color(row->label, GColorWhite);
|
||||||
|
text_layer_set_text_color(row->label, GColorFromHEX(layerColor));
|
||||||
|
|
||||||
|
if (font) {
|
||||||
|
text_layer_set_font(row->label, font);
|
||||||
|
row->unchanged_font = true;
|
||||||
|
} else {
|
||||||
|
row->unchanged_font = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
row->state = IN_FRAME;
|
||||||
|
row->next_string = NULL;
|
||||||
|
|
||||||
|
row->left_pos = -pos.size.w;
|
||||||
|
row->right_pos = pos.size.w;
|
||||||
|
row->still_pos = pos.origin.x;
|
||||||
|
|
||||||
|
row->movement_delay = delay;
|
||||||
|
row->delay_count = 0;
|
||||||
|
|
||||||
|
data->last_hour = -1;
|
||||||
|
data->last_minute = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_static_row(TextLayer *label, GFont font) {
|
||||||
|
|
||||||
|
//set row alignment
|
||||||
|
#if defined(PBL_RECT)
|
||||||
|
text_layer_set_text_alignment(label, row_alignment(s_options.weatherdate_alignment));
|
||||||
|
#elif defined(PBL_ROUND)
|
||||||
|
text_layer_set_text_alignment(label, row_alignment(DEFAULT_CHALK_ALIGNMENT));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
text_layer_set_background_color(label, GColorClear);
|
||||||
|
text_layer_set_text_color(label, GColorWhite);
|
||||||
|
text_layer_set_text_color(label, GColorFromHEX(s_options.wd_color));
|
||||||
|
|
||||||
|
if (font) {
|
||||||
|
text_layer_set_font(label, font);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void slide_in_text(SlidingTextData *data, SlidingRow *row, char* new_text) {
|
||||||
|
(void) data;
|
||||||
|
|
||||||
|
const char *old_text = text_layer_get_text(row->label);
|
||||||
|
if (old_text) {
|
||||||
|
row->next_string = new_text;
|
||||||
|
row->state = PREPARE_TO_MOVE;
|
||||||
|
} else {
|
||||||
|
text_layer_set_text(row->label, new_text);
|
||||||
|
GRect frame = layer_get_frame(text_layer_get_layer(row->label));
|
||||||
|
frame.origin.x = row->right_pos;
|
||||||
|
layer_set_frame(text_layer_get_layer(row->label), frame);
|
||||||
|
row->state = MOVING_IN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool update_sliding_row(SlidingTextData *data, SlidingRow *row) {
|
||||||
|
(void) data;
|
||||||
|
|
||||||
|
GRect frame = layer_get_frame(text_layer_get_layer(row->label));
|
||||||
|
bool something_changed = true;
|
||||||
|
switch (row->state) {
|
||||||
|
case PREPARE_TO_MOVE:
|
||||||
|
frame.origin.x = row->still_pos;
|
||||||
|
row->delay_count++;
|
||||||
|
if (row->delay_count > row->movement_delay) {
|
||||||
|
row->state = MOVING_OUT;
|
||||||
|
row->delay_count = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOVING_IN: {
|
||||||
|
int speed = abs(frame.origin.x - row->still_pos) / 3 + 1;
|
||||||
|
frame.origin.x -= speed;
|
||||||
|
if (frame.origin.x <= row->still_pos) {
|
||||||
|
frame.origin.x = row->still_pos;
|
||||||
|
row->state = IN_FRAME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MOVING_OUT: {
|
||||||
|
int speed = abs(frame.origin.x - row->still_pos) / 3 + 1;
|
||||||
|
frame.origin.x -= speed;
|
||||||
|
|
||||||
|
if (frame.origin.x <= row->left_pos) {
|
||||||
|
frame.origin.x = row->right_pos;
|
||||||
|
row->state = MOVING_IN;
|
||||||
|
text_layer_set_text(row->label, row->next_string);
|
||||||
|
row->next_string = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IN_FRAME:
|
||||||
|
default:
|
||||||
|
something_changed = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (something_changed) {
|
||||||
|
layer_set_frame(text_layer_get_layer(row->label), frame);
|
||||||
|
}
|
||||||
|
return something_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void animation_update(struct Animation *animation, const AnimationProgress time_normalized) {
|
||||||
|
SlidingTextData *data = s_data;
|
||||||
|
|
||||||
|
struct SlidingTextRenderState *rs = &data->render_state;
|
||||||
|
|
||||||
|
time_t now = time(NULL);
|
||||||
|
struct tm t = *localtime(&now);
|
||||||
|
|
||||||
|
bool something_changed = false;
|
||||||
|
|
||||||
|
if (data->last_minute != t.tm_min) {
|
||||||
|
something_changed = true;
|
||||||
|
|
||||||
|
minute_to_formal_words(t.tm_min, s_options.display_prefix, rs->first_minutes[rs->next_minutes], rs->second_minutes[rs->next_minutes]);
|
||||||
|
if(data->last_hour != t.tm_hour || t.tm_min <= 20
|
||||||
|
|| t.tm_min/10 != data->last_minute/10) {
|
||||||
|
slide_in_text(data, &data->rows[MINUTE_ROW1], rs->first_minutes[rs->next_minutes]);
|
||||||
|
} else {
|
||||||
|
// The tens line didn't change, so swap to the correct buffer but don't animate
|
||||||
|
text_layer_set_text(data->rows[MINUTE_ROW1].label, rs->first_minutes[rs->next_minutes]);
|
||||||
|
}
|
||||||
|
slide_in_text(data, &data->rows[MINUTE_ROW2], rs->second_minutes[rs->next_minutes]);
|
||||||
|
rs->next_minutes = rs->next_minutes ? 0 : 1;
|
||||||
|
data->last_minute = t.tm_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->last_hour != t.tm_hour) {
|
||||||
|
hour_to_12h_word(t.tm_hour, rs->hours[rs->next_hours]);
|
||||||
|
slide_in_text(data, &data->rows[HOUR_ROW], rs->hours[rs->next_hours]);
|
||||||
|
rs->next_hours = rs->next_hours ? 0 : 1;
|
||||||
|
data->last_hour = t.tm_hour;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ARRAY_LENGTH(data->rows); ++i) {
|
||||||
|
something_changed = update_sliding_row(data, &data->rows[i]) || something_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!something_changed) {
|
||||||
|
animation_unschedule(data->animation);
|
||||||
|
#ifdef PBL_SDK_2
|
||||||
|
animation_destroy(s_data->animation);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void make_animation() {
|
||||||
|
s_data->animation = animation_create();
|
||||||
|
animation_set_duration(s_data->animation, ANIMATION_DURATION_INFINITE);
|
||||||
|
// the animation will stop itself
|
||||||
|
static const struct AnimationImplementation s_animation_implementation = {
|
||||||
|
.update = animation_update,
|
||||||
|
};
|
||||||
|
animation_set_implementation(s_data->animation, &s_animation_implementation);
|
||||||
|
animation_schedule(s_data->animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 connected and is now disconnected
|
||||||
|
if (s_options.bluetooth_state == 1 &&
|
||||||
|
current_bluetooth_state == 0) {
|
||||||
|
|
||||||
|
if (s_options.vibrate_bt_status) {
|
||||||
|
vibes_short_pulse(); //vibrate on bt disconnect, if option enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tap_handler(AccelAxisType axis, int32_t direction) {
|
||||||
|
if (s_options.shake_for_lohi == 1) {
|
||||||
|
//Display Lo Hi temp info;
|
||||||
|
display_lohi_weather_info();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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());
|
||||||
|
}
|
||||||
|
|
||||||
|
//every minute
|
||||||
|
static void handle_minute_tick(struct tm *tick_time, TimeUnits units_changed) {
|
||||||
|
|
||||||
|
if (units_changed & DAY_UNIT) {
|
||||||
|
//vibes_double_pulse(); //hourly vibration
|
||||||
|
}
|
||||||
|
|
||||||
|
make_animation(); //animate mew time
|
||||||
|
update_date_layer(); //check/update date layer
|
||||||
|
|
||||||
|
//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) handle_minute_tick 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 handle_deinit(void) {
|
||||||
|
|
||||||
|
//save watchface options
|
||||||
|
persist_write_data(KEY_OPTIONS, &s_options, sizeof(s_options));
|
||||||
|
|
||||||
|
text_layer_destroy(weather_layer1);
|
||||||
|
#if defined(PBL_ROUND)
|
||||||
|
text_layer_destroy(weather_layer_center);
|
||||||
|
text_layer_destroy(weather_layer2);
|
||||||
|
#endif
|
||||||
|
text_layer_destroy(date_layer);
|
||||||
|
|
||||||
|
#ifdef PBL_SDK_2
|
||||||
|
bluetooth_connection_service_unsubscribe();
|
||||||
|
#elif PBL_SDK_3
|
||||||
|
connection_service_unsubscribe();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
accel_tap_service_unsubscribe();
|
||||||
|
tick_timer_service_unsubscribe();
|
||||||
|
|
||||||
|
free(s_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_init() {
|
||||||
|
SlidingTextData *data = (SlidingTextData*)malloc(sizeof(SlidingTextData));
|
||||||
|
s_data = data;
|
||||||
|
|
||||||
|
g_weather_retry_count = 0;
|
||||||
|
|
||||||
|
int chalk_time_X_offset = 0;
|
||||||
|
int chalk_time_Y_offset = 0;
|
||||||
|
|
||||||
|
#if defined(PBL_RECT)
|
||||||
|
chalk_time_X_offset = 0;
|
||||||
|
chalk_time_Y_offset = 0;
|
||||||
|
#elif defined(PBL_ROUND)
|
||||||
|
chalk_time_X_offset = DEFAULT_CHALK_TIME_X_OFFSET;
|
||||||
|
chalk_time_Y_offset = DEFAULT_CHALK_TIME_Y_OFFSET;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
data->render_state.next_hours = 0;
|
||||||
|
data->render_state.next_minutes = 0;
|
||||||
|
data->render_state.demo_time.secs = 0;
|
||||||
|
data->render_state.demo_time.mins = 0;
|
||||||
|
data->render_state.demo_time.hour = 0;
|
||||||
|
|
||||||
|
data->window = window_create();
|
||||||
|
Layer *window_layer = window_get_root_layer(data->window);
|
||||||
|
GRect layer_frame = layer_get_frame(window_layer);
|
||||||
|
const int16_t width = layer_frame.size.w;
|
||||||
|
|
||||||
|
//set-retrieve watchface options
|
||||||
|
init_options();
|
||||||
|
|
||||||
|
init_window_background_color();
|
||||||
|
|
||||||
|
data->hour_text = fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD);
|
||||||
|
if (s_options.minutes_readability) {
|
||||||
|
data->minute_text = fonts_get_system_font(FONT_KEY_BITHAM_42_BOLD);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
data->minute_text = fonts_get_system_font(FONT_KEY_BITHAM_42_LIGHT);
|
||||||
|
}
|
||||||
|
|
||||||
|
//init hour/minutes layers
|
||||||
|
init_sliding_row(data, &data->rows[HOUR_ROW], GRect(0 + chalk_time_X_offset, 20 + chalk_time_Y_offset, width - (chalk_time_X_offset * 2), 60), data->hour_text, 6, s_options.hr_color);
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(data->rows[HOUR_ROW].label));
|
||||||
|
|
||||||
|
init_sliding_row(data, &data->rows[MINUTE_ROW1], GRect(0 + chalk_time_X_offset, 56 + chalk_time_Y_offset, width - (chalk_time_X_offset * 2), 96), data->minute_text, 3, s_options.min_color);
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(data->rows[MINUTE_ROW1].label));
|
||||||
|
|
||||||
|
init_sliding_row(data, &data->rows[MINUTE_ROW2], GRect(0 + chalk_time_X_offset, 92 + chalk_time_Y_offset, width - (chalk_time_X_offset * 2), 132), data->minute_text, 0, s_options.min_color);
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(data->rows[MINUTE_ROW2].label));
|
||||||
|
|
||||||
|
//add weather and date layers
|
||||||
|
add_weatherdate_layers(window_layer, width);
|
||||||
|
|
||||||
|
GFont norm14 = fonts_get_system_font(FONT_KEY_GOTHIC_14);
|
||||||
|
|
||||||
|
data->demo_label = text_layer_create(GRect(0, -3, 100, 20));
|
||||||
|
text_layer_set_background_color(data->demo_label, GColorClear);
|
||||||
|
text_layer_set_text_color(data->demo_label, GColorWhite);
|
||||||
|
text_layer_set_font(data->demo_label, norm14);
|
||||||
|
text_layer_set_text(data->demo_label, "demo mode");
|
||||||
|
layer_add_child(window_layer, text_layer_get_layer(data->demo_label));
|
||||||
|
|
||||||
|
layer_set_hidden(text_layer_get_layer(data->demo_label), true);
|
||||||
|
layer_mark_dirty(window_layer);
|
||||||
|
|
||||||
|
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_date_layer(); //update date_layer
|
||||||
|
update_weather_layer(); //update weather layer
|
||||||
|
make_animation(); //animate new time layers
|
||||||
|
|
||||||
|
tick_timer_service_subscribe(MINUTE_UNIT | SECOND_UNIT, handle_tick);
|
||||||
|
accel_tap_service_subscribe(tap_handler);
|
||||||
|
|
||||||
|
// 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());
|
||||||
|
|
||||||
|
const bool animated = true;
|
||||||
|
window_stack_push(data->window, animated);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
handle_init();
|
||||||
|
app_event_loop();
|
||||||
|
handle_deinit();
|
||||||
|
}
|
||||||
97
src/c/sliding_time_wd.h
Normal file
97
src/c/sliding_time_wd.h
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
#include <pebble.h>
|
||||||
|
|
||||||
|
|
||||||
|
TextLayer *weather_layer1, *weather_layer2, *weather_layer_center, *date_layer;
|
||||||
|
AppTimer *lohi_display_timer;
|
||||||
|
|
||||||
|
void init_static_row(TextLayer *label, GFont font); //creates/configures static (weather/date) display lines
|
||||||
|
GTextAlignment row_alignment(int alignment); //accepts int alignement and sets row GTextAlignment (0 left, 1 center, 2 right)
|
||||||
|
void set_time_layers_color(GColor textColor);
|
||||||
|
void set_hr_layer_color(GColor textColor);
|
||||||
|
void set_min_layers_color(GColor textColor);
|
||||||
|
void set_wd_layers_color(GColor textColor);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int shake_for_lohi;
|
||||||
|
int tempF;
|
||||||
|
int tempFLo;
|
||||||
|
int tempFHi;
|
||||||
|
int tempC;
|
||||||
|
int tempCLo;
|
||||||
|
int tempCHi;
|
||||||
|
int weatherdate_alignment;
|
||||||
|
int hourminute_alignment;
|
||||||
|
int display_weather;
|
||||||
|
int weather_use_GPS;
|
||||||
|
char weather_location[64];
|
||||||
|
int use_celsius;
|
||||||
|
int weather_frequency;
|
||||||
|
int min_since_last_forecast;
|
||||||
|
int display_prefix;
|
||||||
|
int time_color;
|
||||||
|
int hr_color;
|
||||||
|
int min_color;
|
||||||
|
int wd_color;
|
||||||
|
int background_color;
|
||||||
|
int weatherdate_readability;
|
||||||
|
int minutes_readability;
|
||||||
|
int condition_code;
|
||||||
|
int vibrate_bt_status;
|
||||||
|
int pebble_js_ready;
|
||||||
|
int display_date;
|
||||||
|
bool bluetooth_state;
|
||||||
|
time_t last_update;
|
||||||
|
char conditions[32];
|
||||||
|
char last_weather_update12hr[16];
|
||||||
|
char last_weather_update24hr[16];
|
||||||
|
} Options;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MOVING_IN,
|
||||||
|
IN_FRAME,
|
||||||
|
PREPARE_TO_MOVE,
|
||||||
|
MOVING_OUT
|
||||||
|
} SlideState;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TextLayer *label;
|
||||||
|
SlideState state; // animation state
|
||||||
|
char *next_string; // what to say in the next phase of animation
|
||||||
|
bool unchanged_font;
|
||||||
|
|
||||||
|
int left_pos;
|
||||||
|
int right_pos;
|
||||||
|
int still_pos;
|
||||||
|
|
||||||
|
int movement_delay;
|
||||||
|
int delay_count;
|
||||||
|
} SlidingRow;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
TextLayer *demo_label;
|
||||||
|
SlidingRow rows[3];
|
||||||
|
int last_hour;
|
||||||
|
int last_minute;
|
||||||
|
|
||||||
|
GFont hour_text;
|
||||||
|
GFont minute_text;
|
||||||
|
|
||||||
|
Window *window;
|
||||||
|
Animation *animation;
|
||||||
|
|
||||||
|
struct SlidingTextRenderState {
|
||||||
|
// double buffered string storage
|
||||||
|
char hours[2][32];
|
||||||
|
uint8_t next_hours;
|
||||||
|
char first_minutes[2][32];
|
||||||
|
char second_minutes[2][32];
|
||||||
|
uint8_t next_minutes;
|
||||||
|
|
||||||
|
struct SlidingTextRenderDemoTime {
|
||||||
|
int secs;
|
||||||
|
int mins;
|
||||||
|
int hour;
|
||||||
|
} demo_time;
|
||||||
|
} render_state;
|
||||||
|
|
||||||
|
} SlidingTextData;
|
||||||
Reference in New Issue
Block a user