mirror of
https://github.com/Threnklyn/pebble-directions.git
synced 2026-05-18 12:53:27 +02:00
complies but not working yet
* The thing is crashing :/
This commit is contained in:
+23
-3
@@ -18,15 +18,17 @@
|
||||
"location"
|
||||
],
|
||||
"watchapp": {
|
||||
"watchface": false
|
||||
"watchface": false,
|
||||
"hiddenApp": false,
|
||||
"onlyShownOnCommunication": false
|
||||
},
|
||||
"messageKeys": [
|
||||
"READY",
|
||||
"SEARCH",
|
||||
"SUCCESS",
|
||||
"DISTANCE",
|
||||
"TIME",
|
||||
"STEPS",
|
||||
"STEPS_DISTANCES"
|
||||
"INSTRUCTIONS[20]"
|
||||
],
|
||||
"resources": {
|
||||
"media": [
|
||||
@@ -77,6 +79,24 @@
|
||||
"name": "ICON_WALK_WHITE",
|
||||
"targetPlatforms": null,
|
||||
"type": "bitmap"
|
||||
},
|
||||
{
|
||||
"file": "images/error_network.png",
|
||||
"name": "ICON_ERROR_NETWORK",
|
||||
"targetPlatforms": null,
|
||||
"type": "bitmap"
|
||||
},
|
||||
{
|
||||
"file": "images/error_api.png",
|
||||
"name": "ICON_ERROR_API",
|
||||
"targetPlatforms": null,
|
||||
"type": "bitmap"
|
||||
},
|
||||
{
|
||||
"file": "images/error_other.png",
|
||||
"name": "ICON_ERROR_OTHER",
|
||||
"targetPlatforms": null,
|
||||
"type": "bitmap"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 895 B |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
@@ -4,3 +4,5 @@
|
||||
#define COLOR_BIKE GColorTiffanyBlue
|
||||
#define COLOR_TRAIN GColorSunsetOrange
|
||||
#define COLOR_WALK GColorChromeYellow
|
||||
|
||||
#define COLOR_ERROR GColorLightGray
|
||||
|
||||
+158
-10
@@ -1,11 +1,11 @@
|
||||
#include <pebble.h>
|
||||
#include "colors.h"
|
||||
#include "directions_window.h"
|
||||
|
||||
#include <pebble.h>
|
||||
#include "colors.h"
|
||||
#include "select_window.h"
|
||||
#include "directions_window.h"
|
||||
#include "error_window.h"
|
||||
|
||||
#define MAX_STEP_COUNT 20
|
||||
#define MAX_STEP_CHARS 128
|
||||
|
||||
// The main window
|
||||
static Window *window;
|
||||
@@ -17,6 +17,18 @@ static GColor selected_type_color;
|
||||
static DictationSession *dictation_session;
|
||||
static char *address;
|
||||
|
||||
// TODO: implement a timer, that kills the proccess if the message is never send (needed?)
|
||||
static bool AppMessageIsReady;
|
||||
static bool AppMessageSendOnCallback;
|
||||
static int RouteDataDistance;
|
||||
static int RouteDataTime;
|
||||
static char RouteDataSteps[MAX_STEP_COUNT][MAX_STEP_CHARS];
|
||||
static int RouteDataStepsCount;
|
||||
|
||||
// Function declarations
|
||||
static void app_message_send_search_data();
|
||||
void window_display_error(enum ErrorType err);
|
||||
|
||||
|
||||
// ******************************
|
||||
// * DIRECTON LIST (MENU LAYER) *
|
||||
@@ -51,6 +63,7 @@ static void draw_row_callback(GContext *ctx, const Layer *cell_layer, MenuIndex
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: Will probably not be necessary later!
|
||||
static void selection_will_change_callback(struct MenuLayer *menu_layer, MenuIndex *new_index, MenuIndex old_index, void *context) {
|
||||
// Change the highlight color
|
||||
#ifdef PBL_COLOR
|
||||
@@ -62,7 +75,6 @@ static void selection_will_change_callback(struct MenuLayer *menu_layer, MenuInd
|
||||
// All other cells
|
||||
default:
|
||||
menu_layer_set_highlight_colors(directions_list, GColorWhite, selected_type_color);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -77,22 +89,150 @@ static void dictation_session_callback(DictationSession *session, DictationSessi
|
||||
if (status == DictationSessionStatusSuccess) {
|
||||
// Store the address and load a route
|
||||
address = transcript;
|
||||
// TODO load route data
|
||||
// Send the search data
|
||||
app_message_send_search_data();
|
||||
} else {
|
||||
// TODO display proper error window
|
||||
// Dictation failed, remove this window
|
||||
window_stack_remove(window, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ******************
|
||||
// * APP SYNC STUFF *
|
||||
// ******************
|
||||
// *********************
|
||||
// * APP MESSAGE STUFF *
|
||||
// *********************
|
||||
|
||||
// Accept data from the watch
|
||||
static void app_message_inbox_recived_callback(DictionaryIterator *iter, void *context) {
|
||||
// Test all possible message types
|
||||
Tuple *message;
|
||||
|
||||
// Test if the recived message is for key READY
|
||||
message = dict_find(iter, MESSAGE_KEY_READY);
|
||||
if (message) {
|
||||
// Set status to ready
|
||||
AppMessageIsReady = (bool)message->value->int16;
|
||||
// Send pending search data
|
||||
if (AppMessageSendOnCallback) {
|
||||
app_message_send_search_data();
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the recived message is for key SUCCESS
|
||||
message = dict_find(iter, MESSAGE_KEY_SUCCESS);
|
||||
if (message) {
|
||||
// Respond with the correct UI
|
||||
switch ((int)message->value->int32) {
|
||||
// Success
|
||||
case 0:
|
||||
// TODO: update the ui in some way
|
||||
window_display_error(Other);
|
||||
break;
|
||||
// Route not found / api error
|
||||
case 1:
|
||||
window_display_error(Api);
|
||||
break;
|
||||
// Too many steps (== route not found error)
|
||||
case 2:
|
||||
window_display_error(Api);
|
||||
break;
|
||||
default:
|
||||
window_display_error(Other);
|
||||
}
|
||||
}
|
||||
|
||||
// Test if the recived message is for key DISTANCE
|
||||
message = dict_find(iter, MESSAGE_KEY_DISTANCE);
|
||||
if (message) {
|
||||
RouteDataDistance = (int)message->value->int32;
|
||||
}
|
||||
|
||||
// Test if the recived message is for key TIME
|
||||
message = dict_find(iter, MESSAGE_KEY_TIME);
|
||||
if (message) {
|
||||
RouteDataTime = (int)message->value->int32;
|
||||
}
|
||||
|
||||
// Test if the recived message is for key INSTRUCTIONS
|
||||
for (int i = 0; i < MAX_STEP_COUNT; i++) {
|
||||
message = dict_find(iter, MESSAGE_KEY_INSTRUCTIONS + i);
|
||||
if (message) {
|
||||
// Copy the string into the string array
|
||||
static char *empty;
|
||||
strncat(empty, message->value->cstring, MAX_STEP_CHARS);
|
||||
strcpy(RouteDataSteps[i], empty);
|
||||
// Store the new length of the RouteDataSteps
|
||||
RouteDataStepsCount = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Respond with error, if any data is lost
|
||||
static void app_message_inbox_dropped_callback(AppMessageResult reason, void *context) {
|
||||
// Display the network error
|
||||
window_display_error(Network);
|
||||
}
|
||||
|
||||
// Respond with error, if data can not be send to watch
|
||||
static void app_message_outbox_failed_callback(DictionaryIterator *iter, AppMessageResult reason, void *context) {
|
||||
// Display the network error
|
||||
window_display_error(Network);
|
||||
}
|
||||
|
||||
// Send the search data to the phone
|
||||
static void app_message_send_search_data() {
|
||||
// Send the data to the phone if conn is ready
|
||||
if (AppMessageIsReady) {
|
||||
// Create a string with the correct length
|
||||
char message[sizeof(address) + 1];
|
||||
// Add the type as the first char
|
||||
message[0] = '0' + selected_type_enum;
|
||||
// Add the address
|
||||
strcat(message, address);
|
||||
// Make sure the string is terminated correctely, just in case
|
||||
message[sizeof(message) - 1] = '\n';
|
||||
|
||||
// Write string to bluetooth storage
|
||||
DictionaryIterator *iter;
|
||||
if (app_message_outbox_begin(&iter) == APP_MSG_OK) {
|
||||
dict_write_cstring(iter, MESSAGE_KEY_SEARCH, message);
|
||||
// Send the outbox
|
||||
app_message_outbox_send();
|
||||
} else {
|
||||
// Display network error
|
||||
window_display_error(Network);
|
||||
}
|
||||
} else {
|
||||
AppMessageSendOnCallback = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the whole app message thing (once the address is worked out)
|
||||
static void app_message_start() {
|
||||
// Set initial values
|
||||
AppMessageIsReady = true;
|
||||
AppMessageSendOnCallback = false;
|
||||
// Register all callbacks
|
||||
app_message_register_inbox_received(app_message_inbox_recived_callback);
|
||||
app_message_register_inbox_dropped(app_message_inbox_dropped_callback);
|
||||
app_message_register_outbox_failed(app_message_outbox_failed_callback);
|
||||
// Open the app-message
|
||||
app_message_open(APP_MESSAGE_INBOX_SIZE_MINIMUM, APP_MESSAGE_OUTBOX_SIZE_MINIMUM);
|
||||
}
|
||||
|
||||
|
||||
// ********************
|
||||
// * WINDOW LIFECYCLE *
|
||||
// ********************
|
||||
|
||||
// Network error callback
|
||||
void window_display_error(enum ErrorType err) {
|
||||
// Show the error window
|
||||
error_window_push(err);
|
||||
// Remove this window from the window stack
|
||||
window_stack_remove(window, false);
|
||||
}
|
||||
|
||||
// Window unload handler
|
||||
static void window_unload() {
|
||||
// Destroy the menu layer
|
||||
@@ -101,6 +241,9 @@ static void window_unload() {
|
||||
// Destroy the dictation session
|
||||
dictation_session_destroy(dictation_session);
|
||||
|
||||
// Remove all app message callbacks
|
||||
app_message_deregister_callbacks();
|
||||
|
||||
// Destroy the window
|
||||
window_destroy(window);
|
||||
window = NULL;
|
||||
@@ -175,4 +318,9 @@ void directions_window_push() {
|
||||
// Start the dictation session TODO: Change this, once app sync stuff is working
|
||||
// dictation_session_start(dictation_session);
|
||||
address = "Meerbusch Brockhofweg 9"; // WIP address string
|
||||
|
||||
// Open the connection to the phone
|
||||
app_message_start();
|
||||
// TODO: Remove this for final version; this is a playeholder implementation (skipping the dictation)
|
||||
app_message_send_search_data();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
#include <pebble.h>
|
||||
#include "colors.h"
|
||||
#include "error_window.h"
|
||||
|
||||
// The main window
|
||||
static Window *window;
|
||||
static BitmapLayer *error_icon_layer;
|
||||
static TextLayer *error_text_layer;
|
||||
|
||||
// The error to be displayed
|
||||
int display_error_type;
|
||||
|
||||
// Error icon / text
|
||||
static GBitmap *icon_error;
|
||||
static char *text_error;
|
||||
|
||||
|
||||
static void window_unload() {
|
||||
// Destroy the text layer & the error icon layer
|
||||
bitmap_layer_destroy(error_icon_layer);
|
||||
text_layer_destroy(error_text_layer);
|
||||
|
||||
// Destroy the image resource
|
||||
gbitmap_destroy(icon_error);
|
||||
|
||||
// Destroy the window
|
||||
window_destroy(window);
|
||||
window = NULL;
|
||||
}
|
||||
|
||||
static void window_load() {
|
||||
// Get the root layer
|
||||
Layer *window_layer = window_get_root_layer(window);
|
||||
GRect bounds = layer_get_bounds(window_layer);
|
||||
|
||||
switch(display_error_type) {
|
||||
// Network
|
||||
case 0:
|
||||
icon_error = gbitmap_create_with_resource(RESOURCE_ID_ICON_ERROR_NETWORK);
|
||||
text_error = "Could not reach phone";
|
||||
break;
|
||||
// Api
|
||||
case 1:
|
||||
icon_error = gbitmap_create_with_resource(RESOURCE_ID_ICON_ERROR_API);
|
||||
text_error = "No route could be found";
|
||||
break;
|
||||
// Other / Undefined
|
||||
case 2:
|
||||
icon_error = gbitmap_create_with_resource(RESOURCE_ID_ICON_ERROR_OTHER);
|
||||
text_error = "Something went wrong";
|
||||
break;
|
||||
}
|
||||
|
||||
// Set up the error image layer GRect(x, y, w, h)
|
||||
#ifdef PBL_ROUND
|
||||
// Round spacing / Align
|
||||
error_icon_layer = bitmap_layer_create(GRect(0, 0, bounds.size.w, 110));
|
||||
bitmap_layer_set_alignment(error_icon_layer, GAlignBottom);
|
||||
#else
|
||||
// Square spacing / Align
|
||||
error_icon_layer = bitmap_layer_create(GRect(0, 0, bounds.size.w, 100));
|
||||
bitmap_layer_set_alignment(error_icon_layer, GAlignCenter);
|
||||
#endif
|
||||
bitmap_layer_set_bitmap(error_icon_layer, icon_error);
|
||||
bitmap_layer_set_compositing_mode(error_icon_layer, GCompOpSet);
|
||||
#ifdef PBL_COLOR
|
||||
// Color only
|
||||
bitmap_layer_set_background_color(error_icon_layer, COLOR_ERROR);
|
||||
#endif
|
||||
|
||||
layer_add_child(window_layer, (Layer *)error_icon_layer);
|
||||
|
||||
// Set up the error text
|
||||
#ifdef PBL_ROUND
|
||||
// Round spacing
|
||||
error_text_layer = text_layer_create(GRect(0, 110, bounds.size.w, bounds.size.h - 110));
|
||||
#else
|
||||
// Square spacing
|
||||
error_text_layer = text_layer_create(GRect(0, 100, bounds.size.w, bounds.size.h - 100));
|
||||
#endif
|
||||
text_layer_set_text(error_text_layer, text_error);
|
||||
text_layer_set_font(error_text_layer, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD));
|
||||
text_layer_set_text_alignment(error_text_layer, GTextAlignmentCenter);
|
||||
text_layer_set_text_color(error_text_layer, GColorBlack);
|
||||
#ifdef PBL_COLOR
|
||||
// Color only
|
||||
text_layer_set_background_color(error_text_layer, COLOR_ERROR);
|
||||
#endif
|
||||
|
||||
layer_add_child(window_layer, (Layer *)error_text_layer);
|
||||
#ifdef PBL_ROUND
|
||||
// Round text insets
|
||||
text_layer_enable_screen_text_flow_and_paging(error_text_layer, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void error_window_push(enum ErrorType error_type) {
|
||||
display_error_type = error_type;
|
||||
if (!window) {
|
||||
// Create the window
|
||||
window = window_create();
|
||||
|
||||
// Set up the window handlers
|
||||
window_set_window_handlers(window, (WindowHandlers) {
|
||||
.load = window_load,
|
||||
.unload = window_unload,
|
||||
});
|
||||
}
|
||||
|
||||
// Display the window
|
||||
window_stack_push(window, true);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <pebble.h>
|
||||
|
||||
enum ErrorType {
|
||||
// Problem connection to phone
|
||||
Network = 0,
|
||||
// Error response from api
|
||||
Api = 1,
|
||||
// Something simply went wrong
|
||||
Other = 2
|
||||
};
|
||||
|
||||
void error_window_push(enum ErrorType);
|
||||
+112
-22
@@ -1,33 +1,123 @@
|
||||
/**
|
||||
* SETUP OVERVIEW
|
||||
*
|
||||
* About the send messages
|
||||
* –––
|
||||
* (1) Overview data is send (distance, time needed)
|
||||
* (2) Step data array is send (each step string, max 20 entrys) -> THE LAST SEND INDEX IS THE LENGTH!
|
||||
* (3) Success value is send (terminates the transmittion; it's true/false
|
||||
* value determines whether the transmition was successfull or not (E.g.
|
||||
* if false is send as the success first, no route was found)
|
||||
*
|
||||
* About the success codes:
|
||||
* –––
|
||||
* 0 = Success; 1 = Route not found; 2 = Too many steps; ...
|
||||
*
|
||||
* About the recived message:
|
||||
* –––
|
||||
* Field: SEARCH
|
||||
* Contents: {selected_type}{address} (e.g. 0Brockhofweg 9)
|
||||
* The first character is always the type selected, the rest
|
||||
* is the written address.
|
||||
* {selected_type} vals: 0 = Car; 1 = Bike; 2 = Train; 3 = Walk;
|
||||
*/
|
||||
|
||||
|
||||
// Data keys
|
||||
var keys = require('message_keys');
|
||||
var maxStepCount = 20;
|
||||
|
||||
// Common functions
|
||||
function createData(success, distance, time, steps, stepsDistances) {
|
||||
|
||||
// App Message functions
|
||||
function sendSuccess(code) {
|
||||
// Build message
|
||||
var key = keys.SUCCESS;
|
||||
var dict = {};
|
||||
dict[keys.SUCCESS] = success;
|
||||
dict[keys.DISTANCE] = distance;
|
||||
dict[keys.TIME] = time;
|
||||
dict[keys.STEPS] = steps;
|
||||
dict[keys.STEPS_DISTANCES] = stepsDistances;
|
||||
return dict;
|
||||
dict[key] = +code;
|
||||
|
||||
// Send message to pebble
|
||||
Pebble.sendAppMessage(dict, function() {
|
||||
// Success!
|
||||
console.log('Transmission completed');
|
||||
}, function() {
|
||||
// Error
|
||||
console.log('Transmission failed at [SUCCESS MESSAGE]');
|
||||
});
|
||||
}
|
||||
|
||||
// Some dummy data (let's make the c app work first ;)
|
||||
function sendStepItem(stepList, index) {
|
||||
// Build message
|
||||
var key = keys.INSTRUCTIONS + index;
|
||||
var dict = {};
|
||||
dict[key] = stepList[index];
|
||||
|
||||
// Send message to pebble
|
||||
Pebble.sendAppMessage(dict, function() {
|
||||
// Success, send next item
|
||||
index ++;
|
||||
if (index < stepList.length && index < maxStepCount) {
|
||||
// Recursive callbacks, hell yeah!
|
||||
sendStepItem(stepList, index);
|
||||
} else {
|
||||
// We are finished
|
||||
sendSuccess(0);
|
||||
}
|
||||
}, function() {
|
||||
// Error
|
||||
console.log('Transmission failed at index '.concat(index));
|
||||
});
|
||||
}
|
||||
|
||||
function sendRoute(success, distance, time, stepList) {
|
||||
// Send message to pebble if a route was found
|
||||
if (success) {
|
||||
// Build message
|
||||
var keyDistance = keys.DISTANCE;
|
||||
var keyTime = keys.TIME;
|
||||
dict[keyDistance] = +distance;
|
||||
dict[keyTime] = +time;
|
||||
|
||||
// Transmit
|
||||
Pebble.sendAppMessage(dict, function() {
|
||||
// Success!
|
||||
sendStepItem(stepList, 0);
|
||||
}, function() {
|
||||
// Error
|
||||
console.log('Transmission failed at [OVERVIEW]');
|
||||
});
|
||||
} else {
|
||||
// Send error message (route not found)
|
||||
sendSuccess(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Api data functions FIXME: Acutally use api
|
||||
function fetchAndSendRoute(routeType, destination) {
|
||||
// TODO: Add api data here (+ use geolocation etc)
|
||||
console.log(routeType);
|
||||
console.log(destination);
|
||||
/* dummy data: */
|
||||
sendRoute(true, 560, 16, ['This is the first step', 'This is the second step', 'This is the third step', 'This is the final step']);
|
||||
}
|
||||
|
||||
// Accept data from the pebble watch
|
||||
Pebble.addEventListener('appmessage', function(e) {
|
||||
// Get the dictionary from the message
|
||||
var dict = e.payload;
|
||||
console.log(dict.SEARCH);
|
||||
|
||||
var message = createData(
|
||||
true,
|
||||
140,
|
||||
13,
|
||||
["Do sometoing", "Step 3", "the very last step"],
|
||||
[11, 0, 5321]
|
||||
);
|
||||
Pebble.sendAppMessage(message, function() {
|
||||
console.log('Message sent successfully: ' + JSON.stringify(message));
|
||||
}, function(e) {
|
||||
console.log('Message failed: ' + JSON.stringify(message));
|
||||
});
|
||||
// Does the SEARCH field exist?
|
||||
if (dict['SEARCH']) {
|
||||
fetchAndSendRoute(dict['SEARCH'].substr(0, 1), dict['SEARCH'].substr(1));
|
||||
}
|
||||
});
|
||||
|
||||
// Ready event
|
||||
Pebble.addEventListener('ready', function() {
|
||||
// Tell the watch that the js part is ready
|
||||
var key = keys.READY;
|
||||
var dict = {};
|
||||
dict[key] = true;
|
||||
Pebble.sendAppMessage(dict);
|
||||
|
||||
console.log('Js part is ready!');
|
||||
});
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ static uint16_t get_num_rows_callback(struct MenuLayer *menu_layer, uint16_t sec
|
||||
|
||||
static int16_t get_cell_height_callback(struct MenuLayer *menu_layer, MenuIndex *cell_index, void *context) {
|
||||
// This part is for round watches only
|
||||
#if defined(PBL_ROUND)
|
||||
#ifdef PBL_ROUND
|
||||
// Round
|
||||
bool selected = menu_layer_is_index_selected(menu_layer, cell_index);
|
||||
if (selected) {
|
||||
|
||||
Reference in New Issue
Block a user