
(These are changes cherry-picked from in-flight branches since they are more independent and could be helpful even without those changes.) - Change RouteBuilder's signature to take a single argument in which the other fields are placed, so that we can keep iterating on those arguments without having to break compatibility each time. Also, this makes defining route builders much simpler (only one argument to ignore rather than a variable number). - Expose the next performance to RouteBuilders, since sometimes the route itself might not be where it's used. - Allow BuildContext to be used to walk children, just like it can for ancestors - Allow BuildContext to be used to get the Widget of the current BuildContext - Allow StatefulComponentElement to be referenced with a type specialisation so that you don't have to cast when you know what the type you're dealing with actually is.
173 lines
4.0 KiB
Dart
173 lines
4.0 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.
|
|
|
|
library fitness;
|
|
|
|
import 'package:playfair/playfair.dart' as playfair;
|
|
import 'package:sky/animation.dart';
|
|
import 'package:sky/material.dart';
|
|
import 'package:sky/painting.dart';
|
|
import 'package:sky/widgets.dart';
|
|
|
|
import 'user_data.dart';
|
|
import 'date_utils.dart';
|
|
import 'dart:async';
|
|
import 'dart:math' as math;
|
|
|
|
part 'feed.dart';
|
|
part 'fitness_item.dart';
|
|
part 'fitness_types.dart';
|
|
part 'meal.dart';
|
|
part 'measurement.dart';
|
|
part 'settings.dart';
|
|
|
|
abstract class UserData {
|
|
BackupMode get backupMode;
|
|
double get goalWeight;
|
|
List<FitnessItem> get items;
|
|
}
|
|
|
|
class UserDataImpl extends UserData {
|
|
UserDataImpl();
|
|
|
|
List<FitnessItem> _items = [];
|
|
|
|
BackupMode _backupMode;
|
|
BackupMode get backupMode => _backupMode;
|
|
void set backupMode(BackupMode value) {
|
|
_backupMode = value;
|
|
}
|
|
|
|
double _goalWeight;
|
|
double get goalWeight => _goalWeight;
|
|
void set goalWeight(double value) {
|
|
_goalWeight = value;
|
|
}
|
|
|
|
List<FitnessItem> get items => _items;
|
|
|
|
void sort() {
|
|
_items.sort((a, b) => a.when.compareTo(b.when));
|
|
}
|
|
|
|
void add(FitnessItem item) {
|
|
_items.add(item);
|
|
sort();
|
|
}
|
|
|
|
void remove(FitnessItem item) {
|
|
_items.remove(item);
|
|
}
|
|
|
|
Future save() => saveFitnessData(this);
|
|
|
|
UserDataImpl.fromJson(Map json) {
|
|
json['items'].forEach((item) {
|
|
_items.add(new Measurement.fromJson(item));
|
|
});
|
|
try {
|
|
_backupMode = BackupMode.values.firstWhere((BackupMode mode) {
|
|
return mode.toString() == json['backupMode'];
|
|
});
|
|
} catch(e) {
|
|
print("Failed to load backup mode: ${e}");
|
|
}
|
|
_goalWeight = json['goalWeight'];
|
|
}
|
|
|
|
Map toJson() {
|
|
Map json = new Map();
|
|
json['items'] = _items.map((item) => item.toJson()).toList();
|
|
json['backupMode'] = _backupMode.toString();
|
|
json['goalWeight'] = _goalWeight;
|
|
return json;
|
|
}
|
|
}
|
|
|
|
class FitnessApp extends StatefulComponent {
|
|
FitnessAppState createState() => new FitnessAppState();
|
|
}
|
|
|
|
class FitnessAppState extends State<FitnessApp> {
|
|
UserDataImpl _userData;
|
|
|
|
void initState() {
|
|
super.initState();
|
|
loadFitnessData().then((UserData data) {
|
|
setState(() => _userData = data);
|
|
}).catchError((e) {
|
|
print("Failed to load data: $e");
|
|
setState(() => _userData = new UserDataImpl());
|
|
});
|
|
}
|
|
|
|
void _handleItemCreated(FitnessItem item) {
|
|
setState(() {
|
|
_userData.add(item);
|
|
_userData.save();
|
|
});
|
|
}
|
|
|
|
void _handleItemDeleted(FitnessItem item) {
|
|
setState(() {
|
|
_userData.remove(item);
|
|
_userData.save();
|
|
});
|
|
}
|
|
|
|
void settingsUpdater({ BackupMode backup, double goalWeight }) {
|
|
setState(() {
|
|
if (backup != null)
|
|
_userData.backupMode = backup;
|
|
if (goalWeight != null)
|
|
_userData.goalWeight = goalWeight;
|
|
_userData.save();
|
|
});
|
|
}
|
|
|
|
Widget build(BuildContext) {
|
|
return new App(
|
|
theme: new ThemeData(
|
|
brightness: ThemeBrightness.light,
|
|
primarySwatch: Colors.indigo,
|
|
accentColor: Colors.pinkAccent[200]
|
|
),
|
|
title: 'Fitness',
|
|
routes: {
|
|
'/': (RouteArguments args) {
|
|
return new FeedFragment(
|
|
navigator: args.navigator,
|
|
userData: _userData,
|
|
onItemCreated: _handleItemCreated,
|
|
onItemDeleted: _handleItemDeleted
|
|
);
|
|
},
|
|
'/meals/new': (RouteArguments args) {
|
|
return new MealFragment(
|
|
navigator: args.navigator,
|
|
onCreated: _handleItemCreated
|
|
);
|
|
},
|
|
'/measurements/new': (RouteArguments args) {
|
|
return new MeasurementFragment(
|
|
navigator: args.navigator,
|
|
onCreated: _handleItemCreated
|
|
);
|
|
},
|
|
'/settings': (RouteArguments args) {
|
|
return new SettingsFragment(
|
|
navigator: args.navigator,
|
|
userData: _userData,
|
|
updater: settingsUpdater
|
|
);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
}
|
|
|
|
void main() {
|
|
runApp(new FitnessApp());
|
|
}
|