flutter/examples/fitness/lib/measurement.dart
Adam Barth cf88993492 RenderInkWell should use gestures
After this patch, InkWell is driven by gesture recognizers, which lets us
cleanly cancel splashes when the user actually scrolls.

I've also refactored all the clients of InkWell to use InkWell to detect
gestures instead of wrapping InkWell in a GestureDetector.

Fixes #1271
2015-10-03 12:49:34 -07:00

213 lines
5.6 KiB
Dart

// Copyright 2014 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.
part of fitness;
class Measurement extends FitnessItem {
Measurement({ DateTime when, this.weight }) : super(when: when);
Measurement.fromJson(Map json) : super.fromJson(json), weight = json['weight'];
final double weight;
// TODO(jackson): Internationalize
String get displayWeight => "${weight.toStringAsFixed(1)} lbs";
@override
Map toJson() {
Map json = super.toJson();
json['weight'] = weight;
json['type'] = runtimeType.toString();
return json;
}
FitnessItemRow toRow({ FitnessItemHandler onDismissed }) {
return new MeasurementRow(measurement: this, onDismissed: onDismissed);
}
}
class MeasurementRow extends FitnessItemRow {
MeasurementRow({ Measurement measurement, FitnessItemHandler onDismissed })
: super(item: measurement, onDismissed: onDismissed);
Widget buildContent(BuildContext context) {
Measurement measurement = item;
List<Widget> children = [
new Flexible(
child: new Text(
measurement.displayWeight,
style: Theme.of(context).text.subhead
)
),
new Flexible(
child: new Text(
measurement.displayDate,
style: Theme.of(context).text.caption.copyWith(textAlign: TextAlign.right)
)
)
];
return new Row(
children,
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(context).textBaseline
);
}
}
class MeasurementDateDialog extends StatefulComponent {
MeasurementDateDialog({ this.navigator, this.previousDate });
final NavigatorState navigator;
final DateTime previousDate;
MeasurementDateDialogState createState() => new MeasurementDateDialogState();
}
class MeasurementDateDialogState extends State<MeasurementDateDialog> {
@override
void initState() {
_selectedDate = config.previousDate;
}
DateTime _selectedDate;
void _handleDateChanged(DateTime value) {
setState(() {
_selectedDate = value;
});
}
Widget build(BuildContext context) {
return new Dialog(
content: new DatePicker(
selectedDate: _selectedDate,
firstDate: new DateTime(2015, 8),
lastDate: new DateTime(2101),
onChanged: _handleDateChanged
),
contentPadding: EdgeDims.zero,
actions: [
new FlatButton(
child: new Text('CANCEL'),
onPressed: config.navigator.pop
),
new FlatButton(
child: new Text('OK'),
onPressed: () {
config.navigator.pop(_selectedDate);
}
),
]
);
}
}
class MeasurementFragment extends StatefulComponent {
MeasurementFragment({ this.navigator, this.onCreated });
final NavigatorState navigator;
final FitnessItemHandler onCreated;
MeasurementFragmentState createState() => new MeasurementFragmentState();
}
class MeasurementFragmentState extends State<MeasurementFragment> {
String _weight = "";
DateTime _when = new DateTime.now();
String _errorMessage = null;
void _handleSave() {
double parsedWeight;
try {
parsedWeight = double.parse(_weight);
} on FormatException catch(e) {
print("Exception $e");
setState(() {
_errorMessage = "Save failed";
});
}
config.onCreated(new Measurement(when: _when, weight: parsedWeight));
config.navigator.pop();
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/close",
onPressed: config.navigator.pop),
center: new Text('New Measurement'),
right: [
// TODO(abarth): Should this be a FlatButton?
new InkWell(
onTap: _handleSave,
child: new Text('SAVE')
)
]
);
}
void _handleWeightChanged(String weight) {
setState(() {
_weight = weight;
});
}
static final GlobalKey weightKey = new GlobalKey();
void _handleDatePressed() {
showDialog(config.navigator, (NavigatorState navigator) {
return new MeasurementDateDialog(navigator: navigator, previousDate: _when);
}).then((DateTime value) {
if (value == null)
return;
setState(() {
_when = value;
});
});
}
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(
type: MaterialType.canvas,
child: new Container(
padding: const EdgeDims.all(20.0),
child: new Column([
new GestureDetector(
onTap: _handleDatePressed,
child: new Container(
height: 50.0,
child: new Column([
new Text('Measurement Date'),
new Text(measurement.displayDate, style: Theme.of(context).text.caption),
], alignItems: FlexAlignItems.start)
)
),
new Input(
key: weightKey,
placeholder: 'Enter weight',
keyboardType: KeyboardType.NUMBER,
onChanged: _handleWeightChanged
),
], alignItems: FlexAlignItems.stretch)
)
);
}
Widget buildSnackBar() {
if (_errorMessage == null)
return null;
// TODO(jackson): This doesn't show up, unclear why.
return new SnackBar(content: new Text(_errorMessage), showing: true);
}
Widget build(BuildContext context) {
return new Scaffold(
toolbar: buildToolBar(),
body: buildBody(context),
snackBar: buildSnackBar()
);
}
}