Merge pull request #78 from abarth/iterate_travis

Attempt to make Travis green
diff --git a/README.md b/README.md
index 346a3cb..5be497b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
 Sky
 ===
 
+[![Build Status](https://travis-ci.org/domokit/sky_engine.svg)](https://travis-ci.org/domokit/sky_engine)
+
 Sky is a new way to build high performance, cross platform mobile apps.
 More specifically, Sky is a rendering engine, a scripting engine, an
 (optional) framework, and a (optional) set of Material Design widgets.
diff --git a/sky/BUILD.gn b/sky/BUILD.gn
index ca79233..ef3c9c8 100644
--- a/sky/BUILD.gn
+++ b/sky/BUILD.gn
@@ -24,6 +24,7 @@
 
   deps = [
     "//sky/sdk",
+    "//sky/sdk/example/demo_launcher",
   ]
 
   if (is_android) {
diff --git a/sky/sdk/example/stocks/lib/stock_menu.dart b/sky/sdk/example/stocks/lib/stock_menu.dart
index 9cb7a09..ef34d40 100644
--- a/sky/sdk/example/stocks/lib/stock_menu.dart
+++ b/sky/sdk/example/stocks/lib/stock_menu.dart
@@ -39,7 +39,10 @@
         items: [
           new PopupMenuItem(child: new Text('Add stock')),
           new PopupMenuItem(child: new Text('Remove stock')),
-          new PopupMenuItem(child: new Flex([new Flexible(child: new Text('Autorefresh')), checkbox])),
+          new PopupMenuItem(
+            onPressed: () => onAutorefreshChanged(!autorefresh),
+            child: new Flex([new Flexible(child: new Text('Autorefresh')), checkbox])
+          ),
         ],
         level: 4,
         showing: showing,
diff --git a/sky/sdk/example/widgets/navigation.dart b/sky/sdk/example/widgets/navigation.dart
index c616831..0af68f7 100644
--- a/sky/sdk/example/widgets/navigation.dart
+++ b/sky/sdk/example/widgets/navigation.dart
@@ -68,6 +68,16 @@
 class NavigationExampleApp extends App {
   NavigationState _navState = new NavigationState(routes);
 
+  void onBack() {
+    if (_navState.hasPrevious()) {
+      setState(() {
+        _navState.pop();
+      });
+    } else {
+      super.onBack();
+    }
+  }
+
   Widget build() {
     return new Flex([new Navigator(_navState)]);
   }
diff --git a/sky/sdk/lib/widgets/navigator.dart b/sky/sdk/lib/widgets/navigator.dart
index 03d8c3b..42df2d2 100644
--- a/sky/sdk/lib/widgets/navigator.dart
+++ b/sky/sdk/lib/widgets/navigator.dart
@@ -5,7 +5,6 @@
 import 'package:sky/animation/animation_performance.dart';
 import 'package:sky/animation/curves.dart';
 import 'package:sky/widgets/animated_component.dart';
-import 'package:sky/widgets/animation_builder.dart';
 import 'package:sky/widgets/basic.dart';
 import 'package:vector_math/vector_math.dart';
 
@@ -42,8 +41,8 @@
 
 // TODO(jackson): Refactor this into its own file
 // and support multiple transition types
-const Duration _kTransitionDuration = const Duration(milliseconds: 200);
-const Point _kTransitionStartPoint = const Point(0.0, 100.0);
+const Duration _kTransitionDuration = const Duration(milliseconds: 150);
+const Point _kTransitionStartPoint = const Point(0.0, 75.0);
 enum TransitionDirection { forward, reverse }
 class Transition extends AnimatedComponent {
   Transition({
@@ -51,12 +50,14 @@
     this.content,
     this.direction,
     this.onDismissed,
+    this.onCompleted,
     this.interactive
   }) : super(key: key);
   Widget content;
   TransitionDirection direction;
   bool interactive;
   Function onDismissed;
+  Function onCompleted;
 
   AnimatedType<Point> _position;
   AnimatedType<double> _opacity;
@@ -73,7 +74,8 @@
     _performance = new AnimationPerformance()
       ..duration = _kTransitionDuration
       ..variable = new AnimatedList([_position, _opacity])
-      ..addListener(_checkDismissed);
+      ..addListener(_checkDismissed)
+      ..addListener(_checkCompleted);
     if (direction == TransitionDirection.reverse)
       _performance.progress = 1.0;
     watch(_performance);
@@ -114,6 +116,17 @@
     }
   }
 
+  bool _completed = false;
+  void _checkCompleted() {
+    if (!_completed &&
+        direction == TransitionDirection.forward &&
+        _performance.isCompleted) {
+      if (onCompleted != null)
+        onCompleted();
+      _completed = true;
+    }
+  }
+
   Widget build() {
     Matrix4 transform = new Matrix4.identity()
       ..translate(_position.value.x, _position.value.y);
@@ -130,8 +143,10 @@
 }
 
 class HistoryEntry {
-  HistoryEntry(this.route);
+  HistoryEntry({ this.route, this.key });
   final RouteBase route;
+  final int key;
+  bool transitionFinished = false;
   // TODO(jackson): Keep track of the requested transition
 }
 
@@ -142,11 +157,12 @@
       if (route.name != null)
         namedRoutes[route.name] = route;
     }
-    history.add(new HistoryEntry(routes[0]));
+    history.add(new HistoryEntry(route: routes[0], key: _lastKey++));
   }
 
   List<HistoryEntry> history = new List<HistoryEntry>();
   int historyIndex = 0;
+  int _lastKey = 0;
   Map<String, RouteBase> namedRoutes = new Map<String, RouteBase>();
 
   RouteBase get currentRoute => history[historyIndex].route;
@@ -159,7 +175,7 @@
   }
 
   void push(RouteBase route) {
-    HistoryEntry historyEntry = new HistoryEntry(route);
+    HistoryEntry historyEntry = new HistoryEntry(route: route, key: _lastKey++);
     history.insert(historyIndex + 1, historyEntry);
     historyIndex++;
   }
@@ -168,6 +184,7 @@
     if (historyIndex > 0) {
       HistoryEntry entry = history[historyIndex];
       entry.route.popState();
+      entry.transitionFinished = false;
       historyIndex--;
     }
   }
@@ -215,7 +232,9 @@
   Widget build() {
     List<Widget> visibleRoutes = new List<Widget>();
     for (int i = 0; i < state.history.length; i++) {
-      // TODO(jackson): Avoid building routes that are not visible
+      // Avoid building routes that are not visible
+      if (i + 1 < state.history.length && state.history[i + 1].transitionFinished)
+        continue;
       HistoryEntry historyEntry = state.history[i];
       Widget content = historyEntry.route.build(this, historyEntry.route);
       if (i == 0) {
@@ -224,9 +243,8 @@
       }
       if (content == null)
         continue;
-      String key = historyEntry.route.key;
       Transition transition = new Transition(
-        key: key,
+        key: historyEntry.key.toString(),
         content: content,
         direction: (i <= state.historyIndex) ? TransitionDirection.forward : TransitionDirection.reverse,
         interactive: (i == state.historyIndex),
@@ -234,6 +252,11 @@
           setState(() {
             state.history.remove(historyEntry);
           });
+        },
+        onCompleted: () {
+          setState(() {
+            historyEntry.transitionFinished = true;
+          });
         }
       );
       visibleRoutes.add(transition);