Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for round screens, color and SDK 3 #7

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
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
73 changes: 42 additions & 31 deletions appinfo.json
Original file line number Diff line number Diff line change
@@ -1,32 +1,43 @@
{
"uuid": "f50e354a-e8d9-46be-be74-0c5f488b3a4d",
"shortName": "Readebble",
"longName": "Readebble",
"companyName": "Neal",
"versionCode": 1,
"versionLabel": "2.2",
"capabilities": [ "configurable" ],
"watchapp": {
"watchface": false
},
"appKeys": {
"type": 0,
"method": 1,
"index": 2,
"title": 3
},
"config": {
"keen": { "projectId": "54532b53383144606491d740", "writeKey": "3d2051dfda71165e1f4693d7ad0787911713fcc4156da4556fb3211c4aee9efa6b7a76b5078e785565a4554b18186ed83dd8bcb59eeaf7931f53a576b2fc2b69cb9c936fb97ef1c83d79239165e0b1682ad56887ad3031ca476b9ed536a9d1edfb129ff85dd3193cc43e2b0308024b97" }
},
"debug": true,
"resources": {
"media": [
{
"menuIcon": true,
"type": "png",
"name": "IMAGE_MENU_ICON",
"file": "icon.png"
}
]
}
}
"uuid": "f50e354a-e8d9-46be-be74-0c5f488b3a4d",
"shortName": "Readebble",
"longName": "Readebble",
"companyName": "Neal",
"versionCode": 1,
"versionLabel": "2.2",
"capabilities": [
"configurable"
],
"watchapp": {
"watchface": false
},
"appKeys": {
"type": 0,
"method": 1,
"index": 2,
"title": 3
},
"config": {
"keen": {
"projectId": "54532b53383144606491d740",
"writeKey": "3d2051dfda71165e1f4693d7ad0787911713fcc4156da4556fb3211c4aee9efa6b7a76b5078e785565a4554b18186ed83dd8bcb59eeaf7931f53a576b2fc2b69cb9c936fb97ef1c83d79239165e0b1682ad56887ad3031ca476b9ed536a9d1edfb129ff85dd3193cc43e2b0308024b97"
}
},
"debug": true,
"resources": {
"media": [
{
"menuIcon": true,
"type": "png",
"name": "IMAGE_MENU_ICON",
"file": "icon.png"
}
]
},
"targetPlatforms": [
"aplite",
"basalt",
"chalk"
],
"sdkVersion": "3"
}
10 changes: 10 additions & 0 deletions src/headlines.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ static Headline *headlines = NULL;

static uint8_t num_headlines = 0;
static uint8_t current_headline = 0;
static uint8_t progress = 0;

static char *error = NULL;

void headlines_init(void) {
progress = 0;
win_headlines_init();
}

Expand All @@ -33,6 +35,7 @@ void headlines_in_received_handler(DictionaryIterator *iter) {
if (!tuple) break;
error = malloc(tuple->length);
strncpy(error, tuple->value->cstring, tuple->length);
progress = 100;
headlines_reload_data_and_mark_dirty();
break;
}
Expand All @@ -41,6 +44,7 @@ void headlines_in_received_handler(DictionaryIterator *iter) {
tuple = dict_find(iter, APP_KEY_INDEX);
if (!tuple) break;
num_headlines = tuple->value->uint8;
progress = (num_headlines == 0 ? 100 : 0);
headlines = malloc(sizeof(Headline) * num_headlines);
if (headlines == NULL) num_headlines = 0;
break;
Expand All @@ -55,6 +59,7 @@ void headlines_in_received_handler(DictionaryIterator *iter) {
if (tuple) {
strncpy(headline->title, tuple->value->cstring, sizeof(headline->title) - 1);
}
progress = ((int)(index + 1) * 100) / num_headlines;
LOG("headline: %d '%s'", headline->index, headline->title);
headlines_reload_data_and_mark_dirty();
break;
Expand All @@ -66,6 +71,10 @@ void headlines_reload_data_and_mark_dirty() {
win_headlines_reload_data_and_mark_dirty();
}

uint8_t headlines_progress() {
return progress;
}

uint8_t headlines_count() {
return num_headlines;
}
Expand Down Expand Up @@ -105,3 +114,4 @@ void headlines_request() {
app_message_outbox_send();
headlines_reload_data_and_mark_dirty();
}

1 change: 1 addition & 0 deletions src/headlines.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ void headlines_deinit(void);
void headlines_in_received_handler(DictionaryIterator *iter);
void headlines_reload_data_and_mark_dirty();
uint8_t headlines_count();
uint8_t headlines_progress();
char* headlines_get_error();
Headline* headlines_get(uint8_t index);
Headline* headlines_get_current();
Expand Down
2 changes: 1 addition & 1 deletion src/js/src/keen.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
var Keen = {
addEvent: function(name, data) {
if (!data || !data instanceof Object) data = {};
if ((!data) || !(data instanceof Object)) data = {};
data.app = { name: AppInfo.shortName, version: AppInfo.versionLabel, uuid: AppInfo.uuid };
data.user = { accountToken: Pebble.getAccountToken() };
if (AppInfo.debug) {
Expand Down
9 changes: 5 additions & 4 deletions src/js/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ Readebble.bufferSize = 440;
Readebble.init = function() {
Readebble.subscriptions = JSON.parse(localStorage.getItem('subscriptions')) || [];
Readebble.pocket = JSON.parse(localStorage.getItem('pocket')) || {};
if (!Readebble.subscriptions instanceof Array) Readebble.subscriptions = [];
if (!Readebble.pocket instanceof Object) Readebble.pocket = {};
if (!(Readebble.subscriptions instanceof Array)) Readebble.subscriptions = [];
if (!(Readebble.pocket instanceof Object)) Readebble.pocket = {};
Readebble.sendSubscriptions();
setTimeout(function() { Keen.addEvent('init', { subscriptions: { count: Readebble.subscriptions.length }, hasPocketToken: (Readebble.pocket.access_token !== 'undefined') }); }, 100);
};
Expand All @@ -23,7 +23,7 @@ Readebble.sendError = function(type, err) {

Readebble.sendSubscriptions = function() {
if (!this.subscriptions.length) {
return Readebble.sendError(TYPE.SUBSCRIPTION, 'No subscriptions found. Use the app settings in the Pebble mobile app to add subscriptions.');
return Readebble.sendError(TYPE.SUBSCRIPTION, 'No feeds configured');
}
appMessageQueue.send({type:TYPE.SUBSCRIPTION, method:METHOD.SIZE, index:Readebble.subscriptions.length});
for (var i = 0; i < Readebble.subscriptions.length; i++) {
Expand All @@ -45,6 +45,7 @@ Readebble.sendHeadlines = function() {

Readebble.sendStory = function(story) {
var maxStoryBuffer = Readebble.bufferSize - 32;
appMessageQueue.send({type:TYPE.STORY, method:METHOD.SIZE, index:story.length});
for (var i = 0; i <= Math.floor(story.length/maxStoryBuffer); i++) {
appMessageQueue.send({type:TYPE.STORY, method:METHOD.DATA, title:story.substring(i * maxStoryBuffer, i * maxStoryBuffer + maxStoryBuffer)});
}
Expand Down Expand Up @@ -95,7 +96,7 @@ Readebble.addToPocket = function() {
if (!Readebble.pocket.access_token) return Pebble.showSimpleNotificationOnPebble('Readebble', 'No Pocket account found. Please log in to your Pocket account via the Pebble mobile app.');
var url = 'https://ineal.me/pebble/readebble/pocket/add';
var data = { access_token: Readebble.pocket.access_token, url: Readebble.currentHeadline.link };
http('POST', url, serialize(data), null, function (e) {
http('POST', url, serialize(data), {"Content-Type": "application/x-www-form-urlencoded"}, function (e) {
var res = JSON.parse(e.responseText);
debugLog(res);
if (res.item && res.status == 1) {
Expand Down
156 changes: 156 additions & 0 deletions src/layers/progress_bar.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#include <pebble.h>
#include "layers/progress_bar.h"

typedef struct _ProgressBarData {
uint8_t progress;
ProgressBarLayerUpdateProc update_proc;
GColor complete;
GColor remaining;
} ProgressBarData;

static void progress_bar_layer_update_proc(ProgressBarLayer *progress_bar_layer, GContext *ctx);
#ifdef PBL_ROUND
float math_sqrt(const float num);
#endif

ProgressBarLayer * progress_bar_layer_create_fullscreen(Window * window) {
GRect window_bounds = layer_get_bounds(window_get_root_layer(window));
GPoint start = GPoint(0, STATUS_BAR_LAYER_HEIGHT - 2);
int16_t width = window_bounds.size.w;

ProgressBarLayer *progress_bar_layer = progress_bar_layer_create(start, width);

Layer *window_layer = window_get_root_layer(window);
layer_add_child(window_layer, progress_bar_layer_get_layer(progress_bar_layer));

return progress_bar_layer;
}

ProgressBarLayer * progress_bar_layer_create(GPoint start, int16_t width) {
// Set up the progress layer
GRect bounds = (GRect){
.origin = start,
.size = GSize(width, 1)
};

ProgressBarLayer *progress_bar_layer = layer_create_with_data(bounds, sizeof(ProgressBarData));
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data((Layer *)progress_bar_layer);
progress_bar_data->progress = 0;
progress_bar_data->complete = GColorBlack;
progress_bar_data->remaining = GColorWhite;
progress_bar_data->update_proc = NULL;

layer_set_update_proc(progress_bar_layer, progress_bar_layer_update_proc);

return progress_bar_layer;
}

void progress_bar_layer_stretch(ProgressBarLayer * progress_bar_layer) {
GRect window_bounds = layer_get_bounds(window_get_root_layer(layer_get_window((Layer *)progress_bar_layer)));
GRect layer_bounds = layer_get_bounds((Layer *)progress_bar_layer);

layer_bounds.origin.x = 0;
layer_bounds.size.w = window_bounds.size.w;
layer_set_frame((Layer *)progress_bar_layer, layer_bounds);
}

void progress_bar_layer_add_to_window(ProgressBarLayer * progress_bar_layer, Window *window) {
layer_add_child(window_get_root_layer(window), (Layer *)progress_bar_layer);
}

void progress_bar_layer_destroy(ProgressBarLayer * progress_bar_layer) {
// Disconnect from other layers
layer_remove_child_layers((Layer *)progress_bar_layer);
layer_remove_from_parent((Layer *)progress_bar_layer);

// Free all memory
layer_destroy((Layer *)progress_bar_layer);
}

void progress_bar_layer_set_pos(ProgressBarLayer * progress_bar_layer, int16_t y) {
GRect window_bounds = layer_get_bounds(window_get_root_layer(layer_get_window((Layer *)progress_bar_layer)));

#ifdef PBL_ROUND
float radius = ((float)window_bounds.size.h / 2.0);
float offset = (radius - (float)y);
int16_t width = (int16_t)math_sqrt((radius * radius) - (offset * offset));
#else
int16_t width = window_bounds.size.w / 2;
#endif

GRect layer_bounds = (GRect){
.origin = GPoint((window_bounds.size.w / 2) - width, y),
.size = GSize(width * 2, 1)
};
layer_set_frame((Layer *)progress_bar_layer, layer_bounds);
}

void progress_bar_layer_set_progress(ProgressBarLayer * progress_bar_layer, uint8_t percent) {
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data((Layer *)progress_bar_layer);

progress_bar_data->progress = percent;
layer_mark_dirty((Layer *)progress_bar_layer);
}

void progress_bar_layer_set_colors(ProgressBarLayer * progress_bar_layer, GColor complete, GColor remaining) {
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data((Layer *)progress_bar_layer);

progress_bar_data->complete = complete;
progress_bar_data->remaining = remaining;
layer_mark_dirty((Layer *)progress_bar_layer);
}

GColor progress_bar_layer_get_complete_color(ProgressBarLayer * progress_bar_layer) {
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data((Layer *)progress_bar_layer);

return progress_bar_data->complete;
}

GColor progress_bar_layer_get_remaining_color(ProgressBarLayer * progress_bar_layer) {
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data((Layer *)progress_bar_layer);

return progress_bar_data->remaining;
}

void progress_bar_layer_set_update_proc(ProgressBarLayer * progress_bar_layer, ProgressBarLayerUpdateProc update_proc) {
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data((Layer *)progress_bar_layer);

progress_bar_data->update_proc = update_proc;
}

static void progress_bar_layer_update_proc(Layer *layer, GContext *ctx) {
ProgressBarData *progress_bar_data = (ProgressBarData *)layer_get_data(layer);

if (progress_bar_data->update_proc != NULL) {
progress_bar_data->update_proc((ProgressBarLayer *)layer, ctx);
}
else {
GRect bounds = layer_get_bounds(layer);

int width = (int)(float)(((float)progress_bar_data->progress / 100.0f) * bounds.size.w);
// Complete
graphics_context_set_stroke_color(ctx, progress_bar_data->complete);
graphics_draw_line(ctx, GPointZero, GPoint(width, 0));
// Remaining
graphics_context_set_stroke_color(ctx, progress_bar_data->remaining);
graphics_draw_line(ctx, GPoint(width, 0), GPoint(bounds.size.w, 0));
}
}

#ifdef PBL_ROUND
// See https://forums.getpebble.com/discussion/comment/79122/#Comment_79122
float math_sqrt(const float num) {
const uint MAX_STEPS = 40;
const float MAX_ERROR = 0.001;

float answer = num;
float ans_sqr = answer * answer;
uint step = 0;
while((ans_sqr - num > MAX_ERROR) && (step++ < MAX_STEPS)) {
answer = (answer + (num / answer)) / 2;
ans_sqr = answer * answer;
}
return answer;
}
#endif

20 changes: 20 additions & 0 deletions src/layers/progress_bar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#pragma once

typedef Layer ProgressBarLayer;
typedef void(* ProgressBarLayerUpdateProc)(ProgressBarLayer *layer, GContext *ctx);

#define progress_bar_layer_get_layer(layer) (Layer *)layer
#define progress_bar_layer_destroy_safe(layer) if (layer != NULL) { progress_bar_layer_destroy(layer); layer = NULL; }

ProgressBarLayer * progress_bar_layer_create(GPoint start, int16_t width);
void progress_bar_layer_destroy(ProgressBarLayer * progress_bar_layer);
void progress_bar_layer_set_pos(ProgressBarLayer * progress_bar_layer, int16_t y);
void progress_bar_layer_set_progress(ProgressBarLayer * progress_bar_layer, uint8_t percent);
void progress_bar_layer_set_colors(ProgressBarLayer * progress_bar_layer, GColor complete, GColor remaining);
GColor progress_bar_layer_get_complete_color(ProgressBarLayer * progress_bar_layer);
GColor progress_bar_layer_get_remaining_color(ProgressBarLayer * progress_bar_layer);
void progress_bar_layer_set_update_proc(ProgressBarLayer * progress_bar_layer, ProgressBarLayerUpdateProc update_proc);
void progress_bar_layer_stretch(ProgressBarLayer * progress_bar_layer);
ProgressBarLayer * progress_bar_layer_create_fullscreen(Window * window);


Loading