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.dart'; import 'package:aitrainer_app/model/exercise_type.dart'; import 'package:aitrainer_app/model/workout_menu_tree.dart'; import 'package:aitrainer_app/library/tree_view.dart'; import 'package:aitrainer_app/util/enums.dart'; import 'package:aitrainer_app/util/trans.dart'; import 'package:aitrainer_app/widgets/app_bar.dart'; import 'package:aitrainer_app/widgets/bottom_nav.dart'; import 'package:aitrainer_app/widgets/menu_image.dart'; import 'package:aitrainer_app/widgets/treeview_parent_widget.dart'; import 'package:ezanimation/ezanimation.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'; import 'package:timeline_tile/timeline_tile.dart'; // ignore: must_be_immutable class TrainingPlanCustomPage extends StatefulWidget { @override _ExercisePlanCustomPage createState() => _ExercisePlanCustomPage(); } class _ExercisePlanCustomPage extends State with Trans { TrainingPlanBloc? bloc; final GlobalKey _scaffoldKey = new GlobalKey(); @override Widget build(BuildContext context) { setContext(context); bloc = BlocProvider.of(context); bloc!.menuBloc.menuTreeRepository.sortByMuscleType(); return Scaffold( key: _scaffoldKey, appBar: AppBarNav(depth: 1), body: Container( padding: EdgeInsets.all(20), decoration: BoxDecoration( image: DecorationImage( image: AssetImage('asset/image/WT_black_background.jpg'), fit: BoxFit.cover, alignment: Alignment.center, ), ), child: BlocConsumer(listener: (context, state) { if (state is TrainingPlanError) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( state.message, ), backgroundColor: Colors.orange, )); } }, builder: (context, state) { return ModalProgressHUD( child: exerciseWidget(bloc!), inAsyncCall: state is TrainingPlanLoading, opacity: 0.5, color: Colors.black54, progressIndicator: CircularProgressIndicator(), ); })), bottomNavigationBar: BottomNavigator(bottomNavIndex: 2), floatingActionButton: FloatingActionButton.extended( onPressed: () => Navigator.of(context).popAndPushNamed('myTrainingPlanExecute'), backgroundColor: Colors.orange[800], icon: Icon(CustomIcon.weight_hanging), label: Text( t("Start") + "!", style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16), ), ), ); } Widget exerciseWidget(TrainingPlanBloc bloc) { return TreeView( startExpanded: false, children: _getTreeChildren(bloc), ); } List _getTreeChildren(TrainingPlanBloc bloc) { List exerciseTypes = []; Card explanation = Card( color: Colors.white60, child: Container( padding: EdgeInsets.only(left: 10, right: 5, top: 12, bottom: 8), child: Column( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ Row( children: [ Icon( Icons.info, color: Colors.orangeAccent, ), Text(" "), Text( t("Custom Exercise Plan"), style: GoogleFonts.archivoBlack(fontSize: 20), ), ], ), Divider( color: Colors.transparent, ), Text( t("Select manually the exercises what you would like to have in your plan. At the end don't forget to save."), style: GoogleFonts.inter(fontSize: 12, fontWeight: FontWeight.normal), ), ], ))); exerciseTypes.add(explanation); bloc.menuBloc.menuTreeRepository.sortedTree.forEach((name, list) { exerciseTypes.add(Container( margin: const EdgeInsets.only(left: 4.0), child: TreeViewChild( startExpanded: bloc.existsAddedExerciseTypeInTree(name), parent: TreeviewParentWidget(text: name), children: getTiles(list, bloc), ))); }); return exerciseTypes; } List getTiles(List list, TrainingPlanBloc bloc) { List tiles = []; tiles.addAll(getExerciseTiles(bloc, list)); return tiles; } List getExerciseTiles(TrainingPlanBloc bloc, List listWorkoutTree) { List tiles = []; listWorkoutTree.forEach((element) { tiles.add(GestureDetector( onTap: () => {}, child: ExerciseTile( bloc: bloc, exerciseType: element.exerciseType!, ))); }); return tiles; } } class ExerciseTile extends StatefulWidget { final TrainingPlanBloc bloc; final ExerciseType exerciseType; ExerciseTile({required this.bloc, required this.exerciseType}); @override _ExerciseTileState createState() => _ExerciseTileState(); } class _ExerciseTileState extends State with Trans { final EzAnimation animation = EzAnimation(1.0, 30.0, Duration(seconds: 3), reverseCurve: Curves.easeIn); @override void initState() { animation.start(); animation.addStatusListener((status) { if (status == AnimationStatus.completed) {} }); super.initState(); } @override bool didUpdateWidget(ExerciseTile oldWidget) { super.didUpdateWidget(oldWidget); Future.delayed(Duration(milliseconds: 400)).then((value) => animation.start()); return true; } void activateCustomPlan() { widget.bloc.add(TrainingPlanAddLoad(exerciseType: widget.exerciseType)); Navigator.of(context).popAndPushNamed("myTrainingPlanCustomAdd"); } Widget getIndicator() { if (widget.exerciseType.trainingPlanState.equalsTo(ExerciseTypeTrainingPlanState.none)) { return GestureDetector( onTap: () { if (widget.bloc.getMyPlan() != null && !widget.bloc.getMyPlan()!.type.equalsTo(CustomerTrainingPlanType.custom)) { showCupertinoDialog( useRootNavigator: true, context: context, builder: (_) => CupertinoAlertDialog( title: Text(t("You have an active Training Plan")), content: Column(children: [ Divider(), Text( t("Do you want to override it?"), style: (TextStyle(color: Colors.blue)), ), ]), actions: [ TextButton( child: Text(t("No")), onPressed: () => Navigator.pop(context), ), TextButton( child: Text(t("Yes")), onPressed: () => activateCustomPlan(), ) ], )); } else { activateCustomPlan(); } }, child: ClipRRect( borderRadius: BorderRadius.circular(24.0), child: Container( color: Colors.blue, child: Icon( CustomIcon.plus_1, size: 28, color: Colors.white, )))); } else if (widget.exerciseType.trainingPlanState.equalsTo(ExerciseTypeTrainingPlanState.added)) { return GestureDetector( onTap: () => widget.bloc.add(TrainingPlanDeleteExerciseType(exerciseType: widget.exerciseType)), child: ClipRRect( borderRadius: BorderRadius.circular(24.0), child: Container( padding: EdgeInsets.only(left: 8, bottom: 3), color: Colors.red[400], child: Text("X", style: GoogleFonts.archivoBlack( fontSize: 30, color: Colors.white, ))))); } else { return ClipRRect( borderRadius: BorderRadius.circular(24.0), child: Container( color: Colors.blue, child: Icon( CustomIcon.down, size: 28, color: Colors.white, ))); } } @override Widget build(BuildContext context) { bool added = widget.exerciseType.trainingPlanState.equalsTo(ExerciseTypeTrainingPlanState.added); setContext(context); 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(), ), endChild: Container( padding: EdgeInsets.only(left: 10), child: Row(children: [ Container( width: 120, height: 80, child: MenuImage( imageName: widget.bloc.getActualImageName(widget.exerciseType.exerciseTypeId), workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.exerciseType.exerciseTypeId)!, ), ), SizedBox( width: 10, ), Expanded( child: RichText( text: TextSpan( style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.bold, color: added ? Colors.white : Colors.grey, ), children: [ TextSpan( text: widget.exerciseType.nameTranslation, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.bold, color: added ? Colors.orange[500] : Colors.white, shadows: [ 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.exerciseType.unitQuantityUnit != null ? TextSpan( text: "\n", ) : TextSpan(), widget.exerciseType.unitQuantityUnit != null ? TextSpan( text: t(widget.exerciseType.unitQuantityUnit!) + ": ", style: GoogleFonts.inter( fontSize: 12, color: added ? Colors.yellow[400] : Colors.grey, fontWeight: FontWeight.bold)) : TextSpan(), widget.exerciseType.unitQuantityUnit != null ? TextSpan( text: added ? widget.bloc.getWeightByExerciseType(widget.exerciseType) : "?", style: GoogleFonts.inter( fontSize: 12, )) : TextSpan(), TextSpan( text: "\n", ), TextSpan( text: t(widget.exerciseType.unit) + ": ", style: GoogleFonts.inter(fontSize: 12, color: added ? Colors.yellow[400] : Colors.grey, fontWeight: FontWeight.bold)), TextSpan( text: added ? widget.bloc.getRepeatsByExerciseType(widget.exerciseType) : "?", style: GoogleFonts.inter( fontSize: 12, )), TextSpan( text: "\n", ), TextSpan( text: t("Set") + ": ", style: GoogleFonts.inter(fontSize: 12, color: added ? Colors.yellow[400] : Colors.grey, fontWeight: FontWeight.bold)), TextSpan( text: added ? widget.bloc.getSetByExerciseType(widget.exerciseType) : "?", style: GoogleFonts.inter( fontSize: 12, )), ]), )), ]), ), ), ); } }