Move nutritional plan diary chart to fl charts

This commit is contained in:
Roland Geider
2023-10-01 20:22:47 +02:00
parent ef5a7081a0
commit 779926bc98
8 changed files with 364 additions and 418 deletions

View File

@@ -82,6 +82,30 @@ class NutritionalPlan {
return out;
}
NutritionalValues get nutritionalValuesToday {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
return logEntriesValues.containsKey(today) ? logEntriesValues[today]! : NutritionalValues();
}
NutritionalValues get nutritionalValues7DayAvg {
final currentDate = DateTime.now();
final sevenDaysAgo = currentDate.subtract(Duration(days: 7));
final entries = logs.where((obj) {
DateTime objDate = obj.datetime;
return objDate.isAfter(sevenDaysAgo) && objDate.isBefore(currentDate);
}).toList();
var out = NutritionalValues();
entries.forEach((log) {
out = out + log.nutritionalValues;
});
return out;
}
/// Calculates the percentage each macro nutrient adds to the total energy
BaseNutritionalValues energyPercentage(NutritionalValues values) {
return BaseNutritionalValues(

View File

@@ -182,19 +182,15 @@ class _DashboardNutritionWidgetState extends State<DashboardNutritionWidget> {
},
),
if (_hasContent)
Container(
color: Colors.blue,
padding: const EdgeInsets.only(left: 10),
child: Column(
children: [
...getContent(),
Container(
padding: const EdgeInsets.all(15),
height: 180,
child: NutritionalPlanPieChartWidget(_plan!.nutritionalValues),
)
],
),
Column(
children: [
...getContent(),
Container(
padding: const EdgeInsets.all(15),
height: 180,
child: FlNutritionalPlanPieChartWidget(_plan!.nutritionalValues),
)
],
)
else
NothingFound(
@@ -345,85 +341,79 @@ class _DashboardMeasurementWidgetState extends State<DashboardMeasurementWidget>
}
return Consumer<MeasurementProvider>(
builder: (context, workoutProvider, child) => Card(
child: Container(
color: Colors.amberAccent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text(
AppLocalizations.of(context).measurements,
style: Theme.of(context).textTheme.headline4,
),
leading: const FaIcon(
FontAwesomeIcons.weight,
color: Colors.black,
),
trailing: IconButton(
icon: const Icon(Icons.arrow_forward),
onPressed: () => Navigator.pushNamed(
context,
MeasurementCategoriesScreen.routeName,
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
title: Text(
AppLocalizations.of(context).measurements,
style: Theme.of(context).textTheme.headline4,
),
leading: const FaIcon(
FontAwesomeIcons.weight,
color: Colors.black,
),
trailing: IconButton(
icon: const Icon(Icons.arrow_forward),
onPressed: () => Navigator.pushNamed(
context,
MeasurementCategoriesScreen.routeName,
),
),
//color: Colors.lightBlue,
Column(
children: [
if (items.isNotEmpty)
Column(children: [
CarouselSlider(
items: items,
carouselController: _controller,
options: CarouselOptions(
autoPlay: false,
enlargeCenterPage: false,
viewportFraction: 1,
enableInfiniteScroll: false,
aspectRatio: 1.1,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
}),
),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: items.asMap().entries.map(
(entry) {
return GestureDetector(
onTap: () => _controller.animateToPage(entry.key),
child: Container(
width: 12.0,
height: 12.0,
margin:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: (Theme.of(context).brightness == Brightness.dark
? Colors.white
: wgerPrimaryColor)
.withOpacity(_current == entry.key ? 0.9 : 0.4)),
),
);
},
).toList(),
),
),
])
else
NothingFound(
AppLocalizations.of(context).noMeasurementEntries,
AppLocalizations.of(context).newEntry,
MeasurementCategoryForm(),
),
Column(
children: [
if (items.isNotEmpty)
Column(children: [
CarouselSlider(
items: items,
carouselController: _controller,
options: CarouselOptions(
autoPlay: false,
enlargeCenterPage: false,
viewportFraction: 1,
enableInfiniteScroll: false,
aspectRatio: 1.1,
onPageChanged: (index, reason) {
setState(() {
_current = index;
});
}),
),
],
),
],
),
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: items.asMap().entries.map(
(entry) {
return GestureDetector(
onTap: () => _controller.animateToPage(entry.key),
child: Container(
width: 12.0,
height: 12.0,
margin: EdgeInsets.symmetric(vertical: 8.0, horizontal: 4.0),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: (Theme.of(context).brightness == Brightness.dark
? Colors.white
: wgerPrimaryColor)
.withOpacity(_current == entry.key ? 0.9 : 0.4)),
),
);
},
).toList(),
),
),
])
else
NothingFound(
AppLocalizations.of(context).noMeasurementEntries,
AppLocalizations.of(context).newEntry,
MeasurementCategoryForm(),
),
],
),
],
),
));
}

View File

@@ -17,7 +17,6 @@
*/
import 'package:charts_flutter/flutter.dart' as charts;
import 'package:collection/collection.dart';
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
@@ -34,16 +33,16 @@ class NutritionData {
NutritionData(this.name, this.value);
}
class NutritionalPlanPieChartWidget extends StatefulWidget {
class FlNutritionalPlanPieChartWidget extends StatefulWidget {
final NutritionalValues nutritionalValues;
const NutritionalPlanPieChartWidget(this.nutritionalValues);
const FlNutritionalPlanPieChartWidget(this.nutritionalValues);
@override
State<StatefulWidget> createState() => FlNutritionalPlanPieChartState();
}
class FlNutritionalPlanPieChartState extends State<NutritionalPlanPieChartWidget> {
class FlNutritionalPlanPieChartState extends State<FlNutritionalPlanPieChartWidget> {
int touchedIndex = -1;
@override
@@ -128,7 +127,7 @@ class FlNutritionalPlanPieChartState extends State<NutritionalPlanPieChartWidget
return PieChartSectionData(
color: colors.current,
value: widget.nutritionalValues.fat,
title: '${widget.nutritionalValues.fat.toStringAsFixed(1)}g',
title: '${widget.nutritionalValues.fat.toStringAsFixed(0)}g',
titlePositionPercentageOffset: 0.5,
radius: radius,
titleStyle: const TextStyle(color: Colors.white70));
@@ -136,7 +135,7 @@ class FlNutritionalPlanPieChartState extends State<NutritionalPlanPieChartWidget
return PieChartSectionData(
color: colors.current,
value: widget.nutritionalValues.protein,
title: '${widget.nutritionalValues.protein.toStringAsFixed(1)}g',
title: '${widget.nutritionalValues.protein.toStringAsFixed(0)}g',
titlePositionPercentageOffset: 0.5,
radius: radius,
);
@@ -144,7 +143,7 @@ class FlNutritionalPlanPieChartState extends State<NutritionalPlanPieChartWidget
return PieChartSectionData(
color: colors.current,
value: widget.nutritionalValues.carbohydrates,
title: '${widget.nutritionalValues.carbohydrates.toStringAsFixed(1)}g',
title: '${widget.nutritionalValues.carbohydrates.toStringAsFixed(0)}g',
titlePositionPercentageOffset: 0.5,
radius: radius,
);
@@ -156,6 +155,244 @@ class FlNutritionalPlanPieChartState extends State<NutritionalPlanPieChartWidget
}
}
class NutritionalDiaryChartWidgetFl extends StatefulWidget {
const NutritionalDiaryChartWidgetFl({
Key? key,
required NutritionalPlan nutritionalPlan,
}) : _nutritionalPlan = nutritionalPlan,
super(key: key);
final NutritionalPlan _nutritionalPlan;
@override
State<StatefulWidget> createState() => NutritionalDiaryChartWidgetFlState();
}
class NutritionalDiaryChartWidgetFlState extends State<NutritionalDiaryChartWidgetFl> {
Widget bottomTitles(double value, TitleMeta meta) {
const style = TextStyle(fontSize: 10);
String text;
switch (value.toInt()) {
case 0:
text = 'Protein';
break;
case 1:
text = 'Carbohydrates';
break;
case 2:
text = 'Sugars';
break;
case 3:
text = 'Fat';
break;
case 4:
text = 'Saturated fat';
break;
default:
text = '';
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
child: Text(text, style: style),
);
}
Widget leftTitles(double value, TitleMeta meta) {
if (value == meta.max) {
return Container();
}
const style = TextStyle(
fontSize: 10,
);
return SideTitleWidget(
axisSide: meta.axisSide,
child: Text(
meta.formattedValue,
style: style,
),
);
}
@override
Widget build(BuildContext context) {
final NutritionalValues planned = widget._nutritionalPlan.nutritionalValues;
final NutritionalValues loggedToday = widget._nutritionalPlan.nutritionalValuesToday;
final NutritionalValues logged7DayAvg = widget._nutritionalPlan.nutritionalValues7DayAvg;
final colorPlanned = LIST_OF_COLORS3[0];
final colorLoggedToday = LIST_OF_COLORS3[1];
final colorLogged7Day = LIST_OF_COLORS3[2];
return AspectRatio(
aspectRatio: 1.66,
child: Padding(
padding: const EdgeInsets.only(top: 16),
child: LayoutBuilder(
builder: (context, constraints) {
final barsSpace = 4.0 * constraints.maxWidth / 400;
final barsWidth = 8.0 * constraints.maxWidth / 400;
return BarChart(
BarChartData(
alignment: BarChartAlignment.center,
barTouchData: BarTouchData(
enabled: false,
),
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 48,
getTitlesWidget: bottomTitles,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
reservedSize: 40,
getTitlesWidget: leftTitles,
),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
gridData: FlGridData(
show: true,
checkToShowHorizontalLine: (value) => value % 10 == 0,
getDrawingHorizontalLine: (value) => FlLine(
color: Colors.black,
strokeWidth: 1,
),
drawVerticalLine: false,
),
borderData: FlBorderData(
show: false,
),
groupsSpace: 30,
// groupsSpace: barsSpace,
barGroups: [
BarChartGroupData(
x: 0,
barsSpace: barsSpace,
barRods: [
BarChartRodData(
toY: planned.protein,
color: colorPlanned,
width: barsWidth,
),
BarChartRodData(
toY: loggedToday.protein,
color: colorLoggedToday,
width: barsWidth,
),
BarChartRodData(
toY: logged7DayAvg.protein,
color: colorLogged7Day,
width: barsWidth,
),
],
),
BarChartGroupData(
x: 1,
barsSpace: barsSpace,
barRods: [
BarChartRodData(
toY: planned.carbohydrates,
color: colorPlanned,
width: barsWidth,
),
BarChartRodData(
toY: loggedToday.carbohydrates,
color: colorLoggedToday,
width: barsWidth,
),
BarChartRodData(
toY: logged7DayAvg.carbohydrates,
color: colorLogged7Day,
width: barsWidth,
),
],
),
BarChartGroupData(
x: 2,
barsSpace: barsSpace,
barRods: [
BarChartRodData(
toY: planned.carbohydratesSugar,
color: colorPlanned,
width: barsWidth,
),
BarChartRodData(
toY: loggedToday.carbohydratesSugar,
color: colorLoggedToday,
width: barsWidth,
),
BarChartRodData(
toY: logged7DayAvg.carbohydratesSugar,
color: colorLogged7Day,
width: barsWidth,
),
],
),
BarChartGroupData(
x: 3,
barsSpace: barsSpace,
barRods: [
BarChartRodData(
toY: planned.fat,
color: colorPlanned,
width: barsWidth,
),
BarChartRodData(
toY: loggedToday.fat,
color: colorLoggedToday,
width: barsWidth,
),
BarChartRodData(
toY: logged7DayAvg.fat,
color: colorLogged7Day,
width: barsWidth,
),
],
),
BarChartGroupData(
x: 4,
barsSpace: barsSpace,
barRods: [
BarChartRodData(
toY: planned.fatSaturated,
color: colorPlanned,
width: barsWidth,
),
BarChartRodData(
toY: loggedToday.fatSaturated,
color: colorLoggedToday,
width: barsWidth,
),
BarChartRodData(
toY: logged7DayAvg.fatSaturated,
color: colorLogged7Day,
width: barsWidth,
),
],
),
],
// barGroups: getData(barsWidth, barsSpace),
),
);
},
),
),
);
}
}
class NutritionalDiaryChartWidget extends StatelessWidget {
const NutritionalDiaryChartWidget({
Key? key,
@@ -193,311 +430,3 @@ class NutritionalDiaryChartWidget extends StatelessWidget {
);
}
}
/// Nutritional plan hatch bar chart widget
class NutritionalPlanHatchBarChartWidget extends StatelessWidget {
final NutritionalPlan _nutritionalPlan;
/// [_nutritionalPlan] is current opened nutrition plan as plan detail.
const NutritionalPlanHatchBarChartWidget(this._nutritionalPlan);
NutritionalValues nutritionalValuesFromPlanLogsSevenDayAvg() {
NutritionalValues sevenDaysAvg = NutritionalValues();
int count = 0;
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
_nutritionalPlan.logEntriesValues.forEach((key, value) {
if (key.difference(today).inDays >= -7) {
sevenDaysAvg += value;
count++;
}
});
if (count != 0) {
sevenDaysAvg.energy = sevenDaysAvg.energy / count;
sevenDaysAvg.protein = sevenDaysAvg.protein / count;
sevenDaysAvg.carbohydrates = sevenDaysAvg.carbohydrates / count;
sevenDaysAvg.carbohydratesSugar = sevenDaysAvg.carbohydratesSugar / count;
sevenDaysAvg.fat = sevenDaysAvg.fat / count;
sevenDaysAvg.fatSaturated = sevenDaysAvg.fatSaturated / count;
sevenDaysAvg.fibres = sevenDaysAvg.fibres / count;
sevenDaysAvg.sodium = sevenDaysAvg.sodium / count;
}
return sevenDaysAvg;
}
NutritionalValues nutritionalValuesFromPlanLogsToday() {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
return _nutritionalPlan.logEntriesValues[_nutritionalPlan.logEntriesValues.keys
.firstWhereOrNull((d) => d.difference(today).inDays == 0)] ??
NutritionalValues();
}
@override
Widget build(BuildContext context) {
final NutritionalValues loggedNutritionalValues = nutritionalValuesFromPlanLogsToday();
final NutritionalValues sevenDayAvg = nutritionalValuesFromPlanLogsSevenDayAvg();
if (_nutritionalPlan.nutritionalValues.energy == 0) {
return Container();
}
return Column(
children: [
Container(
padding: const EdgeInsets.all(15),
height: 220,
child: charts.BarChart(
[
charts.Series<NutritionData, String>(
id: 'Planned',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
data: [
NutritionData(AppLocalizations.of(context).energy,
_nutritionalPlan.nutritionalValues.energy),
],
),
charts.Series<NutritionData, String>(
id: 'Logged',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
fillPatternFn: (nutritionEntry, index) => charts.FillPatternType.forwardHatch,
data: [
NutritionData(
AppLocalizations.of(context).energy, loggedNutritionalValues.energy),
],
),
charts.Series<NutritionData, String>(
id: 'Avg',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
data: [
NutritionData(AppLocalizations.of(context).energy, sevenDayAvg.energy),
],
),
],
animate: true,
domainAxis: const charts.OrdinalAxisSpec(
///labelRotation was added to rotate text of X Axis. Without that,
///titles would overlap each other
renderSpec: charts.SmallTickRendererSpec(labelRotation: 60),
),
barGroupingType: charts.BarGroupingType.grouped,
defaultRenderer: charts.BarRendererConfig(
groupingType: charts.BarGroupingType.grouped, strokeWidthPx: 0.0, maxBarWidthPx: 8),
primaryMeasureAxis: const charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(desiredTickCount: 5),
),
),
),
Container(
padding: const EdgeInsets.all(15),
height: 300,
child: charts.BarChart(
[
charts.Series<NutritionData, String>(
id: 'Planned',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
data: [
// NutritionData(
// AppLocalizations.of(context).energy,
// _nutritionalPlan.nutritionalValues.energy,
// ),
NutritionData(
AppLocalizations.of(context).protein,
_nutritionalPlan.nutritionalValues.protein,
),
NutritionData(
AppLocalizations.of(context).carbohydrates,
_nutritionalPlan.nutritionalValues.carbohydrates,
),
NutritionData(
AppLocalizations.of(context).sugars,
_nutritionalPlan.nutritionalValues.carbohydratesSugar,
),
NutritionData(
AppLocalizations.of(context).fat,
_nutritionalPlan.nutritionalValues.fat,
),
NutritionData(
AppLocalizations.of(context).saturatedFat,
_nutritionalPlan.nutritionalValues.fatSaturated,
),
NutritionData(
AppLocalizations.of(context).fibres,
_nutritionalPlan.nutritionalValues.fibres,
),
NutritionData(
AppLocalizations.of(context).sodium,
_nutritionalPlan.nutritionalValues.sodium,
),
],
),
charts.Series<NutritionData, String>(
id: 'Logged',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
fillPatternFn: (nutritionEntry, index) => charts.FillPatternType.forwardHatch,
data: [
// NutritionData(
// AppLocalizations.of(context).energy,
// loggedNutritionalValues.energy
// ),
NutritionData(
AppLocalizations.of(context).protein, loggedNutritionalValues.protein),
NutritionData(AppLocalizations.of(context).carbohydrates,
loggedNutritionalValues.carbohydrates),
NutritionData(AppLocalizations.of(context).sugars,
loggedNutritionalValues.carbohydratesSugar),
NutritionData(AppLocalizations.of(context).fat, loggedNutritionalValues.fat),
NutritionData(AppLocalizations.of(context).saturatedFat,
loggedNutritionalValues.fatSaturated),
NutritionData(
AppLocalizations.of(context).fibres, loggedNutritionalValues.fibres),
NutritionData(
AppLocalizations.of(context).sodium, loggedNutritionalValues.sodium),
],
),
charts.Series<NutritionData, String>(
id: 'Avg',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
data: [
// NutritionData(AppLocalizations.of(context).energy, sevenDayAvg.energy),
NutritionData(AppLocalizations.of(context).protein, sevenDayAvg.protein),
NutritionData(
AppLocalizations.of(context).carbohydrates, sevenDayAvg.carbohydrates),
NutritionData(
AppLocalizations.of(context).sugars, sevenDayAvg.carbohydratesSugar),
NutritionData(AppLocalizations.of(context).fat, sevenDayAvg.fat),
NutritionData(
AppLocalizations.of(context).saturatedFat, sevenDayAvg.fatSaturated),
NutritionData(AppLocalizations.of(context).fibres, sevenDayAvg.fibres),
NutritionData(AppLocalizations.of(context).sodium, sevenDayAvg.sodium),
],
),
],
animate: true,
domainAxis: const charts.OrdinalAxisSpec(
///labelRotation was added to rotate text of X Axis. Without that,
///titles would overlap each other
renderSpec: charts.SmallTickRendererSpec(labelRotation: 60),
),
barGroupingType: charts.BarGroupingType.grouped,
primaryMeasureAxis: const charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(
desiredTickCount: 5,
),
),
),
),
],
);
}
}
//creating a seperate chart for energy as the energy value and other nutrient's value is not compatable to show in one graph
class EnergyChart extends StatelessWidget {
const EnergyChart({Key? key, required this.nutritionalPlan}) : super(key: key);
final NutritionalPlan nutritionalPlan;
NutritionalValues nutritionalValuesFromPlanLogsSevenDayAvg() {
NutritionalValues sevenDaysAvg = NutritionalValues();
int count = 0;
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
nutritionalPlan.logEntriesValues.forEach((key, value) {
if (key.difference(today).inDays >= -7) {
sevenDaysAvg += value;
count++;
}
});
if (count != 0) {
sevenDaysAvg.energy = sevenDaysAvg.energy / count;
sevenDaysAvg.protein = sevenDaysAvg.protein / count;
sevenDaysAvg.carbohydrates = sevenDaysAvg.carbohydrates / count;
sevenDaysAvg.carbohydratesSugar = sevenDaysAvg.carbohydratesSugar / count;
sevenDaysAvg.fat = sevenDaysAvg.fat / count;
sevenDaysAvg.fatSaturated = sevenDaysAvg.fatSaturated / count;
sevenDaysAvg.fibres = sevenDaysAvg.fibres / count;
sevenDaysAvg.sodium = sevenDaysAvg.sodium / count;
}
return sevenDaysAvg;
}
NutritionalValues nutritionalValuesFromPlanLogsToday() {
final now = DateTime.now();
final today = DateTime(now.year, now.month, now.day);
return nutritionalPlan.logEntriesValues[nutritionalPlan.logEntriesValues.keys
.firstWhereOrNull((d) => d.difference(today).inDays == 0)] ??
NutritionalValues();
}
@override
Widget build(BuildContext context) {
final NutritionalValues loggedNutritionalValues = nutritionalValuesFromPlanLogsToday();
final NutritionalValues sevenDayAvg = nutritionalValuesFromPlanLogsSevenDayAvg();
if (nutritionalPlan.nutritionalValues.energy == 0) {
return Container();
}
return charts.BarChart(
[
charts.Series<NutritionData, String>(
id: 'Planned',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
data: [
NutritionData(
AppLocalizations.of(context).energy,
nutritionalPlan.nutritionalValues.energy,
),
],
),
charts.Series<NutritionData, String>(
id: 'Logged',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
fillPatternFn: (nutritionEntry, index) => charts.FillPatternType.forwardHatch,
data: [
NutritionData(AppLocalizations.of(context).energy, loggedNutritionalValues.energy),
],
),
charts.Series<NutritionData, String>(
id: 'Avg',
domainFn: (nutritionEntry, index) => nutritionEntry.name,
measureFn: (nutritionEntry, index) => nutritionEntry.value,
data: [
NutritionData(AppLocalizations.of(context).energy, sevenDayAvg.energy),
],
),
],
animate: true,
domainAxis: const charts.OrdinalAxisSpec(
///labelRotation was added to rotate text of X Axis. Without that,
///titles would overlap each other
renderSpec: charts.SmallTickRendererSpec(labelRotation: 60),
),
barGroupingType: charts.BarGroupingType.grouped,
defaultRenderer: charts.BarRendererConfig(
groupingType: charts.BarGroupingType.grouped, strokeWidthPx: 0.0, maxBarWidthPx: 8),
primaryMeasureAxis: const charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(desiredTickCount: 5),
),
);
}
}

View File

@@ -32,6 +32,7 @@ class NutritionalDiaryDetailWidget extends StatelessWidget {
final NutritionalPlan _nutritionalPlan;
final DateTime _date;
static const double tablePadding = 7;
const NutritionalDiaryDetailWidget(this._nutritionalPlan, this._date);
Widget getTable(
@@ -223,7 +224,7 @@ class NutritionalDiaryDetailWidget extends StatelessWidget {
Container(
padding: const EdgeInsets.all(15),
height: 220,
child: NutritionalPlanPieChartWidget(valuesDate),
child: FlNutritionalPlanPieChartWidget(valuesDate),
),
Padding(
padding: const EdgeInsets.all(8.0),

View File

@@ -32,7 +32,9 @@ import 'package:wger/widgets/nutrition/meal.dart';
class NutritionalPlanDetailWidget extends StatelessWidget {
final NutritionalPlan _nutritionalPlan;
const NutritionalPlanDetailWidget(this._nutritionalPlan);
static const double tablePadding = 7;
@override
@@ -70,7 +72,7 @@ class NutritionalPlanDetailWidget extends StatelessWidget {
Container(
padding: const EdgeInsets.all(15),
height: 220,
child: NutritionalPlanPieChartWidget(nutritionalValues), // chart
child: FlNutritionalPlanPieChartWidget(nutritionalValues), // chart
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
@@ -210,13 +212,11 @@ class NutritionalPlanDetailWidget extends StatelessWidget {
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.headline6,
),
NutritionalPlanHatchBarChartWidget(_nutritionalPlan),
// Container(
// padding: const EdgeInsets.all(15),
// height: 300,
// child: NutritionalPlanHatchBarChartWidget(_nutritionalPlan), // chart
// ),
Container(
padding: const EdgeInsets.all(15),
height: 300,
child: NutritionalDiaryChartWidgetFl(nutritionalPlan: _nutritionalPlan), // chart
),
const Padding(padding: EdgeInsets.all(8.0)),
Text(
AppLocalizations.of(context).nutritionalDiary,

View File

@@ -82,8 +82,9 @@ void main() {
await tester.tap(find.byType(TextButton));
await tester.pumpAndSettle();
expect(find.text('8/1/2021'), findsOneWidget);
expect(find.text('8/10/2021'), findsOneWidget);
// From the entries list and from the chart
expect(find.text('8/1/2021'), findsNWidgets(3));
expect(find.text('8/10/2021'), findsNWidgets(2));
});
testWidgets('Tests the localization of dates - DE', (WidgetTester tester) async {

View File

@@ -41,7 +41,7 @@ void main() {
testWidgets('Test the detail view for the nutritional plan', (WidgetTester tester) async {
await tester.pumpWidget(getWidget());
expect(find.byType(NutritionalPlanPieChartWidget), findsOneWidget);
expect(find.byType(FlNutritionalPlanPieChartWidget), findsOneWidget);
expect(find.byType(Table), findsOneWidget);
expect(find.text('519kcal'), findsOneWidget, reason: 'find total energy');

View File

@@ -83,8 +83,9 @@ void main() {
testWidgets('Tests the localization of dates - EN', (WidgetTester tester) async {
await tester.pumpWidget(createWeightScreen());
expect(find.text('1/1/2021'), findsOneWidget);
expect(find.text('1/10/2021'), findsOneWidget);
// One in the entries list, one in the chart
expect(find.text('1/1/2021'), findsNWidgets(2));
expect(find.text('1/10/2021'), findsNWidgets(2));
});
testWidgets('Tests the localization of dates - DE', (WidgetTester tester) async {