Skip to content

Commit

Permalink
Merge branch 'flyout-anim': add segment view flyout/flyin animations
Browse files Browse the repository at this point in the history
* flyout-anim:
  Remove flyin/flyout animation from TODO
  Change parameter name in progress_layer_init for clarity
  Use accessors for layer frame get and set
  I should probably be updating the app version define
  Add comments to flyout animation
  Push sublayer removal into flyout animation
  Factor flyout animation out of segment view
  Factor progress layer out of segment view
  Clean up some variables and code cruft
  Fix a bug where flyin/out occurred even if segment type wasn't changing
  Hack a Z-order bug affecting fly in/out animation and add a TODO
  Add reworked flyout animation and new flyin animation
  Add a terrible first hack flyout animation for segment layer
  • Loading branch information
jonspeicher committed Sep 23, 2013
2 parents 99fe95a + c828686 commit eaddcac
Show file tree
Hide file tree
Showing 9 changed files with 231 additions and 49 deletions.
9 changes: 7 additions & 2 deletions TODO.markdown
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# To Do

* Add fancy flyout animation when changing the segment view from pomodoro to
break and vice-versa
* Make pomodoro, short, and long break intervals configurable?
* Add a stats module that tracks complete and aborts
* Add a stats page that shows complete/abort percentages, averages, and etc.
Expand All @@ -13,3 +11,10 @@
countdown hasn't elapsed
* The code isn't bulletproof
* Null pointers aren't checked
* There are some leaky abstractions
* The segment view knows that the window it's added to has an action bar
* The pomodoro controller initializes the segment view and the countdown
view in a specific order to ensure that the resultant layer Z order is
correct
* A timer window "class" or something could help with this but that seems
like overkill at this point
8 changes: 5 additions & 3 deletions src/countdown_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ void countdown_view_show_abort() {
// Private functions ----------------------------------------------------------

void load_and_add_view(Window* window, ClickConfigProvider provider) {
GRect window_frame, text_layer_frame;

heap_bitmap_init(&icons.start, RESOURCE_ID_ICON_START);
heap_bitmap_init(&icons.restart, RESOURCE_ID_ICON_RESTART);
heap_bitmap_init(&icons.abort, RESOURCE_ID_ICON_ABORT);
Expand All @@ -85,9 +87,9 @@ void load_and_add_view(Window* window, ClickConfigProvider provider) {
action_bar_layer_add_to_window(&action_bar, window);
action_bar_layer_set_click_config_provider(&action_bar, provider);

// TBD: Is there a nicer way to do this? - JRS 8/16
text_layer_init(&countdown_text_layer, GRect(0, 20,
window->layer.frame.size.w - ACTION_BAR_WIDTH, 55));
window_frame = layer_get_frame(&window->layer);
text_layer_frame = GRect(0, 20, window_frame.size.w - ACTION_BAR_WIDTH, 55);
text_layer_init(&countdown_text_layer, text_layer_frame);
text_layer_set_text_alignment(&countdown_text_layer, GTextAlignmentCenter);
text_layer_set_font(&countdown_text_layer,
fonts_get_system_font(FONT_KEY_BITHAM_42_LIGHT));
Expand Down
61 changes: 61 additions & 0 deletions src/flyout_animation.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// ----------------------------------------------------------------------------
// flyout_animation - Switches between two layers with flyout/flyin animation
// Copyright (c) 2013 Jonathan Speicher ([email protected])
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// ----------------------------------------------------------------------------

#include <pebble_os.h>
#include "flyout_animation.h"

// Public functions -----------------------------------------------------------

void flyout_animation_init(FlyoutAnimation* animation, Layer* on, Layer* off) {
GRect on_screen_frame, off_screen_frame;

animation->on_screen_layer = on;
animation->off_screen_layer = off;

on_screen_frame = layer_get_frame(animation->on_screen_layer);
animation->target_rect = on_screen_frame;

off_screen_frame = on_screen_frame;
off_screen_frame.origin.x = -on_screen_frame.size.w;
layer_set_frame(animation->off_screen_layer, off_screen_frame);

animation_set_curve(&animation->flyout.animation, AnimationCurveEaseInOut);
animation_set_curve(&animation->flyin.animation, AnimationCurveEaseInOut);
}

void flyout_animation_add_child(Layer* layer, FlyoutAnimation* animation) {
layer_add_child(layer, animation->on_screen_layer);
layer_add_child(layer, animation->off_screen_layer);
}

void flyout_animation_remove_from_parent(FlyoutAnimation* animation) {
layer_remove_from_parent(animation->on_screen_layer);
layer_remove_from_parent(animation->off_screen_layer);
}

void flyout_animation_swap_layers(FlyoutAnimation* animation) {
Layer* temp = animation->on_screen_layer;
animation->on_screen_layer = animation->off_screen_layer;
animation->off_screen_layer = temp;
}

void flyout_animation_schedule(FlyoutAnimation* animation) {
GRect offscreen_left_rect, offscreen_right_rect;

offscreen_left_rect = animation->target_rect;
offscreen_left_rect.origin.x = -animation->target_rect.size.w;

offscreen_right_rect = animation->target_rect;
offscreen_right_rect.origin.x = animation->target_rect.size.w;

property_animation_init_layer_frame(&animation->flyout,
animation->off_screen_layer, &animation->target_rect, &offscreen_left_rect);
property_animation_init_layer_frame(&animation->flyin,
animation->on_screen_layer, &offscreen_right_rect, &animation->target_rect);

animation_schedule(&animation->flyout.animation);
animation_schedule(&animation->flyin.animation);
}
50 changes: 50 additions & 0 deletions src/flyout_animation.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// ----------------------------------------------------------------------------
// flyout_animation - Switches between two layers with flyout/flyin animation
// Copyright (c) 2013 Jonathan Speicher ([email protected])
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// ----------------------------------------------------------------------------

#pragma once

#include <pebble_os.h>

// Defines a type to hold the layers to be animated, as well as the elements
// necessary to perform the animation.

typedef struct {
Layer* on_screen_layer;
Layer* off_screen_layer;
GRect target_rect;
PropertyAnimation flyout;
PropertyAnimation flyin;
} FlyoutAnimation;

// Initializes the animation. The on-screen layer's frame will be used as the
// target "landing-zone" frame for the flyin animation, and the off-screen
// layer will be moved off-screen at initialization time automatically.

void flyout_animation_init(FlyoutAnimation* animation, Layer* on_screen_layer,
Layer* off_screen_layer);

// Adds the entire animation structure as a child of the layer specified. This
// will add the on- and off-screen layers as necessary.

void flyout_animation_add_child(Layer* layer, FlyoutAnimation* animation);

// Removes the entire animation structure from its parent layer. This will
// remove the on- and off-screen layers as necessary.

void flyout_animation_remove_from_parent(FlyoutAnimation* animation);

// Swaps the layers such that the on-screen layer becomes the off-screen layer,
// and vice-versa. Note that this function does not initiate any animation.

void flyout_animation_swap_layers(FlyoutAnimation* animation);

// Schedules the flyin and flyout animation. The layer that is currently set as
// the off-screen layer will be animated to a position that is off the screen,
// and the layer that is currently set as the on-screen layer will be animated
// to a position that is on the screen, defined by the target "landing-zone"
// frame originally identified when the animation was initialized.

void flyout_animation_schedule(FlyoutAnimation* animation);
8 changes: 4 additions & 4 deletions src/pomodoro_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ void pomodoro_controller_init(AppContextRef ctx) {

timer_window_init(&timer_window);

countdown_controller_init(ctx, &timer_window);
countdown_controller_set_countdown_handlers(handlers);
countdown_controller_set_interval(&pomodoro.this_segment->interval);

segment_view_init(&timer_window);
segment_view_set_num_pomodoro_indicators(POMODORO_COUNT_FOR_LONG_BREAK);
segment_view_show_segment_type(pomodoro.this_segment->type);

countdown_controller_init(ctx, &timer_window);
countdown_controller_set_countdown_handlers(handlers);
countdown_controller_set_interval(&pomodoro.this_segment->interval);

timer_window_push(&timer_window);
}

Expand Down
57 changes: 57 additions & 0 deletions src/progress_layer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// ----------------------------------------------------------------------------
// progress_layer - Displays a configurable progress bar
// Copyright (c) 2013 Jonathan Speicher ([email protected])
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// ----------------------------------------------------------------------------

#include <pebble_os.h>
#include "progress_layer.h"

// Define a variable to hold the number of steps indicated by the layer.

static unsigned int num_steps;

// Define a variable to hold the number of steps completed.

static unsigned int steps_completed;

// Private functions.

static void update_progress_layer(Layer* layer, GContext* ctx);

// Public functions -----------------------------------------------------------

void progress_layer_init(Layer* layer, GRect frame) {
layer_init(layer, frame);
layer_set_update_proc(layer, update_progress_layer);
}

void progress_layer_set_num_steps(Layer* layer, unsigned int steps) {
num_steps = steps;
}

void progress_layer_set_num_steps_completed(Layer* layer, unsigned int steps) {
if (steps > num_steps) steps = num_steps;
steps_completed = steps;
}

// Private functions ----------------------------------------------------------

void update_progress_layer(Layer* layer, GContext* ctx) {
GRect frame = layer_get_frame(layer);
unsigned int span = frame.size.w / (num_steps + 1);
unsigned int radius = 5;
GPoint center = GPoint(span, 20);

graphics_context_set_stroke_color(ctx, GColorBlack);
graphics_context_set_fill_color(ctx, GColorBlack);

for (unsigned int i = 0; i < num_steps; i++) {
center.x = span * (i + 1);
if (i < steps_completed) {
graphics_fill_circle(ctx, center, radius);
} else {
graphics_draw_circle(ctx, center, radius);
}
}
}
23 changes: 23 additions & 0 deletions src/progress_layer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// ----------------------------------------------------------------------------
// progress_layer - Displays a configurable progress bar
// Copyright (c) 2013 Jonathan Speicher ([email protected])
// Licensed under the MIT license: http://opensource.org/licenses/MIT
// ----------------------------------------------------------------------------

#pragma once

#include <pebble_os.h>

// Initializes the progress layer.

void progress_layer_init(Layer* layer, GRect frame);

// Sets the number of steps that can be displayed by this progress layer.

void progress_layer_set_num_steps(Layer* layer, unsigned int steps);

// Sets the number of steps completed to be displayed by this progress layer.
// If this number is larger than the maximum number of steps, it will be
// clipped.

void progress_layer_set_num_steps_completed(Layer* layer, unsigned int steps);
62 changes: 23 additions & 39 deletions src/segment_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,20 @@
#include <pebble_os.h>
#include <pebble_fonts.h>

#include "flyout_animation.h"
#include "pomodoro.h"
#include "progress_layer.h"
#include "segment_view.h"

// Define a variable to hold the number of pomodoro indicators on the view.
// Define a variable to hold the currently-displayed segment type.

static unsigned int num_pomodoro_indicators;

// Define a variable to hold the count of pomodoros completed.

static unsigned int pomodoros_completed;
static PomodoroSegmentType current_segment_type;

// Define the various user interface elements comprising this view.

static TextLayer break_layer;
static Layer pomodoro_layer;
static FlyoutAnimation flyout_animation;

// Define a variable to hold the previous unload handler for chaining.

Expand All @@ -30,11 +30,11 @@ static WindowHandler previous_unload_handler;

static void load_and_add_view(Window* window);
static void remove_and_unload_view(Window* window);
static void update_pomodoro_layer(Layer* layer, GContext* ctx);

// Public functions -----------------------------------------------------------

void segment_view_init(Window* window) {
current_segment_type = POMODORO_SEGMENT_TYPE_POMODORO;
load_and_add_view(window);
previous_unload_handler = window->window_handlers.unload;
window_set_window_handlers(window, (WindowHandlers) {
Expand All @@ -43,57 +43,41 @@ void segment_view_init(Window* window) {
}

void segment_view_set_num_pomodoro_indicators(unsigned int num_indicators) {
num_pomodoro_indicators = num_indicators;
progress_layer_set_num_steps(&pomodoro_layer, num_indicators);
}

void segment_view_set_pomodoros_completed(unsigned int completed) {
pomodoros_completed = completed;
void segment_view_set_pomodoros_completed(unsigned int pomodoros_completed) {
progress_layer_set_num_steps_completed(&pomodoro_layer, pomodoros_completed);
}

void segment_view_show_segment_type(PomodoroSegmentType type) {
// TBD: This would be the place to kick off flyout animation - JRS 9/4
layer_set_hidden(&break_layer.layer, (type != POMODORO_SEGMENT_TYPE_BREAK));
layer_set_hidden(&pomodoro_layer, (type != POMODORO_SEGMENT_TYPE_POMODORO));
if (type == current_segment_type) return;
current_segment_type = type;
flyout_animation_swap_layers(&flyout_animation);
flyout_animation_schedule(&flyout_animation);
}

// Private functions ----------------------------------------------------------

void load_and_add_view(Window* window) {
unsigned int width = window->layer.frame.size.w - ACTION_BAR_WIDTH;
GRect window_frame = layer_get_frame(&window->layer);
unsigned int width = window_frame.size.w - ACTION_BAR_WIDTH;
GRect view_frame = GRect(0, 90, width, 40);

layer_init(&pomodoro_layer, GRect(0, 90, width, 40));
layer_set_update_proc(&pomodoro_layer, update_pomodoro_layer);
layer_add_child(&window->layer, &pomodoro_layer);
progress_layer_init(&pomodoro_layer, view_frame);

text_layer_init(&break_layer, GRect(0, 90, width, 40));
text_layer_init(&break_layer, view_frame);
text_layer_set_text_alignment(&break_layer, GTextAlignmentCenter);
text_layer_set_font(&break_layer, fonts_get_system_font(FONT_KEY_GOTHIC_28));
text_layer_set_text(&break_layer, "break");
layer_add_child(&window->layer, &break_layer.layer);

flyout_animation_init(&flyout_animation, &pomodoro_layer, &break_layer.layer);
flyout_animation_add_child(&window->layer, &flyout_animation);
}

void remove_and_unload_view(Window* window) {
layer_remove_from_parent(&pomodoro_layer);
layer_remove_from_parent(&break_layer.layer);
flyout_animation_remove_from_parent(&flyout_animation);
if (previous_unload_handler) {
previous_unload_handler(window);
}
}

void update_pomodoro_layer(Layer* layer, GContext* ctx) {
unsigned int span = layer->frame.size.w / (num_pomodoro_indicators + 1);
unsigned int radius = 5;
GPoint center = GPoint(span, 20);

graphics_context_set_stroke_color(ctx, GColorBlack);
graphics_context_set_fill_color(ctx, GColorBlack);

for (unsigned int i = 0; i < num_pomodoro_indicators; i++) {
center.x = span * (i + 1);
if (i < pomodoros_completed) {
graphics_fill_circle(ctx, center, radius);
} else {
graphics_draw_circle(ctx, center, radius);
}
}
}
2 changes: 1 addition & 1 deletion src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@
#define APP_NAME "Pomade"
#define APP_AUTHOR "Jon Speicher"
#define APP_VERSION_MAJOR 0
#define APP_VERSION_MINOR 1
#define APP_VERSION_MINOR 5

0 comments on commit eaddcac

Please sign in to comment.