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/exercise_plan_detail.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:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:modal_progress_hud/modal_progress_hud.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: 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 TestSetExecuteError) { Scaffold.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: () => executeExercise(executeBloc, executeBloc.getNext(), context), 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 = List(); tiles.add(getStartTile(bloc)); tiles.addAll(getExerciseTiles(bloc, context)); tiles.add(getEndTile()); /* if (bloc.isDone100Percent()) { tiles.add(Victory( victory: true, )); } */ 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 = List(); if (bloc.exercisePlanDetails != null) { bloc.exercisePlanDetails.forEach((element) { if (element != null && element.exerciseTypeId != null) { tiles.add(GestureDetector( onDoubleTap: () => print("Execute ${element.exerciseType.nameTranslation}"), onTap: () => executeExercise(bloc, element, context), child: ExerciseTile( bloc: bloc, exercisePlanDetail: element, ))); } }); } return tiles; } void executeExercise(TestSetExecuteBloc bloc, ExercisePlanDetail exercisePlanDetail, BuildContext context) { ExercisePlanDetail next = bloc.getNext(); print("Detail: $next"); if (next != null) { final HashMap args = HashMap(); args['exerciseType'] = exercisePlanDetail.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 StatelessWidget with Trans { final TestSetExecuteBloc bloc; final ExercisePlanDetail exercisePlanDetail; ExerciseTile({this.bloc, this.exercisePlanDetail}); Widget getIndicator(ExercisePlanDetailState state) { ExercisePlanDetail next = bloc.getNext(); bool actual = false; if (next != null) { if (next.exerciseTypeId == 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 = exercisePlanDetail.state; final bool done = state.equalsTo(ExercisePlanDetailState.finished); final String countSerie = exercisePlanDetail.exercises == null ? "1" : (exercisePlanDetail.exercises.length).toString(); final String serie = 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: bloc.getActualImageName(exercisePlanDetail.exerciseType.exerciseTypeId), workoutTreeId: bloc.getActualWorkoutTreeId(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: 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, ), ], )), exercisePlanDetail.exerciseType.unitQuantityUnit != null ? TextSpan( text: "\n", ) : TextSpan(), exercisePlanDetail.exerciseType.unitQuantityUnit != null ? TextSpan( text: t(exercisePlanDetail.exerciseType.unitQuantityUnit) + ": ", style: GoogleFonts.inter( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)) : TextSpan(), exercisePlanDetail.exerciseType.unitQuantityUnit != null ? TextSpan( text: t(bloc.getExerciseWeight(exercisePlanDetail)), style: GoogleFonts.inter( fontSize: 12, )) : TextSpan(), TextSpan( text: "\n", ), TextSpan( text: t(exercisePlanDetail.exerciseType.unit) + ": ", style: GoogleFonts.inter( fontSize: 12, color: done ? Colors.grey[100] : Colors.yellow[400], fontWeight: FontWeight.bold)), TextSpan( text: bloc.repeatTimesText(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, )), ]), )), ]), ), ), ); } }