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);