From 95bc449cfb940b9b98e1c4040dce033e048870dd Mon Sep 17 00:00:00 2001 From: dyedgreen Date: Sat, 25 Jun 2016 16:45:02 +0200 Subject: [PATCH] New directions ui * Beautiful directions list ui * Fixed a bug where the js part would send too long strings * Fixed a bug where the js part would send directions data although there where to many steps --- package.json | 37 +++++++ resources/images/step_attr.png | Bin 0 -> 360 bytes resources/images/step_forward.png | Bin 0 -> 147 bytes resources/images/step_left.png | Bin 0 -> 569 bytes resources/images/step_right.png | Bin 0 -> 553 bytes resources/images/step_uleft.png | Bin 0 -> 587 bytes resources/images/step_uright.png | Bin 0 -> 588 bytes src/directions_draw.c | 158 +++++++++++++++++++----------- src/directions_draw.h | 4 +- src/directions_window.c | 99 ++++++++++++++++++- src/js/app.js | 30 +++--- src/js/location.js | 26 +++-- 12 files changed, 270 insertions(+), 84 deletions(-) create mode 100644 resources/images/step_attr.png create mode 100644 resources/images/step_forward.png create mode 100644 resources/images/step_left.png create mode 100644 resources/images/step_right.png create mode 100644 resources/images/step_uleft.png create mode 100644 resources/images/step_uright.png diff --git a/package.json b/package.json index 61b4636..1d150e4 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "SUCCESS", "DISTANCE", "TIME", + "INSTRUCTION_ICONS", "INSTRUCTIONS[20]" ], "resources": { @@ -96,6 +97,42 @@ "name": "ICON_ERROR_OTHER", "targetPlatforms": null, "type": "bitmap" + }, + { + "file": "images/step_forward.png", + "name": "ICON_STEP_FORWARD", + "targetPlatforms": null, + "type": "bitmap" + }, + { + "file": "images/step_left.png", + "name": "ICON_STEP_LEFT", + "targetPlatforms": null, + "type": "bitmap" + }, + { + "file": "images/step_uleft.png", + "name": "ICON_STEP_ULEFT", + "targetPlatforms": null, + "type": "bitmap" + }, + { + "file": "images/step_right.png", + "name": "ICON_STEP_RIGHT", + "targetPlatforms": null, + "type": "bitmap" + }, + { + "file": "images/step_uright.png", + "name": "ICON_STEP_URIGHT", + "targetPlatforms": null, + "type": "bitmap" + }, + { + "file": "images/step_attr.png", + "name": "ICON_STEP_ATTR", + "targetPlatforms": null, + "type": "bitmap" } ] } diff --git a/resources/images/step_attr.png b/resources/images/step_attr.png new file mode 100644 index 0000000000000000000000000000000000000000..24ffb32e34d16a231124471ac14a7843e97250bf GIT binary patch literal 360 zcmV-u0hj)XP)4RGwQ%F1Gnfx*c)#cJ-3VuIVPji z3*m-BUDEJ&sXKIai5);4%8(>>w_ZyG1WM066a?R6X1T{GmWgpKP!QNOdkk+SpF=jP zaE>EH8*eYYK?pWzT87V)r)oBU1*90SMejNU*EHh|zao#qd&JXw{k;Omlon)4^_W7y zF(t>MJIH5{j#3=p*mcpetzl*hC(O3)A;)W5BeDJF;F3{|Lc}=^?iUpJ7&5g00000BTJ}G` zSS5XOZ}bX*2`x%`e?#uvpL@JL{YK2amp4M@b)K93+;`%M?&esb^V+O33p$?X6f`Pm v@qcjWImIQZQdF>+l}(`k7Q>H&ugjU%v^WK|m>kOl+QQ)J>gTe~DWM4f1MxPL literal 0 HcmV?d00001 diff --git a/resources/images/step_left.png b/resources/images/step_left.png new file mode 100644 index 0000000000000000000000000000000000000000..3859e0510ce5fb0ce313777affd6640f5f6c0163 GIT binary patch literal 569 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D%zBQrxHN+NuH ztdjF{^%7I^lT!66atnZ}7#M6Stboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?} z6yY17;GAESs$i;TqGzCF$EBd4U{jQmW)z9|8>y;bpKhp88yV>WRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4Z zS&rlwh)=OyF978;K-%jS{YETexQMU5`{<3(+&gAEv zvs%RjMa*vUGKsT=95dhX%HT`U8-^1?ts)+KS4^Izd7UYf>wfIXmcR0PYb#f;=}tEL zUBUG1<j9NU!#XX!i$aK5%BM#hwtgL6uo&ZdBs&lnyyUYc;rU7O8k)9ru?n@<{i q&GtuvY#e_WzhzXMeskeI*&U1zy$rRQHtC%PMY5->pUXO@geCyK1iWGZ literal 0 HcmV?d00001 diff --git a/resources/images/step_right.png b/resources/images/step_right.png new file mode 100644 index 0000000000000000000000000000000000000000..a1a4c4d6533c6145eddb60f24f29096211da3d7c GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D%zBQrxHN+NuH ztdjF{^%7I^lT!66atnZ}7#M6Stboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?} z6yY17;GAESs$i;TqGzCF$EBd4U{jQmW)z9|8>y;bpKhp88yV>WRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4Z zS&rlwh)=7R=-|F%ZvLVm9Fq z_mTgNI~Y4MnUorq^%ZzKJoM(vJ0Pa$bAu&Qm#x@VvHDOW*NLv2BpnWBsekMpj#<(T zGgKT-GzBckOp)d*;8X1F literal 0 HcmV?d00001 diff --git a/resources/images/step_uleft.png b/resources/images/step_uleft.png new file mode 100644 index 0000000000000000000000000000000000000000..31885ee0eb57e64734d220ca067d7765ef7e94f9 GIT binary patch literal 587 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D%zBQrxHN+NuH ztdjF{^%7I^lT!66atnZ}7#M6Stboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?} z6yY17;GAESs$i;TqGzCF$EBd4U{jQmW)z9|8>y;bpKhp88yV>WRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4Z zS&rlwh)=5XSYFOG5p!2G z=Y9W}b3ofT#oL8Rv+Jrtt%dnafVa-TYQd%R$lZ>FVdQ I&MBb@0AtF*Pyhe` literal 0 HcmV?d00001 diff --git a/resources/images/step_uright.png b/resources/images/step_uright.png new file mode 100644 index 0000000000000000000000000000000000000000..6f0c33d8f6388416f5404ad58819ad8781e238f1 GIT binary patch literal 588 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjjKx9jP7LeL$-D%zBQrxHN+NuH ztdjF{^%7I^lT!66atnZ}7#M6Stboki)RIJnirk#MVyg;UC9n!BAR8pCucQE0Qj%?} z6yY17;GAESs$i;TqGzCF$EBd4U{jQmW)z9|8>y;bpKhp88yV>WRp=I1=9MH?=;jqGLkxkLMfuL^+7WFhI$72aI=A0Z9t+{{zaLoK$}74+Zoz`RicPN?Xl4Z zS&rlwh)=iEuY zQzvT|oD^BEc_i>cd(6gtM@6*a?o=PkGi|+<{AgcLoRiA$-z;MPCMnI9xDej~ig!;} KKbLh*2~7ZN<;cVU literal 0 HcmV?d00001 diff --git a/src/directions_draw.c b/src/directions_draw.c index 13a166a..d01ed54 100644 --- a/src/directions_draw.c +++ b/src/directions_draw.c @@ -1,120 +1,160 @@ #include "directions_draw.h" -#define SQUARE_CELL_HEIGHT_SUMMARY 64 -#define SQUARE_CELL_HEIGHT_STEP 122 +// Draw the more indicator and return the new bounds (excluding the space occupied by the more indicator) +GRect directions_draw_more_indicator(GContext *ctx, GRect bounds) { + // Set the colors + GColor color_bg; + GColor color_arrow = GColorBlack; + #ifdef PBL_COLOR + color_bg = GColorLightGray; + #else + color_bg = GColorWhite; + #endif + + // Draw the background + graphics_context_set_fill_color(ctx, color_bg); + graphics_fill_rect(ctx, GRect(0, bounds.size.h - 17, bounds.size.w, 17), 0, GCornerNone); + // Draw the arrow (draws a path) + struct GPathInfo path_arrow_info = { + .num_points = 3, + .points = (GPoint []) { {0,0}, {6,5}, {12,0} }, + }; + GPath *path_arrow = gpath_create(&path_arrow_info); + gpath_move_to(path_arrow, (GPoint) {(bounds.size.w - 12) / 2, bounds.size.h - 10}); + graphics_context_set_fill_color(ctx, color_arrow); + gpath_draw_filled(ctx, path_arrow); + gpath_destroy(path_arrow); + + // Return the new bounds + bounds.size.h -= 15; + return bounds; +} // Work out the height of each cell int16_t directions_get_cell_height(int16_t window_height, int16_t cell_index) { - // Round watches paginate! - #ifdef PBL_ROUND - return window_height; - #endif - // Square watches scroll! - switch (cell_index) { - case 0: - return SQUARE_CELL_HEIGHT_SUMMARY; - break; - default: - return SQUARE_CELL_HEIGHT_STEP; - } + // Each cell occupies an entire screen! + return window_height; } // Draw the title card -void directions_draw_summary(GContext *ctx, GRect bounds, GColor color, int distance, int time) { +void directions_draw_summary(GContext *ctx, GRect bounds, GColor color, int distance, int time, char *string_address) { // Get the strings char string_distance[10]; char string_time[10]; snprintf(string_distance, sizeof(string_distance), "%i m", distance); snprintf(string_time, sizeof(string_time), "%i min", time); + // Get the colors #ifdef PBL_COLOR - GColor color_secondary = GColorDarkGray; + GColor color_distance = GColorDarkGray; #else - GColor color_secondary = GColorWhite; + GColor color_distance = GColorWhite; color = GColorBlack; #endif - // Draw the background - graphics_context_set_fill_color(ctx, color); + + // White background + graphics_context_set_fill_color(ctx, GColorWhite); graphics_fill_rect(ctx, bounds, 0, GCornerNone); + // Draw the more indicator and get the new bounds size + bounds = directions_draw_more_indicator(ctx, bounds); + + // Draw the UI #ifdef PBL_ROUND // ************ // * Round UI * // ************ - // Outside ring - graphics_context_set_fill_color(ctx, GColorWhite); - graphics_fill_radial(ctx, bounds, GOvalScaleModeFitCircle, 30, 0, TRIG_MAX_ANGLE); + // Header bg (takes 1/2 of screen height) + graphics_context_set_fill_color(ctx, color); + graphics_fill_circle(ctx, (GPoint) {bounds.size.w / 2, bounds.size.h / (-2)}, bounds.size.h); // Time - GRect time_box = GRect(4, (bounds.size.h - 46) / 2, bounds.size.w - 8, 28); + GRect time_box = GRect(0, 23, bounds.size.w, 28); graphics_context_set_text_color(ctx, GColorWhite); graphics_draw_text(ctx, string_time, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD), time_box, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); // Distance - GRect distance_box = GRect(4, (bounds.size.h - 46) / 2 + time_box.size.h, bounds.size.w - 8, 18); - graphics_context_set_text_color(ctx, color_secondary); + GRect distance_box = GRect(0, 23 + time_box.size.h, bounds.size.w, 18); + graphics_context_set_text_color(ctx, color_distance); graphics_draw_text(ctx, string_distance, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), distance_box, GTextOverflowModeWordWrap, GTextAlignmentCenter, NULL); + // Address + GRect address_box = GRect(0, 7 + bounds.size.h / 2, bounds.size.w, bounds.size.h / 2 - 14); + GTextAttributes *text_attributes = graphics_text_attributes_create(); + graphics_text_attributes_enable_screen_text_flow(text_attributes, 7); + graphics_context_set_text_color(ctx, color); + graphics_draw_text(ctx, string_address, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), address_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentCenter, text_attributes); + graphics_text_attributes_destroy(text_attributes); #else // ************* // * Square UI * // ************* + // Header bg + GRect header_box = GRect(0, 0, bounds.size.w, 67); + graphics_context_set_fill_color(ctx, color); + graphics_fill_rect(ctx, header_box, 0, GCornerNone); // Time - GRect time_box = GRect(7, 5, bounds.size.w - 14, 28); + GRect time_box = GRect(7, 7, bounds.size.w - 14, 28); graphics_context_set_text_color(ctx, GColorWhite); graphics_draw_text(ctx, string_time, fonts_get_system_font(FONT_KEY_GOTHIC_28_BOLD), time_box, GTextOverflowModeWordWrap, GTextAlignmentLeft, NULL); // Distance - GRect distance_box = GRect(7, time_box.size.h + 5, bounds.size.w - 14, 18); - graphics_context_set_text_color(ctx, color_secondary); + GRect distance_box = GRect(7, 7 + time_box.size.h, bounds.size.w - 14, 18); + graphics_context_set_text_color(ctx, color_distance); graphics_draw_text(ctx, string_distance, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), distance_box, GTextOverflowModeWordWrap, GTextAlignmentLeft, NULL); + // Address + GRect address_box = GRect(7, 7 + header_box.size.h, bounds.size.w - 14, bounds.size.h - header_box.size.h - 14); + graphics_context_set_text_color(ctx, color); + graphics_draw_text(ctx, string_address, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), address_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL); #endif } // Draw a step -void directions_draw_step(GContext *ctx, GRect bounds, GColor color, char *text, int16_t data_index, int16_t data_count) { +void directions_draw_step(GContext *ctx, GRect bounds, GColor color, char *text, GBitmap *step_icon, int16_t data_index, int16_t data_count) { // Get the colors - #ifdef PBL_COLOR - GColor color_text = GColorDarkGray; - #else - GColor color_text = GColorBlack; - color = GColorBlack; + #ifdef PBL_BW + color = GColorWhite; #endif - // Draw the background + GColor color_text = GColorBlack; + + // White background graphics_context_set_fill_color(ctx, GColorWhite); graphics_fill_rect(ctx, bounds, 0, GCornerNone); + // Draw the more indicator and get the new bounds size (if this is not the last cell) + if (data_index + 1 < data_count) { + bounds = directions_draw_more_indicator(ctx, bounds); + } + + // Draw the UI #ifdef PBL_ROUND // ************ // * Round UI * // ************ - // Draw text - GRect text_box = GRect(5, (bounds.size.w - 96) / 2, bounds.size.w - 10, 96); - GTextAttributes *text_attributes = graphics_text_attributes_create(); - graphics_text_attributes_enable_screen_text_flow(text_attributes, 5); - graphics_context_set_text_color(ctx, color_text); - graphics_draw_text(ctx, text, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), text_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentCenter, text_attributes); - graphics_text_attributes_destroy(text_attributes); - // Draw more indicators + // Draw header / icon bg (takes 60px of screen height) graphics_context_set_fill_color(ctx, color); - if (data_index < data_count - 1) { - // Bottom - graphics_fill_circle(ctx, GPoint(bounds.size.w / 2, bounds.size.h), 8); - } - if (data_index > 0) { - // Top - graphics_fill_circle(ctx, GPoint(bounds.size.w / 2, 0), 8); - } + graphics_fill_circle(ctx, GPoint(bounds.size.w / 2, -80), 140); + // Draw icon + graphics_context_set_compositing_mode(ctx, GCompOpSet); + graphics_draw_bitmap_in_rect(ctx, step_icon, GRect((bounds.size.w - 24) / 2, 24, 24, 24)); + // Draw text + GRect text_box = GRect(0, 67, bounds.size.w, bounds.size.h - 74); + GTextAttributes *text_attributes = graphics_text_attributes_create(); + graphics_text_attributes_enable_screen_text_flow(text_attributes, 7); + graphics_context_set_text_color(ctx, color_text); + graphics_draw_text(ctx, text, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), text_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentCenter, text_attributes); + graphics_text_attributes_destroy(text_attributes); #else // ************* // * Square UI * // ************* + // Draw header/icon bg + GRect header_box = GRect(0, 0, bounds.size.w, 52); + graphics_context_set_fill_color(ctx, color); + graphics_fill_rect(ctx, header_box, 0, GCornerNone); + // Draw icon + graphics_context_set_compositing_mode(ctx, GCompOpSet); + graphics_draw_bitmap_in_rect(ctx, step_icon, GRect((bounds.size.w - 24) / 2, 14, 24, 24)); // Draw text - GRect text_box = GRect(7, 3, bounds.size.w - 14, bounds.size.h - 6); + GRect text_box = GRect(7, 7 + header_box.size.h, bounds.size.w - 14, bounds.size.h - header_box.size.h - 14); graphics_context_set_text_color(ctx, color_text); - graphics_draw_text(ctx, text, fonts_get_system_font(FONT_KEY_GOTHIC_24_BOLD), text_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL); - // Draw block-end indicator (if not last block) - if (data_index < data_count - 1) { - GRect line_box = GRect(7, text_box.size.h + 1, 40, 4); - graphics_context_set_fill_color(ctx, color); - graphics_fill_rect(ctx, line_box, 2, GCornersAll); - } + graphics_draw_text(ctx, text, fonts_get_system_font(FONT_KEY_GOTHIC_18_BOLD), text_box, GTextOverflowModeTrailingEllipsis, GTextAlignmentLeft, NULL); #endif } diff --git a/src/directions_draw.h b/src/directions_draw.h index ccaba76..e1fdecd 100644 --- a/src/directions_draw.h +++ b/src/directions_draw.h @@ -4,5 +4,5 @@ // Return the height of a cell (this groupes layout functions in one file) int16_t directions_get_cell_height(int16_t window_height, int16_t cell_index); // Draw cells -void directions_draw_summary(GContext *ctx, GRect bounds, GColor color, int distance, int time); -void directions_draw_step(GContext *ctx, GRect bounds, GColor color, char *text, int16_t data_index, int16_t data_count); +void directions_draw_summary(GContext *ctx, GRect bounds, GColor color, int distance, int time, char *address); +void directions_draw_step(GContext *ctx, GRect bounds, GColor color, char *text, GBitmap *step_icon, int16_t data_index, int16_t data_count); diff --git a/src/directions_window.c b/src/directions_window.c index 1eb5ce2..2fedfce 100644 --- a/src/directions_window.c +++ b/src/directions_window.c @@ -9,6 +9,7 @@ #define PROGRESS_SEARCH_SEND 50 #define PROGRESS_DISTANCE_RECIVED 80 #define PROGRESS_TIME_RECIVED PROGRESS_DISTANCE_RECIVED +#define PROGRESS_ICONS_RECIVED PROGRESS_DISTANCE_RECIVED #define PROGRESS_STEP_RECIVED 95 #define PROGRESS_SUCCESS_RECIVED 100 @@ -17,6 +18,7 @@ struct RouteData { // Data fields int distance; int time; + char icons[MAX_STEP_COUNT + 1]; char steps[MAX_STEP_COUNT][MAX_STEP_CHARS]; int count; }; @@ -28,6 +30,15 @@ static int window_height; static MenuLayer *directions_list; static GColor selected_type_color; +// Step icons +static GBitmap *icon_step_type; +static GBitmap *icon_step_forward; +static GBitmap *icon_step_right; +static GBitmap *icon_step_left; +static GBitmap *icon_step_uright; +static GBitmap *icon_step_uleft; +static GBitmap *icon_step_attr; + // Dictation input static DictationSession *dictation_session; static char *address; @@ -58,15 +69,44 @@ static int16_t get_cell_height_callback(struct MenuLayer *menu_layer, MenuIndex // Draw menu cell callback static void draw_row_callback(GContext *ctx, const Layer *cell_layer, MenuIndex *cell_index, void *context) { - // Determine what row to draw TODO: implement nicer UI + // Local vars + int data_index = cell_index->row - 1; + GBitmap *icon; + // Determine what row to draw switch (cell_index->row) { // Summary case 0: - directions_draw_summary(ctx, layer_get_bounds(cell_layer), selected_type_color, route_data->distance, route_data->time); + directions_draw_summary(ctx, layer_get_bounds(cell_layer), selected_type_color, route_data->distance, route_data->time, address); break; // Step description default: - directions_draw_step(ctx, layer_get_bounds(cell_layer), selected_type_color, route_data->steps[cell_index->row - 1], cell_index->row - 1, (int16_t)route_data->count); + // Select the correct icon + switch (route_data->icons[data_index]) { + case 'a': + icon = icon_step_type; + break; + case 'b': + icon = icon_step_forward; + break; + case 'c': + icon = icon_step_right; + break; + case 'd': + icon = icon_step_left; + break; + case 'e': + icon = icon_step_uright; + break; + case 'f': + icon = icon_step_uleft; + break; + case 'g': + icon = icon_step_attr; + break; + default: + icon = icon_step_type; + } + directions_draw_step(ctx, layer_get_bounds(cell_layer), selected_type_color, route_data->steps[data_index], icon, data_index, (int16_t)route_data->count); } } @@ -144,6 +184,16 @@ static void app_message_inbox_recived_callback(DictionaryIterator *iter, void *c route_data->time = (int)message->value->int32; } + // Test if the recived message is fof key INSTRUCTION_ICONS + message = dict_find(iter, MESSAGE_KEY_INSTRUCTION_ICONS); + if (message) { + // Set the progress + progress_layer_set_progress(progress_layer, PROGRESS_ICONS_RECIVED, true); + // Copy the icon string + strcpy(route_data->icons, message->value->cstring); + route_data->icons[MAX_STEP_COUNT] = '\0'; + } + // 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); @@ -212,6 +262,11 @@ static void app_message_start() { route_data->distance = 0; route_data->time = 0; route_data->count = 0; + // Initialise the icons string (has the length of MAX_STEP_COUNT + 1 for correct null termination) + for (int i = 0; i < MAX_STEP_COUNT; i ++) { + route_data->icons[i] = 'a'; + } + route_data->icons[MAX_STEP_COUNT] = '\0'; // Register all callbacks app_message_register_inbox_received(app_message_inbox_recived_callback); app_message_register_inbox_dropped(app_message_inbox_dropped_callback); @@ -274,6 +329,15 @@ static void window_unload() { // Destroy the window window_destroy(window); window = NULL; + + // Destroy the step icons + gbitmap_destroy(icon_step_type); + gbitmap_destroy(icon_step_forward); + gbitmap_destroy(icon_step_right); + gbitmap_destroy(icon_step_left); + gbitmap_destroy(icon_step_uright); + gbitmap_destroy(icon_step_uleft); + gbitmap_destroy(icon_step_attr); } static void window_disappear() { @@ -328,6 +392,35 @@ static void window_load() { // Create the progress layer progress_layer = progress_layer_create(bounds); + + // Create the step icon resources + switch (selected_type_enum) { + case 0: + // Car icon + icon_step_type = gbitmap_create_with_resource(RESOURCE_ID_ICON_CAR_BLACK); + break; + case 1: + // Bike icon + icon_step_type = gbitmap_create_with_resource(RESOURCE_ID_ICON_BIKE_BLACK); + break; + case 2: + // Train icon + icon_step_type = gbitmap_create_with_resource(RESOURCE_ID_ICON_TRAIN_BLACK); + break; + case 3: + // Walk icon + icon_step_type = gbitmap_create_with_resource(RESOURCE_ID_ICON_WALK_BLACK); + break; + default: + // Forward icon + icon_step_type = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_FORWARD); + } + icon_step_forward = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_FORWARD); + icon_step_right = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_RIGHT); + icon_step_left = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_LEFT); + icon_step_uright = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_URIGHT); + icon_step_uleft = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_ULEFT); + icon_step_attr = gbitmap_create_with_resource(RESOURCE_ID_ICON_STEP_ATTR); } // Push the window to the window stack diff --git a/src/js/app.js b/src/js/app.js index 2140285..a107c76 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -4,8 +4,9 @@ * 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 +* (2) Step icon data is send as a 20 char string (each char encodes one icon!) +* (3) Step data array is send (each step string, max 20 entrys) -> THE LAST SEND INDEX IS THE LENGTH! +* (4) 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) * @@ -21,12 +22,17 @@ * 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; +* +* About the step icon data string +* ––– +* Chars map to the following icons: type: 'a', forward: 'b', right: 'c', left: 'd', uRight: 'e', uLeft: 'f', attr: 'g' */ // Data keys var keys = require('message_keys'); var maxStepCount = 20; +var maxStepStringLength = 128; var currentMessageNumber = 0; var messagePadding = 10; @@ -55,16 +61,13 @@ function sendStepItem(stepList, index, messageNumber) { // Build message var key = keys.INSTRUCTIONS + index; var dict = {}; - dict[key] = stepList[index]; + dict[key] = stepList[index].substr(0, maxStepStringLength); // Send message to pebble Pebble.sendAppMessage(dict, function() { // Success, send next item index ++; - if (maxStepCount > stepList.length) { - // Too many steps error - sendSuccess(2, messageNumber); - } else if (index < stepList.length && index < maxStepCount) { + if (index < stepList.length && index < maxStepCount) { // Recursive callbacks, hell yeah! sendStepItem(stepList, index, messageNumber); } else { @@ -77,15 +80,17 @@ function sendStepItem(stepList, index, messageNumber) { }); } -function sendRoute(success, distance, time, stepList, stepIconList, messageNumber) { +function sendRoute(success, distance, time, stepList, stepIconsString, messageNumber) { // Send message to pebble if a route was found - if (success) { + if (success && maxStepCount >= stepList.length) { // Build message var keyDistance = keys.DISTANCE; var keyTime = keys.TIME; + var keyIcons = keys.INSTRUCTION_ICONS; var dict = {}; dict[keyDistance] = +distance; dict[keyTime] = +time; + dict[keyIcons] = ''.concat(stepIconsString); // Transmit Pebble.sendAppMessage(dict, function() { @@ -95,6 +100,9 @@ function sendRoute(success, distance, time, stepList, stepIconList, messageNumbe // Error console.log('Transmission failed at [OVERVIEW]'); }); + } else if (maxStepCount < stepList.length) { + // Too many steps error + sendSuccess(2, messageNumber); } else { // Send error message (route not found) sendSuccess(1, messageNumber); @@ -106,9 +114,9 @@ function fetchAndSendRoute(routeType, searchText, messageNumber) { // Log the recived data console.log('Route type:', routeType); console.log('Search text:', searchText); - // Load a route from here api. Data format: { distance, time, stepList[string], stepIconList[int] } + // Load a route from here api. Data format: { distance, time, stepList[string], stepIconsString } locationService.createRoute(routeType, searchText, function(success, data) { - sendRoute(success, data.distance, data.time, data.stepList, data.stepIconList, messageNumber); + sendRoute(success, data.distance, data.time, data.stepList, data.stepIconsString, messageNumber); }); } diff --git a/src/js/location.js b/src/js/location.js index ceb8d46..8bbca1b 100644 --- a/src/js/location.js +++ b/src/js/location.js @@ -82,7 +82,15 @@ function loadRouteData(routeType, fromLat, fromLon, toLat, toLon, callback) { // Transport modes, mapped to pebble ids var modes = ['car', 'bicycle', 'publicTransport', 'pedestrian']; // Pebble direction icons, mapped to pebble ids (type = show nav type icon, attr = show attribution icon) - var icons = ['type', 'forward', 'right', 'left', 'uRight', 'uLeft', 'attr']; + var icons = { + type: 'a', + forward: 'b', + right: 'c', + left: 'd', + uRight: 'e', + uLeft: 'f', + attr: 'g', + }; // Maps the direction retrived from here api to icon name var directionMap = { forward: 'forward', @@ -107,14 +115,14 @@ function loadRouteData(routeType, fromLat, fromLon, toLat, toLon, callback) { if (success) { // Success (will fail if expected fields are not available in response) try { - // Our route data will go here. Format: { distance, time, stepList[string], stepIconList[int] } + // Our route data will go here. Format: { distance, time, stepList[string], stepIconsString[int] } var routeData = {}; // Get the summary routeData.distance = res.response.route[0].summary.distance; /* in meters */ routeData.time = Math.ceil(res.response.route[0].summary.travelTime / 60); /* in minutes */ // Get the steps routeData.stepList = []; - routeData.stepIconList = []; + routeData.stepIconsString = ''; res.response.route[0].leg[0].maneuver.forEach(function(step, index) { // Add the text routeData.stepList[index] = step.instruction; @@ -122,21 +130,21 @@ function loadRouteData(routeType, fromLat, fromLon, toLat, toLon, callback) { if (step.hasOwnProperty('direction')) { // Display the specified icon if (directionMap.hasOwnProperty(step.direction)) { - routeData.stepIconList[index] = icons.indexOf(directionMap[step.direction]); + routeData.stepIconsString = routeData.stepIconsString.concat(icons[directionMap[step.direction]]); } else { // Display the travel type icon - routeData.stepIconList[index] = icons.indexOf('type'); + routeData.stepIconsString = routeData.stepIconsString.concat(icons['type']); } } else { // Display the travel type icon - routeData.stepIconList[index] = icons.indexOf('type'); + routeData.stepIconsString = routeData.stepIconsString.concat(icons['type']); } }); // Test for attribution if (res.response.hasOwnProperty('sourceAttribution')) { // Add attribution text as last list entry, removing all html markup from it routeData.stepList.push(res.response.sourceAttribution.attribution.replace(/<.+?>/g, '')); - routeData.stepIconList.push(icons.indexOf('attr')); + routeData.stepIconsString = routeData.stepIconsString.concat(icons['attr']); } // We are done callback(true, routeData); @@ -147,7 +155,7 @@ function loadRouteData(routeType, fromLat, fromLon, toLat, toLon, callback) { // Error routeErrorCallback(callback); } - }, true); + }); } // Performs all the steps neccessary to return a complete route (the callback takes: success / route data) @@ -173,7 +181,7 @@ function createRoute(routeType, searchText, callback) { } // Helper function to define createRoute error callback all in one place function routeErrorCallback(callback) { - callback(false, { distance: 0, time: 0, stepList: [], stepIconList: [] }); + callback(false, { distance: 0, time: 0, stepList: [], stepIconsString: '' }); }