WT 1.1.22 reengineering: Training Plan execution, registration

This commit is contained in:
bossanyit
2021-08-25 01:05:03 +02:00
parent 6b25fdfe0e
commit cebd83648b
51 changed files with 2605 additions and 663 deletions
+21
View File
@@ -12,6 +12,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:aitrainer_app/widgets/bottom_nav.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:firebase_in_app_messaging/firebase_in_app_messaging.dart';
// ignore: must_be_immutable
class AccountPage extends StatelessWidget with Trans {
@@ -151,6 +152,7 @@ class AccountPage extends StatelessWidget with Trans {
),
devices(context, accountBloc),
loginOut(context, accountBloc),
//messaging(),
//getMyTrainees(context, accountBloc),
]);
}
@@ -180,6 +182,25 @@ class AccountPage extends StatelessWidget with Trans {
return element;
}
ListTile messaging() {
FirebaseInAppMessaging fiam = FirebaseInAppMessaging();
ListTile element = ListTile(
leading: Icon(Icons.message),
title: TextButton(
style: TextButton.styleFrom(
backgroundColor: Colors.white38,
onSurface: Colors.grey,
),
child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
Text(t("Trigger message"), style: TextStyle(color: Colors.purple)),
]),
onPressed: () => fiam.triggerEvent("mydevelopment"),
),
);
return element;
}
ListTile loginOut(BuildContext context, AccountBloc accountBloc) {
ListTile element = ListTile();
+160 -184
View File
@@ -1,6 +1,7 @@
import 'dart:collection';
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/model/cache.dart';
import 'package:aitrainer_app/model/sport.dart';
import 'package:aitrainer_app/util/app_localization.dart';
@@ -14,6 +15,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.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 '../bloc/customer_change/customer_change_bloc.dart';
import '../library/dropdown_search/dropdown_search.dart';
@@ -31,11 +33,13 @@ class CustomerFitnessPage extends StatefulWidget {
class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final double cWidth = MediaQuery.of(context).size.width * 0.75;
cWidth = MediaQuery.of(context).size.width * 0.75;
CustomerRepository customerRepository;
dynamic args = ModalRoute.of(context)!.settings.arguments;
if (args is HashMap && args['personal_data'] != null) {
@@ -49,186 +53,122 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 50, min: 26);
_bar = AppBarProgress(max: 30, min: 15);
}
final double h = 27;
return Scaffold(
appBar: _bar,
body: BlocProvider(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: Builder(builder: (context) {
// ignore: close_sinks
CustomerChangeBloc changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
selected = changeBloc.selectedFitnessItem;
if (selected == null) {
selected = FitnessState.beginner;
}
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Container(
padding: EdgeInsets.only(bottom: 200),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Divider(),
Wrap(
//runAlignment: WrapAlignment.center,
alignment: WrapAlignment.center,
children: [
Text(
t("Your Fitness State"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.beginner),
),
child: Container(
width: cWidth,
child: Column(
children: [
Text(t("Beginner"),
textWidthBasis: TextWidthBasis.longestLine,
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900)),
Text(
t("I am beginner"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
],
)),
onPressed: () => {
setState(() {
selected = FitnessState.beginner;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
}),
}),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.intermediate),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
t("Intermediate"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
t("I am intermediate"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
setState(() {
selected = FitnessState.intermediate;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
print(selected);
}),
}),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.advanced),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
t("Advanced"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
t("I am advanced"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
setState(() {
selected = FitnessState.advanced;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
print(selected);
}),
}),
Divider(),
TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, FitnessState.professional),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
AppLocalizations.of(context)!.translate("Professional"),
style: TextStyle(color: Colors.blue, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
highlightColor: Colors.white,
),
InkWell(
child: Text(
AppLocalizations.of(context)!.translate("I am professional"),
style: TextStyle(color: Colors.black, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
setState(() {
selected = FitnessState.professional;
changeBloc.add(CustomerFitnessChange(fitness: selected!));
print(selected);
}),
}),
Divider(),
Text(
t("Your Primary Sport") + ":",
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 20,
),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("customerSexPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
if (!fulldata)
{
changeBloc.add(CustomerSaveFitness()),
}
else
{
changeBloc.add(CustomerSave()),
}
},
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("Your Fitness State"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton("Beginner", "I am beginner", FitnessState.beginner),
SizedBox(
height: h,
),
getButton("Intermediate", "I am intermediate", FitnessState.intermediate),
SizedBox(
height: h,
),
getButton("Advanced", "I am advanced", FitnessState.advanced),
SizedBox(
height: h,
),
getButton("Professional", "I am professional", FitnessState.professional),
/* Divider(),
Text(
t("Your Primary Sport") + ":",
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 20,
),
getSport(changeBloc),
Divider(),
), */
//getSport(changeBloc),
/* Divider(),
ElevatedButton(
style: ElevatedButton.styleFrom(
onPrimary: Colors.white,
@@ -240,22 +180,58 @@ class _CustomerFitnessPageState extends State<CustomerFitnessPage> with Trans {
Navigator.of(context).pop(),
if (!fulldata) {Navigator.of(context).pushNamed("customerBodyTypePage", arguments: customerRepository)}
},
)
],
),
) */
],
),
);
}
TextButton getButton(String title, String desc, String state) {
return TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, state),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: Text(
AppLocalizations.of(context)!.translate(title),
style: TextStyle(color: Colors.white, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
);
})));
highlightColor: Colors.white,
),
InkWell(
child: Text(
AppLocalizations.of(context)!.translate(desc),
style: TextStyle(color: Colors.white, fontSize: 20, fontFamily: 'Arial', fontWeight: FontWeight.w100),
),
highlightColor: Colors.white,
),
],
),
),
onPressed: () => {
changeBloc.add(CustomerFitnessChange(fitness: state)),
});
}
dynamic getShape(CustomerChangeBloc changeBloc, String fitnessLevel) {
String? selected = changeBloc.selectedFitnessItem;
dynamic returnCode = (selected == fitnessLevel)
? RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.orange),
side: BorderSide(
width: 4,
color: Color(0xffb4f500),
),
borderRadius: BorderRadius.circular(12),
)
: RoundedRectangleBorder(
side: BorderSide(width: 1, color: Colors.blue),
side: BorderSide(width: 4, color: Colors.white24),
borderRadius: BorderRadius.circular(12),
);
//return
return returnCode;
+120 -66
View File
@@ -10,6 +10,7 @@ import 'package:flutter/cupertino.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';
enum Goals { gain_muscle, weight_loss, endurance, muscle_endurance, flexibility, gain_strength, explosiveness, shape_forming }
@@ -69,18 +70,21 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
CustomerRepository customerRepository;
dynamic args = ModalRoute.of(context)!.settings.arguments;
if (args is HashMap && args['personal_data'] != null) {
fulldata = args['personal_data'];
customerRepository = args['bloc'];
if (args != null) {
if (args is HashMap && args['personal_data'] != null) {
fulldata = args['personal_data'];
customerRepository = args['bloc'];
} else {
customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
}
} else {
customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
customerRepository = CustomerRepository();
}
PreferredSizeWidget _bar = AppBarMin(
back: true,
back: false,
);
if (!fulldata) {
_bar = AppBarProgress(max: 50, min: 26);
_bar = AppBarProgress(max: 14, min: 0);
}
return Scaffold(
@@ -88,7 +92,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_light_background.jpg'),
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -97,75 +101,120 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: Builder(builder: (context) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return SingleChildScrollView(
child: Center(
child: Column(
children: [
Divider(),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("Set Your Primary Goal"),
maxLines: 2,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.orange,
fontSize: 30,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 3.0,
color: Colors.black87,
),
],
),
),
]),
Divider(),
getItem(changeBloc, Goals.gain_muscle),
Divider(),
getItem(changeBloc, Goals.weight_loss),
Divider(),
getItem(changeBloc, Goals.shape_forming),
Divider(),
getItem(changeBloc, Goals.endurance),
Divider(),
getItem(changeBloc, Goals.gain_strength),
Divider(),
getItem(changeBloc, Goals.muscle_endurance),
Divider(),
getItem(changeBloc, Goals.flexibility),
Divider(),
getItem(changeBloc, Goals.explosiveness),
Divider(),
],
),
));
}),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
//changingViewModel.saveCustomer(),
changeBloc.add(CustomerSave()),
Navigator.of(context).pop(),
if (!fulldata) {Navigator.of(context).pushNamed("customerFitnessPage", arguments: changeBloc.customerRepository)}
print("Fulldata: $fulldata bloc $changeBloc"),
if (!fulldata)
{
print("Savegoal"),
changeBloc.add(CustomerSaveGoal()),
}
else
{
changeBloc.add(CustomerSave()),
}
},
backgroundColor: Colors.orange[800],
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
size: 20,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 12),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
return SingleChildScrollView(
child: Center(
child: Column(
children: [
Divider(),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("Set Your Primary Goal"),
maxLines: 2,
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 3.0,
color: Colors.black87,
),
],
),
),
]),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.gain_muscle),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.weight_loss),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.shape_forming),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.endurance),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.gain_strength),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.muscle_endurance),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.flexibility),
SizedBox(
height: h,
),
getItem(changeBloc, Goals.explosiveness),
SizedBox(
height: h,
),
],
),
));
}
Widget getItem(CustomerChangeBloc changeBloc, Goals goal) {
return Stack(alignment: Alignment.bottomLeft, children: [
TextButton(
@@ -188,7 +237,7 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
child: Text(
t(goal.description(goal)),
style: GoogleFonts.archivoBlack(
color: Colors.yellow[300],
color: Colors.white,
fontSize: 28,
shadows: <Shadow>[
Shadow(
@@ -204,13 +253,18 @@ class _CustomerGoalPage extends State<CustomerGoalPage> with Trans {
}
dynamic getShape(CustomerChangeBloc customerBloc, String goal) {
if (customerBloc.customerRepository.goal == null) return null;
dynamic baseCode = RoundedRectangleBorder(
side: BorderSide(width: 2, color: Colors.white24),
borderRadius: BorderRadius.circular(12),
);
if (customerBloc.customerRepository.goal == null) return baseCode;
String selectedGoal = customerBloc.customerRepository.goal!;
dynamic returnCode = (selectedGoal == goal)
? RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.red),
side: BorderSide(width: 6, color: Color(0xffb4f500)),
borderRadius: BorderRadius.circular(12),
)
: null;
: baseCode;
//return
return returnCode;
}
+178
View File
@@ -0,0 +1,178 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import '../bloc/customer_change/customer_change_bloc.dart';
// ignore: must_be_immutable
class CustomerHeightPage extends StatefulWidget {
late _CustomerHeightPageState _state;
_CustomerHeightPageState createState() {
_state = _CustomerHeightPageState();
return _state;
}
}
class _CustomerHeightPageState extends State<CustomerHeightPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerRepository customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 75, min: 60);
}
return Scaffold(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("registration", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return getPage();
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => changeBloc.add(CustomerSaveHeight()),
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Finish"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
cWidth = MediaQuery.of(context).size.width * 0.75;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("What is your height?"),
textAlign: TextAlign.center,
maxLines: 2,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton(),
],
),
);
}
Widget getButton() {
double mediaWidth = MediaQuery.of(context).size.width * .4;
double mediaHeight = MediaQuery.of(context).size.height * .4;
return Row(children: [
changeBloc.customerRepository.customer!.sex == "m"
? Image.asset(
"asset/image/test_picto_m.png",
height: mediaHeight,
width: mediaWidth,
)
: Image.asset(
"asset/image/test_picto_w.png",
height: mediaHeight,
width: mediaWidth,
),
SfLinearGauge(
minimum: 140,
maximum: 220,
markerPointers: [
LinearWidgetPointer(
value: changeBloc.height,
offset: 55,
position: LinearElementPosition.inside,
markerAlignment: LinearMarkerAlignment.center,
child: Container(
height: 25,
width: 55,
color: Colors.transparent,
child: Text(changeBloc.height.toString(),
style: GoogleFonts.inter(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xffb4f500),
)),
),
),
LinearShapePointer(
height: 25,
width: 55,
color: Color(0xffb4f500),
value: changeBloc.height,
onValueChanged: (value) => {
changeBloc.add(CustomerHeightChange(height: value.toInt())),
},
),
],
orientation: LinearGaugeOrientation.vertical,
majorTickStyle: LinearTickStyle(length: 20, color: Colors.white),
axisLabelStyle: TextStyle(fontSize: 12.0, color: Colors.white),
axisTrackStyle:
LinearAxisTrackStyle(color: Colors.cyan, edgeStyle: LinearEdgeStyle.bothFlat, thickness: 1.0, borderColor: Colors.white))
]);
}
}
+185
View File
@@ -0,0 +1,185 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.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 '../bloc/customer_change/customer_change_bloc.dart';
// ignore: must_be_immutable
class CustomerSexPage extends StatefulWidget {
late _CustomerSexPageState _state;
_CustomerSexPageState createState() {
_state = _CustomerSexPageState();
return _state;
}
}
class _CustomerSexPageState extends State<CustomerSexPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerRepository customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 45, min: 30);
}
return Scaffold(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("customerWeightPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
changeBloc.add(CustomerSaveSex()),
},
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
cWidth = MediaQuery.of(context).size.width * 0.75;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("What is your biological sex?"),
textAlign: TextAlign.center,
maxLines: 2,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton("Man", "", "m"),
SizedBox(
height: h,
),
getButton("Woman", "", "w"),
],
),
);
}
TextButton getButton(String title, String desc, String state) {
return TextButton(
style: TextButton.styleFrom(
padding: EdgeInsets.all(10.0),
shape: getShape(changeBloc, state),
),
child: Container(
width: cWidth,
child: Column(
children: [
InkWell(
child: ListTile(
leading: Icon(
state == "m" ? Icons.male_outlined : Icons.female,
color: Color(0xffb4f500),
size: 60,
),
title: Text(
AppLocalizations.of(context)!.translate(title),
style: TextStyle(color: Colors.white, fontSize: 32, fontFamily: 'Arial', fontWeight: FontWeight.w900),
),
)),
],
),
),
onPressed: () => {
print("Sex $state"),
changeBloc.add(CustomerGenderChange(gender: state == "m" ? 0 : 1)),
});
}
dynamic getShape(CustomerChangeBloc changeBloc, String sex) {
String? selected = changeBloc.customerRepository.customer!.sex;
dynamic returnCode = (selected == sex)
? RoundedRectangleBorder(
side: BorderSide(
width: 4,
color: Color(0xffb4f500),
),
borderRadius: BorderRadius.circular(12),
)
: RoundedRectangleBorder(
side: BorderSide(width: 4, color: Colors.white24),
borderRadius: BorderRadius.circular(12),
);
return returnCode;
}
}
+147
View File
@@ -0,0 +1,147 @@
import 'package:aitrainer_app/bloc/customer_change/customer_change_bloc.dart';
import 'package:aitrainer_app/library/custom_icon_icons.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/repository/customer_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:aitrainer_app/widgets/app_bar_progress.dart';
import 'package:aitrainer_app/widgets/number_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.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 '../bloc/customer_change/customer_change_bloc.dart';
// ignore: must_be_immutable
class CustomerWeightPage extends StatefulWidget {
late _CustomerWeightPageState _state;
_CustomerWeightPageState createState() {
_state = _CustomerWeightPageState();
return _state;
}
}
class _CustomerWeightPageState extends State<CustomerWeightPage> with Trans {
String? selected;
bool fulldata = false;
late CustomerChangeBloc changeBloc;
late double cWidth;
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerRepository customerRepository = ModalRoute.of(context)!.settings.arguments as CustomerRepository;
PreferredSizeWidget _bar = AppBarMin(
back: true,
);
if (!fulldata) {
_bar = AppBarProgress(max: 60, min: 45);
}
return Scaffold(
appBar: _bar,
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_plainblack_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
height: double.infinity,
width: double.infinity,
child: BlocProvider(
create: (context) => CustomerChangeBloc(customerRepository: customerRepository),
child: BlocConsumer<CustomerChangeBloc, CustomerChangeState>(
listener: (context, state) {
if (state is CustomerSaveError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is CustomerSaveSuccess) {
Navigator.of(context).pop();
Navigator.of(context).pushNamed("customerHeightPage", arguments: changeBloc.customerRepository);
}
},
builder: (context, state) {
changeBloc = BlocProvider.of<CustomerChangeBloc>(context);
return ModalProgressHUD(
child: getPage(),
inAsyncCall: state is CustomerChangeLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
},
),
)),
floatingActionButton: FloatingActionButton.extended(
onPressed: () => {
changeBloc.add(CustomerSaveWeight()),
},
backgroundColor: Color(0xffb4f500),
icon: Icon(
CustomIcon.save,
color: Colors.black,
size: 26,
),
label: Text(
fulldata ? t("Save") : t("Next"),
style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 18, color: Colors.black),
),
),
);
}
Widget getPage() {
final double h = 27;
cWidth = MediaQuery.of(context).size.width * 0.75;
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
height: h,
),
Wrap(alignment: WrapAlignment.center, children: [
Text(
t("What is your weight?"),
textAlign: TextAlign.center,
maxLines: 2,
style: GoogleFonts.archivoBlack(
color: Colors.white,
fontSize: 30,
fontWeight: FontWeight.w900,
),
)
]),
SizedBox(
height: h,
),
getButton(),
],
),
);
}
Widget getButton() {
return NumberPickerWidget(
minValue: 40,
maxValue: 150,
fontSize: 30,
diameterRatio: 1.1,
itemExtent: 40,
fontWeight: FontWeight.w700,
initalValue: changeBloc.weight.toInt(),
unit: t("kg"),
color: Color(0xffb4f500),
onChange: (value) => changeBloc.add(CustomerWeightChange(weight: value)));
}
}
+66 -12
View File
@@ -1,6 +1,10 @@
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/library/button_animations.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
import 'package:flutter/material.dart';
import 'package:flutter_fadein/flutter_fadein.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:percent_indicator/circular_percent_indicator.dart';
// ignore: must_be_immutable
class CustomerWelcomePage extends StatefulWidget {
@@ -12,11 +16,14 @@ class CustomerWelcomePage extends StatefulWidget {
}
}
class _CustomerWelcomePageState extends State<CustomerWelcomePage> {
class _CustomerWelcomePageState extends State<CustomerWelcomePage> with Trans {
@override
Widget build(BuildContext context) {
setContext(context);
return Scaffold(
appBar: AppBarMin(),
appBar: AppBarMin(
back: true,
),
body: Container(
decoration: BoxDecoration(
image: DecorationImage(
@@ -30,17 +37,64 @@ class _CustomerWelcomePageState extends State<CustomerWelcomePage> {
child: Center(
child: Column(
children: [
Divider(
color: Colors.transparent,
SizedBox(
height: 200,
),
ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.orange,
onSurface: Colors.white,
CircularPercentIndicator(
radius: 250.0,
animation: true,
animationDuration: 4800,
lineWidth: 20.0,
percent: 0.98,
curve: Curves.bounceInOut,
backgroundWidth: 4,
center: Text(
t("Training Plan Generation"),
textAlign: TextAlign.center,
style: GoogleFonts.archivoBlack(
fontWeight: FontWeight.bold,
fontSize: 28.0,
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,
),
],
),
),
child: InkWell(child: Text(AppLocalizations.of(context)!.translate("Next"))),
onPressed: () => {Navigator.of(context).pop(), Navigator.of(context).pushNamed("home")},
)
circularStrokeCap: CircularStrokeCap.round,
progressColor: Color(0xffb4f500),
backgroundColor: Colors.black,
),
SizedBox(
height: 90,
),
FadeIn(
child: Container(
width: 160,
height: 80,
child: GestureDetector(
onTap: () => Navigator.of(context).popAndPushNamed("home"),
child: Stack(
alignment: Alignment.center,
children: [
Image.asset('asset/icon/gomb_orange_a.png', width: 140, height: 80),
Text(
t("Next"),
style: GoogleFonts.archivoBlack(fontSize: 20, color: Colors.white),
),
],
),
)),
duration: Duration(seconds: 6),
),
],
),
))),
+1 -1
View File
@@ -502,7 +502,7 @@ class EvaluationPage extends StatelessWidget with Trans {
Divider(color: Colors.transparent),
getSuggestionWidget(resultBloc, "Gain Strength", "asset/image/pict_weight_volumen_tonna.png", "3x4-8", 0.95, "3-5"),
Divider(color: Colors.transparent),
getSuggestionWidget(resultBloc, "Endurance", "asset/image/pict_reps_volumen_db.png", "4x25-35", 0.50, "3"),
getSuggestionWidget(resultBloc, "Muscle Endurance", "asset/image/pict_reps_volumen_db.png", "4x25-35", 0.50, "3"),
],
),
);
+103 -22
View File
@@ -2,6 +2,7 @@ import 'dart:io';
import 'package:aitrainer_app/bloc/account/account_bloc.dart';
import 'package:aitrainer_app/bloc/login/login_bloc.dart';
import 'package:aitrainer_app/repository/training_plan_repository.dart';
import 'package:aitrainer_app/repository/user_repository.dart';
import 'package:aitrainer_app/util/trans.dart';
import 'package:aitrainer_app/widgets/app_bar_min.dart';
@@ -33,17 +34,18 @@ class RegistrationPage extends StatelessWidget with Trans {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(t(state.message), style: TextStyle(color: Colors.white))));
} else if (state is LoginSuccess) {
TrainingPlanRepository trainingPlanRepository = TrainingPlanRepository();
showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
title: t("Successful Registration"),
descriptions: t("Now we would like to know you better to lift the experience of the app."),
description2: t("Please go through the pages, it will take couple of minutes!"),
descriptions: t("Based on your initial data, we will generate the personalized training plan for you."),
text: "OK",
onTap: () => {Navigator.of(context).pushNamed('customerModifyPage')},
onTap: () => {Navigator.of(context).pushNamed('customerWelcomePage')},
onCancel: () => {
Navigator.of(context).pushNamed("home"),
trainingPlanRepository.generateTrainingPlan(),
Navigator.of(context).pushNamed("customerWelcomePage"),
},
);
});
@@ -83,7 +85,7 @@ class RegistrationPage extends StatelessWidget with Trans {
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_login.jpg'),
image: AssetImage('asset/image/WT_menu_dark.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
@@ -99,17 +101,32 @@ class RegistrationPage extends StatelessWidget with Trans {
child: Container(
padding: const EdgeInsets.only(left: 20, right: 20),
child: ListView(shrinkWrap: false, padding: EdgeInsets.only(top: 10.0), children: <Widget>[
GestureDetector(
onTap: () => loginBloc.add(LoginSkip()),
child: Text(
t("I Execute My First Test Now"),
textAlign: TextAlign.right,
style: GoogleFonts.inter(color: loginBloc.testColor, decoration: TextDecoration.underline, fontWeight: FontWeight.bold),
)),
SizedBox(
height: 120,
height: 100,
),
ListTile(
title: Text(
t("SignUp"),
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
)),
SizedBox(
height: 20,
),
ListTile(title: Text(t("SignUp"), style: GoogleFonts.inter())),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
@@ -140,7 +157,6 @@ class RegistrationPage extends StatelessWidget with Trans {
: Offstage(),
],
),
//ListTile(title: Text(t("OR"), style: GoogleFonts.inter())),
Divider(
color: Colors.transparent,
),
@@ -149,6 +165,10 @@ class RegistrationPage extends StatelessWidget with Trans {
decoration: InputDecoration(
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
labelText: t('Email'),
labelStyle: TextStyle(
fontSize: 14,
color: Color(0xffb4f500),
),
fillColor: Colors.white24,
filled: true,
border: OutlineInputBorder(
@@ -165,7 +185,7 @@ class RegistrationPage extends StatelessWidget with Trans {
},
onChanged: (value) => loginBloc.add(LoginEmailChange(email: value)),
keyboardType: TextInputType.emailAddress,
style: new TextStyle(fontSize: 16, color: Colors.indigo),
style: new TextStyle(fontSize: 16, color: Colors.white),
),
Divider(
color: Colors.transparent,
@@ -174,7 +194,10 @@ class RegistrationPage extends StatelessWidget with Trans {
key: LibraryKeys.loginPasswordField,
obscureText: loginBloc.obscure,
decoration: InputDecoration(
labelStyle: TextStyle(fontSize: 14),
labelStyle: TextStyle(
fontSize: 14,
color: Color(0xffb4f500),
),
contentPadding: EdgeInsets.only(left: 15, top: 15, bottom: 15),
suffixIcon: IconButton(
onPressed: () => {loginBloc.add(LoginPasswordChangeObscure())},
@@ -197,7 +220,7 @@ class RegistrationPage extends StatelessWidget with Trans {
},
onChanged: (value) => loginBloc.add(LoginPasswordChange(password: value)),
keyboardType: TextInputType.visiblePassword,
style: new TextStyle(fontSize: 16, color: Colors.indigo),
style: new TextStyle(fontSize: 16, color: Colors.white),
),
Divider(
color: Colors.transparent,
@@ -214,7 +237,22 @@ class RegistrationPage extends StatelessWidget with Trans {
),
title: Text(
t("With the registration I accept the data policy and the terms of use."),
style: GoogleFonts.inter(color: Colors.indigo),
style: GoogleFonts.inter(
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
),
),
Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
@@ -242,7 +280,23 @@ class RegistrationPage extends StatelessWidget with Trans {
InkWell(
child: Text(
t('Login'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
),
onTap: () => Navigator.of(context).pushNamed('login'),
),
@@ -250,7 +304,23 @@ class RegistrationPage extends StatelessWidget with Trans {
InkWell(
child: Text(
t('Terms Of Use'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
Shadow(
offset: Offset(-3.0, 3.0),
blurRadius: 6.0,
color: Colors.black54,
),
],
),
),
onTap: () => {
showDialog(
@@ -263,7 +333,18 @@ class RegistrationPage extends StatelessWidget with Trans {
InkWell(
child: Text(
t('Privacy'),
style: GoogleFonts.inter(decoration: TextDecoration.underline),
style: GoogleFonts.inter(
decoration: TextDecoration.underline,
color: Colors.white,
fontWeight: FontWeight.w500,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 10.0,
color: Colors.black87,
),
],
),
),
onTap: () => {
showDialog(
+28 -3
View File
@@ -1,3 +1,5 @@
import 'dart:io';
import 'package:aitrainer_app/bloc/menu/menu_bloc.dart';
import 'package:aitrainer_app/bloc/settings/settings_bloc.dart';
import 'package:aitrainer_app/bloc/tutorial/tutorial_bloc.dart';
@@ -17,7 +19,8 @@ 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:toggle_switch/toggle_switch.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/services.dart';
import 'dart:async';
// ignore: must_be_immutable
class SettingsPage extends StatelessWidget with Trans {
@@ -81,7 +84,7 @@ class SettingsPage extends StatelessWidget with Trans {
Track().track(TrackingEvent.settings_lang, eventValue: lang)
})),
getServer(settingsBloc),
getTuturialBasic(settingsBloc),
//getTuturialBasic(settingsBloc),
getTermsOfUse(),
getPrivacy(),
getFaq(),
@@ -96,7 +99,7 @@ class SettingsPage extends StatelessWidget with Trans {
title: Container(),
);
}
print("Live: ${Cache().liveServer}");
return ListTile(
leading: Icon(Icons.data_usage_sharp),
subtitle: Text("For Test purpuses select Test-Server. After that please restart the the App"),
@@ -260,4 +263,26 @@ class SettingsPage extends StatelessWidget with Trans {
),
);
}
Future<void> _printAndCopy(String cmd) async {
print(cmd);
await Clipboard.setData(ClipboardData(text: cmd));
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Copied to Clipboard')),
);
}
void link1() {
String? cmd;
String cmdSuffix;
if (Platform.isIOS) {
cmd = '/usr/bin/xcrun simctl openurl booted';
} else if (Platform.isAndroid) {
cmd = '\$ANDROID_HOME/platform-tools/adb shell \'am start'
' -a android.intent.action.VIEW'
' -c android.intent.category.BROWSABLE -d';
cmdSuffix = "'";
}
}
}
+4 -1
View File
@@ -128,7 +128,10 @@ class TrainingPlanActivatePage extends StatelessWidget with Trans {
child: Text(
parentTitle,
maxLines: 2,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
)),
],
),
+649
View File
@@ -0,0 +1,649 @@
import 'dart:collection';
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/customer_training_plan_details.dart';
import 'package:aitrainer_app/model/exercise_plan_detail.dart';
import 'package:aitrainer_app/util/app_localization.dart';
import 'package:aitrainer_app/util/trans.dart';
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:badges/badges.dart';
import 'package:extended_tabs/extended_tabs.dart';
import 'package:flutter/cupertino.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';
class TrainingPlanExecute extends StatefulWidget {
const TrainingPlanExecute({Key? key}) : super(key: key);
@override
_TrainingPlanExecuteState createState() => _TrainingPlanExecuteState();
}
class _TrainingPlanExecuteState extends State<TrainingPlanExecute> with Trans {
@override
Widget build(BuildContext context) {
final TrainingPlanBloc bloc = BlocProvider.of<TrainingPlanBloc>(context);
bloc.activateDays();
setContext(context);
return Scaffold(
appBar: AppBarNav(depth: 0),
body: Container(
padding: EdgeInsets.all(0),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_black_background.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
child: BlocConsumer<TrainingPlanBloc, TrainingPlanState>(listener: (context, state) {
if (state is TrainingPlanError) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white))));
} else if (state is TrainingPlanDayFinished) {
bloc.celebrating = false;
final HashMap args = HashMap();
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(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("The training is finished")),
content: Column(children: [Divider(), Text(t("Do you want to restart, or select a new Training Plan?"))]),
actions: [
TextButton(
child: Text(t("New Training Plan"), textAlign: TextAlign.center),
onPressed: () => {
Navigator.pop(context),
Navigator.of(context).popAndPushNamed('myTrainingPlans'),
bloc.restarting = false,
}),
TextButton(
child: Text(t("Restart")),
onPressed: () {
bloc.restart();
Navigator.pop(context);
Navigator.of(context).popAndPushNamed('home');
},
)
],
));
}
}
}, builder: (context, state) {
return ModalProgressHUD(
child: ExerciseTabs(bloc: bloc),
inAsyncCall: state is TrainingPlanLoading,
opacity: 0.5,
color: Colors.black54,
progressIndicator: CircularProgressIndicator(),
);
}),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
final HashMap args = HashMap();
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[600], //Color(0xffb4f500),
icon: Icon(
CustomIcon.weight_hanging,
color: Colors.black,
),
label: Text(
t("Next Exercise"),
style: GoogleFonts.inter(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 16),
),
),
);
}
}
class ExerciseTabs extends StatefulWidget {
final TrainingPlanBloc bloc;
ExerciseTabs({required this.bloc});
@override
_ExerciseTabs createState() => _ExerciseTabs();
}
class _ExerciseTabs extends State<ExerciseTabs> with TickerProviderStateMixin {
late TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(length: widget.bloc.dayNames.length, vsync: this);
tabController.animateTo(widget.bloc.activeDayIndex, duration: Duration(milliseconds: 300));
}
@override
void dispose() {
tabController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return getTabs(widget.bloc);
}
Widget getTabs(TrainingPlanBloc bloc) {
return Column(children: [
Text(
bloc.getMyPlan()!.name!,
style: GoogleFonts.archivoBlack(
fontSize: 14,
color: Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
],
),
),
ExtendedTabBar(
indicator: BoxDecoration(
color: Colors.black87,
border: Border(
bottom: BorderSide(width: 4.0, color: Color(0xffb4f500)),
// top: BorderSide(width: 4.0, color: Colors.blue),
)),
labelPadding: EdgeInsets.only(left: 0, right: 0),
tabs: getTabNames(),
controller: tabController,
onTap: (index) => bloc.activeDayIndex = index,
),
Expanded(
child: ExtendedTabBarView(
children: getExerciseLists(),
controller: tabController,
/// if link is true and current tabbarview over scroll,
/// it will check and scroll ancestor or child tabbarView.
link: true,
/// cache page count
/// default is 0.
/// if cacheExtent is 1, it has two pages in cache
/// null is infinity, it will cache all pages
cacheExtent: 0,
)),
]);
}
List<Tab> getTabNames() {
List<Tab> tabs = [];
final int tabCount = widget.bloc.dayNames.length;
double cWidth = MediaQuery.of(context).size.width;
widget.bloc.dayNames.forEach((element) {
final Widget widget = Container(
//height: 40,
padding: EdgeInsets.only(top: 3, left: 10, right: 10, bottom: 3),
width: (cWidth / tabCount),
color: Colors.white10,
child: RichText(
textScaleFactor: 0.8,
text: TextSpan(
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.white,
),
children: [
TextSpan(
text: AppLocalizations.of(context)!.translate("Training Day") + ": \n",
style: GoogleFonts.inter(
fontSize: 14,
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,
),
],
)),
TextSpan(
text: element,
style: GoogleFonts.inter(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color(0xffb4f500),
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,
),
],
)),
])));
tabs.add(Tab(child: widget));
});
return tabs;
}
List<Widget> getExerciseLists() {
List<Widget> list = [];
widget.bloc.dayNames.forEach((element) {
list.add(ExerciseList(bloc: widget.bloc, dayName: element));
});
return list;
}
}
class ExerciseList extends StatefulWidget {
final TrainingPlanBloc bloc;
final String dayName;
ExerciseList({required this.bloc, required this.dayName});
@override
_ExerciseListState createState() => _ExerciseListState();
}
class _ExerciseListState extends State<ExerciseList> with Trans {
final scrollController = ScrollController();
double offset = 5;
@override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((_) {
animate();
});
super.initState();
}
@override
void didUpdateWidget(ExerciseList page) {
super.didUpdateWidget(page);
WidgetsBinding.instance!.addPostFrameCallback((_) {
animate();
});
}
void animate() {
offset = widget.bloc.getOffset();
if (scrollController.hasClients) {
scrollController.animateTo(offset, duration: Duration(milliseconds: 300), curve: Curves.easeIn);
}
}
@override
void dispose() {
scrollController.dispose();
super.dispose();
}
static void executeExercise(TrainingPlanBloc bloc, CustomerTrainingPlanDetails detail, BuildContext context) {
CustomerTrainingPlanDetails? next = bloc.getNext();
if (next != null) {
String title = "";
String description = "";
String description2 = "";
if (next.exerciseTypeId != detail.exerciseTypeId) {
title = AppLocalizations.of(context)!.translate("Stop!");
description = AppLocalizations.of(context)!.translate("Please continue with the next exercise in the queue:") +
next.exerciseType!.nameTranslation;
} else {
final HashMap args = HashMap();
args['exerciseType'] = next.exerciseType;
args['customerTrainingPlanDetails'] = detail;
Navigator.of(context).pushNamed('myTrainingPlanExercise', arguments: args);
return;
}
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return DialogCommon(
title: title,
descriptions: description,
description2: description2,
text: "OK",
onTap: () => {Navigator.of(context).pop()},
onCancel: () => {Navigator.of(context).pop()},
);
});
} else {
Navigator.of(context).pushNamed('home');
}
}
@override
Widget build(BuildContext context) {
setContext(context);
return CustomScrollView(controller: scrollController, slivers: [
SliverList(delegate: SliverChildListDelegate(getTiles(widget.bloc))),
]);
}
List<Widget> getTiles(TrainingPlanBloc bloc) {
List<Widget> tiles = [];
tiles.addAll(getExerciseTiles(bloc, context));
return tiles;
}
List<Widget> getExerciseTiles(TrainingPlanBloc bloc, BuildContext context) {
List<Widget> tiles = [];
CustomerTrainingPlanDetails? prev;
if (bloc.getMyPlan() != null &&
bloc.getMyPlan()!.details.isNotEmpty &&
bloc.getMyPlan()!.days[widget.dayName] != null &&
bloc.getMyPlan()!.days[widget.dayName]!.isNotEmpty) {
bloc.getMyPlan()!.days[widget.dayName]!.forEach((element) {
if (prev != null && prev!.exerciseTypeId != element.exerciseTypeId) {
tiles.add(GestureDetector(
onTap: () =>
bloc.getNext() != null ? executeExercise(bloc, bloc.getNext()!, context) : Navigator.of(context).pushNamed('home'),
child: ExerciseTile(bloc: bloc, detail: element)));
}
prev = element;
});
}
return tiles;
}
}
// ignore: must_be_immutable
class ExerciseTile extends StatelessWidget with Trans {
final TrainingPlanBloc bloc;
final CustomerTrainingPlanDetails detail;
ExerciseTile({required this.bloc, required this.detail});
Widget getExerciseQuantities(CustomerTrainingPlanDetails detail, int step, bool noFilter) {
bool skipped = detail.state == ExercisePlanDetailState.skipped;
String quantities = "";
String set = "";
List<TextSpan> spans = [];
if (detail.exerciseType!.name == "Warming Up") {
quantities = t("Min. 10 minutes");
spans.add(
TextSpan(text: quantities),
);
} else if (detail.exerciseType!.name == "Stretching") {
quantities = t("Recommended");
spans.add(
TextSpan(text: quantities),
);
} else {
set = detail.set! > 1 ? "${detail.set} " + t("set") : "";
List<CustomerTrainingPlanDetails> details = bloc.getAllDetailsSameExercise(detail);
int index = 0;
bool isWeight = true;
if (set.length > 0) {
spans.add(
TextSpan(
text: step.toString() + " ",
style: GoogleFonts.archivoBlack(
color: Colors.orange[600],
)),
);
spans.add(
TextSpan(text: "/ " + set),
);
}
details.forEach((element) {
quantities = "";
String delimiter = ",";
if (index == 0) {
delimiter = "";
}
if (element.repeats == -1) {
quantities += delimiter + " MAX ";
} else {
quantities += delimiter + " ${element.repeats}";
}
if (element.exerciseType!.unitQuantityUnit != null) {
quantities += "x";
if (element.weight == -1 || element.weight == -2 || element.weight == -3) {
quantities += "? kg";
} else {
num weight = element.weight! % element.weight!.round() == 0 ? element.weight!.round() : element.weight!;
quantities += "$weight kg";
}
} else {
isWeight = false;
}
if (step == index && noFilter) {
spans.add(
TextSpan(
text: quantities,
style: GoogleFonts.archivoBlack(
color: Colors.orange[600],
),
),
);
} else {
spans.add(
TextSpan(text: quantities),
);
}
index++;
});
if (isWeight) {
quantities += " kg";
}
}
return RichText(
text: TextSpan(
style: GoogleFonts.archivoBlack(
fontSize: 20,
color: skipped ? Colors.grey : Colors.white,
shadows: <Shadow>[
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
Shadow(
offset: Offset(2.0, 2.0),
blurRadius: 6.0,
color: Colors.black87,
),
],
),
children: spans),
);
}
@override
Widget build(BuildContext context) {
setContext(context);
final CustomerTrainingPlanDetails? next = bloc.getNext();
final bool noFilter = next != null && next.exerciseTypeId == detail.exerciseTypeId;
final bool done = detail.state == ExercisePlanDetailState.finished;
final int step = bloc.getStep(detail); //detail.exercises.length;
final bool buddyWarning = detail.exerciseType == null ? false : detail.exerciseType!.buddyWarning;
return Container(
child: Stack(alignment: Alignment.bottomLeft, children: [
Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topEnd(top: 5, end: 5),
animationDuration: Duration(milliseconds: 1500),
animationType: BadgeAnimationType.fade,
badgeColor: Colors.transparent,
showBadge: noFilter || done,
badgeContent: IconButton(
iconSize: 40,
onPressed: () => !done ? skip() : {},
icon: Icon(
done ? CustomIcon.ok_circled : Icons.cancel,
color: done ? Colors.green[600] : Colors.red[600],
)),
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topStart(top: 5, start: 5),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.slide,
badgeColor: Colors.transparent,
showBadge: true,
badgeContent: IconButton(
iconSize: 36,
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogHTML(
title: detail.exerciseType!.nameTranslation,
htmlData: '<p>' + detail.exerciseType!.descriptionTranslation + '</p>');
}),
icon: Icon(
Icons.info_outline,
color: Colors.yellow[200],
)),
child: Badge(
elevation: 0,
padding: EdgeInsets.all(0),
position: BadgePosition.topEnd(top: 65, end: 1),
animationDuration: Duration(milliseconds: 500),
animationType: BadgeAnimationType.fade,
badgeColor: Colors.transparent,
showBadge: buddyWarning,
badgeContent: IconButton(
iconSize: 50,
onPressed: () => showDialog(
context: context,
builder: (BuildContext context) {
return DialogCommon(
warning: true,
text: "Warning",
descriptions: t("Attention!"),
description2: t("The safe and exact execution of this exercise you need a training buddy or a trainer"),
description3: t("Execution at your own risk!"),
onTap: () => Navigator.of(context).pop(),
onCancel: () => Navigator.of(context).pop(),
title: t('Training Buddy'),
);
}),
icon: Icon(
CustomIcon.exclamation_circle,
color: Colors.red[800],
)),
child: Column(children: [
MenuImage(
imageName: bloc.getActualImageName(detail.exerciseType!.exerciseTypeId),
workoutTreeId: bloc.getActualWorkoutTreeId(detail.exerciseType!.exerciseTypeId)!,
radius: 0,
filter: !noFilter,
),
Container(
padding: EdgeInsets.only(left: 20, top: 10, bottom: 0),
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('asset/image/WT_zold.jpg'),
fit: BoxFit.cover,
alignment: Alignment.center,
),
),
foregroundDecoration: !noFilter
? BoxDecoration(
color: Colors.black38,
backgroundBlendMode: BlendMode.darken,
)
: null,
height: 80,
width: double.infinity,
child: getExerciseQuantities(detail, step, noFilter),
)
])))),
Container(
padding: EdgeInsets.only(left: 15, bottom: 80, right: 15),
width: double.infinity,
color: Colors.transparent,
child: Text(
detail.exerciseType!.nameTranslation,
maxLines: 3,
style: GoogleFonts.archivoBlack(
color: noFilter ? Colors.white : Colors.grey,
fontSize: 36,
height: 1.1,
shadows: <Shadow>[
Shadow(
offset: Offset(16.0, 16.0),
blurRadius: 16.0,
color: Colors.black54,
),
Shadow(
offset: Offset(16.0, 16.0),
blurRadius: 16.0,
color: Colors.black54,
),
],
),
),
),
]),
);
}
void skip() {
showCupertinoDialog(
useRootNavigator: true,
context: context,
builder: (_) => CupertinoAlertDialog(
title: Text(t("You want to skip really this exercise?")),
content: Column(children: [
Divider(),
]),
actions: [
TextButton(
child: Text(t("No")),
onPressed: () => {
Navigator.pop(context),
}),
TextButton(
child: Text(t("Yes")),
onPressed: () {
Navigator.pop(context);
bloc.add(TrainingPlanSkipExercise(detail: detail));
},
)
],
));
}
}