import 'dart:collection'; import 'package:aitrainer_app/bloc/menu/menu_bloc.dart'; import 'package:aitrainer_app/bloc/test_set_execute/test_set_execute_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/repository/exercise_repository.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/menu_image.dart'; import 'package:aitrainer_app/widgets/victory_widget.dart'; import 'package:ezanimation/ezanimation.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 TestSetExecute extends StatelessWidget with Trans { @override Widget build(BuildContext context) { // ignore: close_sinks final MenuBloc menuBloc = BlocProvider.of(context); // ignore: close_sinks TestSetExecuteBloc executeBloc = BlocProvider.of(context); executeBloc.menuBloc = menuBloc; executeBloc.add(TestSetExecuteLoad()); setContext(context); return Scaffold( appBar: AppBarNav(depth: 0), 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 TestSetExecuteError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(backgroundColor: Colors.orange, content: Text(state.message, style: TextStyle(color: Colors.white)))); } else if (state is TestSetExecuteFinished) { showDialog( context: context, barrierDismissible: true, builder: (BuildContext context) { return Victory( victory: true, ); }); } }, builder: (context, state) { executeBloc = BlocProvider.of(context); return ModalProgressHUD( child: getExercises(executeBloc, context), inAsyncCall: state is TestSetExecuteLoading, opacity: 0.5, color: Colors.black54, progressIndicator: CircularProgressIndicator(), ); }), ), floatingActionButton: FloatingActionButton.extended( onPressed: () => executeBloc.getNext() != null ? executeExercise(executeBloc, executeBloc.getNext()!, context) : Navigator.of(context).pushNamed('home'), backgroundColor: Colors.orange[800], icon: Icon(CustomIcon.weight_hanging), label: Text( t("Next"), style: GoogleFonts.inter(fontWeight: FontWeight.bold, fontSize: 16), ), ), ); } Widget getExercises(TestSetExecuteBloc bloc, BuildContext context) { return CustomScrollView(slivers: [ SliverList(delegate: SliverChildListDelegate(getTiles(bloc, context))), ]); } List getTiles(TestSetExecuteBloc bloc, BuildContext context) { List tiles = []; tiles.add(getStartTile(bloc)); tiles.addAll(getExerciseTiles(bloc, context)); tiles.add(getEndTile()); return tiles; } Widget getStartTile(TestSetExecuteBloc bloc) { return TimelineTile( alignment: TimelineAlign.manual, lineXY: 0.1, isFirst: true, afterLineStyle: const LineStyle( color: Colors.orange, thickness: 6, ), indicatorStyle: IndicatorStyle( width: 40, color: Colors.orange, padding: const EdgeInsets.all(8), iconStyle: IconStyle( color: Colors.white, iconData: Icons.insert_emoticon, ), ), endChild: Container( padding: EdgeInsets.only(top: 30), constraints: const BoxConstraints( minHeight: 120, ), color: Colors.transparent, child: RichText( text: TextSpan( style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white, ), children: [ TextSpan( text: bloc.isFirst() ? t("Start") : t("Continue"), style: GoogleFonts.inter( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.yellow[400], 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, ), ], )), TextSpan( text: t(" your ") + t(bloc.testType), style: GoogleFonts.inter( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.yellow[400], 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, ), ], )), TextSpan( text: "\n", style: GoogleFonts.inter( fontSize: 16, color: Colors.white, )), TextSpan( text: bloc.testName == null ? "" : bloc.testName, style: GoogleFonts.inter( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, )), TextSpan( text: t("\nyour plan is available for 24 hours"), style: GoogleFonts.inter( fontSize: 16, color: Colors.white, )) ])), ), ); } Widget getEndTile() { return Container( color: Colors.transparent, child: TimelineTile( alignment: TimelineAlign.manual, lineXY: 0.1, isLast: true, beforeLineStyle: const LineStyle( color: Colors.orange, thickness: 6, ), indicatorStyle: IndicatorStyle( width: 40, color: Colors.orange, padding: const EdgeInsets.all(8), iconStyle: IconStyle( color: Colors.white, iconData: Icons.thumb_up, ), ), endChild: Container( padding: EdgeInsets.only(top: 50), constraints: const BoxConstraints( minHeight: 120, ), color: Colors.transparent, child: RichText( text: TextSpan( style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white, ), children: [ TextSpan( text: "Finish!", style: GoogleFonts.inter( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.yellow[400], 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, ), ], )), ])), ), ), ); } List getExerciseTiles(TestSetExecuteBloc bloc, BuildContext context) { List tiles = []; if (bloc.exercisePlanDetails != null) { bloc.exercisePlanDetails!.forEach((element) { //if (element != null && element.exerciseTypeId != null) { tiles.add(GestureDetector( onDoubleTap: () => print("Execute ${element.exerciseType!.nameTranslation}"), onTap: () => element.state.equalsTo(ExercisePlanDetailState.finished) ? evaluation(bloc, element) : executeExercise(bloc, element, context), child: ExerciseTile( bloc: bloc, exercisePlanDetail: element, ))); //} }); } return tiles; } void evaluation(TestSetExecuteBloc bloc, ExercisePlanDetail planDetail) { if (planDetail.exercises != null && planDetail.exercises!.isNotEmpty) { ExerciseRepository exerciseRepository = ExerciseRepository(); exerciseRepository.start = planDetail.exercises![0].dateAdd; exerciseRepository.exerciseList = Cache().getExercises(); exerciseRepository.actualExerciseList = planDetail.exercises!; print("actualEx ${exerciseRepository.actualExerciseList}"); LinkedHashMap args = LinkedHashMap(); args['exerciseRepository'] = exerciseRepository; args['exercise'] = planDetail.exercises![0]; args['past'] = true; Navigator.of(context).pushNamed('evaluationPage', arguments: args); } } void executeExercise(TestSetExecuteBloc bloc, ExercisePlanDetail exercisePlanDetail, BuildContext context) { ExercisePlanDetail? next = bloc.getNext(); if (next != null) { final HashMap args = HashMap(); args['exerciseType'] = next.exerciseType; args['exercisePlanDetailId'] = exercisePlanDetail.exercisePlanDetailId; args['testSetExecuteBloc'] = bloc; String title = ""; String description = ""; String description2 = ""; if (next.exerciseTypeId != exercisePlanDetail.exerciseTypeId) { title = t("Stop!"); description = t("Please continue with the next exercise in the queue:") + next.exerciseType!.nameTranslation; description2 = t("Or, you can redifine this exercise queue in the Compact Test menu"); } else { if (exercisePlanDetail.state.equalsTo(ExercisePlanDetailState.inProgress)) { final HashMap args = HashMap(); args['exerciseType'] = exercisePlanDetail.exerciseType; args['exercisePlanDetail'] = exercisePlanDetail; args['testSetExecuteBloc'] = bloc; Navigator.of(context).pushNamed('testSetControl', arguments: args); } else { Navigator.of(context).pushNamed('testSetNew', 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'); } } } // ignore: must_be_immutable class ExerciseTile extends StatefulWidget { final TestSetExecuteBloc bloc; final ExercisePlanDetail exercisePlanDetail; ExerciseTile({required this.bloc, required this.exercisePlanDetail}); @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); animation.start(); return true; } Widget getIndicator(ExercisePlanDetailState state) { ExercisePlanDetail? next = widget.bloc.getNext(); bool actual = false; if (next != null) { if (next.exerciseTypeId == widget.exercisePlanDetail.exerciseTypeId) { actual = true; } } if (state.equalsTo(ExercisePlanDetailState.inProgress)) { return ClipRRect( borderRadius: BorderRadius.circular(24.0), child: Container( color: actual ? Colors.green : Colors.orange, 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 { return Image.asset( "asset/image/pict_reps_volumen_db.png", ); } } @override Widget build(BuildContext context) { final ExercisePlanDetailState state = widget.exercisePlanDetail.state; final bool done = state.equalsTo(ExercisePlanDetailState.finished); final String countSerie = widget.exercisePlanDetail.exercises == null ? "1" : (widget.exercisePlanDetail.exercises!.length).toString(); final String serie = widget.exercisePlanDetail.exerciseType!.unitQuantityUnit == null ? "/1" : "/4"; 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(state), ), endChild: Container( padding: EdgeInsets.only(left: 10), child: Row(children: [ Container( width: 120, height: 80, child: MenuImage( imageName: widget.bloc.getActualImageName(widget.exercisePlanDetail.exerciseType!.exerciseTypeId), workoutTreeId: widget.bloc.getActualWorkoutTreeId(widget.exercisePlanDetail.exerciseType!.exerciseTypeId)!, )), SizedBox( width: 10, ), Expanded( child: RichText( text: TextSpan( style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.bold, color: done ? Colors.grey[400] : Colors.white, ), children: [ TextSpan( text: widget.exercisePlanDetail.exerciseType!.nameTranslation, style: GoogleFonts.inter( fontSize: 14, fontWeight: FontWeight.bold, color: done ? Colors.grey[400] : Colors.orange[500], 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.exercisePlanDetail.exerciseType!.unitQuantityUnit != null ? TextSpan( text: "\n", ) : TextSpan(), widget.exercisePlanDetail.exerciseType!.unitQuantityUnit != null ? TextSpan( text: t(widget.exercisePlanDetail.exerciseType!.unitQuantityUnit!) + ": ", style: GoogleFonts.inter( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)) : TextSpan(), widget.exercisePlanDetail.exerciseType!.unitQuantityUnit != null ? TextSpan( text: t(widget.bloc.getExerciseWeight(widget.exercisePlanDetail)), style: GoogleFonts.inter( fontSize: 12, )) : TextSpan(), TextSpan( text: "\n", ), TextSpan( text: t(widget.exercisePlanDetail.exerciseType!.unit) + ": ", style: GoogleFonts.inter( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)), TextSpan( text: widget.bloc.repeatTimesText(widget.exercisePlanDetail), style: GoogleFonts.inter( fontSize: 12, )), TextSpan( text: "\n", ), TextSpan( text: t("Set") + ": ", style: GoogleFonts.inter( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)), TextSpan( text: countSerie + serie, style: GoogleFonts.inter( fontSize: 12, )), ]), )), done ? AnimatedBuilder( animation: animation, builder: (context, snapshot) { return Column(mainAxisAlignment: MainAxisAlignment.center, children: [ Image.asset( "asset/image/kupa.png", width: animation.value, ), Text("Result", style: GoogleFonts.inter(fontSize: 10, color: Colors.white)), ]); }) : Offstage() ]), ), ), ); } }