WT 1.1.26+4 radar chart 1
This commit is contained in:
parent
225172f950
commit
e59e225582
10
i18n/hu.json
10
i18n/hu.json
@ -59,7 +59,7 @@
|
|||||||
"Endurance": "Állóképesség",
|
"Endurance": "Állóképesség",
|
||||||
"Pushups": "Fekvőtámasz",
|
"Pushups": "Fekvőtámasz",
|
||||||
"Timed Pushups": "Fekvőtámasz időre",
|
"Timed Pushups": "Fekvőtámasz időre",
|
||||||
"Core": "Core (plank)",
|
"Core": "Core (törzs-has)",
|
||||||
"Squats": "Guggolás",
|
"Squats": "Guggolás",
|
||||||
"Sit-ups": "Felülés",
|
"Sit-ups": "Felülés",
|
||||||
"1RM": "1RM - Maxerő",
|
"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!",
|
"You have only 1-2 exercise left to finish!": "Már csak 1-2 gyakorlat van a hátra!",
|
||||||
"exercise!": "gyakorlattal!",
|
"exercise!": "gyakorlattal!",
|
||||||
"exercise": "gyakorlat",
|
"exercise": "gyakorlat",
|
||||||
"Chest": "mell",
|
"Chest": "Mell",
|
||||||
"Back": "hát",
|
"Back": "Hát",
|
||||||
"Thigh": "comb",
|
"Thigh": "Comb",
|
||||||
"Calf": "vádli",
|
"Calf": "Vádli",
|
||||||
"Bring me there": "Vigyél oda",
|
"Bring me there": "Vigyél oda",
|
||||||
"My Body Development": "Testem fejlődése",
|
"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",
|
"You see here your whole body development by muscle groups.": "Itt láthatod a tested fejlődését izomcsoportonként",
|
||||||
|
@ -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 'dart:async';
|
||||||
import 'package:aitrainer_app/bloc/development_diagram/development_diagram_bloc.dart';
|
import 'package:aitrainer_app/bloc/development_diagram/development_diagram_bloc.dart';
|
||||||
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
import 'package:aitrainer_app/repository/exercise_repository.dart';
|
||||||
import 'package:aitrainer_app/repository/workout_tree_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:bloc/bloc.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -15,6 +19,10 @@ class BodyDevelopmentBloc extends Bloc<BodyDevelopmentEvent, BodyDevelopmentStat
|
|||||||
final WorkoutTreeRepository workoutTreeRepository;
|
final WorkoutTreeRepository workoutTreeRepository;
|
||||||
final ExerciseRepository exerciseRepository = ExerciseRepository();
|
final ExerciseRepository exerciseRepository = ExerciseRepository();
|
||||||
|
|
||||||
|
List<String> legendsL3t = ['2 trainigs ago', '1 training ago', 'last training'];
|
||||||
|
List<String> legendsFmlm = ['First month', '1 month ago', 'last month'];
|
||||||
|
List<String> legendsL3m = ['2 months ago', '1 month ago', 'last month'];
|
||||||
|
List<String> legends = [];
|
||||||
List<int> radarTicks = [];
|
List<int> radarTicks = [];
|
||||||
List<String> radarFeatures = [];
|
List<String> radarFeatures = [];
|
||||||
List<List<int>> radarData = [];
|
List<List<int>> radarData = [];
|
||||||
@ -23,7 +31,7 @@ class BodyDevelopmentBloc extends Bloc<BodyDevelopmentEvent, BodyDevelopmentStat
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
BodyDevelopmentBloc({required this.workoutTreeRepository}) : super(BodyDevelopmentInitial()) {
|
BodyDevelopmentBloc({required this.workoutTreeRepository}) : super(BodyDevelopmentInitial()) {
|
||||||
on<BodyDevelopmentLoad>(_onLoad);
|
getData();
|
||||||
on<BodyDevelopmentChangeDate>(_onDateFilterChange);
|
on<BodyDevelopmentChangeDate>(_onDateFilterChange);
|
||||||
on<BodyDevelopmentChangeGroup>(_onGroupChange);
|
on<BodyDevelopmentChangeGroup>(_onGroupChange);
|
||||||
}
|
}
|
||||||
@ -35,20 +43,52 @@ class BodyDevelopmentBloc extends Bloc<BodyDevelopmentEvent, BodyDevelopmentStat
|
|||||||
Colors.orange,
|
Colors.orange,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
void getExerciseData() {
|
||||||
|
workoutTreeRepository.sortedTree.clear();
|
||||||
|
workoutTreeRepository.sortByMuscleType();
|
||||||
|
int index = 0;
|
||||||
|
this.workoutTreeRepository.sortedTree.forEach((name, list) {
|
||||||
|
print("name: $name");
|
||||||
|
list.forEach((element) {
|
||||||
|
exerciseRepository.exerciseList = exerciseRepository.getExercisesByExerciseTypeId(element.exerciseTypeId);
|
||||||
|
exerciseRepository.sortByDate();
|
||||||
|
});
|
||||||
|
|
||||||
|
index++;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> getData() async {
|
Future<void> getData() async {
|
||||||
radarTicks = [20, 40, 60, 80, 100];
|
this.getExerciseData();
|
||||||
radarFeatures = ["Mell", "Bicepsz", "Tricepsz", "Hát", "Váll", "Core", "Comb", "Vádli"];
|
radarTicks = [20, 40, 60, 80, 100, 120, 140, 160];
|
||||||
radarData = [
|
radarData = [
|
||||||
[80, 95, 45, 67, 83, 40, 56, 78],
|
[80, 95, 45, 67, 83, 40, 56, 78],
|
||||||
[82, 90, 56, 77, 82, 40, 50, 87],
|
[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<BodyDevelopmentState> emit) {
|
legends = [
|
||||||
emit(BodyDevelopmentLoading());
|
DateFormat(DateFormat.YEAR, AppLanguage().appLocal.toString()).format(date.subtract(Duration(days: 365 * 2))),
|
||||||
getData();
|
DateFormat(DateFormat.YEAR, AppLanguage().appLocal.toString()).format(date.subtract(Duration(days: 365))),
|
||||||
emit(BodyDevelopmentReady());
|
DateFormat(DateFormat.YEAR, AppLanguage().appLocal.toString()).format(date)
|
||||||
|
];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
legends = legendsL3t;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onDateFilterChange(BodyDevelopmentChangeDate event, Emitter<BodyDevelopmentState> emit) {
|
void _onDateFilterChange(BodyDevelopmentChangeDate event, Emitter<BodyDevelopmentState> emit) {
|
||||||
|
@ -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<int> ticks;
|
|
||||||
final List<String> features;
|
|
||||||
final List<List<int>> data;
|
|
||||||
final bool reverseAxis;
|
|
||||||
final TextStyle ticksTextStyle;
|
|
||||||
final TextStyle featuresTextStyle;
|
|
||||||
final Color outlineColor;
|
|
||||||
final Color axisColor;
|
|
||||||
final List<Color> 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<int> ticks,
|
|
||||||
required List<String> features,
|
|
||||||
required List<List<int>> 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<int> ticks,
|
|
||||||
required List<String> features,
|
|
||||||
required List<List<int>> 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<RadarChart> with SingleTickerProviderStateMixin {
|
|
||||||
double fraction = 0;
|
|
||||||
late Animation<double> 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<int> ticks;
|
|
||||||
final List<String> features;
|
|
||||||
final List<List<int>> data;
|
|
||||||
final bool reverseAxis;
|
|
||||||
final TextStyle ticksTextStyle;
|
|
||||||
final TextStyle featuresTextStyle;
|
|
||||||
final Color outlineColor;
|
|
||||||
final Color axisColor;
|
|
||||||
final List<Color> 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -424,9 +424,8 @@ class ExerciseRepository {
|
|||||||
return sumA >= sumB ? 1 : -1;
|
return sumA >= sumB ? 1 : -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
double withCompare = oldExercises.last.unitQuantity != null
|
double withCompare =
|
||||||
? oldExercises.last.quantity! * oldExercises.last.unitQuantity!
|
oldExercises.last.unitQuantity != null ? oldExercises.last.quantity! * oldExercises.last.unitQuantity! : oldExercises.last.quantity!;
|
||||||
: oldExercises.last.quantity!;
|
|
||||||
|
|
||||||
//result = toCompare >= withCompare ? (1 - toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100;
|
//result = toCompare >= withCompare ? (1 - toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100;
|
||||||
//print("Last Best: ${oldExercises.last} - result: $result");
|
//print("Last Best: ${oldExercises.last} - result: $result");
|
||||||
@ -457,9 +456,8 @@ class ExerciseRepository {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (oldExercises.isNotEmpty) {
|
if (oldExercises.isNotEmpty) {
|
||||||
double withCompare = oldExercises.first.unitQuantity != null
|
double withCompare =
|
||||||
? oldExercises.first.quantity! * oldExercises.first.unitQuantity!
|
oldExercises.first.unitQuantity != null ? oldExercises.first.quantity! * oldExercises.first.unitQuantity! : oldExercises.first.quantity!;
|
||||||
: oldExercises.first.quantity!;
|
|
||||||
|
|
||||||
result = toCompare >= withCompare ? (toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100;
|
result = toCompare >= withCompare ? (toCompare / withCompare) * 100 : (1 - toCompare / withCompare) * -100;
|
||||||
print("Last Last: ${oldExercises.first} vs. $exercise - - result: $result");
|
print("Last Last: ${oldExercises.first} vs. $exercise - - result: $result");
|
||||||
@ -522,4 +520,18 @@ class ExerciseRepository {
|
|||||||
prevExercise.summary = summary;
|
prevExercise.summary = summary;
|
||||||
exerciseLogList!.add(prevExercise);
|
exerciseLogList!.add(prevExercise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<Exercise> getExercisesByExerciseTypeId(int exerciseTypeId) {
|
||||||
|
List<Exercise> list = [];
|
||||||
|
List<Exercise>? allExercise = Cache().getExercises();
|
||||||
|
if (allExercise == null) {
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
allExercise.forEach((element) {
|
||||||
|
if (element.exerciseTypeId == exerciseTypeId) {
|
||||||
|
list.add(element);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'package:aitrainer_app/util/string_extension.dart';
|
||||||
|
|
||||||
enum LoginType { email, fb, google, apple }
|
enum LoginType { email, fb, google, apple }
|
||||||
|
|
||||||
extension LoginTypeExt on LoginType {
|
extension LoginTypeExt on LoginType {
|
||||||
@ -112,3 +114,15 @@ extension ExerciseSaveTypeExt on ExerciseSaveType {
|
|||||||
bool equalsTo(ExerciseSaveType type) => this.toString() == type.toString();
|
bool equalsTo(ExerciseSaveType type) => this.toString() == type.toString();
|
||||||
bool equalsStringTo(String type) => this.toStr() == type;
|
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();
|
||||||
|
}
|
||||||
|
5
lib/util/string_extension.dart
Normal file
5
lib/util/string_extension.dart
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
extension StringExtension on String {
|
||||||
|
String capitalize() {
|
||||||
|
return "${this[0].toUpperCase()}${this.substring(1).toLowerCase()}";
|
||||||
|
}
|
||||||
|
}
|
@ -2,17 +2,17 @@ import 'dart:async';
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'package:aitrainer_app/bloc/development_diagram/development_diagram_bloc.dart';
|
import 'package:aitrainer_app/bloc/development_diagram/development_diagram_bloc.dart';
|
||||||
import 'package:aitrainer_app/bloc/menu/menu_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/app_bar.dart';
|
||||||
import 'package:aitrainer_app/widgets/bottom_nav.dart';
|
import 'package:aitrainer_app/widgets/bottom_nav.dart';
|
||||||
import 'package:aitrainer_app/widgets/dialog_premium.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/model/cache.dart';
|
||||||
import 'package:aitrainer_app/util/common.dart';
|
import 'package:aitrainer_app/util/common.dart';
|
||||||
import 'package:aitrainer_app/util/trans.dart';
|
import 'package:aitrainer_app/util/trans.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:aitrainer_app/bloc/body_development/body_development_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:google_fonts/google_fonts.dart';
|
||||||
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
|
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
|
||||||
|
|
||||||
@ -23,13 +23,12 @@ class MyDevelopmentBodyPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Common {
|
class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Common {
|
||||||
bool isStart = false;
|
bool isStart = false;
|
||||||
// ignore: close_sinks
|
|
||||||
late BodyDevelopmentBloc bloc;
|
late BodyDevelopmentBloc bloc;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
if (!Cache().hasPurchased || true) {
|
if (!Cache().hasPurchased && Cache().userLoggedIn != null) {
|
||||||
Timer(
|
Timer(
|
||||||
Duration(milliseconds: 2000),
|
Duration(milliseconds: 2000),
|
||||||
() => {
|
() => {
|
||||||
@ -49,11 +48,6 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We require the initializers to run after the loading screen is rendered
|
|
||||||
SchedulerBinding.instance!.addPostFrameCallback((_) {
|
|
||||||
BlocProvider.of<BodyDevelopmentBloc>(context).add(BodyDevelopmentLoad());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -195,42 +189,48 @@ class _MyDevelopmentBodyPage extends State<MyDevelopmentBodyPage> with Trans, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget getLegend(BodyDevelopmentBloc bloc) {
|
Widget getLegend(BodyDevelopmentBloc bloc) {
|
||||||
if (bloc.filter == DiagramDateFilterGroup.yearly) {
|
|
||||||
return Offstage();
|
|
||||||
}
|
|
||||||
return Wrap(
|
return Wrap(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 6,
|
height: 6,
|
||||||
color: Colors.green,
|
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(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 6,
|
height: 6,
|
||||||
color: Colors.blue,
|
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(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
width: 100,
|
width: 100,
|
||||||
height: 6,
|
height: 6,
|
||||||
color: Colors.red,
|
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<MyDevelopmentBodyPage> with Trans, Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget exerciseWidget(int customerId, BodyDevelopmentBloc bloc) {
|
Widget exerciseWidget(int customerId, BodyDevelopmentBloc bloc) {
|
||||||
return RadarChart.light(ticks: bloc.radarTicks, features: bloc.radarFeatures, data: bloc.radarData);
|
List<String> 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() {
|
Widget explanationWidget() {
|
||||||
|
@ -189,7 +189,7 @@ class _SizeState extends State<SizesDevelopmentPage> with Trans {
|
|||||||
t("Red icon means you have not saved this size."),
|
t("Red icon means you have not saved this size."),
|
||||||
//overflow: TextOverflow.clip,
|
//overflow: TextOverflow.clip,
|
||||||
style: GoogleFonts.inter(
|
style: GoogleFonts.inter(
|
||||||
fontSize: 14,
|
fontSize: 12,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -199,7 +199,7 @@ class _SizeState extends State<SizesDevelopmentPage> with Trans {
|
|||||||
t("Tap on the green icon to see your development in a diagram"),
|
t("Tap on the green icon to see your development in a diagram"),
|
||||||
//overflow: TextOverflow.clip,
|
//overflow: TextOverflow.clip,
|
||||||
style: GoogleFonts.inter(
|
style: GoogleFonts.inter(
|
||||||
fontSize: 14,
|
fontSize: 12,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
14
pubspec.lock
14
pubspec.lock
@ -592,6 +592,13 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.0"
|
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:
|
flutter_secure_storage:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -1106,13 +1113,6 @@ packages:
|
|||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.1+1"
|
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:
|
rainbow_color:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -31,7 +31,7 @@ dependencies:
|
|||||||
flutter_bloc: ^8.0.1
|
flutter_bloc: ^8.0.1
|
||||||
equatable: ^2.0.3
|
equatable: ^2.0.3
|
||||||
|
|
||||||
radar_chart: ^2.1.0
|
flutter_radar_chart: ^0.2.1
|
||||||
rainbow_color: ^2.0.1
|
rainbow_color: ^2.0.1
|
||||||
percent_indicator: ^4.0.0
|
percent_indicator: ^4.0.0
|
||||||
fl_chart: ^0.50.0
|
fl_chart: ^0.50.0
|
||||||
|
Loading…
Reference in New Issue
Block a user