mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
285 lines
7.0 KiB
Dart
285 lines
7.0 KiB
Dart
// 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 'calculator_logic.dart';
|
|
|
|
class Calculator extends StatefulWidget {
|
|
Calculator({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 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(color: Colors.black, 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 Flexible(
|
|
flex: _flex,
|
|
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 Material(
|
|
elevation: 12,
|
|
color: Colors.grey[800],
|
|
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) {
|
|
return new Flexible(
|
|
child: new Material(
|
|
elevation: 24,
|
|
color: Colors.grey[700],
|
|
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) {
|
|
return new Flexible(
|
|
// child: new Container(
|
|
child: new InkResponse(
|
|
onTap: this.onTap,
|
|
child: new Center(
|
|
child: new Text(
|
|
this.text,
|
|
style: const TextStyle(color: Colors.white, fontSize: 32.0)
|
|
)
|
|
)
|
|
)
|
|
// )
|
|
);
|
|
}
|
|
}
|
|
|
|
class NumberKey extends CalcKey {
|
|
NumberKey(int value, _CalculatorState calcState)
|
|
: super('$value', () {
|
|
calcState.handleNumberTap(value);
|
|
});
|
|
}
|