From e59e225582a593321a215167ecb8ef709540d227 Mon Sep 17 00:00:00 2001 From: "Tibor Bossanyi (Freelancer)" Date: Sat, 16 Apr 2022 21:55:59 +0200 Subject: [PATCH] WT 1.1.26+4 radar chart 1 --- i18n/hu.json | 10 +- .../body_development_bloc.dart | 58 +++- lib/library/radar_chart.dart | 295 ------------------ lib/repository/exercise_repository.dart | 24 +- lib/util/enums.dart | 14 + lib/util/string_extension.dart | 5 + lib/view/mydevelopment_body_page.dart | 48 +-- lib/view/mydevelopment_sizes_page.dart | 4 +- pubspec.lock | 14 +- pubspec.yaml | 2 +- 10 files changed, 130 insertions(+), 344 deletions(-) delete mode 100644 lib/library/radar_chart.dart create mode 100644 lib/util/string_extension.dart diff --git a/i18n/hu.json b/i18n/hu.json index ad8cccc..00b7149 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -59,7 +59,7 @@ "Endurance": "Állóképesség", "Pushups": "Fekvőtámasz", "Timed Pushups": "Fekvőtámasz időre", - "Core": "Core (plank)", + "Core": "Core (törzs-has)", "Squats": "Guggolás", "Sit-ups": "Felülés", "1RM": "1RM - Maxerő", @@ -202,10 +202,10 @@ "You have only 1-2 exercise left to finish!": "Már csak 1-2 gyakorlat van a hátra!", "exercise!": "gyakorlattal!", "exercise": "gyakorlat", - "Chest": "mell", - "Back": "hát", - "Thigh": "comb", - "Calf": "vádli", + "Chest": "Mell", + "Back": "Hát", + "Thigh": "Comb", + "Calf": "Vádli", "Bring me there": "Vigyél oda", "My Body Development": "Testem fejlődése", "You see here your whole body development by muscle groups.": "Itt láthatod a tested fejlődését izomcsoportonként", diff --git a/lib/bloc/body_development/body_development_bloc.dart b/lib/bloc/body_development/body_development_bloc.dart index 1cab930..8a173b7 100644 --- a/lib/bloc/body_development/body_development_bloc.dart +++ b/lib/bloc/body_development/body_development_bloc.dart @@ -1,7 +1,11 @@ +import 'package:aitrainer_app/model/exercise.dart'; +import 'package:aitrainer_app/util/enums.dart'; +import 'package:intl/intl.dart'; import 'dart:async'; import 'package:aitrainer_app/bloc/development_diagram/development_diagram_bloc.dart'; import 'package:aitrainer_app/repository/exercise_repository.dart'; import 'package:aitrainer_app/repository/workout_tree_repository.dart'; +import 'package:aitrainer_app/util/app_language.dart'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:flutter/material.dart'; @@ -15,6 +19,10 @@ class BodyDevelopmentBloc extends Bloc legendsL3t = ['2 trainigs ago', '1 training ago', 'last training']; + List legendsFmlm = ['First month', '1 month ago', 'last month']; + List legendsL3m = ['2 months ago', '1 month ago', 'last month']; + List legends = []; List radarTicks = []; List radarFeatures = []; List> radarData = []; @@ -23,7 +31,7 @@ class BodyDevelopmentBloc extends Bloc(_onLoad); + getData(); on(_onDateFilterChange); on(_onGroupChange); } @@ -35,20 +43,52 @@ class BodyDevelopmentBloc extends Bloc getData() async { - radarTicks = [20, 40, 60, 80, 100]; - radarFeatures = ["Mell", "Bicepsz", "Tricepsz", "Hát", "Váll", "Core", "Comb", "Vádli"]; + this.getExerciseData(); + radarTicks = [20, 40, 60, 80, 100, 120, 140, 160]; radarData = [ [80, 95, 45, 67, 83, 40, 56, 78], [82, 90, 56, 77, 82, 40, 50, 87], - [86, 92, 58, 70, 80, 49, 52, 87], + [26, 112, 58, 70, 130, 49, 52, 127], ]; - } + switch (this.filter) { + case DiagramDateFilterGroup.l3t: + legends = legendsL3t; + break; + case DiagramDateFilterGroup.l3m: + legends = legendsL3m; + break; + case DiagramDateFilterGroup.fm_lm: + legends = legendsFmlm; + break; + case DiagramDateFilterGroup.yearly: + var date = DateTime.now(); - void _onLoad(BodyDevelopmentLoad event, Emitter emit) { - emit(BodyDevelopmentLoading()); - getData(); - emit(BodyDevelopmentReady()); + legends = [ + DateFormat(DateFormat.YEAR, AppLanguage().appLocal.toString()).format(date.subtract(Duration(days: 365 * 2))), + DateFormat(DateFormat.YEAR, AppLanguage().appLocal.toString()).format(date.subtract(Duration(days: 365))), + DateFormat(DateFormat.YEAR, AppLanguage().appLocal.toString()).format(date) + ]; + break; + + default: + legends = legendsL3t; + } } void _onDateFilterChange(BodyDevelopmentChangeDate event, Emitter emit) { diff --git a/lib/library/radar_chart.dart b/lib/library/radar_chart.dart deleted file mode 100644 index 32c0696..0000000 --- a/lib/library/radar_chart.dart +++ /dev/null @@ -1,295 +0,0 @@ -library flutter_radar_chart; - -import 'dart:math' as math; - -import 'package:flutter/material.dart'; -import 'dart:math' show pi, cos, sin; - -const defaultGraphColors = [ - Colors.green, - Colors.blue, - Colors.red, - Colors.orange, -]; - -class RadarChart extends StatefulWidget { - final List ticks; - final List features; - final List> data; - final bool reverseAxis; - final TextStyle ticksTextStyle; - final TextStyle featuresTextStyle; - final Color outlineColor; - final Color axisColor; - final List graphColors; - final int sides; - - const RadarChart({ - Key? key, - required this.ticks, - required this.features, - required this.data, - this.reverseAxis = false, - this.ticksTextStyle = const TextStyle(color: Colors.grey, fontSize: 12), - this.featuresTextStyle = const TextStyle(color: Colors.black, fontSize: 16), - this.outlineColor = Colors.black, - this.axisColor = Colors.grey, - this.graphColors = defaultGraphColors, - this.sides = 0, - }) : super(key: key); - - factory RadarChart.light({ - required List ticks, - required List features, - required List> data, - bool reverseAxis = false, - bool useSides = false, - }) { - return RadarChart(ticks: ticks, features: features, data: data, reverseAxis: reverseAxis, sides: useSides ? features.length : 0); - } - - factory RadarChart.dark({ - required List ticks, - required List features, - required List> data, - bool reverseAxis = false, - bool useSides = false, - }) { - return RadarChart( - ticks: ticks, - features: features, - data: data, - featuresTextStyle: const TextStyle(color: Colors.white, fontSize: 16), - outlineColor: Colors.white, - axisColor: Colors.grey, - reverseAxis: reverseAxis, - sides: useSides ? features.length : 0); - } - - @override - _RadarChartState createState() => _RadarChartState(); -} - -class _RadarChartState extends State with SingleTickerProviderStateMixin { - double fraction = 0; - late Animation animation; - late AnimationController animationController; - - @override - void initState() { - super.initState(); - animationController = AnimationController(duration: Duration(milliseconds: 1000), vsync: this); - - animation = Tween(begin: 0.0, end: 1.0).animate(CurvedAnimation( - curve: Curves.fastOutSlowIn, - parent: animationController, - )) - ..addListener(() { - setState(() { - fraction = animation.value; - }); - }); - - animationController.forward(); - } - - @override - void didUpdateWidget(RadarChart oldWidget) { - super.didUpdateWidget(oldWidget); - - animationController.reset(); - animationController.forward(); - } - - @override - Widget build(BuildContext context) { - return CustomPaint( - size: Size(double.infinity, double.infinity), - painter: RadarChartPainter(widget.ticks, widget.features, widget.data, widget.reverseAxis, widget.ticksTextStyle, - widget.featuresTextStyle, widget.outlineColor, widget.axisColor, widget.graphColors, widget.sides, this.fraction), - ); - } - - @override - void dispose() { - animationController.dispose(); - super.dispose(); - } -} - -class RadarChartPainter extends CustomPainter { - final List ticks; - final List features; - final List> data; - final bool reverseAxis; - final TextStyle ticksTextStyle; - final TextStyle featuresTextStyle; - final Color outlineColor; - final Color axisColor; - final List graphColors; - final int sides; - final double fraction; - - RadarChartPainter( - this.ticks, - this.features, - this.data, - this.reverseAxis, - this.ticksTextStyle, - this.featuresTextStyle, - this.outlineColor, - this.axisColor, - this.graphColors, - this.sides, - this.fraction, - ); - - Path variablePath(Size size, double radius, int sides) { - var path = Path(); - var angle = (math.pi * 2) / sides; - - Offset center = Offset(size.width / 2, size.height / 2); - - if (sides < 3) { - // Draw a circle - path.addOval(Rect.fromCircle( - center: Offset(size.width / 2, size.height / 2), - radius: radius, - )); - } else { - // Draw a polygon - Offset startPoint = Offset(radius * cos(-pi / 2), radius * sin(-pi / 2)); - - path.moveTo(startPoint.dx + center.dx, startPoint.dy + center.dy); - - for (int i = 1; i <= sides; i++) { - double x = radius * cos(angle * i - pi / 2) + center.dx; - double y = radius * sin(angle * i - pi / 2) + center.dy; - path.lineTo(x, y); - } - path.close(); - } - return path; - } - - @override - void paint(Canvas canvas, Size size) { - final centerX = size.width / 2.0; - final centerY = size.height / 2.0; - final centerOffset = Offset(centerX, centerY); - final radius = math.min(centerX, centerY) * 0.8; - final scale = radius / ticks.last; - - // Painting the chart outline - var outlinePaint = Paint() - ..color = outlineColor - ..style = PaintingStyle.stroke - ..strokeWidth = 2.0 - ..isAntiAlias = true; - - var ticksPaint = Paint() - ..color = axisColor - ..style = PaintingStyle.stroke - ..strokeWidth = 1.0 - ..isAntiAlias = true; - - canvas.drawPath(variablePath(size, radius, this.sides), outlinePaint); - // Painting the circles and labels for the given ticks (could be auto-generated) - // The last tick is ignored, since it overlaps with the feature label - var tickDistance = radius / (ticks.length); - var tickLabels = reverseAxis ? ticks.reversed.toList() : ticks; - - if (reverseAxis) { - TextPainter( - text: TextSpan(text: tickLabels[0].toString(), style: ticksTextStyle), - textDirection: TextDirection.ltr, - ) - ..layout(minWidth: 0, maxWidth: size.width) - ..paint(canvas, Offset(centerX, centerY - ticksTextStyle.fontSize!)); - } - - tickLabels.sublist(reverseAxis ? 1 : 0, reverseAxis ? ticks.length : ticks.length - 1).asMap().forEach((index, tick) { - var tickRadius = tickDistance * (index + 1); - - canvas.drawPath(variablePath(size, tickRadius, this.sides), ticksPaint); - - TextPainter( - text: TextSpan(text: tick.toString(), style: ticksTextStyle), - textDirection: TextDirection.ltr, - ) - ..layout(minWidth: 0, maxWidth: size.width) - ..paint(canvas, Offset(centerX, centerY - tickRadius - ticksTextStyle.fontSize!)); - }); - - // Painting the axis for each given feature - var angle = (2 * pi) / features.length; - - features.asMap().forEach((index, feature) { - var xAngle = cos(angle * index - pi / 2); - var yAngle = sin(angle * index - pi / 2); - - var featureOffset = Offset(centerX + radius * xAngle, centerY + radius * yAngle); - - canvas.drawLine(centerOffset, featureOffset, ticksPaint); - - var featureLabelFontHeight = featuresTextStyle.fontSize; - var featureLabelFontWidth = featuresTextStyle.fontSize! - 5; - var labelYOffset = yAngle < 0 ? -featureLabelFontHeight! : 0; - var labelXOffset = xAngle < 0 ? -featureLabelFontWidth * feature.length : 0; - - TextPainter( - text: TextSpan(text: feature, style: featuresTextStyle), - textAlign: TextAlign.left, - textDirection: TextDirection.ltr, - ) - ..layout(minWidth: 0, maxWidth: size.width) - ..paint(canvas, Offset(featureOffset.dx + labelXOffset, featureOffset.dy + labelYOffset)); - }); - - // Painting each graph - data.asMap().forEach((index, graph) { - var graphPaint = Paint() - ..color = graphColors[index % graphColors.length].withOpacity(0.3) - ..style = PaintingStyle.fill; - - var graphOutlinePaint = Paint() - ..color = graphColors[index % graphColors.length] - ..style = PaintingStyle.stroke - ..strokeWidth = 2.0 - ..isAntiAlias = true; - - // Start the graph on the initial point - var scaledPoint = scale * graph[0] * fraction; - var path = Path(); - - if (reverseAxis) { - path.moveTo(centerX, centerY - (radius * fraction - scaledPoint)); - } else { - path.moveTo(centerX, centerY - scaledPoint); - } - - graph.asMap().forEach((index, point) { - if (index == 0) return; - - var xAngle = cos(angle * index - pi / 2); - var yAngle = sin(angle * index - pi / 2); - var scaledPoint = scale * point * fraction; - - if (reverseAxis) { - path.lineTo(centerX + (radius * fraction - scaledPoint) * xAngle, centerY + (radius * fraction - scaledPoint) * yAngle); - } else { - path.lineTo(centerX + scaledPoint * xAngle, centerY + scaledPoint * yAngle); - } - }); - - path.close(); - canvas.drawPath(path, graphPaint); - canvas.drawPath(path, graphOutlinePaint); - }); - } - - @override - bool shouldRepaint(RadarChartPainter oldDelegate) { - return oldDelegate.fraction != fraction; - } -} diff --git a/lib/repository/exercise_repository.dart b/lib/repository/exercise_repository.dart index db3aef9..d72861d 100644 --- a/lib/repository/exercise_repository.dart +++ b/lib/repository/exercise_repository.dart @@ -424,9 +424,8 @@ class ExerciseRepository { return sumA >= sumB ? 1 : -1; }); - double withCompare = oldExercises.last.unitQuantity != null - ? oldExercises.last.quantity! * oldExercises.last.unitQuantity! - : oldExercises.last.quantity!; + double withCompare = + oldExercises.last.unitQuantity != null ? oldExercises.last.quantity! * oldExercises.last.unitQuantity! : oldExercises.last.quantity!; //result = toCompare >= withCompare ? (1 - toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100; //print("Last Best: ${oldExercises.last} - result: $result"); @@ -457,9 +456,8 @@ class ExerciseRepository { }); if (oldExercises.isNotEmpty) { - double withCompare = oldExercises.first.unitQuantity != null - ? oldExercises.first.quantity! * oldExercises.first.unitQuantity! - : oldExercises.first.quantity!; + double withCompare = + oldExercises.first.unitQuantity != null ? oldExercises.first.quantity! * oldExercises.first.unitQuantity! : oldExercises.first.quantity!; result = toCompare >= withCompare ? (toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100; print("Last Last: ${oldExercises.first} vs. $exercise - - result: $result"); @@ -522,4 +520,18 @@ class ExerciseRepository { prevExercise.summary = summary; exerciseLogList!.add(prevExercise); } + + List getExercisesByExerciseTypeId(int exerciseTypeId) { + List list = []; + List? allExercise = Cache().getExercises(); + if (allExercise == null) { + return list; + } + allExercise.forEach((element) { + if (element.exerciseTypeId == exerciseTypeId) { + list.add(element); + } + }); + return list; + } } diff --git a/lib/util/enums.dart b/lib/util/enums.dart index 0660e94..8f68e89 100644 --- a/lib/util/enums.dart +++ b/lib/util/enums.dart @@ -1,3 +1,5 @@ +import 'package:aitrainer_app/util/string_extension.dart'; + enum LoginType { email, fb, google, apple } extension LoginTypeExt on LoginType { @@ -112,3 +114,15 @@ extension ExerciseSaveTypeExt on ExerciseSaveType { bool equalsTo(ExerciseSaveType type) => this.toString() == type.toString(); bool equalsStringTo(String type) => this.toStr() == type; } + +enum MuscleGroup { chest, biceps, triceps, back, shoulders, core, thigh, calf } + +extension MuscleGroupExt on MuscleGroup { + String toStr() => this.toString().split(".").last; + String toText() => this.toString().split(".").last.capitalize(); + bool equalsTo(MuscleGroup type) => this.toString() == type.toString(); + bool equalsStringTo(String type) => this.toStr() == type; + String getStrByIndex(int index) => MuscleGroup.values.elementAt(index).toStr(); + MuscleGroup getByIndex(int index) => MuscleGroup.values.elementAt(index); + String getTextByIndex(int index) => MuscleGroup.values.elementAt(index).toText(); +} diff --git a/lib/util/string_extension.dart b/lib/util/string_extension.dart new file mode 100644 index 0000000..d48c06a --- /dev/null +++ b/lib/util/string_extension.dart @@ -0,0 +1,5 @@ +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${this.substring(1).toLowerCase()}"; + } +} diff --git a/lib/view/mydevelopment_body_page.dart b/lib/view/mydevelopment_body_page.dart index 68cd091..cc5c62e 100644 --- a/lib/view/mydevelopment_body_page.dart +++ b/lib/view/mydevelopment_body_page.dart @@ -2,17 +2,17 @@ import 'dart:async'; import 'dart:collection'; import 'package:aitrainer_app/bloc/development_diagram/development_diagram_bloc.dart'; import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; -import 'package:aitrainer_app/library/radar_chart.dart'; +import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart'; import 'package:aitrainer_app/widgets/dialog_premium.dart'; -import 'package:flutter/scheduler.dart'; import 'package:aitrainer_app/model/cache.dart'; import 'package:aitrainer_app/util/common.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:aitrainer_app/bloc/body_development/body_development_bloc.dart'; +import 'package:flutter_radar_chart/flutter_radar_chart.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart'; @@ -23,13 +23,12 @@ class MyDevelopmentBodyPage extends StatefulWidget { class _MyDevelopmentBodyPage extends State with Trans, Common { bool isStart = false; - // ignore: close_sinks late BodyDevelopmentBloc bloc; @override void initState() { super.initState(); - if (!Cache().hasPurchased || true) { + if (!Cache().hasPurchased && Cache().userLoggedIn != null) { Timer( Duration(milliseconds: 2000), () => { @@ -49,11 +48,6 @@ class _MyDevelopmentBodyPage extends State with Trans, Co }) }); } - - /// We require the initializers to run after the loading screen is rendered - SchedulerBinding.instance!.addPostFrameCallback((_) { - BlocProvider.of(context).add(BodyDevelopmentLoad()); - }); } @override @@ -195,42 +189,48 @@ class _MyDevelopmentBodyPage extends State with Trans, Co } Widget getLegend(BodyDevelopmentBloc bloc) { - if (bloc.filter == DiagramDateFilterGroup.yearly) { - return Offstage(); - } return Wrap( children: [ Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, children: [ Container( width: 100, height: 6, color: Colors.green, ), - Text("First Month", style: GoogleFonts.inter(fontSize: 14)), + SizedBox( + width: 10, + ), + Text(t(bloc.legends[0]), style: GoogleFonts.inter(fontSize: 14)), ], ), Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, children: [ Container( width: 100, height: 6, color: Colors.blue, ), - Text("First Month", style: GoogleFonts.inter(fontSize: 14)), + SizedBox( + width: 10, + ), + Text(t(bloc.legends[1]), style: GoogleFonts.inter(fontSize: 14)), ], ), Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.start, children: [ Container( width: 100, height: 6, color: Colors.red, ), - Text("First Month", style: GoogleFonts.inter(fontSize: 14)), + SizedBox( + width: 10, + ), + Text(t(bloc.legends[2]), style: GoogleFonts.inter(fontSize: 14)), ], ) ], @@ -250,7 +250,17 @@ class _MyDevelopmentBodyPage extends State with Trans, Co } Widget exerciseWidget(int customerId, BodyDevelopmentBloc bloc) { - return RadarChart.light(ticks: bloc.radarTicks, features: bloc.radarFeatures, data: bloc.radarData); + List radarFeatures = [ + t(MuscleGroup.chest.toText()), + t(MuscleGroup.biceps.toText()), + t(MuscleGroup.triceps.toText()), + t(MuscleGroup.back.toText()), + t(MuscleGroup.shoulders.toText()), + t(MuscleGroup.core.toText()), + t(MuscleGroup.thigh.toText()), + t(MuscleGroup.calf.toText()) + ]; + return RadarChart.light(ticks: bloc.radarTicks, features: radarFeatures, data: bloc.radarData); } Widget explanationWidget() { diff --git a/lib/view/mydevelopment_sizes_page.dart b/lib/view/mydevelopment_sizes_page.dart index 3c693d6..b283e35 100644 --- a/lib/view/mydevelopment_sizes_page.dart +++ b/lib/view/mydevelopment_sizes_page.dart @@ -189,7 +189,7 @@ class _SizeState extends State with Trans { t("Red icon means you have not saved this size."), //overflow: TextOverflow.clip, style: GoogleFonts.inter( - fontSize: 14, + fontSize: 12, color: Colors.white, ), ), @@ -199,7 +199,7 @@ class _SizeState extends State with Trans { t("Tap on the green icon to see your development in a diagram"), //overflow: TextOverflow.clip, style: GoogleFonts.inter( - fontSize: 14, + fontSize: 12, color: Colors.white, ), ), diff --git a/pubspec.lock b/pubspec.lock index 97202c1..1b875e4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -592,6 +592,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.5.0" + flutter_radar_chart: + dependency: "direct main" + description: + name: flutter_radar_chart + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.1" flutter_secure_storage: dependency: "direct main" description: @@ -1106,13 +1113,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1+1" - radar_chart: - dependency: "direct main" - description: - name: radar_chart - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" rainbow_color: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 21004a2..038f3fb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -31,7 +31,7 @@ dependencies: flutter_bloc: ^8.0.1 equatable: ^2.0.3 - radar_chart: ^2.1.0 + flutter_radar_chart: ^0.2.1 rainbow_color: ^2.0.1 percent_indicator: ^4.0.0 fl_chart: ^0.50.0