flutter/examples/fitness/lib/feed.dart
Adam Barth 09665c0d7f Change the default MaterialType to canvas
Canvas is by far the most popular type of material by call site (and makes for
a faster default because it doesn't have a RRect clip).
2015-10-12 09:36:47 -07:00

277 lines
7.7 KiB
Dart

// Copyright 2015 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 FitnessItemList extends StatelessComponent {
FitnessItemList({ Key key, this.items, this.onDismissed }) : super(key: key) {
assert(items != null);
assert(onDismissed != null);
}
final List<FitnessItem> items;
final FitnessItemHandler onDismissed;
Widget build(BuildContext context) {
return new Material(
child: new ScrollableList<FitnessItem>(
padding: const EdgeDims.all(4.0),
items: items,
itemExtent: kFitnessItemHeight,
itemBuilder: (_, item) => item.toRow(onDismissed: onDismissed)
)
);
}
}
class DialogMenuItem extends StatelessComponent {
DialogMenuItem(this.children, { Key key, this.onPressed }) : super(key: key);
List<Widget> children;
Function onPressed;
Widget build(BuildContext context) {
return new Container(
height: 48.0,
child: new InkWell(
onTap: onPressed,
child: new Padding(
padding: const EdgeDims.symmetric(horizontal: 16.0),
child: new Row(children)
)
)
);
}
}
class FeedFragment extends StatefulComponent {
FeedFragment({ this.navigator, this.userData, this.onItemCreated, this.onItemDeleted });
final NavigatorState navigator;
final UserData userData;
final FitnessItemHandler onItemCreated;
final FitnessItemHandler onItemDeleted;
FeedFragmentState createState() => new FeedFragmentState();
}
class FeedFragmentState extends State<FeedFragment> {
final GlobalKey<PlaceholderState> _snackBarPlaceholderKey = new GlobalKey<PlaceholderState>();
FitnessMode _fitnessMode = FitnessMode.feed;
void _handleFitnessModeChange(FitnessMode value) {
setState(() {
_fitnessMode = value;
});
config.navigator.pop();
}
void _showDrawer() {
showDrawer(
navigator: config.navigator,
child: new Block([
new DrawerHeader(child: new Text('Fitness')),
new DrawerItem(
icon: 'action/view_list',
onPressed: () => _handleFitnessModeChange(FitnessMode.feed),
selected: _fitnessMode == FitnessMode.feed,
child: new Text('Feed')),
new DrawerItem(
icon: 'action/assessment',
onPressed: () => _handleFitnessModeChange(FitnessMode.chart),
selected: _fitnessMode == FitnessMode.chart,
child: new Text('Chart')),
new DrawerDivider(),
new DrawerItem(
icon: 'action/settings',
onPressed: _handleShowSettings,
child: new Text('Settings')),
new DrawerItem(
icon: 'action/help',
child: new Text('Help & Feedback'))
])
);
}
void _handleShowSettings() {
config.navigator.pop();
config.navigator.pushNamed('/settings');
}
// TODO(jackson): We should be localizing
String get fitnessModeTitle {
switch(_fitnessMode) {
case FitnessMode.feed: return "Feed";
case FitnessMode.chart: return "Chart";
}
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/menu",
onPressed: _showDrawer),
center: new Text(fitnessModeTitle)
);
}
void _handleItemDismissed(FitnessItem item) {
config.onItemDeleted(item);
showSnackBar(
navigator: config.navigator,
placeholderKey: _snackBarPlaceholderKey,
content: new Text("Item deleted."),
actions: [new SnackBarAction(label: "UNDO", onPressed: () {
config.onItemCreated(item);
config.navigator.pop();
})]
);
}
Widget buildChart() {
double startX;
double endX;
double startY;
double endY;
List<Point> dataSet = new List<Point>();
for (FitnessItem item in config.userData.items) {
if (item is Measurement) {
double x = item.when.millisecondsSinceEpoch.toDouble();
double y = item.weight;
if (startX == null || startX > x)
startX = x;
if (endX == null || endX < x)
endX = x;
if (startY == null || startY > y)
startY = y;
if (endY == null || endY < y)
endY = y;
dataSet.add(new Point(x, y));
}
}
if (config.userData.goalWeight != null && config.userData.goalWeight > 0.0) {
startY = math.min(startY, config.userData.goalWeight);
endY = math.max(endY, config.userData.goalWeight);
}
playfair.ChartData data = new playfair.ChartData(
startX: startX,
startY: startY,
endX: endX,
endY: endY,
dataSet: dataSet,
numHorizontalGridlines: 5,
roundToPlaces: 1,
indicatorLine: config.userData.goalWeight,
indicatorText: "GOAL WEIGHT"
);
return new playfair.Chart(data: data);
}
Widget buildBody() {
TextStyle style = Theme.of(context).text.title;
if (config.userData == null)
return new Material();
if (config.userData.items.length == 0)
return new Material(
child: new Row(
[new Text("No data yet.\nAdd some!", style: style)],
justifyContent: FlexJustifyContent.center
)
);
switch (_fitnessMode) {
case FitnessMode.feed:
return new FitnessItemList(
items: config.userData.items.reversed.toList(),
onDismissed: _handleItemDismissed
);
case FitnessMode.chart:
return new Material(
child: new Container(
padding: const EdgeDims.all(20.0),
child: buildChart()
)
);
}
}
void _handleActionButtonPressed() {
showDialog(config.navigator, (NavigatorState navigator) => new AddItemDialog(navigator)).then((routeName) {
if (routeName != null)
config.navigator.pushNamed(routeName);
});
}
Widget buildFloatingActionButton() {
switch (_fitnessMode) {
case FitnessMode.feed:
return new FloatingActionButton(
child: new Icon(type: 'content/add', size: 24),
onPressed: _handleActionButtonPressed
);
case FitnessMode.chart:
return null;
}
}
Widget build(BuildContext context) {
return new Scaffold(
toolBar: buildToolBar(),
body: buildBody(),
snackBar: new Placeholder(key: _snackBarPlaceholderKey),
floatingActionButton: buildFloatingActionButton()
);
}
}
class AddItemDialog extends StatefulComponent {
AddItemDialog(this.navigator);
final NavigatorState navigator;
AddItemDialogState createState() => new AddItemDialogState();
}
class AddItemDialogState extends State<AddItemDialog> {
// TODO(jackson): Internationalize
static final Map<String, String> _labels = {
'/measurements/new': 'Measure',
'/meals/new': 'Eat',
};
String _addItemRoute = _labels.keys.first;
void _handleAddItemRouteChanged(String routeName) {
setState(() {
_addItemRoute = routeName;
});
}
Widget build(BuildContext context) {
List<Widget> menuItems = [];
for(String routeName in _labels.keys) {
menuItems.add(new DialogMenuItem([
new Flexible(child: new Text(_labels[routeName])),
new Radio(value: routeName, groupValue: _addItemRoute, onChanged: _handleAddItemRouteChanged),
], onPressed: () => _handleAddItemRouteChanged(routeName)));
}
return new Dialog(
title: new Text("What are you doing?"),
content: new Block(menuItems),
onDismiss: config.navigator.pop,
actions: [
new FlatButton(
child: new Text('CANCEL'),
onPressed: config.navigator.pop
),
new FlatButton(
child: new Text('ADD'),
onPressed: () {
config.navigator.pop(_addItemRoute);
}
),
]
);
}
}