From f051beb603a481e00a51a8c742cbce765392ad8b Mon Sep 17 00:00:00 2001 From: JumpMaster Date: Thu, 17 Apr 2014 01:56:05 -0700 Subject: [PATCH] improved display function Faster cycle through codes --- appinfo.json | 4 +- src/js/pebble-js-app.js | 2 +- src/main.c | 286 ++++++++++++++++++++++------------------ src/main.h | 3 + wscript | 40 ++++++ 5 files changed, 202 insertions(+), 133 deletions(-) create mode 100644 wscript diff --git a/appinfo.json b/appinfo.json index 04c7a4d..37b66ef 100644 --- a/appinfo.json +++ b/appinfo.json @@ -1,5 +1,5 @@ { - "versionLabel": "1.2", + "versionLabel": "1.3", "uuid": "1f4d9835-3b9a-4ddd-907e-41a25d06f19c", "appKeys": { "transmit_key": 2, @@ -12,7 +12,7 @@ "timezone": 3 }, "longName": "PebbleAuth", - "versionCode": 4, + "versionCode": 5, "capabilities": [ "configurable" ], diff --git a/src/js/pebble-js-app.js b/src/js/pebble-js-app.js index 2af5f79..d7267b3 100644 --- a/src/js/pebble-js-app.js +++ b/src/js/pebble-js-app.js @@ -8,7 +8,7 @@ var font_style = 0; var timezoneOffset = 0; var message_send_retries = 0; var message_send_max_retries = 5; -var app_version = 4; +var app_version = 5; var debug = false; function loadLocalVariables() { diff --git a/src/main.c b/src/main.c index b147a2a..e17a3da 100644 --- a/src/main.c +++ b/src/main.c @@ -1,5 +1,5 @@ // -// Copyright 2014. +// Copyright 2014 // PebbleAuth for the Pebble Smartwatch // Author: Kevin Cooper // https://github.com/JumpMaster/PebbleAuth @@ -49,8 +49,9 @@ static AppFont font_label; static GFont font_UNISPACE_20; bool perform_full_refresh = true; // Start refreshing at launch -bool finish_refresh = true; // The text boxes are places offscreen to just whiz them back on bool fonts_changed; +bool loading_complete = false; +bool animation_running = false; unsigned int details_selected_key = 0; unsigned int js_message_retry_count = 0; @@ -93,13 +94,17 @@ enum { JS_FONT_STYLE }; -void refresh_screen_data() { +void refresh_screen_data(bool flyUp) { perform_full_refresh = true; + + if (loading_complete) { + start_refreshing(flyUp); + } } void update_screen_fonts() { fonts_changed = true; - refresh_screen_data(); + refresh_screen_data(false); } void expand_key(char *inputString, bool new_code) { @@ -140,7 +145,7 @@ void expand_key(char *inputString, bool new_code) { if (otp_selected != i) otp_selected = i; - refresh_screen_data(); + refresh_screen_data(false); } } } @@ -157,7 +162,7 @@ void expand_key(char *inputString, bool new_code) { } watch_otp_count++; otp_selected = watch_otp_count-1; - refresh_screen_data(); + refresh_screen_data(false); } if (phone_otp_count > 0 && phone_otp_count < requesting_code) { @@ -172,94 +177,114 @@ void on_animation_stopped(Animation *anim, bool finished, void *context) { property_animation_destroy((PropertyAnimation*) anim); } -void animate_layer(Layer *layer, AnimationCurve curve, GRect *start, GRect *finish, int duration, int delay) { +void on_animation_stopped_finish(Animation *anim, bool finished, void *context) { + //Free the memory used by the Animation + property_animation_destroy((PropertyAnimation*) anim); + + finish_refreshing(); +} + +void animate_layer(Layer *layer, AnimationCurve curve, GRect *start, GRect *finish, int duration, bool finish_after_animation) { //Declare animation PropertyAnimation *anim = property_animation_create_layer_frame(layer, start, finish); //Set characteristics animation_set_duration((Animation*) anim, duration); - animation_set_delay((Animation*) anim, delay); animation_set_curve((Animation*) anim, curve); - //Set stopped handler to free memory - AnimationHandlers handlers = { - //The reference to the stopped handler is the only one in the array - .stopped = (AnimationStoppedHandler) on_animation_stopped - }; - animation_set_handlers((Animation*) anim, handlers, NULL); + if (finish_after_animation) { + //Set stopped handler to free memory + AnimationHandlers handlers = { + .stopped = (AnimationStoppedHandler) on_animation_stopped_finish + }; + animation_set_handlers((Animation*) anim, handlers, NULL); + } else { + AnimationHandlers handlers = { + .stopped = (AnimationStoppedHandler) on_animation_stopped + }; + animation_set_handlers((Animation*) anim, handlers, NULL); + } //Start animation! animation_schedule((Animation*) anim); } -static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed) { - - int seconds = tick_time->tm_sec; - - if (seconds % 30 == 0) - otp_update_tick++; - - if (!finish_refresh && - (perform_full_refresh || seconds == 29 || seconds == 59 || otp_updated_at_tick != otp_update_tick)) +void start_refreshing(bool flyUp) { + if (perform_full_refresh) { - if (perform_full_refresh) - { - GRect finish = text_label_rect; + GRect finish = text_label_rect; + if (flyUp) + finish.origin.y = -80; + else finish.origin.y = 154; - animate_layer(text_layer_get_layer(text_label_layer), AnimationCurveEaseIn, &text_label_rect, &finish, 300, 0); - } - - GRect finish = text_pin_rect; - finish.origin.y = 184; - animate_layer(text_layer_get_layer(text_pin_layer), AnimationCurveEaseIn, &text_pin_rect, &finish, 300, 0); - finish_refresh = true; + animate_layer(text_layer_get_layer(text_label_layer), AnimationCurveEaseIn, &text_label_rect, &finish, 300, false); } - else if (finish_refresh) - { - if (perform_full_refresh) - { - if (watch_otp_count) - strcpy(label_text, otp_labels[otp_selected]); - else - strcpy(label_text, "NO"); - - if (fonts_changed) { - set_fonts(); - fonts_changed = false; - } - - GRect start = text_label_rect; - start.origin.x = 144; - animate_layer(text_layer_get_layer(text_label_layer), AnimationCurveEaseOut, &start, &text_label_rect, 300, 0); - perform_full_refresh = false; - } + + GRect finish = text_pin_rect; + if (flyUp) + finish.origin.y = -50; + else + finish.origin.y = 184; + animate_layer(text_layer_get_layer(text_pin_layer), AnimationCurveEaseIn, &text_pin_rect, &finish, 300, true);; +} +void finish_refreshing() { + if (perform_full_refresh) + { if (watch_otp_count) - strcpy(pin_text, generateCode(otp_keys[otp_selected], timezone_offset)); + strcpy(label_text, otp_labels[otp_selected]); else - strcpy(pin_text, "SECRETS"); + strcpy(label_text, "NO"); - otp_updated_at_tick = otp_update_tick; - finish_refresh = false; + if (fonts_changed) { + set_fonts(); + fonts_changed = false; + } - GRect start = text_pin_rect; + GRect start = text_label_rect; start.origin.x = 144; - animate_layer(text_layer_get_layer(text_pin_layer), AnimationCurveEaseOut, &start, &text_pin_rect, 300, 0); + animate_layer(text_layer_get_layer(text_label_layer), AnimationCurveEaseOut, &start, &text_label_rect, 300, false); + perform_full_refresh = false; } + if (watch_otp_count) + strcpy(pin_text, generateCode(otp_keys[otp_selected], timezone_offset)); + else + strcpy(pin_text, "SECRETS"); + + otp_updated_at_tick = otp_update_tick; + + GRect start = text_pin_rect; + start.origin.x = 144; + animate_layer(text_layer_get_layer(text_pin_layer), AnimationCurveEaseOut, &start, &text_pin_rect, 300, false); +} + +static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed) { + + int seconds = tick_time->tm_sec; + + if (seconds % 30 == 0) + otp_update_tick++; + + if (otp_updated_at_tick != otp_update_tick) + start_refreshing(false); + + // + // update countdown layer + // Layer *window_layer = window_get_root_layer(main_window); GRect bounds = layer_get_bounds(window_layer); GRect start = layer_get_frame(text_layer_get_layer(countdown_layer)); GRect finish = (GRect(0, bounds.size.h-10, bounds.size.w, 10)); - float boxsize = (30-(seconds%30))/((double)30); + float boxpercent = (30-(seconds%30))/((double)30); - finish.size.w = finish.size.w * boxsize; + finish.size.w = finish.size.w * boxpercent; if (seconds % 30 == 0) - animate_layer(text_layer_get_layer(countdown_layer), AnimationCurveEaseInOut, &start, &finish, 900, 0); + animate_layer(text_layer_get_layer(countdown_layer), AnimationCurveEaseInOut, &start, &finish, 900, false); else - animate_layer(text_layer_get_layer(countdown_layer), AnimationCurveLinear, &start, &finish, 900, 0); + animate_layer(text_layer_get_layer(countdown_layer), AnimationCurveLinear, &start, &finish, 900, false); } void up_single_click_handler(ClickRecognizerRef recognizer, void *context) { @@ -269,7 +294,7 @@ void up_single_click_handler(ClickRecognizerRef recognizer, void *context) { else otp_selected--; - refresh_screen_data(); + refresh_screen_data(false); } } @@ -280,7 +305,7 @@ void down_single_click_handler(ClickRecognizerRef recognizer, void *context) { else otp_selected++; - refresh_screen_data(); + refresh_screen_data(true); } } @@ -312,58 +337,13 @@ void request_key(int code_id) { sendJSMessage(TupletInteger(JS_REQUEST_KEY, code_id)); } -static void key_menu_select_callback(int index, void *ctx) { - details_selected_key = index; - window_stack_push(details_window, true /* Animated */); -} - -static void select_window_load(Window *window) { - - int num_menu_items = 0; - - for(unsigned int i = 0; i < watch_otp_count; i++) { - if (DEBUG) { - key_menu_items[num_menu_items++] = (SimpleMenuItem) { - .title = otp_labels[i], - .callback = key_menu_select_callback, - .subtitle = otp_keys[i], - }; - } - else { - key_menu_items[num_menu_items++] = (SimpleMenuItem) { - .title = otp_labels[i], - .callback = key_menu_select_callback, - }; - } - } - - // Bind the menu items to the corresponding menu sections - key_menu_sections[0] = (SimpleMenuSection){ - .num_items = num_menu_items, - .items = key_menu_items, - }; - - Layer *select_window_layer = window_get_root_layer(select_window); - GRect bounds = layer_get_frame(select_window_layer); - - // Initialize the simple menu layer - key_menu_layer = simple_menu_layer_create(bounds, select_window, key_menu_sections, 1, NULL); - - // Add it to the window for display - layer_add_child(select_window_layer, simple_menu_layer_get_layer(key_menu_layer)); -} - -void select_window_unload(Window *window) { - simple_menu_layer_destroy(key_menu_layer); -} - void details_actionbar_up_click_handler(ClickRecognizerRef recognizer, void *context) { otp_default = details_selected_key; persist_write_int(PS_DEFAULT_KEY, otp_default); if (otp_selected != otp_default) { otp_selected = otp_default; - refresh_screen_data(); + refresh_screen_data(false); } window_stack_remove(select_window, false); @@ -382,7 +362,6 @@ void details_actionbar_config_provider(void *context) { window_single_click_subscribe(BUTTON_ID_DOWN, (ClickHandler) details_actionbar_down_click_handler); } - static void details_window_load(Window *window) { Layer *details_window_layer = window_get_root_layer(details_window); @@ -436,11 +415,72 @@ void details_window_unload(Window *window) { text_layer_destroy(details_title_layer); text_layer_destroy(details_key_layer); fonts_unload_custom_font(font_UNISPACE_20); + window_destroy(details_window); +} + +static void key_menu_select_callback(int index, void *ctx) { + details_selected_key = index; + + details_window = window_create(); + window_set_window_handlers(details_window, (WindowHandlers) { + .load = details_window_load, + .unload = details_window_unload, + }); + + window_stack_push(details_window, true /* Animated */); +} + +static void select_window_load(Window *window) { + + int num_menu_items = 0; + + for(unsigned int i = 0; i < watch_otp_count; i++) { + if (DEBUG) { + key_menu_items[num_menu_items++] = (SimpleMenuItem) { + .title = otp_labels[i], + .callback = key_menu_select_callback, + .subtitle = otp_keys[i], + }; + } + else { + key_menu_items[num_menu_items++] = (SimpleMenuItem) { + .title = otp_labels[i], + .callback = key_menu_select_callback, + }; + } + } + + // Bind the menu items to the corresponding menu sections + key_menu_sections[0] = (SimpleMenuSection){ + .num_items = num_menu_items, + .items = key_menu_items, + }; + + Layer *select_window_layer = window_get_root_layer(select_window); + GRect bounds = layer_get_frame(select_window_layer); + + // Initialize the simple menu layer + key_menu_layer = simple_menu_layer_create(bounds, select_window, key_menu_sections, 1, NULL); + + // Add it to the window for display + layer_add_child(select_window_layer, simple_menu_layer_get_layer(key_menu_layer)); +} + +void select_window_unload(Window *window) { + simple_menu_layer_destroy(key_menu_layer); + window_destroy(select_window); } void select_single_click_handler(ClickRecognizerRef recognizer, void *context) { - if (watch_otp_count) + if (watch_otp_count) { + select_window = window_create(); + window_set_window_handlers(select_window, (WindowHandlers) { + .load = select_window_load, + .unload = select_window_unload, + }); + window_stack_push(select_window, true /* Animated */); + } } void window_config_provider(Window *window) { @@ -607,7 +647,7 @@ static void in_received_handler(DictionaryIterator *iter, void *context) { if (otp_selected >= key_found) { if (otp_selected == key_found) - refresh_screen_data(); + refresh_screen_data(false); otp_selected--; } @@ -621,7 +661,7 @@ static void in_received_handler(DictionaryIterator *iter, void *context) { if (tz_offset != timezone_offset) { timezone_offset = tz_offset; persist_write_int(PS_TIMEZONE_KEY, timezone_offset); - refresh_screen_data(); + refresh_screen_data(false); } if (DEBUG) APP_LOG(APP_LOG_LEVEL_DEBUG, "Timezone Offset: %d", timezone_offset); @@ -715,8 +755,8 @@ static void window_load(Window *window) { set_theme(); set_fonts(); - - refresh_screen_data(); + loading_complete = true; + finish_refreshing(); } void window_unload(Window *window) { @@ -735,18 +775,6 @@ void handle_init(void) { .unload = window_unload, }); - select_window = window_create(); - window_set_window_handlers(select_window, (WindowHandlers) { - .load = select_window_load, - .unload = select_window_unload, - }); - - details_window = window_create(); - window_set_window_handlers(details_window, (WindowHandlers) { - .load = details_window_load, - .unload = details_window_unload, - }); - window_stack_push(main_window, true /* Animated */); app_message_register_inbox_received(in_received_handler); @@ -765,8 +793,6 @@ void handle_deinit(void) { fonts_unload_custom_font(font_label.font); if (font_pin.isCustom) fonts_unload_custom_font(font_pin.font); - window_destroy(details_window); - window_destroy(select_window); window_destroy(main_window); } diff --git a/src/main.h b/src/main.h index 6d3e5d5..669416f 100644 --- a/src/main.h +++ b/src/main.h @@ -28,5 +28,8 @@ typedef struct { void window_config_provider(Window *window); void request_key(int code_id); void set_fonts(); +static void handle_second_tick(struct tm *tick_time, TimeUnits units_changed); +void start_refreshing(bool flyUp); +void finish_refreshing(); #endif /* _MAIN_H_ */ \ No newline at end of file diff --git a/wscript b/wscript new file mode 100644 index 0000000..0b9279e --- /dev/null +++ b/wscript @@ -0,0 +1,40 @@ + +# +# This file is the default set of rules to compile a Pebble project. +# +# Feel free to customize this to your needs. +# + +try: + from sh import jshint, ErrorReturnCode_2 + hint = jshint +except ImportError: + hint = None + +top = '.' +out = 'build' + +def options(ctx): + ctx.load('pebble_sdk') + +def configure(ctx): + ctx.load('pebble_sdk') + global hint + if hint is not None: + hint = hint.bake(['--config', 'pebble-jshintrc']) + +def build(ctx): + if False and hint is not None: + try: + hint("src/js/pebble-js-app.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) + + ctx.load('pebble_sdk') + + ctx.pbl_program(source=ctx.path.ant_glob('src/**/*.c'), + target='pebble-app.elf') + + ctx.pbl_bundle(elf='pebble-app.elf', + js=ctx.path.ant_glob('src/js/**/*.js')) +