Commit 1f768ce2 authored by Collin Jackson's avatar Collin Jackson

First pass at adding meal tracking to fitness app

parent 6b748e65
// 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.
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/card.dart';
import 'package:sky/widgets/dismissable.dart';
typedef void FitnessItemHandler(FitnessItem item);
const double kFitnessItemHeight = 79.0;
class FitnessItem {
FitnessItem({ this.when }) {
assert(when != null);
}
final DateTime when;
// TODO(jackson): Internationalize
String get displayDate => "${when.year.toString()}-${when.month.toString().padLeft(2,'0')}-${when.day.toString().padLeft(2,'0')}";
}
abstract class FitnessItemRow extends Component {
FitnessItemRow({ FitnessItem item, this.onDismissed })
: this.item = item,
super(key: item.when.toString());
final FitnessItem item;
final FitnessItemHandler onDismissed;
Widget buildContent();
Widget build() {
return new Dismissable(
onDismissed: () => onDismissed(item),
child: new Card(
child: new Container(
height: kFitnessItemHeight,
padding: const EdgeDims.all(8.0),
child: buildContent()
)
)
);
}
}
...@@ -2,5 +2,5 @@ ...@@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
enum FitnessMode { measure, run } enum FitnessMode { feed, chart }
enum BackupMode { enabled, disabled } enum BackupMode { enabled, disabled }
...@@ -9,31 +9,44 @@ import 'package:sky/widgets/theme.dart'; ...@@ -9,31 +9,44 @@ import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/widget.dart'; import 'package:sky/widgets/widget.dart';
import 'package:sky/widgets/task_description.dart'; import 'package:sky/widgets/task_description.dart';
import 'meal.dart';
import 'measurement.dart'; import 'measurement.dart';
import 'home.dart'; import 'feed.dart';
import 'settings.dart'; import 'settings.dart';
import 'fitness_item.dart';
import 'fitness_types.dart'; import 'fitness_types.dart';
class FitnessApp extends App { class FitnessApp extends App {
NavigationState _navigationState; NavigationState _navigationState;
final List<FitnessItem> _userData = [
new Measurement(weight: 180.0, when: new DateTime.now().add(const Duration(days: -1))),
new Measurement(weight: 160.0, when: new DateTime.now()),
];
void initState() { void initState() {
_navigationState = new NavigationState([ _navigationState = new NavigationState([
new Route( new Route(
name: '/', name: '/',
builder: (navigator, route) => new HomeFragment( builder: (navigator, route) => new FeedFragment(
navigator: navigator, navigator: navigator,
userData: _userData, userData: _userData,
onMeasurementCreated: _handleMeasurementCreated, onItemCreated: _handleItemCreated,
onMeasurementDeleted: _handleMeasurementDeleted onItemDeleted: _handleItemDeleted
)
),
new Route(
name: '/meals/new',
builder: (navigator, route) => new MealFragment(
navigator: navigator,
onCreated: _handleItemCreated
) )
), ),
new Route( new Route(
name: '/measurements/new', name: '/measurements/new',
builder: (navigator, route) => new MeasurementFragment( builder: (navigator, route) => new MeasurementFragment(
navigator: navigator, navigator: navigator,
onCreated: _handleMeasurementCreated onCreated: _handleItemCreated
) )
), ),
new Route( new Route(
...@@ -54,16 +67,16 @@ class FitnessApp extends App { ...@@ -54,16 +67,16 @@ class FitnessApp extends App {
} }
} }
void _handleMeasurementCreated(Measurement measurement) { void _handleItemCreated(FitnessItem item) {
setState(() { setState(() {
_userData.add(measurement); _userData.add(item);
_userData.sort((a, b) => a.when.compareTo(b.when)); _userData.sort((a, b) => a.when.compareTo(b.when));
}); });
} }
void _handleMeasurementDeleted(Measurement measurement) { void _handleItemDeleted(FitnessItem item) {
setState(() { setState(() {
_userData.remove(measurement); _userData.remove(item);
}); });
} }
...@@ -76,11 +89,6 @@ class FitnessApp extends App { ...@@ -76,11 +89,6 @@ class FitnessApp extends App {
}); });
} }
final List<Measurement> _userData = [
new Measurement(weight: 180.0, when: new DateTime.now().add(const Duration(days: -1))),
new Measurement(weight: 160.0, when: new DateTime.now()),
];
Widget build() { Widget build() {
return new Theme( return new Theme(
data: new ThemeData( data: new ThemeData(
......
// 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.
import 'package:sky/painting/text_style.dart';
import 'package:sky/editing/input.dart';
import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/ink_well.dart';
import 'package:sky/widgets/material.dart';
import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/scrollable_viewport.dart';
import 'package:sky/widgets/snack_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart';
import 'fitness_item.dart';
class Meal extends FitnessItem {
Meal({ DateTime when, this.description }) : super(when: when);
final String description;
}
class MealRow extends FitnessItemRow {
MealRow({ Meal meal, FitnessItemHandler onDismissed })
: super(item: meal, onDismissed: onDismissed);
Widget buildContent() {
Meal meal = item;
List<Widget> children = [
new Flexible(
child: new Text(
meal.description,
style: const TextStyle(textAlign: TextAlign.right)
)
),
new Flexible(
child: new Text(
meal.displayDate,
style: Theme.of(this).text.caption.copyWith(textAlign: TextAlign.right)
)
)
];
return new Flex(
children,
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(this).textBaseline
);
}
}
class MealFragment extends StatefulComponent {
MealFragment({ this.navigator, this.onCreated });
Navigator navigator;
FitnessItemHandler onCreated;
void syncFields(MealFragment source) {
navigator = source.navigator;
onCreated = source.onCreated;
}
String _description = "";
void _handleSave() {
onCreated(new Meal(when: new DateTime.now(), description: _description));
navigator.pop();
}
Widget buildToolBar() {
return new ToolBar(
left: new IconButton(
icon: "navigation/close",
onPressed: navigator.pop),
center: new Text('New Meal'),
right: [new InkWell(
child: new Listener(
onGestureTap: (_) => _handleSave(),
child: new Text('SAVE')
)
)]
);
}
void _handleDescriptionChanged(String description) {
setState(() {
_description = description;
});
}
Widget buildBody() {
Meal meal = new Meal(when: new DateTime.now());
return new Material(
type: MaterialType.canvas,
child: new ScrollableViewport(
child: new Container(
padding: const EdgeDims.all(20.0),
child: new Block([
new Text(meal.displayDate),
new Input(
focused: false,
placeholder: 'Describe meal',
onChanged: _handleDescriptionChanged
),
])
)
)
);
}
Widget build() {
return new Scaffold(
toolbar: buildToolBar(),
body: buildBody()
);
}
}
...@@ -2,8 +2,10 @@ ...@@ -2,8 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:sky/painting/text_style.dart';
import 'package:sky/editing/input.dart'; import 'package:sky/editing/input.dart';
import 'package:sky/widgets/basic.dart'; import 'package:sky/widgets/basic.dart';
import 'package:sky/widgets/default_text_style.dart';
import 'package:sky/widgets/icon_button.dart'; import 'package:sky/widgets/icon_button.dart';
import 'package:sky/widgets/ink_well.dart'; import 'package:sky/widgets/ink_well.dart';
import 'package:sky/widgets/material.dart'; import 'package:sky/widgets/material.dart';
...@@ -11,19 +13,46 @@ import 'package:sky/widgets/navigator.dart'; ...@@ -11,19 +13,46 @@ import 'package:sky/widgets/navigator.dart';
import 'package:sky/widgets/scaffold.dart'; import 'package:sky/widgets/scaffold.dart';
import 'package:sky/widgets/scrollable_viewport.dart'; import 'package:sky/widgets/scrollable_viewport.dart';
import 'package:sky/widgets/snack_bar.dart'; import 'package:sky/widgets/snack_bar.dart';
import 'package:sky/widgets/theme.dart';
import 'package:sky/widgets/tool_bar.dart'; import 'package:sky/widgets/tool_bar.dart';
typedef void MeasurementHandler(Measurement measurement); import 'fitness_item.dart';
class Measurement { class Measurement extends FitnessItem {
Measurement({ this.when, this.weight }); Measurement({ DateTime when, this.weight }) : super(when: when);
final DateTime when;
final double weight; final double weight;
// TODO(jackson): Internationalize // TODO(jackson): Internationalize
String get displayWeight => "${weight.toStringAsFixed(2)} lbs"; String get displayWeight => "${weight.toStringAsFixed(2)} lbs";
String get displayDate => "${when.year.toString()}-${when.month.toString().padLeft(2,'0')}-${when.day.toString().padLeft(2,'0')}"; }
class MeasurementRow extends FitnessItemRow {
MeasurementRow({ Measurement measurement, FitnessItemHandler onDismissed })
: super(item: measurement, onDismissed: onDismissed);
Widget buildContent() {
Measurement measurement = item;
List<Widget> children = [
new Flexible(
child: new Text(
measurement.displayWeight,
style: const TextStyle(textAlign: TextAlign.right)
)
),
new Flexible(
child: new Text(
measurement.displayDate,
style: Theme.of(this).text.caption.copyWith(textAlign: TextAlign.right)
)
)
];
return new Flex(
children,
alignItems: FlexAlignItems.baseline,
textBaseline: DefaultTextStyle.of(this).textBaseline
);
}
} }
class MeasurementFragment extends StatefulComponent { class MeasurementFragment extends StatefulComponent {
...@@ -31,7 +60,7 @@ class MeasurementFragment extends StatefulComponent { ...@@ -31,7 +60,7 @@ class MeasurementFragment extends StatefulComponent {
MeasurementFragment({ this.navigator, this.onCreated }); MeasurementFragment({ this.navigator, this.onCreated });
Navigator navigator; Navigator navigator;
MeasurementHandler onCreated; FitnessItemHandler onCreated;
void syncFields(MeasurementFragment source) { void syncFields(MeasurementFragment source) {
navigator = source.navigator; navigator = source.navigator;
...@@ -76,7 +105,7 @@ class MeasurementFragment extends StatefulComponent { ...@@ -76,7 +105,7 @@ class MeasurementFragment extends StatefulComponent {
}); });
} }
Widget buildMeasurementPane() { Widget buildBody() {
Measurement measurement = new Measurement(when: new DateTime.now()); Measurement measurement = new Measurement(when: new DateTime.now());
return new Material( return new Material(
type: MaterialType.canvas, type: MaterialType.canvas,
...@@ -105,7 +134,7 @@ class MeasurementFragment extends StatefulComponent { ...@@ -105,7 +134,7 @@ class MeasurementFragment extends StatefulComponent {
Widget build() { Widget build() {
return new Scaffold( return new Scaffold(
toolbar: buildToolBar(), toolbar: buildToolBar(),
body: buildMeasurementPane(), body: buildBody(),
snackBar: buildSnackBar() snackBar: buildSnackBar()
); );
} }
......
...@@ -27,8 +27,6 @@ class SettingsFragment extends Component { ...@@ -27,8 +27,6 @@ class SettingsFragment extends Component {
final BackupMode backup; final BackupMode backup;
final SettingsUpdater updater; final SettingsUpdater updater;
bool showModeDialog = false;
void _handleBackupChanged(bool value) { void _handleBackupChanged(bool value) {
if (updater != null) if (updater != null)
updater(backup: value ? BackupMode.enabled : BackupMode.disabled); updater(backup: value ? BackupMode.enabled : BackupMode.disabled);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment