Works on all three platforms

This commit is contained in:
Neale Pickett 2015-12-25 13:32:26 -07:00
parent 01033395eb
commit a84417f1a7
13 changed files with 441 additions and 0 deletions

121
appinfo.json Normal file
View File

@ -0,0 +1,121 @@
{
"appKeys": {
"align": 1,
"font": 2,
"theme": 0
},
"capabilities": [
""
],
"companyName": "dartcatcher@gmail.com",
"longName": "Twatch Fonts",
"projectType": "native",
"resources": {
"media": [
{
"characterRegex": "[\uf10b]",
"file": "fonts/fontawesome.ttf",
"name": "FONT_SYMBOLS_52",
"targetPlatforms": null,
"type": "font"
},
{
"characterRegex": "[0-9:]",
"file": "fonts/Ubuntu-Bold.ttf",
"name": "FONT_UBUNTU_B_64",
"targetPlatforms": [
"chalk"
],
"type": "font"
},
{
"characterRegex": "[0-9:]",
"file": "fonts/Ubuntu-Bold.ttf",
"name": "FONT_UBUNTU_B_48",
"targetPlatforms": [
"aplite",
"basalt"
],
"type": "font"
},
{
"characterRegex": "[0-9A-Za-z\u00e9\u00f4 ]",
"file": "fonts/Ubuntu-Regular.ttf",
"name": "FONT_UBUNTU_R_28",
"targetPlatforms": null,
"type": "font"
},
{
"characterRegex": "[0-9A-Za-z\u00e9\u00f4 ]",
"file": "fonts/AveriaSerif-Regular.ttf",
"name": "FONT_AVERIA_R_28",
"targetPlatforms": null,
"type": "font"
},
{
"characterRegex": "[0-9:]",
"file": "fonts/AveriaSerif-Bold.ttf",
"name": "FONT_AVERIA_B_64",
"targetPlatforms": [
"chalk"
],
"type": "font"
},
{
"characterRegex": "[0-9:]",
"file": "fonts/AveriaSerif-Bold.ttf",
"name": "FONT_AVERIA_B_48",
"targetPlatforms": [
"aplite",
"basalt"
],
"type": "font"
},
{
"file": "images/icon.png",
"menuIcon": true,
"name": "ICON",
"targetPlatforms": null,
"type": "bitmap"
},
{
"characterRegex": "[0-9A-Za-z\u00e9\u00f4 ]",
"file": "fonts/Helvetica-Regular.ttf",
"name": "FONT_HELVETICA_R_28",
"targetPlatforms": null,
"type": "font"
},
{
"characterRegex": "[0-9:]",
"file": "fonts/Helvetica-Bold.ttf",
"name": "FONT_HELVETICA_B_64",
"targetPlatforms": [
"chalk"
],
"type": "font"
},
{
"characterRegex": "[0-9:]",
"file": "fonts/Helvetica-Bold.ttf",
"name": "FONT_HELVETICA_B_48",
"targetPlatforms": [
"aplite",
"basalt"
],
"type": "font"
}
]
},
"sdkVersion": "3",
"shortName": "Twatch Fonts",
"targetPlatforms": [
"aplite",
"basalt",
"chalk"
],
"uuid": "2dce4324-374b-4e5e-9b98-3275561118f3",
"versionLabel": "1.0",
"watchapp": {
"watchface": true
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
resources/images/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 973 B

162
src/main.c Normal file
View File

@ -0,0 +1,162 @@
#include <pebble.h>
#include "settings.h"
static Window *s_main_window;
static TextLayer *s_date_layer, *s_time_layer, *s_alert_layer;
bool bt_connected = false;
static void bt_handler(bool connected) {
bt_connected = connected;
if (! bt_connected) {
vibes_double_pulse();
}
layer_mark_dirty(text_layer_get_layer(s_alert_layer));
}
static void handle_minute_tick(struct tm *tick_time, TimeUnits units_changed) {
// Need to be static because they're used by the system later.
static char s_time_text[] = "00:00";
static char s_date_text[] = "00 Çêû";
// Bluetooth alert
if (bt_connected) {
text_layer_set_text(s_alert_layer, "");
} else {
text_layer_set_text(s_alert_layer, "");
}
// Date
strftime(s_date_text, sizeof(s_date_text), "%d %b", tick_time);
text_layer_set_text(s_date_layer, NOZERO(s_date_text));
// Time
if (clock_is_24h_style()) {
strftime(s_time_text, sizeof(s_time_text), "%R", tick_time);
} else {
strftime(s_time_text, sizeof(s_time_text), "%I:%M", tick_time);
}
text_layer_set_text(s_time_layer, NOZERO(s_time_text));
}
static void main_window_load(Window *window) {
Layer *window_layer = window_get_root_layer(window);
#ifdef PBL_RECT
s_date_layer = text_layer_create(GRect(8, 66, 128, 100));
s_time_layer = text_layer_create(GRect(7, 92, 130, 76));
s_alert_layer = text_layer_create(GRect(110, 7, 52, 52));
text_layer_set_text_alignment(s_date_layer, GTextAlignmentLeft);
text_layer_set_text_alignment(s_time_layer, GTextAlignmentLeft);
#else
s_date_layer = text_layer_create(GRect(0, 20, 180, 100));
s_time_layer = text_layer_create(GRect(0, 48, 180, 76));
s_alert_layer = text_layer_create(GRect(0, 120, 180, 52));
text_layer_set_text_alignment(s_date_layer, GTextAlignmentCenter);
text_layer_set_text_alignment(s_time_layer, GTextAlignmentCenter);
text_layer_set_text_alignment(s_alert_layer, GTextAlignmentCenter);
#endif
text_layer_set_background_color(s_date_layer, GColorClear);
layer_add_child(window_layer, text_layer_get_layer(s_date_layer));
text_layer_set_background_color(s_time_layer, GColorClear);
layer_add_child(window_layer, text_layer_get_layer(s_time_layer));
text_layer_set_background_color(s_alert_layer, GColorClear);
text_layer_set_font(s_alert_layer, fonts_load_custom_font(resource_get_handle(RESOURCE_ID_FONT_SYMBOLS_52)));
layer_add_child(window_layer, text_layer_get_layer(s_alert_layer));
}
static void restore() {
int sel_theme = 0;
int sel_font = 0;
int i;
for (i = 0; i < KEY_LAST; i += 1) {
if (! persist_exists(i)) {
continue;
}
switch (i) {
case KEY_THEME:
sel_theme = persist_read_int(i);
break;
case KEY_FONT:
sel_font = persist_read_int(i);
break;
}
}
window_set_background_color(s_main_window, *themes[sel_theme][0]);
text_layer_set_text_color(s_date_layer, *themes[sel_theme][1]);
text_layer_set_text_color(s_time_layer, *themes[sel_theme][2]);
text_layer_set_text_color(s_alert_layer, *themes[sel_theme][2]);
text_layer_set_font(s_date_layer, fonts_load_custom_font(resource_get_handle(fonts[sel_font][0])));
text_layer_set_font(s_time_layer, fonts_load_custom_font(resource_get_handle(fonts[sel_font][1])));
}
static void in_received_handler(DictionaryIterator *rec, void *context) {
int i;
for (i = 0; i < KEY_LAST; i += 1) {
Tuple *cur = dict_find(rec, i);
if (! cur) {
APP_LOG(APP_LOG_LEVEL_DEBUG, "Holy crap! Key %i isn't around!", i);
continue;
}
persist_write_int(i, cur->value->int32);
}
restore();
}
static void in_dropped_handler(AppMessageResult reason, void *context) {
// XXX: I don't understand what we could possibly do here
}
static void main_window_unload(Window *window) {
text_layer_destroy(s_date_layer);
text_layer_destroy(s_time_layer);
text_layer_destroy(s_alert_layer);
}
static void init() {
s_main_window = window_create();
window_set_window_handlers(s_main_window, (WindowHandlers) {
.load = main_window_load,
.unload = main_window_unload,
});
window_stack_push(s_main_window, true);
tick_timer_service_subscribe(MINUTE_UNIT, handle_minute_tick);
bluetooth_connection_service_subscribe(bt_handler);
bt_connected = bluetooth_connection_service_peek();
app_message_register_inbox_received(in_received_handler);
app_message_register_inbox_dropped(in_dropped_handler);
app_message_open(256, 64);
// Prevent starting blank
time_t now = time(NULL);
struct tm *t = localtime(&now);
handle_minute_tick(t, MINUTE_UNIT);
setlocale(LC_ALL, "");
restore();
}
static void deinit() {
window_destroy(s_main_window);
tick_timer_service_unsubscribe();
}
int main() {
init();
app_event_loop();
deinit();
}

40
src/pebble-js-app.js Normal file
View File

@ -0,0 +1,40 @@
var initialized = false;
function appMessageAck(e) {
console.log("Configuration sent");
}
function appMessageNak(e) {
console.log("Configuration not sent: ", e);
}
Pebble.addEventListener("ready", function() {
console.log("ready called!");
initialized = true;
});
Pebble.addEventListener("showConfiguration", function() {
console.log("showing configuration");
Pebble.openURL('http://woozle.org/neale/misc/twatch-config/fonts.html');
});
var themes = {"Dark": 0,
"Light": 1,
"Green": 2};
var aligns = {"Left": 0,
"Center": 1,
"Right": 2};
var fonts = {"Helvetica": 0,
"Avería": 1,
"Ubuntu": 2};
Pebble.addEventListener("webviewclosed", function(e) {
console.log("configuration closed");
// webview closed
var options = JSON.parse(decodeURIComponent(e.response));
options.theme = themes[options.theme];
options.align = aligns[options.align];
options.font = fonts[options.font];
console.log("Options = " + options.theme + options.align + options.font);
Pebble.sendAppMessage(options, appMessageAck, appMessageNak);
});

56
src/settings.h Normal file
View File

@ -0,0 +1,56 @@
#include <pebble.h>
#pragma once
#define NOZERO(s) ((*s == '0')?(s+1):s)
typedef enum {
KEY_THEME = 0,
KEY_ALIGN,
KEY_FONT,
KEY_LAST
} MessageKey;
enum {
THEME_DARK = 0,
THEME_LIGHT,
THEME_GREEN,
THEME_LAST
};
enum {
ALIGN_LEFT = 0,
ALIGN_CENTER,
ALIGN_RIGHT,
ALIGN_LAST
};
enum {
FONT_HELVETICA = 0,
FONT_AVERIA,
FONT_UBUNTU,
FONT_LAST
};
GColor8 *themes[THEME_LAST][3] = {
{&GColorBlack, &GColorWhite, &GColorWhite},
{&GColorWhite, &GColorBlack, &GColorBlack},
{&GColorDarkGreen, &GColorWhite, &GColorWhite}
};
GTextAlignment aligns[ALIGN_LAST] = {
GTextAlignmentLeft,
GTextAlignmentCenter,
GTextAlignmentRight
};
const int fonts[FONT_LAST][2] = {
#ifdef PBL_RECT
{RESOURCE_ID_FONT_HELVETICA_R_28, RESOURCE_ID_FONT_HELVETICA_B_48},
{RESOURCE_ID_FONT_AVERIA_R_28, RESOURCE_ID_FONT_AVERIA_B_48},
{RESOURCE_ID_FONT_UBUNTU_R_28, RESOURCE_ID_FONT_UBUNTU_B_48}
#else
{RESOURCE_ID_FONT_HELVETICA_R_28, RESOURCE_ID_FONT_HELVETICA_B_64},
{RESOURCE_ID_FONT_AVERIA_R_28, RESOURCE_ID_FONT_AVERIA_B_64},
{RESOURCE_ID_FONT_UBUNTU_R_28, RESOURCE_ID_FONT_UBUNTU_B_64}
#endif
};

62
wscript Normal file
View File

@ -0,0 +1,62 @@
#
# This file is the default set of rules to compile a Pebble project.
#
# Feel free to customize this to your needs.
#
import os.path
try:
from sh import CommandNotFound, jshint, cat, ErrorReturnCode_2
hint = jshint
except (ImportError, CommandNotFound):
hint = None
top = '.'
out = 'build'
def options(ctx):
ctx.load('pebble_sdk')
def configure(ctx):
ctx.load('pebble_sdk')
def build(ctx):
if False and hint is not None:
try:
hint([node.abspath() for node in ctx.path.ant_glob("src/**/*.js")], _tty_out=False) # no tty because there are none in the cloudpebble sandbox.
except ErrorReturnCode_2 as e:
ctx.fatal("\nJavaScript linting failed (you can disable this in Project Settings):\n" + e.stdout)
# Concatenate all our JS files (but not recursively), and only if any JS exists in the first place.
ctx.path.make_node('src/js/').mkdir()
js_paths = ctx.path.ant_glob(['src/*.js', 'src/**/*.js'])
if js_paths:
ctx(rule='cat ${SRC} > ${TGT}', source=js_paths, target='pebble-js-app.js')
has_js = True
else:
has_js = False
ctx.load('pebble_sdk')
build_worker = os.path.exists('worker_src')
binaries = []
for p in ctx.env.TARGET_PLATFORMS:
ctx.set_env(ctx.all_envs[p])
ctx.set_group(ctx.env.PLATFORM_NAME)
app_elf='{}/pebble-app.elf'.format(p)
ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'),
target=app_elf)
if build_worker:
worker_elf='{}/pebble-worker.elf'.format(p)
binaries.append({'platform': p, 'app_elf': app_elf, 'worker_elf': worker_elf})
ctx.pbl_worker(source=ctx.path.ant_glob('worker_src/**/*.c'),
target=worker_elf)
else:
binaries.append({'platform': p, 'app_elf': app_elf})
ctx.set_group('bundle')
ctx.pbl_bundle(binaries=binaries, js='pebble-js-app.js' if has_js else [])