Merge pull request #1429 from HansMuller/add_clamped_simulation

Add clamped simulation
diff --git a/examples/demo_launcher/lib/main.dart b/examples/demo_launcher/lib/main.dart
index 537d5c6..76a3d3d 100644
--- a/examples/demo_launcher/lib/main.dart
+++ b/examples/demo_launcher/lib/main.dart
@@ -5,7 +5,7 @@
 import 'package:sky/material.dart';
 import 'package:sky/painting.dart';
 import 'package:sky/services.dart';
-import 'package:sky/widgets.dart';
+import 'package:sky/widgets_next.dart';
 
 AssetBundle _initBundle() {
   if (rootBundle != null)
@@ -138,7 +138,7 @@
 const double kCardHeight = 120.0;
 const EdgeDims kListPadding = const EdgeDims.all(4.0);
 
-class DemoList extends Component {
+class DemoList extends StatelessComponent {
   Widget buildCardContents(SkyDemo demo) {
       return new Container(
         decoration: demo.decoration,
@@ -158,7 +158,7 @@
     );
   }
 
-  Widget buildDemo(SkyDemo demo) {
+  Widget buildDemo(BuildContext context, SkyDemo demo) {
     return new GestureDetector(
       key: demo.key,
       onTap: () => launch(demo.href, demo.bundle),
@@ -171,7 +171,7 @@
     );
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new ScrollableList<SkyDemo>(
       items: demos,
       itemExtent: kCardHeight,
@@ -181,27 +181,29 @@
   }
 }
 
-class SkyHome extends App {
-  Widget build() {
-    return new Theme(
-      data: new ThemeData(
-        brightness: ThemeBrightness.light,
-        primarySwatch: Colors.teal
-      ),
-      child: new Title(
-        title: 'Sky Demos',
-        child: new Scaffold(
-          toolbar: new ToolBar(center: new Text('Sky Demos')),
-          body: new Material(
-            type: MaterialType.canvas,
-            child: new DemoList()
-          )
-        )
+final ThemeData _theme = new ThemeData(
+  brightness: ThemeBrightness.light,
+  primarySwatch: Colors.teal
+);
+
+class DemoHome extends StatelessComponent {
+  Widget build(BuildContext context) {
+    return new Scaffold(
+      toolbar: new ToolBar(center: new Text('Sky Demos')),
+      body: new Material(
+        type: MaterialType.canvas,
+        child: new DemoList()
       )
     );
   }
 }
 
 void main() {
-  runApp(new SkyHome());
+  runApp(new App(
+    title: 'Sky Demos',
+    theme: _theme,
+    routes: {
+      '/': (NavigatorState navigator, Route route) => new DemoHome()
+    }
+  ));
 }
diff --git a/examples/fitness/lib/feed.dart b/examples/fitness/lib/feed.dart
index 9b50c95..b689531 100644
--- a/examples/fitness/lib/feed.dart
+++ b/examples/fitness/lib/feed.dart
@@ -4,7 +4,7 @@
 
 part of fitness;
 
-class FitnessItemList extends Component {
+class FitnessItemList extends StatelessComponent {
   FitnessItemList({ Key key, this.items, this.onDismissed }) : super(key: key) {
     assert(items != null);
     assert(onDismissed != null);
@@ -13,32 +13,26 @@
   final List<FitnessItem> items;
   final FitnessItemHandler onDismissed;
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Material(
       type: MaterialType.canvas,
       child: new ScrollableList<FitnessItem>(
         padding: const EdgeDims.all(4.0),
         items: items,
         itemExtent: kFitnessItemHeight,
-        itemBuilder: (item) => item.toRow(onDismissed: onDismissed)
+        itemBuilder: (_, item) => item.toRow(onDismissed: onDismissed)
       )
     );
   }
 }
 
-class DialogMenuItem extends ButtonBase {
+class DialogMenuItem extends StatelessComponent {
   DialogMenuItem(this.children, { Key key, this.onPressed }) : super(key: key);
 
   List<Widget> children;
   Function onPressed;
 
-  void syncConstructorArguments(DialogMenuItem source) {
-    children = source.children;
-    onPressed = source.onPressed;
-    super.syncConstructorArguments(source);
-  }
-
-  Widget buildContent() {
+  Widget build(BuildContext context) {
     return new GestureDetector(
       onTap: onPressed,
       child: new Container(
@@ -57,26 +51,17 @@
 class FeedFragment extends StatefulComponent {
   FeedFragment({ this.navigator, this.userData, this.onItemCreated, this.onItemDeleted });
 
-  Navigator navigator;
-  UserData userData;
-  FitnessItemHandler onItemCreated;
-  FitnessItemHandler onItemDeleted;
+  final NavigatorState navigator;
+  final UserData userData;
+  final FitnessItemHandler onItemCreated;
+  final FitnessItemHandler onItemDeleted;
 
+  FeedFragmentState createState() => new FeedFragmentState();
+}
+
+class FeedFragmentState extends State<FeedFragment> {
   FitnessMode _fitnessMode = FitnessMode.feed;
 
-  void initState() {
-    // if (debug)
-    //   new Timer(new Duration(seconds: 1), dumpState);
-    super.initState();
-  }
-
-  void syncConstructorArguments(FeedFragment source) {
-    navigator = source.navigator;
-    userData = source.userData;
-    onItemCreated = source.onItemCreated;
-    onItemDeleted = source.onItemDeleted;
-  }
-
   AnimationStatus _snackBarStatus = AnimationStatus.dismissed;
   bool _isShowingSnackBar = false;
 
@@ -94,7 +79,7 @@
       showing: _drawerShowing,
       level: 3,
       onDismissed: _handleDrawerDismissed,
-      navigator: navigator,
+      navigator: config.navigator,
       children: [
         new DrawerHeader(child: new Text('Fitness')),
         new DrawerItem(
@@ -136,8 +121,8 @@
   }
 
   void _handleShowSettings() {
-    navigator.pop();
-    navigator.pushNamed('/settings');
+    config.navigator.pop();
+    config.navigator.pushNamed('/settings');
   }
 
   // TODO(jackson): We should be localizing
@@ -160,7 +145,7 @@
   FitnessItem _undoItem;
 
   void _handleItemDismissed(FitnessItem item) {
-    onItemDeleted(item);
+    config.onItemDeleted(item);
     setState(() {
       _undoItem = item;
       _isShowingSnackBar = true;
@@ -174,7 +159,7 @@
     double startY;
     double endY;
     List<Point> dataSet = new List<Point>();
-    for (FitnessItem item in userData.items) {
+    for (FitnessItem item in config.userData.items) {
       if (item is Measurement) {
           double x = item.when.millisecondsSinceEpoch.toDouble();
           double y = item.weight;
@@ -189,9 +174,9 @@
           dataSet.add(new Point(x, y));
       }
     }
-    if (userData.goalWeight != null && userData.goalWeight > 0.0) {
-      startY = math.min(startY, userData.goalWeight);
-      endY = math.max(endY, userData.goalWeight);
+    if (config.userData.goalWeight != null && config.userData.goalWeight > 0.0) {
+      startY = math.min(startY, config.userData.goalWeight);
+      endY = math.max(endY, config.userData.goalWeight);
     }
     playfair.ChartData data = new playfair.ChartData(
       startX: startX,
@@ -201,17 +186,17 @@
       dataSet: dataSet,
       numHorizontalGridlines: 5,
       roundToPlaces: 1,
-      indicatorLine: userData.goalWeight,
+      indicatorLine: config.userData.goalWeight,
       indicatorText: "GOAL WEIGHT"
     );
     return new playfair.Chart(data: data);
   }
 
   Widget buildBody() {
-    TextStyle style = Theme.of(this).text.title;
-    if (userData == null)
+    TextStyle style = Theme.of(context).text.title;
+    if (config.userData == null)
       return new Material(type: MaterialType.canvas);
-    if (userData.items.length == 0)
+    if (config.userData.items.length == 0)
       return new Material(
         type: MaterialType.canvas,
         child: new Row(
@@ -222,7 +207,7 @@
     switch (_fitnessMode) {
       case FitnessMode.feed:
         return new FitnessItemList(
-          items: userData.items.reversed.toList(),
+          items: config.userData.items.reversed.toList(),
           onDismissed: _handleItemDismissed
         );
       case FitnessMode.chart:
@@ -237,7 +222,7 @@
   }
 
   void _handleUndo() {
-    onItemCreated(_undoItem);
+    config.onItemCreated(_undoItem);
     setState(() {
       _undoItem = null;
       _isShowingSnackBar = false;
@@ -256,9 +241,9 @@
   }
 
   void _handleActionButtonPressed() {
-    showDialog(navigator, (navigator) => new AddItemDialog(navigator)).then((routeName) {
+    showDialog(config.navigator, (NavigatorState navigator) => new AddItemDialog(navigator)).then((routeName) {
       if (routeName != null)
-        navigator.pushNamed(routeName);
+        config.navigator.pushNamed(routeName);
     });
   }
 
@@ -274,7 +259,7 @@
     }
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Scaffold(
       toolbar: buildToolBar(),
       body: buildBody(),
@@ -288,12 +273,12 @@
 class AddItemDialog extends StatefulComponent {
   AddItemDialog(this.navigator);
 
-  Navigator navigator;
+  final NavigatorState navigator;
 
-  void syncConstructorArguments(AddItemDialog source) {
-    this.navigator = source.navigator;
-  }
+  AddItemDialogState createState() => new AddItemDialogState();
+}
 
+class AddItemDialogState extends State<AddItemDialog> {
   // TODO(jackson): Internationalize
   static final Map<String, String> _labels = {
     '/measurements/new': 'Measure',
@@ -308,7 +293,7 @@
     });
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     List<Widget> menuItems = [];
     for(String routeName in _labels.keys) {
       menuItems.add(new DialogMenuItem([
@@ -319,16 +304,16 @@
     return new Dialog(
       title: new Text("What are you doing?"),
       content: new Block(menuItems),
-      onDismiss: navigator.pop,
+      onDismiss: config.navigator.pop,
       actions: [
         new FlatButton(
           child: new Text('CANCEL'),
-          onPressed: navigator.pop
+          onPressed: config.navigator.pop
         ),
         new FlatButton(
           child: new Text('ADD'),
           onPressed: () {
-            navigator.pop(_addItemRoute);
+            config.navigator.pop(_addItemRoute);
           }
         ),
       ]
diff --git a/examples/fitness/lib/fitness_item.dart b/examples/fitness/lib/fitness_item.dart
index c868c07..8b90af3 100644
--- a/examples/fitness/lib/fitness_item.dart
+++ b/examples/fitness/lib/fitness_item.dart
@@ -26,7 +26,7 @@
   FitnessItemRow toRow({ FitnessItemHandler onDismissed });
 }
 
-abstract class FitnessItemRow extends Component {
+abstract class FitnessItemRow extends StatelessComponent {
 
   FitnessItemRow({ FitnessItem item, this.onDismissed })
    : this.item = item,
@@ -37,9 +37,9 @@
   final FitnessItem item;
   final FitnessItemHandler onDismissed;
 
-  Widget buildContent();
+  Widget buildContent(BuildContext context);
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Dismissable(
       onDismissed: () => onDismissed(item),
       child: new Container(
@@ -51,10 +51,10 @@
         // stay put even when the tile is dismissed!
         decoration: new BoxDecoration(
           border: new Border(
-            bottom: new BorderSide(color: Theme.of(this).dividerColor)
+            bottom: new BorderSide(color: Theme.of(context).dividerColor)
           )
         ),
-        child: buildContent()
+        child: buildContent(context)
       )
     );
   }
diff --git a/examples/fitness/lib/main.dart b/examples/fitness/lib/main.dart
index b371435..43e7790 100644
--- a/examples/fitness/lib/main.dart
+++ b/examples/fitness/lib/main.dart
@@ -8,7 +8,7 @@
 import 'package:sky/animation.dart';
 import 'package:sky/material.dart';
 import 'package:sky/painting.dart';
-import 'package:sky/widgets.dart';
+import 'package:sky/src/fn3.dart';
 
 import 'user_data.dart';
 import 'date_utils.dart';
@@ -85,63 +85,53 @@
   }
 }
 
-class FitnessApp extends App {
-  NavigationState _navigationState;
+class FitnessApp extends StatefulComponent {
+  FitnessAppState createState() => new FitnessAppState();
+}
+
+class FitnessAppState extends State<FitnessApp> {
   UserDataImpl _userData;
 
-  void didMount() {
-    super.didMount();
+  Map<String, RouteBuilder> _routes;
+
+  void initState() {
+    super.initState();
     loadFitnessData().then((UserData data) {
       setState(() => _userData = data);
     }).catchError((e) {
       print("Failed to load data: $e");
       setState(() => _userData = new UserDataImpl());
     });
-  }
 
-  void initState() {
-    _navigationState = new NavigationState([
-      new Route(
-        name: '/',
-        builder: (navigator, route) => new FeedFragment(
+    _routes = {
+      '/': (NavigatorState navigator, Route route) {
+        return new FeedFragment(
           navigator: navigator,
           userData: _userData,
           onItemCreated: _handleItemCreated,
           onItemDeleted: _handleItemDeleted
-        )
-      ),
-      new Route(
-        name: '/meals/new',
-        builder: (navigator, route) => new MealFragment(
+        );
+      },
+      '/meals/new': (navigator, route) {
+        return new MealFragment(
           navigator: navigator,
           onCreated: _handleItemCreated
-        )
-      ),
-      new Route(
-        name: '/measurements/new',
-        builder: (navigator, route) => new MeasurementFragment(
+        );
+      },
+      '/measurements/new': (NavigatorState navigator, Route route) {
+        return new MeasurementFragment(
           navigator: navigator,
           onCreated: _handleItemCreated
-        )
-      ),
-      new Route(
-        name: '/settings',
-        builder: (navigator, route) => new SettingsFragment(
+        );
+      },
+      '/settings': (navigator, route) {
+        return new SettingsFragment(
           navigator: navigator,
           userData: _userData,
           updater: settingsUpdater
-        )
-      ),
-    ]);
-    super.initState();
-  }
-
-  void onBack() {
-    if (_navigationState.hasPrevious()) {
-      setState(() => _navigationState.pop());
-    } else {
-      super.onBack();
-    }
+        );
+      }
+    };
   }
 
   void _handleItemCreated(FitnessItem item) {
@@ -168,17 +158,17 @@
     });
   }
 
-  Widget build() {
-    return new Theme(
-      data: new ThemeData(
-        brightness: ThemeBrightness.light,
-        primarySwatch: Colors.indigo,
-        accentColor: Colors.pinkAccent[200]
-      ),
-      child: new Title(
-        title: 'Fitness',
-        child: new Navigator(_navigationState)
-      )
+  final ThemeData _theme = new ThemeData(
+    brightness: ThemeBrightness.light,
+    primarySwatch: Colors.indigo,
+    accentColor: Colors.pinkAccent[200]
+  );
+
+  Widget build(BuildContext) {
+    return new App(
+      theme: _theme,
+      title: 'Fitness',
+      routes: _routes
     );
   }
 }
diff --git a/examples/fitness/lib/meal.dart b/examples/fitness/lib/meal.dart
index e18e418..5e65025 100644
--- a/examples/fitness/lib/meal.dart
+++ b/examples/fitness/lib/meal.dart
@@ -18,7 +18,7 @@
   MealRow({ Meal meal, FitnessItemHandler onDismissed })
     : super(item: meal, onDismissed: onDismissed);
 
-  Widget buildContent() {
+  Widget buildContent(BuildContext context) {
     Meal meal = item;
     List<Widget> children = [
       new Flexible(
@@ -30,42 +30,40 @@
       new Flexible(
         child: new Text(
           meal.displayDate,
-          style: Theme.of(this).text.caption.copyWith(textAlign: TextAlign.right)
+          style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right)
         )
       )
     ];
     return new Row(
       children,
       alignItems: FlexAlignItems.baseline,
-      textBaseline: DefaultTextStyle.of(this).textBaseline
+      textBaseline: DefaultTextStyle.of(context).textBaseline
     );
   }
 }
 
 class MealFragment extends StatefulComponent {
-
   MealFragment({ this.navigator, this.onCreated });
 
-  Navigator navigator;
+  NavigatorState navigator;
   FitnessItemHandler onCreated;
 
-  void syncConstructorArguments(MealFragment source) {
-    navigator = source.navigator;
-    onCreated = source.onCreated;
-  }
+  MealFragmentState createState() => new MealFragmentState();
+}
 
+class MealFragmentState extends State<MealFragment> {
   String _description = "";
 
   void _handleSave() {
-    onCreated(new Meal(when: new DateTime.now(), description: _description));
-    navigator.pop();
+    config.onCreated(new Meal(when: new DateTime.now(), description: _description));
+    config.navigator.pop();
   }
 
   Widget buildToolBar() {
     return new ToolBar(
       left: new IconButton(
         icon: "navigation/close",
-        onPressed: navigator.pop),
+        onPressed: config.navigator.pop),
       center: new Text('New Meal'),
       right: [new InkWell(
         child: new GestureDetector(
@@ -104,7 +102,7 @@
     );
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Scaffold(
       toolbar: buildToolBar(),
       body: buildBody()
diff --git a/examples/fitness/lib/measurement.dart b/examples/fitness/lib/measurement.dart
index ebea00b..5732286 100644
--- a/examples/fitness/lib/measurement.dart
+++ b/examples/fitness/lib/measurement.dart
@@ -30,26 +30,26 @@
   MeasurementRow({ Measurement measurement, FitnessItemHandler onDismissed })
     : super(item: measurement, onDismissed: onDismissed);
 
-  Widget buildContent() {
+  Widget buildContent(BuildContext context) {
     Measurement measurement = item;
     List<Widget> children = [
       new Flexible(
         child: new Text(
           measurement.displayWeight,
-          style: Theme.of(this).text.subhead
+          style: Theme.of(context).text.subhead
         )
       ),
       new Flexible(
         child: new Text(
           measurement.displayDate,
-          style: Theme.of(this).text.caption.copyWith(textAlign: TextAlign.right)
+          style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right)
         )
       )
     ];
     return new Row(
       children,
       alignItems: FlexAlignItems.baseline,
-      textBaseline: DefaultTextStyle.of(this).textBaseline
+      textBaseline: DefaultTextStyle.of(context).textBaseline
     );
   }
 }
@@ -57,17 +57,16 @@
 class MeasurementDateDialog extends StatefulComponent {
   MeasurementDateDialog({ this.navigator, this.previousDate });
 
-  Navigator navigator;
-  DateTime previousDate;
+  final NavigatorState navigator;
+  final DateTime previousDate;
 
+  MeasurementDateDialogState createState() => new MeasurementDateDialogState();
+}
+
+class MeasurementDateDialogState extends State<MeasurementDateDialog> {
   @override
   void initState() {
-    _selectedDate = previousDate;
-  }
-
-  void syncConstructorArguments(MeasurementDateDialog source) {
-    navigator = source.navigator;
-    previousDate = source.previousDate;
+    _selectedDate = config.previousDate;
   }
 
   DateTime _selectedDate;
@@ -78,7 +77,7 @@
     });
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Dialog(
       content: new DatePicker(
         selectedDate: _selectedDate,
@@ -90,12 +89,12 @@
       actions: [
         new FlatButton(
           child: new Text('CANCEL'),
-          onPressed: navigator.pop
+          onPressed: config.navigator.pop
         ),
         new FlatButton(
           child: new Text('OK'),
           onPressed: () {
-            navigator.pop(_selectedDate);
+            config.navigator.pop(_selectedDate);
           }
         ),
       ]
@@ -104,17 +103,15 @@
 }
 
 class MeasurementFragment extends StatefulComponent {
-
   MeasurementFragment({ this.navigator, this.onCreated });
 
-  Navigator navigator;
-  FitnessItemHandler onCreated;
+  final NavigatorState navigator;
+  final FitnessItemHandler onCreated;
 
-  void syncConstructorArguments(MeasurementFragment source) {
-    navigator = source.navigator;
-    onCreated = source.onCreated;
-  }
+  MeasurementFragmentState createState() => new MeasurementFragmentState();
+}
 
+class MeasurementFragmentState extends State<MeasurementFragment> {
   String _weight = "";
   DateTime _when = new DateTime.now();
   String _errorMessage = null;
@@ -129,15 +126,15 @@
         _errorMessage = "Save failed";
       });
     }
-    onCreated(new Measurement(when: _when, weight: parsedWeight));
-    navigator.pop();
+    config.onCreated(new Measurement(when: _when, weight: parsedWeight));
+    config.navigator.pop();
   }
 
   Widget buildToolBar() {
     return new ToolBar(
       left: new IconButton(
         icon: "navigation/close",
-        onPressed: navigator.pop),
+        onPressed: config.navigator.pop),
       center: new Text('New Measurement'),
       right: [new InkWell(
         child: new GestureDetector(
@@ -157,7 +154,7 @@
   static final GlobalKey weightKey = new GlobalKey();
 
   void _handleDatePressed() {
-    showDialog(navigator, (navigator) {
+    showDialog(config.navigator, (NavigatorState navigator) {
       return new MeasurementDateDialog(navigator: navigator, previousDate: _when);
     }).then((DateTime value) {
       if (value == null)
@@ -168,7 +165,7 @@
     });
   }
 
-  Widget buildBody() {
+  Widget buildBody(BuildContext context) {
     Measurement measurement = new Measurement(when: _when);
     // TODO(jackson): Revisit the layout of this pane to be more maintainable
     return new Material(
@@ -182,7 +179,7 @@
               height: 50.0,
               child: new Column([
                 new Text('Measurement Date'),
-                new Text(measurement.displayDate, style: Theme.of(this).text.caption),
+                new Text(measurement.displayDate, style: Theme.of(context).text.caption),
               ], alignItems: FlexAlignItems.start)
             )
           ),
@@ -204,10 +201,10 @@
     return new SnackBar(content: new Text(_errorMessage), showing: true);
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Scaffold(
       toolbar: buildToolBar(),
-      body: buildBody(),
+      body: buildBody(context),
       snackBar: buildSnackBar()
     );
   }
diff --git a/examples/fitness/lib/settings.dart b/examples/fitness/lib/settings.dart
index 5843380..27cb9a0 100644
--- a/examples/fitness/lib/settings.dart
+++ b/examples/fitness/lib/settings.dart
@@ -10,38 +10,35 @@
 });
 
 class SettingsFragment extends StatefulComponent {
-
   SettingsFragment({ this.navigator, this.userData, this.updater });
 
-  Navigator navigator;
-  UserData userData;
-  SettingsUpdater updater;
+  final NavigatorState navigator;
+  final UserData userData;
+  final SettingsUpdater updater;
 
-  void syncConstructorArguments(SettingsFragment source) {
-    navigator = source.navigator;
-    userData = source.userData;
-    updater = source.updater;
-  }
+  SettingsFragmentState createState() => new SettingsFragmentState();
+}
 
+class SettingsFragmentState extends State<SettingsFragment> {
   void _handleBackupChanged(bool value) {
-    assert(updater != null);
-    updater(backup: value ? BackupMode.enabled : BackupMode.disabled);
+    assert(config.updater != null);
+    config.updater(backup: value ? BackupMode.enabled : BackupMode.disabled);
   }
 
   Widget buildToolBar() {
     return new ToolBar(
       left: new IconButton(
         icon: "navigation/arrow_back",
-        onPressed: navigator.pop),
+        onPressed: config.navigator.pop
+      ),
       center: new Text('Settings')
     );
   }
 
   String get goalWeightText {
-    if (userData.goalWeight == null || userData.goalWeight == 0.0)
+    if (config.userData.goalWeight == null || config.userData.goalWeight == 0.0)
       return "None";
-    else
-      return "${userData.goalWeight}";
+    return "${config.userData.goalWeight}";
   }
 
   static final GlobalKey weightGoalKey = new GlobalKey();
@@ -51,7 +48,7 @@
   void _handleGoalWeightChanged(String goalWeight) {
     // TODO(jackson): Looking for null characters to detect enter key is a hack
     if (goalWeight.endsWith("\u{0}")) {
-      navigator.pop(double.parse(goalWeight.replaceAll("\u{0}", "")));
+      config.navigator.pop(double.parse(goalWeight.replaceAll("\u{0}", "")));
     } else {
       setState(() {
         try {
@@ -64,7 +61,7 @@
   }
 
   void _handleGoalWeightPressed() {
-    showDialog(navigator, (navigator) {
+    showDialog(config.navigator, (NavigatorState navigator) {
       return new Dialog(
         title: new Text("Goal Weight"),
         content: new Input(
@@ -91,10 +88,10 @@
           ),
         ]
       );
-    }).then((double goalWeight) => updater(goalWeight: goalWeight));
+    }).then((double goalWeight) => config.updater(goalWeight: goalWeight));
   }
 
-  Widget buildSettingsPane() {
+  Widget buildSettingsPane(BuildContext context) {
     return new Material(
       type: MaterialType.canvas,
       child: new ScrollableViewport(
@@ -102,17 +99,17 @@
           padding: const EdgeDims.symmetric(vertical: 20.0),
           child: new BlockBody([
             new DrawerItem(
-              onPressed: () { _handleBackupChanged(!(userData.backupMode == BackupMode.enabled)); },
+              onPressed: () { _handleBackupChanged(!(config.userData.backupMode == BackupMode.enabled)); },
               child: new Row([
                 new Flexible(child: new Text('Back up data to the cloud')),
-                new Switch(value: userData.backupMode == BackupMode.enabled, onChanged: _handleBackupChanged),
+                new Switch(value: config.userData.backupMode == BackupMode.enabled, onChanged: _handleBackupChanged),
               ])
             ),
             new DrawerItem(
               onPressed: () => _handleGoalWeightPressed(),
               child: new Column([
                   new Text('Goal Weight'),
-                  new Text(goalWeightText, style: Theme.of(this).text.caption),
+                  new Text(goalWeightText, style: Theme.of(context).text.caption),
                 ],
                 alignItems: FlexAlignItems.start
               )
@@ -123,10 +120,10 @@
     );
   }
 
-  Widget build() {
+  Widget build(BuildContext context) {
     return new Scaffold(
       toolbar: buildToolBar(),
-      body: buildSettingsPane()
+      body: buildSettingsPane(context)
     );
   }
 }
diff --git a/packages/flutter/lib/src/fn3/dialog.dart b/packages/flutter/lib/src/fn3/dialog.dart
index bc9bb98..4a83b9b 100644
--- a/packages/flutter/lib/src/fn3/dialog.dart
+++ b/packages/flutter/lib/src/fn3/dialog.dart
@@ -16,7 +16,7 @@
 import 'package:sky/src/fn3/theme.dart';
 import 'package:sky/src/fn3/transitions.dart';
 
-typedef Dialog DialogBuilder(NavigatorState navigator);
+typedef Widget DialogBuilder(NavigatorState navigator);
 
 /// A material design dialog
 ///