Skip to content
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
43 changes: 41 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,51 @@

<img src="demo_animation.gif" width="144" height="168">

A checklist—on your watch!
A checklist-on your watch!


Thanks to the Pebble's microphone and voice input, it's now possible to keep track of anything on your wrist! Designed to stay out of your way, use Checklist to keep track of anything you need without needing to hold your phone-things to-do, shopping, and more!

Thanks to the Pebble’s microphone and voice input, it’s now possible to keep track of anything on your wrist! Designed to stay out of your way, use Checklist to keep track of anything you need without needing to hold your phone.

Grocery shopping will never be the same.


- Want to add multiple items at once? Just separate those items with periods or commas! (For example, saying "milk comma eggs comma cheese" will create 3 list items!)


- Don't want to use voice? Now you can enter items manually via your phone on the configuration page!



"...only one app, a simple list-making app called Checklist, which uses the watch's microphone to add tasks, really proved useful."
-MIT Technology Review

"I loved the convenience of adding items to the Checklist app just by speaking"
-Tom's Guide


******

Note: If voice isn't working, make sure your Pebble Time app is the newest version (3.6.1 on Android, 3.3.1 on iOS) and that your Pebble is running firmware 3.6 or higher. You can check under "Support" in the Pebble Time app.

In additon, ensure you are subscribed to a voice transcription service, for example http://rebble.io/


## Want to try it?

Grab it from the Rebble/Pebble app store:

https://apps.rebble.io/en_US/application/5620e876768e7ada4e00007a?section=watchapps&dev_settings=true

## Latest version with export

Available from https://github.com/clach04/PebbleChecklist/releases

To export notes:

* open config
* add new note with title "config" (with no quotes), save
* open config again
* copy from the export field (which is the same format the add note field accepts

NOTE check item status is NOT exported. Items end up in local storage.
6 changes: 6 additions & 0 deletions src/checklist.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ void read_data_from_storage() {
// load checklist information from storage
s_checklist_length = persist_read_int(PERSIST_KEY_CHECKLIST_LENGTH);
s_checklist_num_checked = persist_read_int(PERSIST_KEY_CHECKLIST_NUM_CHECKED);
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 s_checklist_length: %d", (int) s_checklist_length);
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 s_checklist_num_checked: %d", (int) s_checklist_num_checked);

// load the checklist by the block
int num_blocks_required = s_checklist_length / s_items_per_block + 1;
Expand All @@ -83,6 +85,10 @@ void read_data_from_storage() {
&s_checklist_items[block * s_items_per_block],
s_block_size);
}
// index 0 is the bottom of the list, higher numbers are top of list
for(int i = 0; i < MAX_CHECKLIST_ITEMS && strlen(s_checklist_items[i].name) > 0; i++) {
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 [%02d] %d %s", i, (int) s_checklist_items[i].is_checked, s_checklist_items[i].name);
}
}

void save_data_to_storage() {
Expand Down
35 changes: 34 additions & 1 deletion src/js/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// var BASE_CONFIG_URL = 'http://localhost:4000/';
// var BASE_CONFIG_URL = 'http://192.168.0.103:4000/';
var BASE_CONFIG_URL = 'http://freakified.github.io/PebbleChecklist/';
var BASE_CONFIG_URL = 'http://clach04.github.io/pebble/checklist/';


Pebble.addEventListener('ready', function(e) {
console.log('JS component loaded!');
Expand All @@ -9,6 +10,22 @@ Pebble.addEventListener('ready', function(e) {
// open the config page when requested
Pebble.addEventListener('showConfiguration', function(e) {
var configURL = BASE_CONFIG_URL + 'config.html';
var items_exported = localStorage.getItem('items_exported') || '[]';

try {
items_exported = JSON.parse(items_exported);
}
catch(error) {
console.error('items_exported parse failed, defaulting to [] - ' + error);
// expected output: ReferenceError: nonExistentFunction is not defined
// Note - error messages will vary depending on browser
items_exported = [];
}

console.log('config items_exported = ', JSON.stringify(items_exported));
//configURL = configURL + '?items_exported=test,notes,here';
//configURL = configURL + '?items_exported=' + encodeURIComponent(items_exported.join(','));
configURL = configURL + '?items_exported=' + items_exported.join(',');

Pebble.openURL(configURL);
});
Expand All @@ -35,10 +52,26 @@ Pebble.addEventListener('webviewclosed', function(e) {
// Send settings to Pebble watchapp
Pebble.sendAppMessage(dict, function(){
console.log('Sent config data to Pebble');
//itemsToAdd = []; // reset export list
}, function() {
console.log('Failed to send config data!');
});
} else {
console.log("No settings changed!");
}
});

Pebble.addEventListener("appmessage", function(e) {
if (e.payload.KEY_ITEMS_TO_ADD) {
var items_exported = [];

console.log('Message from Pebble: ' + JSON.stringify(e.payload));
console.log('Message from Pebble value: ' + e.payload.KEY_ITEMS_TO_ADD);
console.log('pre add items_exported = ', JSON.stringify(items_exported));
items_exported.push(e.payload.KEY_ITEMS_TO_ADD);
console.log('post add items_exported = ', JSON.stringify(items_exported));
//items_exported.push('static');
//console.log('post add static items_exported = ', JSON.stringify(items_exported));
localStorage.setItem('items_exported', JSON.stringify(items_exported)); // global variables do not persist even when watch app is still running, so store now
}
});
64 changes: 61 additions & 3 deletions src/messaging.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#include "messaging.h"
#include "checklist.h"

static char s_items_to_add_buffer[512];
static char s_items_to_add_buffer[(MAX_NAME_LENGTH * MAX_CHECKLIST_ITEMS) + (MAX_CHECKLIST_ITEMS * 1) + 1]= ""; // space for comma and a space, and final trailing blank - total should be smaller than app_message_outbox

void (*message_processed_callback)(void);

Expand All @@ -17,7 +17,13 @@ void messaging_init(void (*processed_callback)(void)) {
app_message_register_outbox_sent(outbox_sent_callback);

// Open AppMessage
app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum());
//app_message_open(app_message_inbox_size_maximum(), app_message_outbox_size_maximum());
//APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 app_message_inbox_size_maximum()=%d", app_message_inbox_size_maximum ()); // 8200 bytes
//APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 app_message_outbox_size_maximum()=%d", app_message_outbox_size_maximum()); // 8200 bytes
//APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 PERSIST_DATA_MAX_LENGTH=%d", PERSIST_DATA_MAX_LENGTH); // 256 bytes
//APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 PERSIST_STRING_MAX_LENGTH=%d", PERSIST_STRING_MAX_LENGTH); // 256 bytes
// with 52 * 50 bytes could send entire checklist as one string to phone....
app_message_open(sizeof(s_items_to_add_buffer) + /* safety net buffer */ + 100, (MAX_NAME_LENGTH * MAX_CHECKLIST_ITEMS) + /* safety net buffer */ + 100);

APP_LOG(APP_LOG_LEVEL_DEBUG, "Watch messaging is started!");
app_message_register_inbox_received(inbox_received_callback);
Expand All @@ -29,8 +35,60 @@ void inbox_received_callback(DictionaryIterator *iterator, void *context) {

if(items_to_add_tuple != NULL) {
strncpy(s_items_to_add_buffer, items_to_add_tuple->value->cstring, sizeof(s_items_to_add_buffer) - 1);
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 inbox value '%s'", s_items_to_add_buffer);
if (strncmp(s_items_to_add_buffer, "export", sizeof(s_items_to_add_buffer) - 1) == 0)
{
s_items_to_add_buffer[0] = '\0';
ChecklistItem *item=NULL;

checklist_add_items(s_items_to_add_buffer);
// magic export mode keyword found
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 got magic export mode keyword");

// index 0 is the bottom of the list, higher numbers are top of list
// dump entire contents, should really make use of success handler
// for array sending but data small enough to do in one go so cheat :-)
for(int id = 0; id < checklist_get_num_items() ; id++) {
item = checklist_get_item_by_id(id);
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 [%02d] %d %s", id, (int) item->is_checked, item->name);

// quick-n-dirty concat all items - ignore "checked" status
// FIXME below will get slower and slower as more items are added
strcat(s_items_to_add_buffer, item->name);
strcat(s_items_to_add_buffer, ",");
}

// Declare the dictionary's iterator
DictionaryIterator *out_iter;

// Prepare the outbox buffer for this message
AppMessageResult result = app_message_outbox_begin(&out_iter);
if(result == APP_MSG_OK) {
// Construct the message
DictionaryResult dict_result = dict_write_cstring(out_iter, KEY_ITEMS_TO_ADD, s_items_to_add_buffer);

if (dict_result == DICT_OK) {
// Send this message
result = app_message_outbox_send();

// Check the result
if(result != APP_MSG_OK) {
APP_LOG(APP_LOG_LEVEL_ERROR, "Error sending the outbox: %d", (int)result);
}
}
else {
APP_LOG(APP_LOG_LEVEL_ERROR, "Error writing cstring to out dict: %d", (int)dict_result);
}


} else {
// The outbox cannot be used right now
APP_LOG(APP_LOG_LEVEL_ERROR, "Error preparing the outbox: %d", (int)result);
}
}
else
{
checklist_add_items(s_items_to_add_buffer);
}
}

// notify the main screen, in case something changed
Expand Down
17 changes: 17 additions & 0 deletions src/windows/checklist_window.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,22 @@ static void select_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index,
}
}

static void select_long_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index, void *callback_context) {
if(cell_index->row == 0) {
// dump counts? export all non-checked?
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 select_long_callback() TOP checklist_get_num_items()=%d", checklist_get_num_items());
} else if(cell_index->row == checklist_get_num_items() + 1) {
// dump all check, export all checked?
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 select_long_callback() BOTTOM (clear)");
} else {
// Dump highlighted
int id = checklist_get_num_items() - (cell_index->row - 1) - 1;

ChecklistItem *item = checklist_get_item_by_id(id);
APP_LOG(APP_LOG_LEVEL_DEBUG, "clach04 [%02d] %d %s", id, (int) item->is_checked, item->name);
}
}

static void window_load(Window *window) {
checklist_init();

Expand Down Expand Up @@ -311,6 +327,7 @@ static void window_load(Window *window) {
.draw_row = (MenuLayerDrawRowCallback)draw_row_callback,
.get_cell_height = (MenuLayerGetCellHeightCallback)get_cell_height_callback,
.select_click = (MenuLayerSelectCallback)select_callback,
.select_long_click = (MenuLayerSelectCallback)select_long_callback,
});

window_set_background_color(window, BG_COLOR);
Expand Down