Refactoring to support dark theme better

R=abarth@chromium.org

Review URL: https://codereview.chromium.org/1218153005.
diff --git a/sky/sdk/BUILD.gn b/sky/sdk/BUILD.gn
index e56dd8a..81e378d 100644
--- a/sky/sdk/BUILD.gn
+++ b/sky/sdk/BUILD.gn
@@ -44,7 +44,6 @@
     "lib/rendering/stack.dart",
     "lib/sky_tool",
     "lib/theme/colors.dart",
-    "lib/theme/edges.dart",
     "lib/theme/shadows.dart",
     "lib/theme/theme_data.dart",
     "lib/theme/typography.dart",
diff --git a/sky/sdk/example/stocks/lib/main.dart b/sky/sdk/example/stocks/lib/main.dart
index 8cf2f81..b358f72 100644
--- a/sky/sdk/example/stocks/lib/main.dart
+++ b/sky/sdk/example/stocks/lib/main.dart
@@ -68,15 +68,15 @@
 
     ThemeData theme;
     if (optimismSetting == StockMode.optimistic) {
-      theme = new ThemeData.light(
-        primary: colors.Purple,
-        accent: colors.RedAccent,
-        darkToolbar: true
+      theme = new ThemeData(
+        brightness: ThemeBrightness.light,
+        primarySwatch: colors.Purple,
+        accentColor: colors.RedAccent[200]
       );
     } else {
-      theme = new ThemeData.dark(
-        primary: colors.Red,
-        accent: colors.PurpleAccent
+      theme = new ThemeData(
+        brightness: ThemeBrightness.dark,
+        accentColor: colors.RedAccent[200]
       );
     }
 
diff --git a/sky/sdk/example/stocks/lib/stock_home.dart b/sky/sdk/example/stocks/lib/stock_home.dart
index 24a9853..f8b686d 100644
--- a/sky/sdk/example/stocks/lib/stock_home.dart
+++ b/sky/sdk/example/stocks/lib/stock_home.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'package:sky/editing/input.dart';
-import 'package:sky/theme/colors.dart' as colors;
 import 'package:sky/widgets/basic.dart';
 import 'package:sky/widgets/drawer.dart';
 import 'package:sky/widgets/drawer_header.dart';
@@ -18,6 +17,7 @@
 import 'package:sky/widgets/radio.dart';
 import 'package:sky/widgets/scaffold.dart';
 import 'package:sky/widgets/tabs.dart';
+import 'package:sky/widgets/theme.dart';
 import 'package:sky/widgets/tool_bar.dart';
 import 'package:sky/widgets/widget.dart';
 
@@ -219,7 +219,7 @@
         focused: true,
         placeholder: 'Search stocks',
         onChanged: _handleSearchQueryChanged),
-      backgroundColor: colors.Grey[50]
+      backgroundColor: Theme.of(this).canvasColor
     );
   }
 
diff --git a/sky/sdk/example/stocks/lib/stock_settings.dart b/sky/sdk/example/stocks/lib/stock_settings.dart
index 04be1ac..127373c 100644
--- a/sky/sdk/example/stocks/lib/stock_settings.dart
+++ b/sky/sdk/example/stocks/lib/stock_settings.dart
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:sky/theme/colors.dart' as colors;
 import 'package:sky/widgets/basic.dart';
 import 'package:sky/widgets/checkbox.dart';
 import 'package:sky/widgets/switch.dart';
 import 'package:sky/widgets/flat_button.dart';
 import 'package:sky/widgets/dialog.dart';
 import 'package:sky/widgets/icon_button.dart';
+import 'package:sky/widgets/material.dart';
 import 'package:sky/widgets/menu_item.dart';
 import 'package:sky/widgets/navigator.dart';
 import 'package:sky/widgets/scaffold.dart';
@@ -87,27 +87,29 @@
   Widget buildSettingsPane() {
     // TODO(ianh): Once we have the gesture API hooked up, fix https://github.com/domokit/mojo/issues/281
     // (whereby tapping the widgets below causes both the widget and the menu item to fire their callbacks)
-    return new Container(
-      padding: const EdgeDims.symmetric(vertical: 20.0),
-      decoration: new BoxDecoration(backgroundColor: colors.Grey[50]),
-      child: new Block([
-        new MenuItem(
-          icon: 'action/thumb_up',
-          onPressed: () => _confirmOptimismChange(),
-          children: [
-            new Flexible(child: new Text('Everything is awesome')),
-            new Checkbox(value: optimism == StockMode.optimistic, onChanged: _handleOptimismChanged)
-          ]
-        ),
-        new MenuItem(
-          icon: 'action/backup',
-          onPressed: () { _handleBackupChanged(!(backup == BackupMode.enabled)); },
-          children: [
-            new Flexible(child: new Text('Back up stock list to the cloud')),
-            new Switch(value: backup == BackupMode.enabled, onChanged: _handleBackupChanged)
-          ]
-        ),
-      ])
+    return new Material(
+      type: MaterialType.canvas,
+      child: new Container(
+        padding: const EdgeDims.symmetric(vertical: 20.0),
+        child: new Block([
+          new MenuItem(
+            icon: 'action/thumb_up',
+            onPressed: () => _confirmOptimismChange(),
+            children: [
+              new Flexible(child: new Text('Everything is awesome')),
+              new Checkbox(value: optimism == StockMode.optimistic, onChanged: _handleOptimismChanged)
+            ]
+          ),
+          new MenuItem(
+            icon: 'action/backup',
+            onPressed: () { _handleBackupChanged(!(backup == BackupMode.enabled)); },
+            children: [
+              new Flexible(child: new Text('Back up stock list to the cloud')),
+              new Switch(value: backup == BackupMode.enabled, onChanged: _handleBackupChanged)
+            ]
+          ),
+        ])
+      )
     );
   }
 
diff --git a/sky/sdk/example/widgets/sector.dart b/sky/sdk/example/widgets/sector.dart
index f1e83a2..0f52e16 100644
--- a/sky/sdk/example/widgets/sector.dart
+++ b/sky/sdk/example/widgets/sector.dart
@@ -74,13 +74,12 @@
 
   Widget build() {
     return new Theme(
-      data: new ThemeData.light(primary: colors.Blue, darkToolbar: true),
+      data: new ThemeData.light(),
       child: new Scaffold(
         toolbar: new ToolBar(
             center: new Text('Sector Layout in a Widget Tree')),
         body: new Material(
-          color: colors.Grey[50],
-          edge: MaterialEdge.canvas,
+          type: MaterialType.canvas,
           child: new Flex([
               new Container(
                 padding: new EdgeDims.symmetric(horizontal: 8.0, vertical: 25.0),
diff --git a/sky/sdk/example/widgets/styled_text.dart b/sky/sdk/example/widgets/styled_text.dart
index eddd81e..c2d1592 100644
--- a/sky/sdk/example/widgets/styled_text.dart
+++ b/sky/sdk/example/widgets/styled_text.dart
@@ -106,7 +106,7 @@
     );
 
     return new Theme(
-      data: new ThemeData.light(primary: colors.Blue, darkToolbar: true),
+      data: new ThemeData.light(),
       child: new Scaffold(
         body: new Material(
           color: colors.Grey[50],
diff --git a/sky/sdk/example/widgets/tabs.dart b/sky/sdk/example/widgets/tabs.dart
index 872a3e7..93d259c 100644
--- a/sky/sdk/example/widgets/tabs.dart
+++ b/sky/sdk/example/widgets/tabs.dart
@@ -76,7 +76,7 @@
     return new Container(
      child: new Card(child: tabNavigator),
      padding: const EdgeDims.all(12.0),
-     decoration: new BoxDecoration(backgroundColor: Theme.of(this).primary[50])
+     decoration: new BoxDecoration(backgroundColor: Theme.of(this).primarySwatch[50])
     );
   }
 
diff --git a/sky/sdk/home.dart b/sky/sdk/home.dart
index 1968484..1addba1 100644
--- a/sky/sdk/home.dart
+++ b/sky/sdk/home.dart
@@ -8,7 +8,6 @@
 import 'package:sky/mojo/shell.dart' as shell;
 import 'package:sky/painting/box_painter.dart';
 import 'package:sky/theme/colors.dart' as colors;
-import 'package:sky/theme/edges.dart';
 import 'package:sky/theme/typography.dart' as typography;
 import 'package:sky/widgets/basic.dart';
 import 'package:sky/widgets/card.dart';
@@ -170,14 +169,14 @@
 class SkyHome extends App {
   Widget build() {
     return new Theme(
-      data: new ThemeData.dark(
-        primary: colors.Teal,
-        accent: colors.Orange
+      data: new ThemeData(
+        brightness: ThemeBrightness.dark,
+        primarySwatch: colors.Teal
       ),
       child: new Scaffold(
         toolbar: new ToolBar(center: new Text('Sky Demos')),
         body: new Material(
-          edge: MaterialEdge.canvas,
+          type: MaterialType.canvas,
           child: new DemoList()
         )
       )
diff --git a/sky/sdk/lib/editing/input.dart b/sky/sdk/lib/editing/input.dart
index f86e993..ad060ad 100644
--- a/sky/sdk/lib/editing/input.dart
+++ b/sky/sdk/lib/editing/input.dart
@@ -68,15 +68,23 @@
       textChildren.add(child);
     }
 
+    ThemeData themeData = Theme.of(this);
+    Color focusHighlightColor = themeData.accentColor;
+    Color cursorColor = themeData.accentColor;
+    if (themeData.primarySwatch != null) {
+      cursorColor = Theme.of(this).primarySwatch[200];
+      focusHighlightColor = focused ? themeData.primarySwatch[400] : themeData.primarySwatch[200];
+    }
+
     textChildren.add(new EditableText(
       value: _editableValue, 
       focused: focused,
       style: textStyle,
-      cursorColor: Theme.of(this).primary[200]
+      cursorColor: cursorColor
     ));
 
     Border focusHighlight = new Border(bottom: new BorderSide(
-      color: focused ? Theme.of(this).primary[400] : Theme.of(this).primary[200],
+      color: focusHighlightColor,
       width: focused ? 2.0 : 1.0
     ));
 
diff --git a/sky/sdk/lib/theme/colors.dart b/sky/sdk/lib/theme/colors.dart
index efa9051..4c7e2ee 100644
--- a/sky/sdk/lib/theme/colors.dart
+++ b/sky/sdk/lib/theme/colors.dart
@@ -370,3 +370,15 @@
   800: const Color(0xFF37474F),
   900: const Color(0xFF263238),
 };
+
+const List<Map<int, Color>> DarkColors = const [
+  Red,
+  Pink,
+  Purple,
+  DeepPurple,
+  Indigo,
+  Blue,
+  Teal,
+  DeepOrange,
+  Brown
+];
\ No newline at end of file
diff --git a/sky/sdk/lib/theme/theme_data.dart b/sky/sdk/lib/theme/theme_data.dart
index fe6d381..cfefa33 100644
--- a/sky/sdk/lib/theme/theme_data.dart
+++ b/sky/sdk/lib/theme/theme_data.dart
@@ -11,29 +11,67 @@
 
 class ThemeData {
 
-  ThemeData.light({
-    this.primary,
-    this.accent,
-    bool darkToolbar: false })
-    : brightness = ThemeBrightness.light,
-      toolbarText = darkToolbar ? typography.white : typography.black,
-      text = typography.black;
+  ThemeData({
+    ThemeBrightness brightness,
+    Map<int, Color> primarySwatch,
+    Color accentColor,
+    Color floatingActionButtonColor,
+    typography.TextTheme text,
+    typography.TextTheme toolbarText })
+    : this.brightness = brightness,
+      this.primarySwatch = primarySwatch,
+      canvasColor = brightness == ThemeBrightness.dark ? colors.Grey[850] : colors.Grey[50],
+      cardColor = brightness == ThemeBrightness.dark ? colors.Grey[800] : colors.White,
+      text = brightness == ThemeBrightness.dark ? typography.white : typography.black {
+    assert(brightness != null);
 
-  ThemeData.dark({ this.primary, this.accent })
-    : brightness = ThemeBrightness.dark,
-      toolbarText = typography.white,
-      text = typography.white;
+    if (primarySwatch == null) {
+      _primaryColor = brightness == ThemeBrightness.dark ? colors.Grey[900] : colors.Grey[100];
+    } else {
+      _primaryColor = primarySwatch[500];
+    }
 
-  ThemeData.fallback()
-    : brightness = ThemeBrightness.light,
-      primary = colors.Indigo,
-      accent = colors.PinkAccent,
-      toolbarText = typography.white,
-      text = typography.black;
+    if (accentColor == null) {
+      _accentColor = primarySwatch == null ? colors.Blue[500] : primarySwatch[500];
+    } else {
+      _accentColor = accentColor;
+    }
+
+    if (floatingActionButtonColor == null) {
+      _floatingActionButtonColor = accentColor == null ? colors.PinkAccent[200] : accentColor;
+    } else {
+      _floatingActionButtonColor = floatingActionButtonColor;
+    }
+
+    if (toolbarText == null) {
+      if (colors.DarkColors.contains(primarySwatch) || _primaryColor == colors.Grey[900])
+        _toolbarText = typography.white;
+      else
+        _toolbarText = typography.black;
+    } else {
+      _toolbarText = toolbarText;
+    }
+  }
+
+  factory ThemeData.light() => new ThemeData(primarySwatch: colors.Blue, brightness: ThemeBrightness.light);
+  factory ThemeData.dark() => new ThemeData(brightness: ThemeBrightness.dark);
+  factory ThemeData.fallback() => new ThemeData.light();
 
   final ThemeBrightness brightness;
-  final Map<int, Color> primary;
-  final Map<int, Color> accent;
+  final Map<int, Color> primarySwatch;
+  final Color canvasColor;
+  final Color cardColor;
   final typography.TextTheme text;
-  final typography.TextTheme toolbarText;
+
+  Color _primaryColor;
+  Color get primaryColor => _primaryColor;
+
+  Color _accentColor;
+  Color get accentColor => _accentColor;
+
+  Color _floatingActionButtonColor;
+  Color get floatingActionButtonColor => _floatingActionButtonColor;
+
+  typography.TextTheme _toolbarText;
+  typography.TextTheme get toolbarText => _toolbarText;
 }
diff --git a/sky/sdk/lib/widgets/card.dart b/sky/sdk/lib/widgets/card.dart
index 6c37376..dca8b55 100644
--- a/sky/sdk/lib/widgets/card.dart
+++ b/sky/sdk/lib/widgets/card.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import '../theme/colors.dart' as colors;
-import '../theme/edges.dart';
 import 'basic.dart';
 import 'material.dart';
 import "theme.dart";
@@ -14,27 +13,16 @@
   final Widget child;
   final Color color;
 
-  Color get materialColor {
-    if (color != null)
-      return color;
-    switch (Theme.of(this).brightness) {
-      case ThemeBrightness.light:
-        return colors.White;
-      case ThemeBrightness.dark:
-        return colors.Grey[800];
-    }
-  }
-
   Widget build() {
     return new Container(
       margin: const EdgeDims.all(4.0),
       child: new Material(
-        color: materialColor,
-        edge: MaterialEdge.card,
+        color: color,
+        type: MaterialType.card,
         level: 2,
         child: new ClipRRect(
-          xRadius: edges[MaterialEdge.card],
-          yRadius: edges[MaterialEdge.card],
+          xRadius: edges[MaterialType.card],
+          yRadius: edges[MaterialType.card],
           child: child
         )
       )
diff --git a/sky/sdk/lib/widgets/checkbox.dart b/sky/sdk/lib/widgets/checkbox.dart
index 2c80612..524d26d 100644
--- a/sky/sdk/lib/widgets/checkbox.dart
+++ b/sky/sdk/lib/widgets/checkbox.dart
@@ -11,7 +11,8 @@
 export 'toggleable.dart' show ValueChanged;
 
 const double _kMidpoint = 0.5;
-const sky.Color _kUncheckedColor = const sky.Color(0x8A000000);
+const sky.Color _kLightUncheckedColor = const sky.Color(0x8A000000);
+const sky.Color _kDarkUncheckedColor = const sky.Color(0xB2FFFFFF);
 const double _kEdgeSize = 20.0;
 const double _kEdgeRadius = 1.0;
 
@@ -26,9 +27,12 @@
   Size get size => const Size(_kEdgeSize + 2.0, _kEdgeSize + 2.0);
 
   void customPaintCallback(sky.Canvas canvas, Size size) {
+    ThemeData themeData = Theme.of(this);
+    Color uncheckedColor = themeData.brightness == ThemeBrightness.light ? _kLightUncheckedColor : _kDarkUncheckedColor;
+
     // Choose a color between grey and the theme color
     sky.Paint paint = new sky.Paint()..strokeWidth = 2.0
-                                     ..color = _kUncheckedColor;
+                                     ..color = uncheckedColor;
 
     // The rrect contracts slightly during the animation
     double inset = 2.0 - (toggleAnimation.value - _kMidpoint).abs() * 2.0;
@@ -46,7 +50,7 @@
         new sky.Gradient.radial(
           new Point(_kEdgeSize / 2.0, _kEdgeSize / 2.0),
           _kEdgeSize * (_kMidpoint - toggleAnimation.value) * 8.0,
-          [const sky.Color(0x00000000), _kUncheckedColor]
+          [const sky.Color(0x00000000), uncheckedColor]
         )
       );
       canvas.drawRRect(rrect, paint);
@@ -57,11 +61,10 @@
 
       // Solid filled rrect
       paint.setStyle(sky.PaintingStyle.strokeAndFill);
-      Color themeColor = Theme.of(this).primary[500];
       paint.color = new Color.fromARGB((t * 255).floor(),
-                                       themeColor.red,
-                                       themeColor.green,
-                                       themeColor.blue);
+                                       themeData.accentColor.red,
+                                       themeData.accentColor.green,
+                                       themeData.accentColor.blue);
       canvas.drawRRect(rrect, paint);
 
       // White inner check
diff --git a/sky/sdk/lib/widgets/drawer.dart b/sky/sdk/lib/widgets/drawer.dart
index 1a577bc..8ff37b6 100644
--- a/sky/sdk/lib/widgets/drawer.dart
+++ b/sky/sdk/lib/widgets/drawer.dart
@@ -6,10 +6,10 @@
 
 import '../animation/animation_performance.dart';
 import '../animation/curves.dart';
-import '../theme/colors.dart';
 import '../theme/shadows.dart';
 import 'animated_component.dart';
 import 'basic.dart';
+import 'theme.dart';
 
 // TODO(eseidel): Draw width should vary based on device size:
 // http://www.google.com/design/spec/layout/structure.html#structure-side-nav
@@ -128,7 +128,7 @@
     Widget content = controller.position.build(
       new Container(
         decoration: new BoxDecoration(
-          backgroundColor: Grey[50],
+          backgroundColor: Theme.of(this).canvasColor,
           boxShadow: shadows[level]),
         width: _kWidth,
         child: new Block(children)
diff --git a/sky/sdk/lib/widgets/drawer_header.dart b/sky/sdk/lib/widgets/drawer_header.dart
index 730055b..6f9b0e8 100644
--- a/sky/sdk/lib/widgets/drawer_header.dart
+++ b/sky/sdk/lib/widgets/drawer_header.dart
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import '../theme/colors.dart';
 import '../theme/view_configuration.dart';
 import 'basic.dart';
 import 'default_text_style.dart';
 import 'theme.dart';
 
+// TODO(jackson): This class should usually render the user's
+// preferred banner image rather than a solid background
+
 class DrawerHeader extends Component {
 
   DrawerHeader({ String key, this.children }) : super(key: key);
@@ -18,7 +20,7 @@
     return new Container(
       height: kStatusBarHeight + kMaterialDrawerHeight,
       decoration: new BoxDecoration(
-        backgroundColor: BlueGrey[50],
+        backgroundColor: Theme.of(this).cardColor,
         border: const Border(
           bottom: const BorderSide(
             color: const Color(0xFFD1D9E1),
diff --git a/sky/sdk/lib/widgets/floating_action_button.dart b/sky/sdk/lib/widgets/floating_action_button.dart
index 78f7a77..6c9eb86 100644
--- a/sky/sdk/lib/widgets/floating_action_button.dart
+++ b/sky/sdk/lib/widgets/floating_action_button.dart
@@ -31,8 +31,8 @@
 
   Widget buildContent() {
     return new Material(
-      color: Theme.of(this).accent[200],
-      edge: MaterialEdge.circle,
+      color: Theme.of(this).floatingActionButtonColor,
+      type: MaterialType.circle,
       level: highlight ? 3 : 2,
       child: new ClipOval(
         child: new Listener(
diff --git a/sky/sdk/lib/widgets/material.dart b/sky/sdk/lib/widgets/material.dart
index 44b6864..444434f 100644
--- a/sky/sdk/lib/widgets/material.dart
+++ b/sky/sdk/lib/widgets/material.dart
@@ -4,14 +4,20 @@
 
 import '../animation/animated_value.dart';
 import '../painting/box_painter.dart';
-import '../theme/edges.dart';
 import '../theme/shadows.dart';
 import 'animated_component.dart';
 import 'basic.dart';
 import 'default_text_style.dart';
 import 'theme.dart';
 
-export '../theme/edges.dart' show MaterialEdge;
+enum MaterialType { canvas, card, circle, button }
+
+const Map<MaterialType, double> edges = const {
+  MaterialType.canvas: null,
+  MaterialType.card: 2.0,
+  MaterialType.circle: null,
+  MaterialType.button: 2.0,
+};
 
 const double _kAnimateShadowDurationMS = 100.0;
 
@@ -34,7 +40,7 @@
   Material({
     String key,
     this.child,
-    this.edge: MaterialEdge.card,
+    this.type: MaterialType.card,
     int level: 0,
     this.color
   }) : super(key: key) {
@@ -43,13 +49,13 @@
   }
 
   Widget child;
-  MaterialEdge edge;
+  MaterialType type;
   AnimatedValue level;
   Color color;
 
   void syncFields(Material source) {
     child = source.child;
-    edge = source.edge;
+    type = source.type;
     // TODO(mpcomplete): duration is wrong, because the current level may be
     // anything. We really want |rate|.
     if (level.value != source.level.value)
@@ -58,15 +64,28 @@
     super.syncFields(source);
   }
 
+  Color get backgroundColor {
+    if (color != null)
+      return color;
+    switch(type) {
+      case MaterialType.canvas:
+        return Theme.of(this).canvasColor;
+      case MaterialType.card:
+        return Theme.of(this).cardColor;
+      default: 
+        return null;
+    }
+  }
+
   // TODO(mpcomplete): make this animate color changes.
 
   Widget build() {
     return new Container(
       decoration: new BoxDecoration(
         boxShadow: _computeShadow(level.value),
-        borderRadius: edges[edge],
-        backgroundColor: color,
-        shape: edge == MaterialEdge.circle ? Shape.circle : Shape.rectangle
+        borderRadius: edges[type],
+        backgroundColor: backgroundColor,
+        shape: type == MaterialType.circle ? Shape.circle : Shape.rectangle
       ),
       child: new DefaultTextStyle(style: Theme.of(this).text.body1, child: child)
     );
diff --git a/sky/sdk/lib/widgets/material_button.dart b/sky/sdk/lib/widgets/material_button.dart
index f1513e5..e6a866e 100644
--- a/sky/sdk/lib/widgets/material_button.dart
+++ b/sky/sdk/lib/widgets/material_button.dart
@@ -42,6 +42,7 @@
         constraints: new BoxConstraints(minWidth: 88.0),
         margin: new EdgeDims.all(8.0),
         child: new Material(
+          type: MaterialType.button,
           child: enabled ? new InkWell(child: contents) : contents,
           level: level,
           color: color
diff --git a/sky/sdk/lib/widgets/menu_item.dart b/sky/sdk/lib/widgets/menu_item.dart
index 6f24377..94a17a8 100644
--- a/sky/sdk/lib/widgets/menu_item.dart
+++ b/sky/sdk/lib/widgets/menu_item.dart
@@ -43,7 +43,7 @@
   TextStyle get textStyle {
     TextStyle result = Theme.of(this).text.body2;
     if (highlight)
-      result = result.copyWith(color: Theme.of(this).primary[500]);
+      result = result.copyWith(color: Theme.of(this).primaryColor);
     return result;
   }
 
diff --git a/sky/sdk/lib/widgets/radio.dart b/sky/sdk/lib/widgets/radio.dart
index eb82dfd..32f0c1c 100644
--- a/sky/sdk/lib/widgets/radio.dart
+++ b/sky/sdk/lib/widgets/radio.dart
@@ -5,9 +5,12 @@
 import 'dart:sky' as sky;
 
 import '../rendering/object.dart';
-import '../theme/colors.dart' as colors;
 import 'basic.dart';
 import 'button_base.dart';
+import 'theme.dart';
+
+const sky.Color _kLightOffColor = const sky.Color(0x8A000000);
+const sky.Color _kDarkOffColor = const sky.Color(0xB2FFFFFF);
 
 typedef void ValueChanged(value);
 
@@ -31,9 +34,14 @@
     super.syncFields(source);
   }
 
+  Color get color {
+    ThemeData themeData = Theme.of(this);
+    if (value == groupValue)
+      return themeData.accentColor;
+    return themeData.brightness == ThemeBrightness.light ? _kLightOffColor : _kDarkOffColor;
+  }
+
   Widget buildContent() {
-    // TODO(jackson): This should change colors with the theme
-    Color color = highlight ? colors.Purple[500] : const Color(0x8A000000);
     const double kDiameter = 16.0;
     const double kOuterRadius = kDiameter / 2;
     const double kInnerRadius = 5.0;
diff --git a/sky/sdk/lib/widgets/raised_button.dart b/sky/sdk/lib/widgets/raised_button.dart
index 2ff1903..40c7adb 100644
--- a/sky/sdk/lib/widgets/raised_button.dart
+++ b/sky/sdk/lib/widgets/raised_button.dart
@@ -30,9 +30,9 @@
           break;
         case ThemeBrightness.dark:
           if (highlight)
-            return Theme.of(this).primary[700];
+            return Theme.of(this).primarySwatch[700];
           else
-            return Theme.of(this).primary[600];
+            return Theme.of(this).primarySwatch[600];
           break;
       }
     } else {
diff --git a/sky/sdk/lib/widgets/scrollable.dart b/sky/sdk/lib/widgets/scrollable.dart
index 3e9c924..a6c4023 100644
--- a/sky/sdk/lib/widgets/scrollable.dart
+++ b/sky/sdk/lib/widgets/scrollable.dart
@@ -8,12 +8,9 @@
 import '../animation/generators.dart';
 import '../animation/mechanics.dart';
 import '../animation/scroll_behavior.dart';
-import '../theme/colors.dart' as colors;
-import '../theme/theme_data.dart';
 import '../theme/view_configuration.dart' as config;
 import 'basic.dart';
 import 'material.dart';
-import 'theme.dart';
 
 const double _kMillisecondsPerSecond = 1000.0;
 
@@ -37,17 +34,6 @@
     backgroundColor = source.backgroundColor;
   }
 
-  Color get _nonNullBackgroundColor {
-    if (backgroundColor != null)
-      return backgroundColor;
-    switch (Theme.of(this).brightness) {
-      case ThemeBrightness.light:
-        return colors.Grey[50];
-      case ThemeBrightness.dark:
-        return colors.Grey[850];
-    }
-  }
-
   double _scrollOffset = 0.0;
   double get scrollOffset => _scrollOffset;
 
@@ -66,9 +52,9 @@
   Widget build() {
     return new Listener(
       child: new Material(
+        type: MaterialType.canvas,
         child: buildContent(),
-        edge: MaterialEdge.canvas,
-        color: _nonNullBackgroundColor
+        color: backgroundColor
       ),
       onPointerDown: _handlePointerDown,
       onPointerUp: _handlePointerUpOrCancel,
diff --git a/sky/sdk/lib/widgets/switch.dart b/sky/sdk/lib/widgets/switch.dart
index 9fb87da..23e4ce5 100644
--- a/sky/sdk/lib/widgets/switch.dart
+++ b/sky/sdk/lib/widgets/switch.dart
@@ -37,7 +37,7 @@
     sky.Color thumbColor = _kThumbOffColor;
     sky.Color trackColor = _kTrackOffColor;
     if (value) {
-      thumbColor = Theme.of(this).primary[500];
+      thumbColor = Theme.of(this).accentColor;
       trackColor = new sky.Color(thumbColor.value & 0x80FFFFFF);
     }
 
diff --git a/sky/sdk/lib/widgets/tabs.dart b/sky/sdk/lib/widgets/tabs.dart
index f66d0ee..f621ff2 100644
--- a/sky/sdk/lib/widgets/tabs.dart
+++ b/sky/sdk/lib/widgets/tabs.dart
@@ -295,8 +295,8 @@
     return new TabBarWrapper(
       children: tabs, 
       selectedIndex: selectedIndex,
-      backgroundColor: Theme.of(this).primary[500],
-      indicatorColor: Theme.of(this).accent[200],
+      backgroundColor: Theme.of(this).primaryColor,
+      indicatorColor: Theme.of(this).accentColor,
       textAndIcons: textAndIcons
     );
   }
diff --git a/sky/sdk/lib/widgets/tool_bar.dart b/sky/sdk/lib/widgets/tool_bar.dart
index df23030..cdc251f 100644
--- a/sky/sdk/lib/widgets/tool_bar.dart
+++ b/sky/sdk/lib/widgets/tool_bar.dart
@@ -54,7 +54,7 @@
       ),
       padding: new EdgeDims.symmetric(horizontal: 8.0),
       decoration: new BoxDecoration(
-        backgroundColor: backgroundColor == null ? Theme.of(this).primary[500] : backgroundColor,
+        backgroundColor: backgroundColor == null ? Theme.of(this).primaryColor : backgroundColor,
         boxShadow: shadows[2]
       )
     );
diff --git a/sky/tests/examples/tabs-expected.txt b/sky/tests/examples/tabs-expected.txt
index e93b9b8..f8b71d6 100644
--- a/sky/tests/examples/tabs-expected.txt
+++ b/sky/tests/examples/tabs-expected.txt
@@ -12,14 +12,14 @@
 2 |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  | paintChild RenderTabBar at Point(0.0, 81.0)
 2 |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
-2 |  |  |  | drawRect(Rect.fromLTRB(0.0, 81.0, 800.0, 129.0), Paint(color:Color(0xff3f51b5)))
+2 |  |  |  | drawRect(Rect.fromLTRB(0.0, 81.0, 800.0, 129.0), Paint(color:Color(0xff2196f3)))
 2 |  |  |  | paintChild RenderInkWell at Point(0.0, 81.0)
 2 |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  | paintChild RenderOpacity at Point(115.33333333333334, 97.0)
 2 |  |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  |  | translate(115.33333333333334, 97.0)
 2 |  |  |  |  |  | translate(-115.33333333333334, -97.0)
-2 |  |  |  | drawRect(Rect.fromLTRB(0.0, 127.0, 266.6666564941406, 129.0), Paint(color:Color(0xffff4081)))
+2 |  |  |  | drawRect(Rect.fromLTRB(0.0, 127.0, 266.6666564941406, 129.0), Paint(color:Color(0xff2196f3)))
 2 |  |  |  | paintChild RenderInkWell at Point(266.6666666666667, 81.0)
 2 |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  | paintChild RenderOpacity at Point(377.5, 97.0)
@@ -38,7 +38,7 @@
 2 |  |  |  |  |  | restore
 2 |  |  | paintChild RenderDecoratedBox at Point(0.0, 129.0)
 2 |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
-2 |  |  |  | drawRect(Rect.fromLTRB(0.0, 129.0, 800.0, 600.0), Paint(color:Color(0xffe8eaf6)))
+2 |  |  |  | drawRect(Rect.fromLTRB(0.0, 129.0, 800.0, 600.0), Paint(color:Color(0xffe3f2fd)))
 2 |  |  |  | paintChild RenderPadding at Point(12.0, 141.0)
 2 |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  | paintChild RenderDecoratedBox at Point(16.0, 145.0)
@@ -48,14 +48,14 @@
 2 |  |  |  |  |  | clipRRect()
 2 |  |  |  |  |  | paintChild RenderTabBar at Point(16.0, 145.0)
 2 |  |  |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
-2 |  |  |  |  |  |  | drawRect(Rect.fromLTRB(16.0, 145.0, 784.0, 193.0), Paint(color:Color(0xff3f51b5)))
+2 |  |  |  |  |  |  | drawRect(Rect.fromLTRB(16.0, 145.0, 784.0, 193.0), Paint(color:Color(0xff2196f3)))
 2 |  |  |  |  |  |  | paintChild RenderInkWell at Point(16.0, 145.0)
 2 |  |  |  |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  |  |  |  | paintChild RenderOpacity at Point(96.5, 159.0)
 2 |  |  |  |  |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  |  |  |  |  | translate(96.5, 159.0)
 2 |  |  |  |  |  |  |  |  | translate(-96.5, -159.0)
-2 |  |  |  |  |  |  | drawRect(Rect.fromLTRB(16.0, 191.0, 208.0, 193.0), Paint(color:Color(0xffff4081)))
+2 |  |  |  |  |  |  | drawRect(Rect.fromLTRB(16.0, 191.0, 208.0, 193.0), Paint(color:Color(0xff2196f3)))
 2 |  |  |  |  |  |  | paintChild RenderInkWell at Point(208.0, 145.0)
 2 |  |  |  |  |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  |  |  |  |  | paintChild RenderOpacity at Point(287.0, 159.0)
@@ -89,7 +89,7 @@
 2 |  |  |  |  |  | restore
 2 |  | paintChild RenderDecoratedBox at Point(0.0, 0.0)
 2 |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
-2 |  |  | drawRect(Rect.fromLTRB(0.0, 0.0, 800.0, 81.0), Paint(color:Color(0xff3f51b5), drawLooper:true))
+2 |  |  | drawRect(Rect.fromLTRB(0.0, 0.0, 800.0, 81.0), Paint(color:Color(0xff2196f3), drawLooper:true))
 2 |  |  | paintChild RenderFlex at Point(8.0, 0.0)
 2 |  |  |  | TestPaintingCanvas() constructor: 800.0 x 600.0
 2 |  |  |  | paintChild RenderConstrainedBox at Point(8.0, 25.0)