WT 1.1.20(4) Training plan improvements

This commit is contained in:
bossanyit
2021-07-05 22:10:32 +02:00
parent 211307e63e
commit 48a0c3f7de
52 changed files with 2086 additions and 1229 deletions
+4 -4
View File
@@ -288,9 +288,9 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
},
showSelectedItem: true,
selectedItem: selected,
itemAsString: (data) => t(data.sportNameTranslation),
itemAsString: (data) => t(data!.sportNameTranslation),
onChanged: (data) {
bloc.add(CustomerSportChange(sport: data));
bloc.add(CustomerSportChange(sport: data!));
},
dropdownBuilder: _customDropDownItem,
popupItemBuilder: _customMenuBuilder,
@@ -305,7 +305,7 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
//items: FitnessItem().toList()));
}
Widget _customMenuBuilder(BuildContext context, Sport sport, bool isSelected) {
Widget _customMenuBuilder(BuildContext context, Sport? sport, bool isSelected) {
return Container(
decoration: !isSelected
? BoxDecoration(color: Colors.grey[300])
@@ -317,7 +317,7 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
child: ListTile(
selected: isSelected,
title: Text(
t(sport.sportNameTranslation),
t(sport!.sportNameTranslation),
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.blue[600]),
),
subtitle: Text(
+7 -90
View File
@@ -281,86 +281,16 @@ class CustomerModifyPage extends StatelessWidget with Trans {
Divider(
color: Colors.transparent,
),
SfLinearGauge(
minimum: 40,
maximum: 150,
labelPosition: LinearLabelPosition.outside,
tickPosition: LinearElementPosition.outside,
markerPointers: [
LinearWidgetPointer(
value: customerBloc.weight,
offset: 5,
position: LinearElementPosition.outside,
markerAlignment: LinearMarkerAlignment.center,
child: Container(
height: 14,
width: 44,
color: Colors.transparent,
child: Text(customerBloc.weight.toStringAsFixed(1),
style: GoogleFonts.inter(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.indigo,
)),
),
),
LinearShapePointer(
position: LinearElementPosition.inside,
shapeType: LinearShapePointerType.triangle,
value: customerBloc.weight,
height: 55,
width: 25,
color: Colors.blue,
onValueChanged: (value) => {
customerBloc.add(CustomerWeightChange(weight: value)),
},
),
],
orientation: LinearGaugeOrientation.horizontal,
majorTickStyle: LinearTickStyle(length: 20),
axisLabelStyle: TextStyle(fontSize: 12.0, color: Colors.black),
axisTrackStyle: LinearAxisTrackStyle(
color: Colors.cyan, edgeStyle: LinearEdgeStyle.bothFlat, thickness: 1.0, borderColor: Colors.grey)),
NumberPickerWidget(
minValue: 40,
maxValue: 150,
initalValue: customerBloc.weight.toInt(),
unit: t("kg"),
color: Colors.blue[800]!,
onChange: (value) => customerBloc.add(CustomerWeightChange(weight: value))),
Divider(
color: Colors.transparent,
),
/* SfRadialGauge(
axes: <RadialAxis>[
RadialAxis(
axisLineStyle: AxisLineStyle(
thickness: 0.1,
thicknessUnit: GaugeSizeUnit.factor,
gradient: const SweepGradient(colors: <Color>[Color(0xffb4f500), Colors.blue], stops: <double>[0.1, 0.9]),
),
minimum: 40,
maximum: 160,
pointers: [
WidgetPointer(
value: customerBloc.weight.toDouble(),
child: Container(
height: 55,
width: 60,
color: Colors.transparent,
child: Text(customerBloc.weight.toStringAsFixed(1),
style: GoogleFonts.inter(
fontSize: 14,
color: Colors.indigo,
)),
)),
NeedlePointer(
needleColor: Colors.blue[200],
knobStyle: KnobStyle(color: Colors.blue[800]),
value: customerBloc.weight.toDouble(),
enableAnimation: true,
//enableDragging: true,
needleStartWidth: 1,
needleEndWidth: 12,
//onValueChanged: (value) => {customerBloc.add(CustomerWeightChange(weight: value))},
)
],
)
],
), */
]),
),
Divider(
@@ -455,19 +385,6 @@ class CustomerModifyPage extends StatelessWidget with Trans {
},
),
Divider(),
/* TextButton(
onPressed: () => {customerBloc.add(CustomerSave())},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Text(
fulldata ? t("Save") : t("Next"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
),
), */
],
),
),
+298 -269
View File
@@ -1,7 +1,6 @@
import 'dart:collection';
import 'dart:ui';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/widgets/tutorial_widget.dart';
import 'package:intl/intl.dart';
import 'package:aitrainer_app/bloc/result/result_bloc.dart';
@@ -23,6 +22,7 @@ import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
// ignore: must_be_immutable
class EvaluationPage extends StatelessWidget with Trans {
bool noRegistration = false;
@override
Widget build(BuildContext context) {
dynamic arguments = ModalRoute.of(context)!.settings.arguments;
@@ -33,9 +33,14 @@ class EvaluationPage extends StatelessWidget with Trans {
exerciseRepository = ExerciseRepository();
}
final TutorialBloc bloc = BlocProvider.of<TutorialBloc>(context);
noRegistration = bloc.actualCheck == "directTest";
ResultType resultType = ResultType.none;
String imageUrl = "";
if (Cache().userLoggedIn!.sex == "m") {
if (Cache().userLoggedIn == null) {
imageUrl = 'asset/image/WT_Results_for_men.jpg';
} else if (Cache().userLoggedIn!.sex == "m") {
resultType = ResultType.man;
imageUrl = 'asset/image/WT_Results_for_men.jpg';
} else {
@@ -59,7 +64,7 @@ class EvaluationPage extends StatelessWidget with Trans {
}
final TutorialBloc tutorialBloc = BlocProvider.of<TutorialBloc>(context);
print("Evaluation page tutorial isActive? ${tutorialBloc.isActive}");
print("Evaluation page tutorial isActive? ${tutorialBloc.isActive} ${exerciseRepository.exercise!.quantity}");
if (tutorialBloc.isActive == false) {
TutorialWidget().close();
}
@@ -107,6 +112,26 @@ class EvaluationPage extends StatelessWidget with Trans {
String exerciseName = AppLanguage().appLocal == Locale("en")
? resultBloc.exerciseRepository.exerciseType!.name
: resultBloc.exerciseRepository.exerciseType!.nameTranslation;
String? volume, volumeEver, oneRepMax, oneRepMaxEver;
if (resultBloc.exerciseRepository.actualExerciseList![0].unitQuantity != null) {
oneRepMax = resultBloc.exerciseRepository.calculate1RM(resultBloc.exerciseRepository.actualExerciseList![0]).toStringAsFixed(1) +
" " +
t("kg");
volume = (resultBloc.exerciseRepository.actualExerciseList![0].quantity! *
resultBloc.exerciseRepository.actualExerciseList![0].unitQuantity!)
.toStringAsFixed(0) +
" " +
t("kg");
volumeEver = resultBloc.exerciseRepository.getBestVolume(resultBloc.exerciseRepository.actualExerciseList![0]).toStringAsFixed(0) +
" " +
t("kg");
oneRepMaxEver =
resultBloc.exerciseRepository.getBest1RM(resultBloc.exerciseRepository.actualExerciseList![0]).toStringAsFixed(1) + " " + t("kg");
}
return Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [
@@ -123,8 +148,8 @@ class EvaluationPage extends StatelessWidget with Trans {
maxLines: 3,
//softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[300],
fontSize: 28,
color: Colors.orange[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
@@ -140,61 +165,268 @@ class EvaluationPage extends StatelessWidget with Trans {
)),
),
),
//getResultSummary(resultBloc),
SliverList(
delegate: SliverChildListDelegate([
Text(DateFormat('y-M-d HH:mm', AppLanguage().appLocal.toString()).format(resultBloc.exerciseRepository.start!),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
Divider(color: Colors.transparent),
Divider(color: Colors.transparent),
Text(t("Summary of your test"),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.yellow[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
]),
),
getResultSummary(resultBloc),
delegate: SliverChildListDelegate([
getEvaluationWidget(resultBloc),
getSummary(resultBloc),
Divider(),
summaryRow("asset/image/pict_time_h.png", "Start of the Exercise",
DateFormat('y-M-d HH:mm', AppLanguage().appLocal.toString()).format(resultBloc.exerciseRepository.start!)),
Divider(),
oneRepMax != null ? summaryRow("asset/image/pict_1rm.png", "Your One Rep Max", oneRepMax) : Offstage(),
Divider(),
resultBloc.exerciseRepository.actualExerciseList![0].unitQuantity != null
? summaryRow("asset/image/pict_weight_volumen_tonna.png", "Total Lift", volume!)
: Offstage(),
Divider(),
resultBloc.exerciseRepository.actualExerciseList![0].unitQuantity != null
? summaryRow("asset/image/pict_history.png", "Total Lift Ever", volumeEver!)
: Offstage(),
Divider(),
resultBloc.exerciseRepository.actualExerciseList![0].unitQuantity != null
? summaryRow("asset/image/pict_1rm.png", "Your One Rep Max Ever", oneRepMaxEver!)
: Offstage(),
])),
cta(resultBloc),
getSuggestionTitle(resultBloc),
getSuggestion(resultBloc),
emptySliver(),
//emptySliver(),
//getResultTitle(resultBloc),
//getResults(resultBloc),
]));
}
Widget getEvaluationWidget(ResultBloc bloc) {
List<Widget> resultList = [];
print("Act ${bloc.exerciseRepository.actualExerciseList}");
if (bloc.exerciseRepository.actualExerciseList == null || bloc.exerciseRepository.actualExerciseList!.isEmpty) {
return Offstage();
}
final int exerciseTypeId = bloc.exerciseRepository.actualExerciseList![0].exerciseTypeId!;
final double quantity = bloc.exerciseRepository.actualExerciseList![0].quantity!;
String eval = bloc.evaluationRepository.getEvaluationTextByExerciseType(exerciseTypeId, quantity);
Color color = bloc.evaluationRepository.getEvaluationColor(eval);
//if (!EvaluationText.fair.equalsStringTo(eval)) {
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(text: t("Your result is") + ": "),
TextSpan(
text: t(eval),
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
color: color,
),
),
]),
));
resultList.add(Divider(color: Colors.transparent));
//}
return Column(children: resultList);
}
Widget cta(ResultBloc resultBloc) {
return SliverList(
delegate: SliverChildListDelegate(
ctaSales(resultBloc),
),
);
}
List<Widget> ctaSales(ResultBloc resultBloc) {
final List<Widget> resultList = [];
if (this.noRegistration) {
resultList.add(Divider());
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('Reach all basic functions, suggestions and'),
style: GoogleFonts.inter(
color: Colors.white,
),
),
TextSpan(text: " "),
TextSpan(
text: t('optimized training plans, customized to your fitness state and strength:'),
style: GoogleFonts.inter(
color: Colors.white,
),
),
])));
resultList.add(
TextButton(
onPressed: () => Navigator.of(context).pushNamed("registration"),
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Text(
t("Register"),
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
),
);
} else {
if (!Cache().hasPurchased) {
resultList.add(Divider());
resultList.add(Divider());
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('How can serve you this result?'),
style: GoogleFonts.inter(
color: Colors.white,
),
),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('Get the Fastlane to your'),
style: GoogleFonts.inter(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('Development'),
style: GoogleFonts.inter(
fontWeight: FontWeight.bold,
color: Colors.yellow[300],
),
)
])));
resultList.add(TextButton(
onPressed: () => {Navigator.of(context).pushNamed("salesPage")},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Text(
t("Go"),
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
));
}
}
return resultList;
}
Widget summaryRow(String imageUrl, String title, String data) {
return Row(
children: [
Image.asset(
imageUrl,
height: 40,
),
SizedBox(
width: 10,
),
Flexible(
fit: FlexFit.tight,
flex: 1,
child: Text(t(title),
textAlign: TextAlign.start,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 18,
color: Colors.orange[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))),
SizedBox(
width: 10,
),
Text(data,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))
],
);
}
Widget getSuggestionTitle(ResultBloc resultBloc) {
if (resultBloc.exerciseRepository.exerciseType!.unitQuantityUnit != null) {
return SliverList(
@@ -294,6 +526,14 @@ class EvaluationPage extends StatelessWidget with Trans {
String unitQuantityUnit = resultBloc.exerciseRepository.exerciseType!.unitQuantityUnit == null
? ""
: resultBloc.exerciseRepository.exerciseType!.unitQuantityUnit!;
String weight = resultBloc.calculate1RM(percent: percent).toStringAsFixed(0);
if (this.noRegistration) {
repeats = "____";
weight = "_____";
restTime = "__";
}
return Column(
children: [
Text(t(title),
@@ -353,7 +593,7 @@ class EvaluationPage extends StatelessWidget with Trans {
),
Row(
children: [
Text(t("Weight") + ": " + resultBloc.calculate1RM(percent: percent).toStringAsFixed(0) + " " + unitQuantityUnit,
Text(t("Weight") + ": " + weight + " " + unitQuantityUnit,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
@@ -454,225 +694,14 @@ class EvaluationPage extends StatelessWidget with Trans {
return Column(children: resultList);
}
Widget getEvaluationWidget(ResultBloc bloc) {
List<Widget> resultList = [];
print("Act ${bloc.exerciseRepository.actualExerciseList}");
if (bloc.exerciseRepository.actualExerciseList == null || bloc.exerciseRepository.actualExerciseList!.isEmpty) {
return Offstage();
}
final int exerciseTypeId = bloc.exerciseRepository.actualExerciseList![0].exerciseTypeId!;
final double quantity = bloc.exerciseRepository.actualExerciseList![0].quantity!;
String eval = bloc.evaluationRepository.getEvaluationTextByExerciseType(exerciseTypeId, quantity);
Color color = bloc.evaluationRepository.getEvaluationColor(eval);
double compareBest = bloc.exerciseRepository.getBestExercisePercent(bloc.exerciseRepository.actualExerciseList![0]);
double compareLast = bloc.exerciseRepository.getLastExercisePercent(bloc.exerciseRepository.actualExerciseList![0]);
bool has1RM = bloc.exerciseRepository.actualExerciseList![0].unitQuantity != null;
double? bestCompared1RM;
double? lastCompared1RM;
if (has1RM) {
lastCompared1RM = bloc.exerciseRepository.getLast1RMPercent(bloc.exerciseRepository.actualExerciseList![0]);
bestCompared1RM = bloc.exerciseRepository.getBest1RMPercent(bloc.exerciseRepository.actualExerciseList![0]);
}
if (!EvaluationText.fair.equalsStringTo(eval)) {
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 30,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(text: t("Your result is: ")),
TextSpan(
text: eval,
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
color: color,
),
),
]),
));
resultList.add(Divider(color: Colors.transparent));
}
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
color: Colors.white,
),
children: [
TextSpan(text: t("Compared with...")),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
color: Colors.white,
),
children: [
TextSpan(text: t("your best")),
TextSpan(text: " "),
TextSpan(text: has1RM ? t("volumen") : t("exercise")),
TextSpan(text: ": "),
TextSpan(
text: compareBest.toStringAsFixed(1) + "%",
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
color: compareBest >= 0 ? Colors.green : Colors.red[600],
),
),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
color: Colors.white,
),
children: [
TextSpan(text: t("your last")),
TextSpan(text: " "),
TextSpan(text: has1RM ? t("volumen") : t("exercise")),
TextSpan(text: ": "),
TextSpan(
text: compareLast.toStringAsFixed(1) + "%",
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
color: compareLast >= 0 ? Colors.green : Colors.red[600],
),
),
]),
));
resultList.add(Divider(color: Colors.transparent));
if (has1RM) {
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
color: Colors.white,
),
children: [
TextSpan(text: t("best")),
TextSpan(text: " "),
TextSpan(text: t("1RM")),
TextSpan(text: ": "),
TextSpan(
text: bestCompared1RM!.toStringAsFixed(1) + "%",
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
color: bestCompared1RM >= 0 ? Colors.green : Colors.red[600],
),
),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
color: Colors.white,
),
children: [
TextSpan(text: t("last")),
TextSpan(text: " "),
TextSpan(text: t("1RM")),
TextSpan(text: ": "),
TextSpan(
text: lastCompared1RM!.toStringAsFixed(1) + "%",
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
color: lastCompared1RM >= 0 ? Colors.green : Colors.red[600],
),
),
]),
));
}
if (!Cache().hasPurchased) {
resultList.add(Divider());
resultList.add(Divider());
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('How can serve you this result?'),
style: GoogleFonts.inter(
color: Colors.white,
),
),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('Get the Fastlane to your'),
style: GoogleFonts.inter(
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
]),
));
resultList.add(RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.normal,
color: Colors.white,
),
children: [
TextSpan(
text: t('Development'),
style: GoogleFonts.inter(
fontWeight: FontWeight.bold,
color: Colors.yellow[300],
),
)
])));
resultList.add(TextButton(
onPressed: () => {Navigator.of(context).pushNamed("salesPage")},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 60),
Text(
t("Go"),
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
],
),
));
}
return Column(children: resultList);
}
Widget getResultSummary(ResultBloc resultBloc) {
return SliverList(
delegate: SliverChildListDelegate(
[Divider(color: Colors.transparent), getSummary(resultBloc), Divider(color: Colors.transparent), getEvaluationWidget(resultBloc)],
[
Divider(color: Colors.transparent),
getSummary(resultBloc),
Divider(color: Colors.transparent),
],
),
);
}
+2 -2
View File
@@ -436,8 +436,8 @@ class _UnitQuantityControlState extends State<UnitQuantityControl> with Trans {
height: 20,
),
NumberPickerWidget(
minValue: (widget.exerciseBloc.unitQuantity - 10).round(),
maxValue: (widget.exerciseBloc.unitQuantity + 10).round(),
minValue: (widget.exerciseBloc.unitQuantity - 30).round(),
maxValue: (widget.exerciseBloc.unitQuantity + 30).round(),
initalValue: widget.exerciseBloc.unitQuantity.round(),
unit: t("kg"),
color: Colors.yellow[50]!,
+25 -27
View File
@@ -15,7 +15,6 @@ import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/bmi_widget.dart';
import 'package:aitrainer_app/widgets/bmr_widget.dart';
import 'package:aitrainer_app/widgets/bottom_bar_multiple_exercises.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/exercise_save.dart';
import 'package:aitrainer_app/widgets/size_widget.dart';
@@ -72,14 +71,21 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
// ignore: close_sinks
final bloc = BlocProvider.of<ExerciseNewBloc>(context);
if (bloc.exerciseRepository.exerciseType!.unitQuantityUnit == null) {
// ignore: close_sinks
final TutorialBloc tutorialBloc = BlocProvider.of<TutorialBloc>(context);
if (tutorialBloc.actualCheck == "directTest") {
args['exerciseRepository'] = bloc.exerciseRepository;
Navigator.of(context).pushNamed('evaluationPage', arguments: args);
} else if (menuBloc.ability!.equalsTo(ExerciseAbility.oneRepMax)) {
args['exerciseRepository'] = bloc.exerciseRepository;
args['percent'] = 0.75;
args['readonly'] = false;
Navigator.of(context).pushNamed('exerciseControlPage', arguments: args);
} else {
if (bloc.exerciseRepository.exerciseType!.unitQuantityUnit == null) {
args['exerciseRepository'] = bloc.exerciseRepository;
Navigator.of(context).pushNamed('evaluationPage', arguments: args);
} else if (menuBloc.ability!.equalsTo(ExerciseAbility.oneRepMax)) {
args['exerciseRepository'] = bloc.exerciseRepository;
args['percent'] = 0.75;
args['readonly'] = false;
Navigator.of(context).pushNamed('exerciseControlPage', arguments: args);
}
}
}
}
@@ -99,25 +105,13 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
Widget getExerciseSaveWidget(ExerciseNewBloc exerciseBloc, ExerciseType exerciseType, MenuBloc menuBloc) {
if (exerciseBloc.exerciseRepository.exerciseType!.name == "BMR") {
if (Cache().userLoggedIn == null) {
exerciseBloc.add(ExerciseNewAddError(message: "Please log in"));
} else {
return BMR(exerciseBloc: exerciseBloc);
}
return BMR(exerciseBloc: exerciseBloc);
}
if (exerciseBloc.exerciseRepository.exerciseType!.name == "BMI") {
if (Cache().userLoggedIn == null) {
exerciseBloc.add(ExerciseNewAddError(message: "Please log in"));
} else {
return BMI(exerciseBloc: exerciseBloc);
}
return BMI(exerciseBloc: exerciseBloc);
}
if (exerciseBloc.exerciseRepository.exerciseType!.name == "Sizes") {
if (Cache().userLoggedIn == null) {
exerciseBloc.add(ExerciseNewAddError(message: "Please log in"));
} else {
return SizeWidget(exerciseBloc: exerciseBloc);
}
return SizeWidget(exerciseBloc: exerciseBloc);
}
return Scaffold(
@@ -159,10 +153,10 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 12),
),
),
bottomNavigationBar: BottomBarMultipleExercises(
/* bottomNavigationBar: BottomBarMultipleExercises(
isSet: false,
exerciseTypeId: exerciseType.exerciseTypeId,
),
), */
);
}
@@ -192,11 +186,11 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
if (executeBloc != null && executeBloc.existsActivePlan() == true) {
confirmationOverride(bloc);
} else {
confirmationSave(bloc, menuBloc);
confirmationSave(bloc, menuBloc, tutorialBloc);
}
}
void confirmationSave(ExerciseNewBloc bloc, MenuBloc menuBloc) {
void confirmationSave(ExerciseNewBloc bloc, MenuBloc menuBloc, TutorialBloc tutorialBloc) {
if (bloc.exerciseRepository.exercise!.quantity == null) {
return;
}
@@ -251,7 +245,11 @@ class _ExerciseNewPageState extends State<ExerciseNewPage> with Trans, Logging {
onPressed: () {
if (Cache().userLoggedIn == null) {
Navigator.pop(context);
bloc.add(ExerciseNewAddError(message: "Please log in, because we can calculate the best suggestions for you"));
if (tutorialBloc.actualCheck == "directTest") {
bloc.add(ExerciseNewSubmitNoRegistration());
} else {
bloc.add(ExerciseNewAddError(message: "Please log in, because we can calculate the best suggestions for you"));
}
} else {
saveAll(bloc);
if (executeBloc.existsActivePlan() == true) {
+2 -2
View File
@@ -6,7 +6,7 @@ import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_long.dart';
import 'package:aitrainer_app/widgets/dialog_web_browser.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -233,7 +233,7 @@ class LoginPage extends StatelessWidget with Trans {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogGDPR();
return DialogWebBrowser(url: 'https://workouttest.com/privacy/', javascriptEnabled: true);
})
}),
]),
+2 -2
View File
@@ -285,7 +285,6 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
getTextStyles: (_) => TextStyle(fontSize: 8, color: Colors.blueGrey),
getTitles: (double value) {
var date = new DateTime.fromMillisecondsSinceEpoch(value.toInt());
//String strDate = DateFormat('MM.dd.', AppLanguage().appLocal.toString()).format(date);
String strDate = getDatePart(date, bloc.dateRate);
return strDate;
},
@@ -293,7 +292,8 @@ class _MyDevelopmentMuscleState extends State<MyDevelopmentMusclePage> with Comm
leftTitles: SideTitles(
showTitles: true,
getTextStyles: (_) => TextStyle(fontSize: 8, color: Colors.blueGrey),
interval: bloc.listChartData[element.exerciseTypeId] == null
interval: bloc.listChartData[element.exerciseTypeId] == null ||
bloc.listChartData[element.exerciseTypeId]!.interval == 0
? 100
: bloc.listChartData[element.exerciseTypeId]!.interval,
margin: 10,
+28 -33
View File
@@ -6,7 +6,7 @@ import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_long.dart';
import 'package:aitrainer_app/widgets/dialog_web_browser.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -102,9 +102,9 @@ class RegistrationPage extends StatelessWidget with Trans {
GestureDetector(
onTap: () => loginBloc.add(LoginSkip()),
child: Text(
t("Skip"),
t("I Execute My First Test Now"),
textAlign: TextAlign.right,
style: GoogleFonts.inter(color: loginBloc.testColor, decoration: TextDecoration.underline),
style: GoogleFonts.inter(color: loginBloc.testColor, decoration: TextDecoration.underline, fontWeight: FontWeight.bold),
)),
SizedBox(
height: 120,
@@ -207,6 +207,16 @@ class RegistrationPage extends StatelessWidget with Trans {
Divider(
color: Colors.transparent,
),
ListTile(
leading: Icon(
Icons.check,
color: Colors.green,
),
title: Text(
t("With the registration I accept the data policy and the terms of use."),
style: GoogleFonts.inter(color: Colors.indigo),
),
),
Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
TextButton(
key: LibraryKeys.loginOKButton,
@@ -236,7 +246,20 @@ class RegistrationPage extends StatelessWidget with Trans {
),
onTap: () => Navigator.of(context).pushNamed('login'),
),
Spacer(flex: 2),
Spacer(flex: 1),
InkWell(
child: Text(
t('Terms Of Use'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
),
onTap: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogWebBrowser(url: 'https://workouttest.com/terms-of-use/', javascriptEnabled: true);
})
}),
Spacer(flex: 1),
InkWell(
child: Text(
t('Privacy'),
@@ -246,39 +269,11 @@ class RegistrationPage extends StatelessWidget with Trans {
showDialog(
context: context,
builder: (BuildContext context) {
return DialogGDPR();
return DialogWebBrowser(url: 'https://workouttest.com/privacy/', javascriptEnabled: true);
})
}),
]),
])),
);
}
Widget getDataProtection(LoginBloc loginBloc) {
return CheckboxListTile(
title: Text(t("Please accept our data protection policy.")),
subtitle: Text(t("For more information please click on 'Privacy'")),
dense: true,
value: loginBloc.dataPolicyAllowed,
activeColor: Colors.indigo,
onChanged: (value) {
loginBloc.add(DataProtectionClicked(marked: value!));
},
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
}
Widget getEmailSubscription(LoginBloc loginBloc) {
return CheckboxListTile(
title: Text(t("Email notifications")),
subtitle: Text(t("We may ask you about your opinion, send events in email")),
dense: true,
value: loginBloc.emailSubscription,
activeColor: Colors.indigo,
onChanged: (value) {
loginBloc.add(EmailSubscriptionClicked(marked: value!));
},
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
}
}
+23 -11
View File
@@ -232,7 +232,7 @@ class SalesPage extends StatelessWidget with Trans, Logging {
}).toList(),
),
getTrialDescription(),
getTrialDescription(bloc),
Html(
data: bloc.premiumFunctions,
//Optional parameters:
@@ -297,22 +297,15 @@ class SalesPage extends StatelessWidget with Trans, Logging {
style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
)),
Divider(),
Container(
padding: EdgeInsets.only(left: 55, right: 55),
child: Text(
t("Account will be charged for renewal within 24 hours prior to the end of the current period"),
style: GoogleFonts.inter(fontSize: 12, color: Colors.white),
)),
])),
]));
}
Widget getTrialDescription() {
final trialText = t("Try free for 3 days!");
Widget getTrialDescription(SalesBloc bloc) {
return Container(
padding: EdgeInsets.only(left: 55, right: 55),
child: Html(
data: "<p>" + trialText + "</p>",
data: bloc.trial,
//Optional parameters:
style: {
"p": Style(
@@ -329,9 +322,28 @@ class SalesPage extends StatelessWidget with Trans, Logging {
],
),
"strong": Style(
color: Colors.yellow[600],
color: Colors.orange[600],
fontSize: FontSize(13),
),
"h2": Style(
color: Colors.orange[600],
fontWeight: FontWeight.bold,
fontSize: FontSize(18),
textAlign: TextAlign.center,
textShadow: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
//padding: const EdgeInsets.all(4),
),
},
));
}
+12 -15
View File
@@ -10,6 +10,7 @@ import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/dialog_web_browser.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@@ -157,7 +158,7 @@ class SettingsPage extends StatelessWidget with Trans {
inactiveFgColor: Colors.grey[900],
labels: [t('Basic Tutorial'), t('Activate')],
onToggle: (index) {
ActivityDone activity = ActivityDone.tutorialBasic;
ActivityDone activity = ActivityDone.tutorialExecuteFirstTest;
if (Cache().userLoggedIn != null) {
if (Cache().userLoggedIn!.sex == "m") {
activity = ActivityDone.tutorialBasicChestPress;
@@ -190,7 +191,11 @@ class SettingsPage extends StatelessWidget with Trans {
),
onPressed: () => {
Track().track(TrackingEvent.terms_of_use),
_launchInBrowser("https://workouttest.com/terms-of-use/"),
showDialog(
context: context,
builder: (BuildContext context) {
return DialogWebBrowser(url: 'https://workouttest.com/terms-of-use/', javascriptEnabled: true);
})
},
),
);
@@ -213,7 +218,11 @@ class SettingsPage extends StatelessWidget with Trans {
),
onPressed: () => {
Track().track(TrackingEvent.data_privacy),
_launchInBrowser("https://workouttest.com/privacy/"),
showDialog(
context: context,
builder: (BuildContext context) {
return DialogWebBrowser(url: 'https://workouttest.com/privacy/', javascriptEnabled: true);
})
},
),
);
@@ -242,18 +251,6 @@ class SettingsPage extends StatelessWidget with Trans {
);
}
Future<void> _launchInBrowser(String url) async {
if (await canLaunch(url)) {
await launch(
url,
forceSafariVC: false,
forceWebView: false,
);
} else {
throw 'Could not launch $url';
}
}
ListTile getVersion() {
final String version = Cache().packageInfo != null ? Cache().packageInfo!.version + "+" + Cache().packageInfo!.buildNumber : "";
return ListTile(
+442
View File
@@ -0,0 +1,442 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/training_evaluation/training_evaluation_bloc.dart';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/model/training_evaluation_exercise.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/victory_widget.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:modal_progress_hud_nsn/modal_progress_hud_nsn.dart';
import 'package:timeline_tile/timeline_tile.dart';
// ignore: must_be_immutable
class TrainingEvaluationPage extends StatelessWidget with Trans {
TrainingEvaluationPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
setContext(context);
String imageUrl = "";
if (Cache().userLoggedIn == null) {
imageUrl = 'asset/image/WT_Results_for_men.jpg';
} else if (Cache().userLoggedIn!.sex == "m") {
imageUrl = 'asset/image/WT_Results_for_men.jpg';
} else {
imageUrl = 'asset/image/WT_Results_for_female.jpg';
}
final HashMap args = ModalRoute.of(context)!.settings.arguments as HashMap;
final TrainingPlanBloc trainingPlanBloc = args["bloc"];
final dayName = args["day"];
return Scaffold(
appBar: AppBarMin(
back: true,
),
body: Container(
height: double.infinity,
width: double.infinity,
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(imageUrl),
fit: BoxFit.cover,
alignment: Alignment.topCenter,
),
),
child: BlocProvider(
create: (context) =>
TrainingEvaluationBloc(trainingPlanBloc: trainingPlanBloc, day: dayName)..add(TrainingEvaluationLoad()),
child: BlocConsumer<TrainingEvaluationBloc, TrainingEvaluationState>(listener: (context, state) {
if (state is TrainingEvaluationError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is TrainingEvaluationVictoryReady) {
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return Victory(
victory: true,
);
});
}
}, builder: (context, state) {
final bloc = BlocProvider.of<TrainingEvaluationBloc>(context);
return ModalProgressHUD(
child: getEvaluationWidgets(bloc, dayName),
inAsyncCall: state is TrainingEvaluationLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}))),
bottomNavigationBar: BottomNavigator(bottomNavIndex: 0));
}
Widget getEvaluationWidgets(TrainingEvaluationBloc bloc, String dayName) {
return Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: CustomScrollView(scrollDirection: Axis.vertical, slivers: [
SliverAppBar(
pinned: true,
backgroundColor: Colors.transparent,
expandedHeight: 100.0,
collapsedHeight: 100,
toolbarHeight: 40,
automaticallyImplyLeading: false,
flexibleSpace: FlexibleSpaceBar(
title: Column(children: [
Divider(),
Text(bloc.trainingPlanBloc.getMyPlan()!.name!,
textAlign: TextAlign.center,
maxLines: 4,
style: GoogleFonts.archivoBlack(
fontSize: 24,
color: Colors.orange[300],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
Text(t("Training Summary"),
textAlign: TextAlign.center,
maxLines: 3,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
]),
),
),
//getResultSummary(resultBloc),
SliverList(
delegate: SliverChildListDelegate([
summaryRow("asset/image/pict_time_h.png", "Duration", bloc.duration + " " + t("mins")),
Divider(color: Colors.transparent),
summaryRow("asset/image/pict_weight_volumen_tonna.png", "Total Lift", bloc.totalLift + " " + t("kg")),
Divider(color: Colors.transparent),
summaryRow("asset/image/pict_hypertrophy.png", "Maximum Repeats", "${bloc.maxRepeats}" + " " + t("reps")),
Divider(color: Colors.transparent),
//summaryRow("asset/image/pict_reps_volumen_db.png", "Total Lift Ever", "100 kg"),
//Divider(color: Colors.transparent),
Text(t("Details"),
textAlign: TextAlign.center,
maxLines: 3,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
])),
SliverList(
delegate: SliverChildListDelegate(
getExerciseLists(bloc, dayName),
))
]));
}
Widget summaryRow(String imageUrl, String title, String data) {
return Row(
children: [
Image.asset(
imageUrl,
height: 40,
),
SizedBox(
width: 10,
),
Flexible(
fit: FlexFit.tight,
flex: 1,
child: Text(t(title),
textAlign: TextAlign.start,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 18,
color: Colors.orange[400],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))),
SizedBox(
width: 10,
),
Text(t(data),
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
))
],
);
}
List<Widget> getExerciseLists(TrainingEvaluationBloc bloc, String dayName) {
List<Widget> list = [];
bloc.evaluationList.forEach((element) {
list.add(ExerciseTile(bloc: bloc, exercise: element));
});
return list;
}
}
// ignore: must_be_immutable
class ExerciseTile extends StatelessWidget with Trans {
final TrainingEvaluationBloc bloc;
final TrainingEvaluationExercise exercise;
ExerciseTile({required this.bloc, required this.exercise});
Widget getIndicator(ExercisePlanDetailState state) {
if (state.equalsTo(ExercisePlanDetailState.inProgress)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.green,
child: Icon(
CustomIcon.calendar_2,
size: 28,
color: Colors.white,
)));
} else if (state.equalsTo(ExercisePlanDetailState.finished)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.ok_circled,
size: 40,
color: Colors.green,
)));
} else if (state.equalsTo(ExercisePlanDetailState.skipped)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.stop_1,
size: 40,
color: Colors.grey,
)));
} else if (state.equalsTo(ExercisePlanDetailState.extra)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.stopwatch_20,
size: 40,
color: Colors.blue[800],
)));
} else {
return Image.asset(
"asset/image/pict_reps_volumen_db.png",
);
}
}
Widget build(BuildContext context) {
setContext(context);
bool hasWeight = exercise.type.equalsTo(TrainingEvaluationExerciseType.weightBased);
bool skipped = exercise.state.equalsTo(ExercisePlanDetailState.skipped);
return Container(
color: Colors.transparent,
child: TimelineTile(
alignment: TimelineAlign.manual,
lineXY: 0.1,
beforeLineStyle: const LineStyle(
color: Color(0xffb4f500),
thickness: 6,
),
afterLineStyle: const LineStyle(
color: Color(0xffb4f500),
thickness: 6,
),
indicatorStyle: IndicatorStyle(
width: 40,
height: 40,
indicator: getIndicator(exercise.state),
),
endChild: Container(
padding: EdgeInsets.only(left: 10),
child: Row(children: [
Container(
width: 120,
height: 80,
child: MenuImage(
imageName: bloc.trainingPlanBloc.getActualImageName(exercise.exerciseTypeId),
workoutTreeId: bloc.trainingPlanBloc.getActualWorkoutTreeId(exercise.exerciseTypeId)!,
radius: 12,
),
),
SizedBox(
width: 10,
),
Expanded(
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: exercise.name,
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.orange[500],
shadows: <Shadow>[
Shadow(
offset: Offset(5.0, 5.0),
blurRadius: 12.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
)),
TextSpan(text: "\n"),
hasWeight
? skipped
? TextSpan(
text: t("skipped") + "!",
style: GoogleFonts.inter(fontSize: 12, color: Colors.grey[400], fontWeight: FontWeight.bold))
: TextSpan(
text: t("One Rep Max") + ": ",
style: GoogleFonts.inter(fontSize: 12, color: Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
hasWeight
? skipped
? TextSpan()
: TextSpan(
text: exercise.oneRepMax!.toStringAsFixed(0) +
" " +
t("kg") +
" (Max: " +
exercise.max1RM!.toStringAsFixed(0) +
" " +
t("kg") +
")",
style: GoogleFonts.inter(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold))
: TextSpan(),
TextSpan(text: "\n"),
hasWeight
? skipped
? TextSpan()
: TextSpan(
text: t("Total Lift") + ": ",
style: GoogleFonts.inter(fontSize: 12, color: Colors.yellow[400], fontWeight: FontWeight.bold))
: TextSpan(),
hasWeight
? skipped
? TextSpan()
: TextSpan(
text: exercise.totalLift!.toStringAsFixed(0) +
" " +
t("kg") +
" (Max: " +
exercise.maxTotalLift!.toStringAsFixed(0) +
" " +
t("kg") +
")",
style: GoogleFonts.inter(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold))
: skipped
? TextSpan()
: TextSpan(
text: exercise.repeats!.toStringAsFixed(0) +
" " +
t("reps") +
" (Max: " +
exercise.maxRepeats!.toStringAsFixed(0) +
" " +
t("reps") +
")",
style: GoogleFonts.inter(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold)),
TextSpan(text: "\n"),
skipped
? TextSpan()
: TextSpan(
text: t("Trend") + ": ",
style: GoogleFonts.inter(fontSize: 12, color: Colors.yellow[400], fontWeight: FontWeight.bold)),
skipped
? TextSpan()
: TextSpan(
text: exercise.trendText,
style: GoogleFonts.inter(fontSize: 12, color: Colors.white, fontWeight: FontWeight.bold)),
]),
)),
]),
),
),
);
}
}
+15 -6
View File
@@ -93,12 +93,21 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
List<Widget> _getTreeChildren(TrainingPlanBloc bloc) {
final List<TrainingPlan> plans = bloc.trainingPlanRepository.getPlansByParent(parentName);
final String parentTitle =
bloc.trainingPlanRepository.parentTree != null ? bloc.trainingPlanRepository.parentTree!.nameTranslation : "";
final String parentDescription =
bloc.trainingPlanRepository.parentTree != null && bloc.trainingPlanRepository.parentTree!.descriptionTranslation != null
? bloc.trainingPlanRepository.parentTree!.descriptionTranslation!
String parentDescription = "";
String parentTitle = "";
if (bloc.trainingPlanRepository.parentTree != null) {
parentTitle = AppLanguage().appLocal.toString() == "en"
? bloc.trainingPlanRepository.parentTree!.name
: bloc.trainingPlanRepository.parentTree!.nameTranslation;
if (bloc.trainingPlanRepository.parentTree!.description != null) {
parentDescription = bloc.trainingPlanRepository.parentTree!.descriptionTranslation != null
? AppLanguage().appLocal.toString() == "en"
? bloc.trainingPlanRepository.parentTree!.description!
: bloc.trainingPlanRepository.parentTree!.descriptionTranslation!
: "";
}
}
List<Widget> listWidget = [];
Card explanation = Card(
@@ -237,7 +246,7 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
? Container(
padding: EdgeInsets.only(bottom: 8),
child: Text(
"Soon! Check back later for the plan details",
t("Soon! Check back later for the plan details"),
style: GoogleFonts.inter(
color: Colors.orange[800],
shadows: <Shadow>[
+97 -71
View File
@@ -10,11 +10,11 @@ import 'package:aitrainer_app/widgets/app_bar.dart';
import 'package:aitrainer_app/widgets/dialog_common.dart';
import 'package:aitrainer_app/widgets/dialog_html.dart';
import 'package:aitrainer_app/widgets/menu_image.dart';
import 'package:aitrainer_app/widgets/victory_widget.dart';
import 'package:aitrainer_app/widgets/weight_control.dart';
import 'package:badges/badges.dart';
import 'package:extended_tabs/extended_tabs.dart';
import 'package:ezanimation/ezanimation.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
@@ -33,6 +33,7 @@ class _TrainingPlanExecutePageState extends State<TrainingPlanExecutePage> with
@override
Widget build(BuildContext context) {
final HashMap args = HashMap();
bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc!.activateDays();
setContext(context);
@@ -52,15 +53,10 @@ class _TrainingPlanExecutePageState extends State<TrainingPlanExecutePage> with
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is TrainingPlanDayFinished) {
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return Victory(
victory: true,
);
});
bloc!.celebrating = false;
args["bloc"] = bloc;
args["day"] = bloc!.dayNames[bloc!.activeDayIndex];
Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args);
} else if (state is TrainingPlanDayReadyToRestart) {
if (!bloc!.celebrating) {
showCupertinoDialog(
@@ -100,9 +96,13 @@ class _TrainingPlanExecutePageState extends State<TrainingPlanExecutePage> with
}),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => bloc!.getNext() != null
? _ExerciseListState.executeExercise(bloc!, bloc!.getNext()!, context)
: Navigator.of(context).pushNamed('home'),
onPressed: () => {
args["bloc"] = bloc,
args["day"] = bloc!.dayNames[bloc!.activeDayIndex],
bloc!.getNext() != null
? _ExerciseListState.executeExercise(bloc!, bloc!.getNext()!, context)
: Navigator.of(context).pushNamed('myTrainingEvaluation', arguments: args),
},
backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.weight_hanging),
label: Text(
@@ -446,12 +446,14 @@ class _ExerciseListState extends State<ExerciseList> with Trans {
bloc.getMyPlan()!.days[widget.dayName] != null &&
bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
tiles.add(GestureDetector(
tiles.add(
/* GestureDetector(
onTap: () => bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),
child: ExerciseTile(
bloc: bloc,
detail: element,
)));
child: */
ExerciseTile(
bloc: bloc,
detail: element,
));
});
}
@@ -507,23 +509,31 @@ class ExerciseTile extends StatefulWidget {
}
class _ExerciseTileState extends State<ExerciseTile> with Trans {
final EzAnimation animation = EzAnimation(1.0, 30.0, Duration(seconds: 3), reverseCurve: Curves.easeIn);
GestureRecognizer? _tapRecognizer;
@override
void initState() {
animation.start();
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {}
});
_tapRecognizer = TapGestureRecognizer()..onTap = _onPlusMinusWeight;
super.initState();
}
@override
bool didUpdateWidget(ExerciseTile oldWidget) {
super.didUpdateWidget(oldWidget);
Future.delayed(Duration(milliseconds: 400)).then((value) => animation.start());
return true;
void dispose() {
if (_tapRecognizer != null) {
_tapRecognizer!.dispose();
}
super.dispose();
}
void _onPlusMinusWeight() {
showDialog(
context: context,
builder: (BuildContext context) {
return WeightControl(
initialValue: widget.detail.weight != null ? widget.detail.weight! : 30,
onTap: (value) => widget.bloc.add(TrainingPlanWeightChangeRecalculate(detail: widget.detail, weight: value)),
);
});
}
Widget getIndicator(ExercisePlanDetailState state) {
@@ -564,6 +574,16 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
size: 40,
color: Colors.grey,
)));
} else if (state.equalsTo(ExercisePlanDetailState.extra)) {
return ClipRRect(
borderRadius: BorderRadius.circular(24.0),
child: Container(
color: Colors.white,
child: Icon(
CustomIcon.stopwatch_20,
size: 40,
color: Colors.blue[800],
)));
} else {
return Image.asset(
"asset/image/pict_reps_volumen_db.png",
@@ -574,7 +594,6 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
@override
Widget build(BuildContext context) {
setContext(context);
print("detail ${widget.detail}");
final ExercisePlanDetailState state = widget.detail.state;
final bool done = state.equalsTo(ExercisePlanDetailState.finished) || state.equalsTo(ExercisePlanDetailState.skipped);
final String countSerie = widget.detail.set.toString();
@@ -582,13 +601,13 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
String weight = widget.detail.weight != null ? widget.detail.weight!.toStringAsFixed(1) : "-";
bool isDrop = false;
if (widget.detail.weight == -3) {
weight = t("DROP");
weight = "DROP";
isDrop = true;
}
String restingTime = widget.detail.restingTime == null ? "" : widget.detail.restingTime!.toStringAsFixed(0);
bool isTest = false;
if (widget.detail.weight != null && widget.detail.weight! == -1) {
weight = t("TEST");
weight = "TEST";
isTest = true;
}
String repeats = widget.detail.repeats!.toString();
@@ -741,11 +760,22 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise
? TextSpan(
text: weight,
text: t(weight),
style: GoogleFonts.inter(
fontSize: 12,
))
: TextSpan(),
widget.detail.exerciseType!.unitQuantityUnit != null && !extraExercise && weight != "TEST" && weight != "DROP"
? TextSpan(
text: " - +",
style: GoogleFonts.archivoBlack(
color: Colors.blue,
fontSize: 16,
),
recognizer: _tapRecognizer,
mouseCursor: SystemMouseCursors.precise,
)
: TextSpan(),
TextSpan(
text: "\n",
),
@@ -796,21 +826,46 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
]),
)),
isTest
? AnimatedBuilder(
animation: animation,
builder: (context, snapshot) {
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
? Container(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: false,
title: t("Why Test?"),
descriptions: t("This is your first exercise after at least 3 weeks."),
description2:
t("The first exercise will be a test. The following sets will be recalculated base on your test."),
description3: t("This is the most optimal way for your development"),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.yellowAccent[700],
size: 16,
)),
]))
: isDrop
? Container(
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: false,
title: t("Why Test?"),
descriptions: t("This is your first exercise after at least 3 weeks."),
title: t("Drop Set"),
descriptions: t(
"Execute at least 3 sets with maximum repeats, without resting time, with decreasing the weight."),
description2:
t("The first exercise will be a test. The following sets will be recalculated base on your test."),
description3: t("This is the most optimal way for your development"),
t("The goal is to completly exhaust your muscle without lifting a ridiculous weight end the end."),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
@@ -820,39 +875,10 @@ class _ExerciseTileState extends State<ExerciseTile> with Trans {
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.yellowAccent[700],
color: Colors.orange[200],
size: 16,
)),
]);
})
: isDrop
? AnimatedBuilder(
animation: animation,
builder: (context, snapshot) {
return Column(mainAxisAlignment: MainAxisAlignment.center, children: [
GestureDetector(
onTap: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: false,
title: t("Drop set"),
descriptions: t("Drop set"),
description2: t("Recommended method:"),
text: "OK",
onTap: () => Navigator.of(context).pop(),
onCancel: () => {
Navigator.of(context).pop(),
},
);
}),
child: Icon(
CustomIcon.question_circle,
color: Colors.orange[200],
size: 16,
)),
]);
})
]))
: Offstage()
]),
),
+93 -140
View File
@@ -19,7 +19,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
final CustomerTrainingPlanDetails detail = args['customerTrainingPlanDetails'];
// ignore: close_sinks
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
final bool isDropSet = detail.weight == -3;
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 1),
@@ -75,7 +75,7 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
backgroundColor: Colors.orange[800],
icon: Icon(CustomIcon.save),
label: Text(
t("Save"),
isDropSet ? t("Done") : t("Save"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16),
),
),
@@ -83,147 +83,100 @@ class TrainingPlanExercise extends StatelessWidget with Trans {
}
Widget getExercises(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
final String noTestTextWithWeight = "Please try to execute this exercise with exact weight and repeats what is suggested";
final String noTestTextNoWeight = "Please try to execute this exercise with exact repeats what is suggested";
final String testMaxRepeats = "Please repeat as much times as you can! MAXIMIZE it!";
final String testWeight = "Please take a relative bigger weight and at least 12 times and do your best! MAXIMIZE it!";
return ExerciseSave(
exerciseName: detail.exerciseType!.nameTranslation,
exerciseDescription: detail.exerciseType!.descriptionTranslation,
exerciseTask: detail.exerciseType!.unitQuantityUnit != null
? detail.weight == -1
? t(testWeight)
: detail.repeats == -1
? t(testMaxRepeats)
: t(noTestTextWithWeight)
: detail.repeats == -1
? t(testMaxRepeats)
: noTestTextNoWeight,
unit: detail.exerciseType!.unit,
unitQuantityUnit: detail.exerciseType!.unitQuantityUnit,
hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null,
weight: detail.weight == -1 ? 30 : detail.weight,
repeats: detail.repeats == -1 ? 99 : detail.repeats,
set: detail.set,
exerciseNr: detail.exercises.length + 1,
onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChange(weight: value, detail: detail)),
onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)),
exerciseTypeId: detail.exerciseType!.exerciseTypeId,
);
int? originalQuantity = bloc.trainingPlanRepository.getOriginalRepeats(bloc.getMyPlan()!.trainingPlanId!, detail);
if (detail.weight != -3) {
return ExerciseSave(
exerciseName: detail.exerciseType!.nameTranslation,
exerciseDescription: detail.exerciseType!.descriptionTranslation,
exerciseTask: getExerciseTask(detail),
unit: detail.exerciseType!.unit,
unitQuantityUnit: detail.exerciseType!.unitQuantityUnit,
hasUnitQuantity: detail.exerciseType!.unitQuantityUnit != null,
weight: detail.weight == -1 ? 0 : detail.weight,
repeats: detail.repeats == -1 ? 99 : detail.repeats,
set: detail.set,
exerciseNr: detail.exercises.length + 1,
onUnitQuantityChanged: (value) => bloc.add(TrainingPlanWeightChange(weight: value, detail: detail)),
onQuantityChanged: (value) => bloc.add(TrainingPlanRepeatsChange(repeats: value.toInt(), detail: detail)),
exerciseTypeId: detail.exerciseType!.exerciseTypeId,
originalQuantity: originalQuantity,
);
} else {
return getDropSet(bloc, detail);
}
}
/* Widget getExerciseForm(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
String getExerciseTask(CustomerTrainingPlanDetails detail) {
String desc = "";
if (detail.exerciseType!.unit == "second") {
return desc;
}
if (detail.exerciseType!.unitQuantityUnit != null) {
if (detail.weight == -1) {
return "Please take a relative bigger weight and at least 12 times and do your best! MAXIMIZE it!";
} else if (detail.repeats == -1) {
return "Please repeat as much times as you can! MAXIMIZE it!";
} else {
return "Please try to execute this exercise with exact weight and repeats what is suggested";
}
} else {
if (detail.repeats == -1) {
return "Please repeat as much times as you can! MAXIMIZE it!";
} else {
return "Please try to execute this exercise with exact repeats what is suggested";
}
}
}
Widget getDropSet(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
return Container(
padding: const EdgeInsets.only(top: 10, left: 25, right: 25),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
Text(
detail.exerciseType!.nameTranslation,
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
fontSize: 24,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 12.0,
color: Colors.black54,
),
],
),
overflow: TextOverflow.fade,
textAlign: TextAlign.center,
maxLines: 2,
softWrap: true,
),
Divider(
color: Colors.transparent,
),
Divider(),
detail.weight != -1 ? numberPickForm(bloc, detail) : numberPickForm(bloc, detail),
],
)));
}
Widget numberPickForm(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail) {
final String strTimes = detail.repeats!.toStringAsFixed(1); // : "maximum";
List<Widget> listWidgets = [
GestureDetector(
onTap: () => {},
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
),
children: [
TextSpan(text: t("Please repeat with ")),
TextSpan(
text: detail.weight!.toStringAsFixed(1) + " " + detail.exerciseType!.unitQuantityUnit!,
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
),
),
TextSpan(text: t("hu_with") + " "),
TextSpan(
text: strTimes + " ",
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
)),
TextSpan(
text: t(
"times!",
)),
]),
)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
NumberPickerWidget(
minValue: 0,
maxValue: 200,
initalValue: detail.repeats!,
unit: t("reps"),
color: Colors.yellow[50]!,
onChange: (value) => {}),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(0),
primary: Colors.white,
onSurface: Colors.blueAccent,
),
onPressed: () => {},
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_c.png', width: 140, height: 60),
Text(
t("Save"),
style: TextStyle(fontSize: 16, color: Colors.white),
),
],
)),
],
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage("asset/image/drop_set.png"),
//fit: BoxFit.cover,
alignment: Alignment.center,
),
),
];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: listWidgets,
padding: EdgeInsets.only(top: 20, left: 30),
child: RichText(
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.normal,
color: Colors.yellow[300],
),
children: [
TextSpan(
text: t("Drop Set"),
style: GoogleFonts.inter(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
),
),
TextSpan(
text: "\n",
),
TextSpan(
text: "\n",
),
TextSpan(text: t("Execute at least 3 sets with maximum repeats, without resting time, with decreasing the weight.")),
TextSpan(
text: "\n",
),
TextSpan(
text: "\n",
),
TextSpan(
text: t("The goal is to completly exhaust your muscle without lifting a ridiculous weight end the end."),
style: GoogleFonts.inter(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.yellow[100],
),
),
],
)),
);
} */
}
}
+2 -2
View File
@@ -3,6 +3,7 @@ import 'dart:collection';
import 'package:aitrainer_app/bloc/training_plan/training_plan_bloc.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/service/logging.dart';
import 'package:aitrainer_app/util/enums.dart';
import 'package:aitrainer_app/util/track.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar.dart';
@@ -112,7 +113,7 @@ class MyTrainingPlans extends StatelessWidget with Trans, Logging {
left: 5,
textColor: color,
onTap: () {
// if (Cache().userLoggedIn != null) {
Track().track(TrackingEvent.training_plan_open, eventValue: route);
if (route == "myTrainingPlanActivate") {
HashMap<String, dynamic> args = HashMap();
args['parentName'] = parentName;
@@ -142,7 +143,6 @@ class MyTrainingPlans extends StatelessWidget with Trans, Logging {
} else {
Navigator.of(context).pushNamed(route);
}
// }
},
isLocked: false,
);