diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index 9f20bb44..84db1a59 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -29,6 +29,10 @@ import 'package:wger/models/http_exception.dart'; class Auth with ChangeNotifier { String token; String serverUrl; + + /// flag to indicate that the application has successfully loaded all initial data + bool dataInit = false; + // DateTime _expiryDate; // String _userId; // Timer _authTimer; diff --git a/lib/providers/nutrition.dart b/lib/providers/nutrition.dart index 3bf3aeff..439a8132 100644 --- a/lib/providers/nutrition.dart +++ b/lib/providers/nutrition.dart @@ -276,6 +276,13 @@ class Nutrition extends WgerBaseProvider with ChangeNotifier { notifyListeners(); } + /// Log meal to nutrition diary + Future fetchAndSetAllLogs() async { + for (var plan in _plans) { + fetchAndSetLogs(plan); + } + } + /// Log meal to nutrition diary Future fetchAndSetLogs(NutritionalPlan plan) async { // TODO: update fetch to that it can use the pagination diff --git a/lib/providers/workout_plans.dart b/lib/providers/workout_plans.dart index 7de3ef46..9ee45d95 100644 --- a/lib/providers/workout_plans.dart +++ b/lib/providers/workout_plans.dart @@ -90,7 +90,13 @@ class WorkoutPlans extends WgerBaseProvider with ChangeNotifier { notifyListeners(); } - Future fetchAndSetFullWorkout(int workoutId) async { + Future setAllFullWorkouts() async { + for (var plan in _workoutPlans) { + setFullWorkout(plan.id); + } + } + + Future setFullWorkout(int workoutId) async { final data = await fetch(makeUrl( _workoutPlansUrlPath, id: workoutId, diff --git a/lib/screens/dashboard.dart b/lib/screens/dashboard.dart index 57b0d5e6..e8cfbf7c 100644 --- a/lib/screens/dashboard.dart +++ b/lib/screens/dashboard.dart @@ -20,6 +20,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:wger/locale/locales.dart'; +import 'package:wger/providers/auth.dart'; import 'package:wger/providers/body_weight.dart'; import 'package:wger/providers/exercises.dart'; import 'package:wger/providers/nutrition.dart'; @@ -43,13 +44,27 @@ class _DashboardScreenState extends State { ); } - /// Load inital data from the server - Future _loadCachedEntries(BuildContext context) async { - await Provider.of(context, listen: false).fetchAndSetExercises(); - await Provider.of(context, listen: false).fetchIngredientsFromCache(); - await Provider.of(context, listen: false).fetchAndSetWorkouts(); - await Provider.of(context, listen: false).fetchAndSetPlans(); - await Provider.of(context, listen: false).fetchAndSetEntries(); + /// Load initial data from the server + Future _loadEntries(BuildContext context) async { + if (!Provider.of(context, listen: false).dataInit) { + // Exercises + await Provider.of(context, listen: false).fetchAndSetExercises(); + + // Nutrition + Nutrition nutritionProvider = Provider.of(context, listen: false); + await nutritionProvider.fetchIngredientsFromCache(); + await nutritionProvider.fetchAndSetPlans(); + await nutritionProvider.fetchAndSetAllLogs(); + + // Workouts + WorkoutPlans workoutProvider = Provider.of(context, listen: false); + await workoutProvider.fetchAndSetWorkouts(); + await workoutProvider.setAllFullWorkouts(); + + // Weight + await Provider.of(context, listen: false).fetchAndSetEntries(); + } + Provider.of(context, listen: false).dataInit = true; } @override @@ -58,7 +73,7 @@ class _DashboardScreenState extends State { appBar: getAppBar(), drawer: AppDrawer(), body: FutureBuilder( - future: _loadCachedEntries(context), + future: _loadEntries(context), builder: (ctx, authResultSnapshot) => authResultSnapshot.connectionState == ConnectionState.waiting ? Column( diff --git a/lib/screens/workout_plan_screen.dart b/lib/screens/workout_plan_screen.dart index 219ee29a..7e7a4682 100644 --- a/lib/screens/workout_plan_screen.dart +++ b/lib/screens/workout_plan_screen.dart @@ -131,8 +131,7 @@ class _WorkoutPlanScreenState extends State { return Scaffold( appBar: getAppBar(workoutPlan), body: FutureBuilder( - future: Provider.of(context, listen: false) - .fetchAndSetFullWorkout(workoutPlan.id), + future: Provider.of(context, listen: false).setFullWorkout(workoutPlan.id), builder: (context, AsyncSnapshot snapshot) => snapshot.connectionState == ConnectionState.waiting ? Center(child: CircularProgressIndicator()) diff --git a/lib/widgets/dashboard/calendar.dart b/lib/widgets/dashboard/calendar.dart index 9e4bfb8a..5d609bda 100644 --- a/lib/widgets/dashboard/calendar.dart +++ b/lib/widgets/dashboard/calendar.dart @@ -72,7 +72,7 @@ class _DashboardCalendarWidgetState extends State _animationController.forward(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - // Fetch weight entries + // Process weight entries BodyWeight weightProvider = Provider.of(context, listen: false); for (var entry in weightProvider.items) { final date = DateTime(entry.date.year, entry.date.month, entry.date.day); @@ -83,7 +83,7 @@ class _DashboardCalendarWidgetState extends State _events[date].add('Body weight: ${entry.weight} kg'); } - // Fetch workout sessions + // Process workout sessions WorkoutPlans plans = Provider.of(context, listen: false); plans.fetchSessionData().then((entries) { for (var entry in entries['results']) { @@ -102,20 +102,17 @@ class _DashboardCalendarWidgetState extends State } }); - // Fetch nutritional plans + // Process nutritional plans Nutrition nutritionProvider = Provider.of(context, listen: false); for (var plan in nutritionProvider.items) { - nutritionProvider.fetchAndSetLogs(plan).then((value) { - //print(plan.logEntriesValues); - for (var entry in plan.logEntriesValues.entries) { - final date = DateTime(entry.key.year, entry.key.month, entry.key.day); - if (!_events.containsKey(date)) { - _events[date] = []; - } - - _events[date].add('Nutrition diary: ${entry.value.energy.toStringAsFixed(0)} kcal'); + for (var entry in plan.logEntriesValues.entries) { + final date = DateTime(entry.key.year, entry.key.month, entry.key.day); + if (!_events.containsKey(date)) { + _events[date] = []; } - }); + + _events[date].add('Nutrition diary: ${entry.value.energy.toStringAsFixed(0)} kcal'); + } } }); } @@ -340,7 +337,7 @@ class _DashboardCalendarWidgetState extends State width: double.infinity, decoration: BoxDecoration( border: Border.all(width: 0.5), - borderRadius: BorderRadius.circular(12.0), + borderRadius: BorderRadius.circular(5), ), margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0), child: ListTile( diff --git a/lib/widgets/dashboard/widgets.dart b/lib/widgets/dashboard/widgets.dart index 43227d4a..0b968fc8 100644 --- a/lib/widgets/dashboard/widgets.dart +++ b/lib/widgets/dashboard/widgets.dart @@ -47,12 +47,10 @@ class _DashboardNutritionWidgetState extends State { Nutrition nutrition; NutritionalPlan plan; - Future _refreshPlanEntries(BuildContext context) async { - plan = Provider.of(context, listen: false).currentPlan; - } - @override Widget build(BuildContext context) { + plan = Provider.of(context, listen: false).currentPlan; + return Card( child: Column( mainAxisSize: MainAxisSize.min, @@ -61,36 +59,31 @@ class _DashboardNutritionWidgetState extends State { AppLocalizations.of(context).nutritionalPlan, style: Theme.of(context).textTheme.headline4, ), - FutureBuilder( - future: _refreshPlanEntries(context), - builder: (context, snapshot) => snapshot.connectionState == ConnectionState.waiting - ? Container(height: 180, child: Center(child: CircularProgressIndicator())) - : plan != null - ? Column( - children: [ - Text( - DateFormat.yMd().format(plan.creationDate), - style: Theme.of(context).textTheme.headline6, - ), - TextButton( - child: Text( - plan.description, - style: TextStyle(fontSize: 20), - ), - onPressed: () { - return Navigator.of(context) - .pushNamed(NutritionalPlanScreen.routeName, arguments: plan); - }, - ), - Container( - padding: EdgeInsets.all(15), - height: 180, - child: NutritionalPlanPieChartWidget(plan.nutritionalValues), - ) - ], - ) - : Text('You have no nutritional plans'), - ), + plan != null + ? Column( + children: [ + Text( + DateFormat.yMd().format(plan.creationDate), + style: Theme.of(context).textTheme.headline6, + ), + TextButton( + child: Text( + plan.description, + style: TextStyle(fontSize: 20), + ), + onPressed: () { + return Navigator.of(context) + .pushNamed(NutritionalPlanScreen.routeName, arguments: plan); + }, + ), + Container( + padding: EdgeInsets.all(15), + height: 180, + child: NutritionalPlanPieChartWidget(plan.nutritionalValues), + ) + ], + ) + : Text('You have no nutritional plans'), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ @@ -127,12 +120,10 @@ class DashboardWeightWidget extends StatefulWidget { class _DashboardWeightWidgetState extends State { BodyWeight weightEntriesData; - Future _refreshWeightEntries(BuildContext context) async { - weightEntriesData = Provider.of(context, listen: false); - } - @override Widget build(BuildContext context) { + weightEntriesData = Provider.of(context, listen: false); + return Card( child: Column( mainAxisSize: MainAxisSize.min, @@ -141,39 +132,31 @@ class _DashboardWeightWidgetState extends State { AppLocalizations.of(context).weight, style: Theme.of(context).textTheme.headline4, ), - FutureBuilder( - future: _refreshWeightEntries(context), - builder: (context, snapshot) => snapshot.connectionState == ConnectionState.waiting - ? Container( - height: 180, - child: Center(child: CircularProgressIndicator()), - ) - : Column( - children: [ - weightEntriesData.items.length > 0 - ? Container( - padding: EdgeInsets.all(15), - height: 180, - child: WeightChartWidget(weightEntriesData.items), - ) - : Text('You have no weight entries'), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - child: const Text('Action one'), - onPressed: () {}, - ), - const SizedBox(width: 8), - TextButton( - child: const Text('Action two'), - onPressed: () {}, - ), - const SizedBox(width: 8), - ], - ), - ], + Column( + children: [ + weightEntriesData.items.length > 0 + ? Container( + padding: EdgeInsets.all(15), + height: 180, + child: WeightChartWidget(weightEntriesData.items), + ) + : Text('You have no weight entries'), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + child: const Text('Action one'), + onPressed: () {}, ), + const SizedBox(width: 8), + TextButton( + child: const Text('Action two'), + onPressed: () {}, + ), + const SizedBox(width: 8), + ], + ), + ], ), ], ), @@ -197,14 +180,16 @@ class _DashboardWorkoutWidgetState extends State { WorkoutPlan _workoutPlan; var showDetail = false; - Future _fetchWorkoutEntries(BuildContext context) async { - _workoutPlan = Provider.of(context, listen: false).activePlan; - _workoutPlan = await Provider.of(context, listen: false) - .fetchAndSetFullWorkout(_workoutPlan.id); + @override + void initState() { + // TODO: implement initState + super.initState(); } @override Widget build(BuildContext context) { + _workoutPlan = Provider.of(context, listen: false).activePlan; + return Card( child: Column( mainAxisSize: MainAxisSize.min, @@ -213,60 +198,52 @@ class _DashboardWorkoutWidgetState extends State { AppLocalizations.of(context).labelWorkoutPlan, style: Theme.of(context).textTheme.headline4, ), - FutureBuilder( - future: _fetchWorkoutEntries(context), - builder: (context, snapshot) => snapshot.connectionState == ConnectionState.waiting - ? Center( - child: - Container(height: 180, child: Center(child: CircularProgressIndicator())), + _workoutPlan != null + ? Column(children: [ + Text( + DateFormat.yMd().format(_workoutPlan.creationDate), + style: Theme.of(context).textTheme.headline6, + ), + TextButton( + child: Text( + _workoutPlan.description, + style: TextStyle(fontSize: 20), + ), + onPressed: () { + return Navigator.of(context) + .pushNamed(WorkoutPlanScreen.routeName, arguments: _workoutPlan); + }, + ), + ..._workoutPlan.days.map((workoutDay) { + return Column(children: [ + const SizedBox(height: 10), + showDetail == true + ? Text( + workoutDay.description, + style: TextStyle(fontWeight: FontWeight.bold), + ) + : Text(workoutDay.description), + if (showDetail) + ...workoutDay.sets + .map((set) => Text(set.exercises.map((e) => e.name).join(','))) + .toList(), + ]); + }).toList(), + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + child: Text(AppLocalizations.of(context).toggleDetails), + onPressed: () { + setState(() { + showDetail = !showDetail; + }); + }, + ), + ], ) - : _workoutPlan != null - ? Column(children: [ - Text( - DateFormat.yMd().format(_workoutPlan.creationDate), - style: Theme.of(context).textTheme.headline6, - ), - TextButton( - child: Text( - _workoutPlan.description, - style: TextStyle(fontSize: 20), - ), - onPressed: () { - return Navigator.of(context) - .pushNamed(WorkoutPlanScreen.routeName, arguments: _workoutPlan); - }, - ), - ..._workoutPlan.days.map((workoutDay) { - return Column(children: [ - const SizedBox(height: 10), - showDetail == true - ? Text( - workoutDay.description, - style: TextStyle(fontWeight: FontWeight.bold), - ) - : Text(workoutDay.description), - if (showDetail) - ...workoutDay.sets - .map((set) => Text(set.exercises.map((e) => e.name).join(','))) - .toList(), - ]); - }).toList(), - Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - TextButton( - child: Text(AppLocalizations.of(context).toggleDetails), - onPressed: () { - setState(() { - showDetail = !showDetail; - }); - }, - ), - ], - ) - ]) - : Text('you have no workouts'), - ), + ]) + : Text('you have no workouts'), ], ), ); diff --git a/lib/widgets/weight/entries_list.dart b/lib/widgets/weight/entries_list.dart index 3cca74c3..0a8d02cb 100644 --- a/lib/widgets/weight/entries_list.dart +++ b/lib/widgets/weight/entries_list.dart @@ -86,7 +86,6 @@ class WeightEntriesList extends StatelessWidget { ), ), background: Container( - //color: Theme.of(context).accentColor, alignment: Alignment.centerLeft, padding: EdgeInsets.only(right: 20), margin: EdgeInsets.symmetric( @@ -98,13 +97,8 @@ class WeightEntriesList extends StatelessWidget { //color: Colors.white, ), ), - //direction: DismissDirection.endToStart, child: Card( child: ListTile( - //onTap: () => Navigator.of(context).pushNamed( - // WorkoutPlanScreen.routeName, - // arguments: currentPlan, - //), onTap: () {}, title: Text(DateFormat.yMd().format(currentEntry.date).toString()), subtitle: Text('${currentEntry.weight} kg'),