diff --git a/lib/helpers/colors.dart b/lib/helpers/colors.dart index b7fd22885..8fb060dd7 100644 --- a/lib/helpers/colors.dart +++ b/lib/helpers/colors.dart @@ -1,3 +1,4 @@ +import 'dart:math'; import 'dart:ui'; const LIST_OF_COLORS8 = [ @@ -40,3 +41,18 @@ Iterable generateChartColors(int nrOfItems) sync* { yield color; } } + +/// Returns a random color based on the given seed +Color getRandomColor(int nrOfItems, int seed) { + final List colors; + + if (nrOfItems <= 3) { + colors = LIST_OF_COLORS3; + } else if (nrOfItems <= 5) { + colors = LIST_OF_COLORS5; + } else { + colors = LIST_OF_COLORS8; + } + + return colors[Random(seed).nextInt(colors.length)]; +} diff --git a/lib/providers/workout_plans.dart b/lib/providers/workout_plans.dart index 47dcea351..7b8d8fa04 100644 --- a/lib/providers/workout_plans.dart +++ b/lib/providers/workout_plans.dart @@ -300,6 +300,8 @@ class WorkoutPlansProvider with ChangeNotifier { query: {'id': base.id.toString()}, ), ); + // log(data.toString()); + return data; } diff --git a/lib/theme/theme.dart b/lib/theme/theme.dart index 89f98fb93..1ba04fac7 100644 --- a/lib/theme/theme.dart +++ b/lib/theme/theme.dart @@ -16,7 +16,6 @@ * along with this program. If not, see . */ -import 'package:charts_flutter/flutter.dart' as charts; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:table_calendar/table_calendar.dart'; @@ -30,8 +29,6 @@ const Color wgerTextMuted = Colors.black38; const Color wgerBackground = Color(0xfff4f4f6); // Chart colors -const charts.Color wgerChartPrimaryColor = charts.Color(r: 0x2a, g: 0x4c, b: 0x7d); -const charts.Color wgerChartSecondaryColor = charts.Color(r: 0xe6, g: 0x39, b: 0x46); /// Original sizes for the material text theme /// https://api.flutter.dev/flutter/material/TextTheme-class.html diff --git a/lib/widgets/workouts/charts.dart b/lib/widgets/workouts/charts.dart index 6cfd628e9..c95dd60a5 100644 --- a/lib/widgets/workouts/charts.dart +++ b/lib/widgets/workouts/charts.dart @@ -16,10 +16,10 @@ * along with this program. If not, see . */ -import 'package:charts_flutter/flutter.dart' as charts; +import 'package:fl_chart/fl_chart.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:intl/intl.dart'; +import 'package:wger/helpers/colors.dart'; /// Sample time series data type. class TimeSeriesLog { @@ -29,53 +29,112 @@ class TimeSeriesLog { TimeSeriesLog(this.time, this.weight); } -class LogChartWidget extends StatelessWidget { +class LogChartWidgetFl extends StatefulWidget { final Map _data; final DateTime _currentDate; - const LogChartWidget(this._data, this._currentDate); + + const LogChartWidgetFl(this._data, this._currentDate); + + @override + State createState() => _LogChartWidgetFlState(); +} + +class _LogChartWidgetFlState extends State { + final interval = 15 * Duration.millisecondsPerDay / 1000 / 60; @override Widget build(BuildContext context) { - return _data.containsKey('chart_data') && _data['chart_data'].length > 0 - ? charts.TimeSeriesChart( - [ - ..._data['chart_data'].map((e) { - return charts.Series( - id: '${e.first['reps']} ${AppLocalizations.of(context).reps}', - domainFn: (datum, index) => datum.time, - measureFn: (datum, index) => datum.weight, - data: [ - ...e.map( - (entry) => TimeSeriesLog( - DateTime.parse(entry['date']), - double.parse(entry['weight']), - ), - ), - ], - ); - }), - ], - primaryMeasureAxis: const charts.NumericAxisSpec( - tickProviderSpec: charts.BasicNumericTickProviderSpec(zeroBound: false), - ), - behaviors: [ - charts.SeriesLegend( - position: charts.BehaviorPosition.bottom, - desiredMaxColumns: 4, + return AspectRatio( + aspectRatio: 1.70, + child: Padding( + padding: const EdgeInsets.only( + right: 18, + left: 12, + top: 24, + bottom: 12, + ), + child: LineChart( + mainData(), + ), + ), + ); + } + + LineChartData mainData() { + return LineChartData( + gridData: FlGridData( + show: true, + drawVerticalLine: true, + //horizontalInterval: 1, + //verticalInterval: interval, + getDrawingHorizontalLine: (value) { + return FlLine( + color: Colors.grey, + strokeWidth: 1, + ); + }, + getDrawingVerticalLine: (value) { + return FlLine( + color: Colors.grey, + strokeWidth: 1, + ); + }, + ), + titlesData: FlTitlesData( + show: true, + rightTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + topTitles: AxisTitles( + sideTitles: SideTitles(showTitles: false), + ), + bottomTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + getTitlesWidget: (value, meta) { + final DateTime date = DateTime.fromMillisecondsSinceEpoch(value.toInt() * 1000 * 60); + return Text( + DateFormat.yMd(Localizations.localeOf(context).languageCode).format(date), + ); + }, + interval: interval, + ), + ), + leftTitles: AxisTitles( + sideTitles: SideTitles( + showTitles: true, + reservedSize: 50, + getTitlesWidget: (value, meta) { + return Text(value.toString()); + }, + ), + ), + ), + borderData: FlBorderData( + show: true, + border: Border.all(color: const Color(0xff37434d)), + ), + lineBarsData: [ + ...widget._data['chart_data'].map( + (e) { + return LineChartBarData( + spots: [ + ...e.map((entry) => FlSpot( + DateTime.parse(entry['date']).millisecondsSinceEpoch / 1000 / 60, + double.parse(entry['weight']), + )) + ], + isCurved: false, + color: getRandomColor(widget._data['chart_data'].length, e.first['reps']), + barWidth: 2, + isStrokeCapRound: true, + dotData: FlDotData( + show: false, ), - charts.RangeAnnotation([ - charts.LineAnnotationSegment( - _currentDate, charts.RangeAnnotationAxisType.domain, - strokeWidthPx: 2, - labelPosition: charts.AnnotationLabelPosition.margin, - color: charts.Color.black, - dashPattern: [0, 1, 1, 1], - //startLabel: DateFormat.yMd(Localizations.localeOf(context).languageCode) - // .format(_currentDate), - ) - ]), - ], - ) - : Container(); + ); + }, + ) + ], + ); } } diff --git a/lib/widgets/workouts/log.dart b/lib/widgets/workouts/log.dart index c0fd30c5b..e58d0d732 100644 --- a/lib/widgets/workouts/log.dart +++ b/lib/widgets/workouts/log.dart @@ -17,7 +17,6 @@ */ import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'package:wger/helpers/ui.dart'; @@ -48,7 +47,7 @@ class ExerciseLogChart extends StatelessWidget { height: 150, child: snapshot.connectionState == ConnectionState.waiting ? const Center(child: CircularProgressIndicator()) - : LogChartWidget(snapshot.data!, _currentDate), + : LogChartWidgetFl(snapshot.data!, _currentDate), ), ); } diff --git a/pubspec.lock b/pubspec.lock index df5187e56..9f0f19360 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -201,22 +201,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" - charts_common: - dependency: transitive - description: - name: charts_common - sha256: "7b8922f9b0d9b134122756a787dab1c3946ae4f3fc5022ff323ba0014998ea02" - url: "https://pub.dev" - source: hosted - version: "0.12.0" - charts_flutter: - dependency: "direct main" - description: - name: charts_flutter - sha256: "4172c3f4b85322fdffe1896ffbed79ae4689ae72cb6fe6690dcaaea620a9c558" - url: "https://pub.dev" - source: hosted - version: "0.12.0" checked_yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d92665f6f..04d8178dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -33,7 +33,6 @@ dependencies: sdk: flutter android_metadata: ^0.2.1 - charts_flutter: ^0.12.0 collection: ^1.17.0 cupertino_icons: ^1.0.5 equatable: ^2.0.5