Reorganize the calculator demo (#4536)

This patch is a warmup to improving the visuals in the calculator demo.

Related to #4535
diff --git a/examples/flutter_gallery/lib/demo/calculator/home.dart b/examples/flutter_gallery/lib/demo/calculator/home.dart
new file mode 100644
index 0000000..09cf8ec
--- /dev/null
+++ b/examples/flutter_gallery/lib/demo/calculator/home.dart
@@ -0,0 +1,269 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+
+import 'logic.dart';
+
+class Calculator extends StatefulWidget {
+  Calculator({Key key}) : super(key: key);
+
+  @override
+  _CalculatorState createState() => new _CalculatorState();
+}
+
+class _CalculatorState extends State<Calculator> {
+  /// As the user taps keys we update the current `_expression` and we also
+  /// keep a stack of previous expressions so we can return to earlier states
+  /// when the user hits the DEL key.
+  final List<CalcExpression> _expressionStack = <CalcExpression>[];
+  CalcExpression _expression = new CalcExpression.Empty();
+
+  // Make `expression` the current expression and push the previous current
+  // expression onto the stack.
+  void pushExpression(CalcExpression expression) {
+    _expressionStack.add(_expression);
+    _expression = expression;
+  }
+
+  /// Pop the top expression off of the stack and make it the current expression.
+  void popCalcExpression() {
+    if (_expressionStack.length > 0) {
+      _expression = _expressionStack.removeLast();
+    } else {
+      _expression = new CalcExpression.Empty();
+    }
+  }
+
+  /// Set `resultExpression` to the currrent expression and clear the stack.
+  void setResult(CalcExpression resultExpression) {
+    _expressionStack.clear();
+    _expression = resultExpression;
+  }
+
+  void handleNumberTap(int n) {
+    final CalcExpression expression = _expression.appendDigit(n);
+    if (expression != null) {
+      setState(() {
+        pushExpression(expression);
+      });
+    }
+  }
+
+  void handlePointTap() {
+    final CalcExpression expression = _expression.appendPoint();
+    if (expression != null) {
+      setState(() {
+        pushExpression(expression);
+      });
+    }
+  }
+
+  void handlePlusTap() {
+    final CalcExpression expression = _expression.appendOperation(Operation.Addition);
+    if (expression != null) {
+      setState(() {
+        pushExpression(expression);
+      });
+    }
+  }
+
+  void handleMinusTap() {
+    final CalcExpression expression = _expression.appendMinus();
+    if (expression != null) {
+      setState(() {
+        pushExpression(expression);
+      });
+    }
+  }
+
+  void handleMultTap() {
+    final CalcExpression expression = _expression.appendOperation(Operation.Multiplication);
+    if (expression != null) {
+      setState(() {
+        pushExpression(expression);
+      });
+    }
+  }
+
+  void handleDivTap() {
+    final CalcExpression expression = _expression.appendOperation(Operation.Division);
+    if (expression != null) {
+      setState(() {
+        pushExpression(expression);
+      });
+    }
+  }
+
+  void handleEqualsTap() {
+    final CalcExpression resultExpression = _expression.computeResult();
+    if (resultExpression != null) {
+      setState(() {
+        setResult(resultExpression);
+      });
+    }
+  }
+
+  void handleDelTap() {
+    setState(() {
+      popCalcExpression();
+    });
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return new Scaffold(
+      appBar: new AppBar(
+        backgroundColor: Theme.of(context).canvasColor,
+        elevation: 0
+      ),
+      body: new Column(
+        crossAxisAlignment: CrossAxisAlignment.stretch,
+        children: <Widget>[
+          // Give the key-pad 3/5 of the vertical space and the display 2/5.
+          new Flexible(
+            flex: 2,
+            child: new CalcDisplay(content: _expression.toString())
+          ),
+          new Divider(height: 1.0),
+          new Flexible(
+            flex: 3,
+            child: new KeyPad(calcState: this)
+          )
+        ]
+      )
+    );
+  }
+}
+
+class CalcDisplay extends StatelessWidget {
+  CalcDisplay({ this.content });
+
+  final String content;
+
+  @override
+  Widget build(BuildContext context) {
+    return new Center(
+      child: new Text(
+        content,
+        style: const TextStyle(fontSize: 24.0)
+      )
+    );
+  }
+}
+
+class KeyPad extends StatelessWidget {
+  KeyPad({ this.calcState });
+
+  final _CalculatorState calcState;
+
+  @override
+  Widget build(BuildContext context) {
+    final ThemeData themeData = new ThemeData(
+      primarySwatch: Colors.purple,
+      brightness: Brightness.dark
+    );
+    return new Theme(
+      data: themeData,
+      child: new Material(
+        child: new Row(
+          children: <Widget>[
+            new Flexible(
+              // We set flex equal to the number of columns so that the main keypad
+              // and the op keypad have sizes proportional to their number of
+              // columns.
+              flex: 3,
+              child: new Column(
+                children: <Widget>[
+                  new KeyRow(<Widget>[
+                    new NumberKey(7, calcState),
+                    new NumberKey(8, calcState),
+                    new NumberKey(9, calcState)
+                  ]),
+                  new KeyRow(<Widget>[
+                    new NumberKey(4, calcState),
+                    new NumberKey(5, calcState),
+                    new NumberKey(6, calcState)
+                  ]),
+                  new KeyRow(<Widget>[
+                    new NumberKey(1, calcState),
+                    new NumberKey(2, calcState),
+                    new NumberKey(3, calcState)
+                  ]),
+                  new KeyRow(<Widget>[
+                    new CalcKey('.', calcState.handlePointTap),
+                    new NumberKey(0, calcState),
+                    new CalcKey('=', calcState.handleEqualsTap),
+                  ])
+                ]
+              )
+            ),
+            new Flexible(
+              child: new Material(
+                color: themeData.backgroundColor,
+                child: new Column(
+                  children: <Widget>[
+                    new CalcKey('\u232B', calcState.handleDelTap),
+                    new CalcKey('\u00F7', calcState.handleDivTap),
+                    new CalcKey('\u00D7', calcState.handleMultTap),
+                    new CalcKey('-', calcState.handleMinusTap),
+                    new CalcKey('+', calcState.handlePlusTap)
+                  ]
+                )
+              )
+            ),
+          ]
+        )
+      )
+    );
+  }
+}
+
+class KeyRow extends StatelessWidget {
+  KeyRow(this.keys);
+
+  final List<Widget> keys;
+
+  @override
+  Widget build(BuildContext context) {
+    return new Flexible(
+      child: new Row(
+        mainAxisAlignment: MainAxisAlignment.center,
+        children: this.keys
+      )
+    );
+  }
+}
+
+class CalcKey extends StatelessWidget {
+  CalcKey(this.text, this.onTap);
+
+  final String text;
+  final GestureTapCallback onTap;
+
+  @override
+  Widget build(BuildContext context) {
+    final Orientation orientation = MediaQuery.of(context).orientation;
+    return new Flexible(
+      child: new InkResponse(
+        onTap: this.onTap,
+        child: new Center(
+          child: new Text(
+            this.text,
+            style: new TextStyle(
+              fontSize: (orientation == Orientation.portrait) ? 32.0 : 24.0
+            )
+          )
+        )
+      )
+    );
+  }
+}
+
+class NumberKey extends CalcKey {
+  NumberKey(int value, _CalculatorState calcState)
+    : super('$value', () {
+        calcState.handleNumberTap(value);
+      });
+}
diff --git a/examples/flutter_gallery/lib/demo/calculator_logic.dart b/examples/flutter_gallery/lib/demo/calculator/logic.dart
similarity index 100%
rename from examples/flutter_gallery/lib/demo/calculator_logic.dart
rename to examples/flutter_gallery/lib/demo/calculator/logic.dart
diff --git a/examples/flutter_gallery/lib/demo/calculator_demo.dart b/examples/flutter_gallery/lib/demo/calculator_demo.dart
index f6ccafe..c76664c 100644
--- a/examples/flutter_gallery/lib/demo/calculator_demo.dart
+++ b/examples/flutter_gallery/lib/demo/calculator_demo.dart
@@ -4,287 +4,13 @@
 
 import 'package:flutter/material.dart';
 
-import 'calculator_logic.dart';
+import 'calculator/home.dart';
 
-class Calculator extends StatefulWidget {
-  Calculator({Key key}) : super(key: key);
+class CalculatorDemo extends StatelessWidget {
+  CalculatorDemo({Key key}) : super(key: key);
 
   static const String routeName = '/calculator';
 
   @override
-  _CalculatorState createState() => new _CalculatorState();
-}
-
-class _CalculatorState extends State<Calculator> {
-  /// As the user taps keys we update the current `_expression` and we also
-  /// keep a stack of previous expressions so we can return to earlier states
-  /// when the user hits the DEL key.
-  final List<CalcExpression> _expressionStack = <CalcExpression>[];
-  CalcExpression _expression = new CalcExpression.Empty();
-
-  // Make `expression` the current expression and push the previous current
-  // expression onto the stack.
-  void pushExpression(CalcExpression expression) {
-    _expressionStack.add(_expression);
-    _expression = expression;
-  }
-
-  /// Pop the top expression off of the stack and make it the current expression.
-  void popCalcExpression() {
-    if (_expressionStack.length > 0) {
-      _expression = _expressionStack.removeLast();
-    } else {
-      _expression = new CalcExpression.Empty();
-    }
-  }
-
-  /// Set `resultExpression` to the currrent expression and clear the stack.
-  void setResult(CalcExpression resultExpression) {
-    _expressionStack.clear();
-    _expression = resultExpression;
-  }
-
-  void handleNumberTap(int n) {
-    final CalcExpression expression = _expression.appendDigit(n);
-    if (expression != null) {
-      setState(() {
-        pushExpression(expression);
-      });
-    }
-  }
-
-  void handlePointTap() {
-    final CalcExpression expression = _expression.appendPoint();
-    if (expression != null) {
-      setState(() {
-        pushExpression(expression);
-      });
-    }
-  }
-
-  void handlePlusTap() {
-    final CalcExpression expression = _expression.appendOperation(Operation.Addition);
-    if (expression != null) {
-      setState(() {
-        pushExpression(expression);
-      });
-    }
-  }
-
-  void handleMinusTap() {
-    final CalcExpression expression = _expression.appendMinus();
-    if (expression != null) {
-      setState(() {
-        pushExpression(expression);
-      });
-    }
-  }
-
-  void handleMultTap() {
-    final CalcExpression expression = _expression.appendOperation(Operation.Multiplication);
-    if (expression != null) {
-      setState(() {
-        pushExpression(expression);
-      });
-    }
-  }
-
-  void handleDivTap() {
-    final CalcExpression expression = _expression.appendOperation(Operation.Division);
-    if (expression != null) {
-      setState(() {
-        pushExpression(expression);
-      });
-    }
-  }
-
-  void handleEqualsTap() {
-    final CalcExpression resultExpression = _expression.computeResult();
-    if (resultExpression != null) {
-      setState(() {
-        setResult(resultExpression);
-      });
-    }
-  }
-
-  void handleDelTap() {
-    setState(() {
-      popCalcExpression();
-    });
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return new Scaffold(
-      appBar: new AppBar(title: new Text('Calculator')),
-      body: new Column(
-        children: <Widget>[
-          // Give the key-pad 3/5 of the vertical space and the display 2/5.
-          new CalcDisplay(2, _expression.toString()),
-          new Divider(height: 1.0),
-          new KeyPad(3, calcState: this)
-        ]
-      )
-    );
-  }
-}
-
-class CalcDisplay extends StatelessWidget {
-  CalcDisplay(this._flex, this._contents);
-
-  final int _flex;
-  final String _contents;
-
-  @override
-  Widget build(BuildContext context) {
-    return new Flexible(
-      flex: _flex,
-      child: new Center(
-        child: new Text(
-          _contents,
-          style: const TextStyle(fontSize: 24.0)
-        )
-      )
-    );
-  }
-}
-
-class KeyPad extends StatelessWidget {
-  KeyPad(this._flex, {this.calcState});
-
-  final int _flex;
-  final _CalculatorState calcState;
-
-  @override
-  Widget build(BuildContext context) {
-    return new Theme(
-      data: new ThemeData(
-        primarySwatch: Colors.purple,
-        brightness: Brightness.dark
-      ),
-      child: new Flexible(
-        flex: _flex,
-        child: new Material(
-          child: new Row(
-            children: <Widget>[
-              new MainKeyPad(calcState: calcState),
-              new OpKeyPad(calcState: calcState),
-            ]
-          )
-        )
-      )
-    );
-  }
-}
-
-class MainKeyPad extends StatelessWidget {
-  MainKeyPad({this.calcState});
-
-  final _CalculatorState calcState;
-
-  @override
-  Widget build(BuildContext context) {
-    return new Flexible(
-      // We set flex equal to the number of columns so that the main keypad
-      // and the op keypad have sizes proportional to their number of
-      // columns.
-      flex: 3,
-      child: new Column(
-        children: <Widget>[
-          new KeyRow(<Widget>[
-            new NumberKey(7, calcState),
-            new NumberKey(8, calcState),
-            new NumberKey(9, calcState)
-          ]),
-          new KeyRow(<Widget>[
-            new NumberKey(4, calcState),
-            new NumberKey(5, calcState),
-            new NumberKey(6, calcState)
-          ]),
-          new KeyRow(<Widget>[
-            new NumberKey(1, calcState),
-            new NumberKey(2, calcState),
-            new NumberKey(3, calcState)
-          ]),
-          new KeyRow(<Widget>[
-            new CalcKey('.', calcState.handlePointTap),
-            new NumberKey(0, calcState),
-            new CalcKey('=', calcState.handleEqualsTap),
-          ])
-        ]
-      )
-    );
-  }
-}
-
-class OpKeyPad extends StatelessWidget {
-  OpKeyPad({this.calcState});
-
-  final _CalculatorState calcState;
-
-  @override
-  Widget build(BuildContext context) {
-    final ThemeData themeData = Theme.of(context);
-    return new Flexible(
-      child: new Material(
-        color: themeData.backgroundColor,
-        child: new Column(
-          children: <Widget>[
-            new CalcKey('\u232B', calcState.handleDelTap),
-            new CalcKey('\u00F7', calcState.handleDivTap),
-            new CalcKey('\u00D7', calcState.handleMultTap),
-            new CalcKey('-', calcState.handleMinusTap),
-            new CalcKey('+', calcState.handlePlusTap)
-          ]
-        )
-      )
-    );
-  }
-}
-
-class KeyRow extends StatelessWidget {
-  KeyRow(this.keys);
-
-  final List<Widget> keys;
-
-  @override
-  Widget build(BuildContext context) {
-    return new Flexible(
-      child: new Row(
-        mainAxisAlignment: MainAxisAlignment.center, children: this.keys
-      )
-    );
-  }
-}
-
-class CalcKey extends StatelessWidget {
-  CalcKey(this.text, this.onTap);
-
-  final String text;
-  final GestureTapCallback onTap;
-
-  @override
-  Widget build(BuildContext context) {
-    final Orientation orientation = MediaQuery.of(context).orientation;
-    return new Flexible(
-      child: new InkResponse(
-        onTap: this.onTap,
-        child: new Center(
-          child: new Text(
-            this.text,
-            style: new TextStyle(
-              fontSize: (orientation == Orientation.portrait) ? 32.0 : 24.0
-            )
-          )
-        )
-      )
-    );
-  }
-}
-
-class NumberKey extends CalcKey {
-  NumberKey(int value, _CalculatorState calcState)
-    : super('$value', () {
-        calcState.handleNumberTap(value);
-      });
+  Widget build(BuildContext context) => new Calculator();
 }
diff --git a/examples/flutter_gallery/lib/gallery/app.dart b/examples/flutter_gallery/lib/gallery/app.dart
index 1925023..3bf3af0 100644
--- a/examples/flutter_gallery/lib/gallery/app.dart
+++ b/examples/flutter_gallery/lib/gallery/app.dart
@@ -12,7 +12,7 @@
 final Map<String, WidgetBuilder> kRoutes = <String, WidgetBuilder>{
   PestoDemo.routeName: (BuildContext context) => new PestoDemo(),
   ShrineDemo.routeName: (BuildContext context) => new ShrineDemo(),
-  Calculator.routeName: (BuildContext context) => new Calculator(),
+  CalculatorDemo.routeName: (BuildContext context) => new CalculatorDemo(),
   ContactsDemo.routeName: (BuildContext context) => new ContactsDemo(),
   ButtonsDemo.routeName: (BuildContext context) => new ButtonsDemo(),
   CardsDemo.routeName: (BuildContext context) => new CardsDemo(),
diff --git a/examples/flutter_gallery/lib/gallery/home.dart b/examples/flutter_gallery/lib/gallery/home.dart
index dac4ef8..2e8dd22 100644
--- a/examples/flutter_gallery/lib/gallery/home.dart
+++ b/examples/flutter_gallery/lib/gallery/home.dart
@@ -73,7 +73,7 @@
             children: <Widget>[
               new GalleryItem(title: 'Pesto', routeName: PestoDemo.routeName),
               new GalleryItem(title: 'Shrine', routeName: ShrineDemo.routeName),
-              new GalleryItem(title: 'Calculator', routeName: Calculator.routeName),
+              new GalleryItem(title: 'Calculator', routeName: CalculatorDemo.routeName),
               new GalleryItem(title: 'Contacts', routeName: ContactsDemo.routeName)
             ]
           ),
diff --git a/examples/flutter_gallery/test/calculator/logic.dart b/examples/flutter_gallery/test/calculator/logic.dart
index 0d2cdba9..b479f3f 100644
--- a/examples/flutter_gallery/test/calculator/logic.dart
+++ b/examples/flutter_gallery/test/calculator/logic.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter_gallery/demo/calculator_logic.dart';
+import 'package:flutter_gallery/demo/calculator/logic.dart';
 import 'package:test/test.dart';
 
 void main() {
diff --git a/examples/flutter_gallery/test/calculator/smoke_test.dart b/examples/flutter_gallery/test/calculator/smoke_test.dart
index 014e043..65a6d12 100644
--- a/examples/flutter_gallery/test/calculator/smoke_test.dart
+++ b/examples/flutter_gallery/test/calculator/smoke_test.dart
@@ -14,7 +14,7 @@
   // We press the "1" and the "2" buttons and check that the display
   // reads "12".
   testWidgets('Flutter calculator app smoke test', (WidgetTester tester)  async {
-    await tester.pumpWidget(new Calculator());
+    await tester.pumpWidget(new CalculatorDemo());
 
     Finder oneButton = find.widgetWithText(InkResponse, '1');
     expect(oneButton, findsOneWidget);