0

I'm working on a Flutter Workout App and I'm having some issues implementing the Workout Sequence and Timer.

I was able to implement the auto countdown and workout sequence however, the countdown skips numbers between and the workout sequence runs only for the first 2 sets.

For example, if an exercise has 4 sets, the cycle only runs for the first two and it's glitchy. I need help with optimized code to help me achieve the workout sequence

JSON DATA

{
    "data": {
        "day1": [
            {
                "id": 1,
                "title": "Reclining Triceps Press",
                "equipment": "Pull Up Bar",
                "level": "Beginner",
                "reps": "15",
                "rest": "45 Seconds",
                "sets": "4",
                "image": "https://wicombit.com/demo/fitpro/images/exercise_1519941887.jpg",
                "video": null,
            },
            {
                "id": 10,
                "title": "Plank with Arm Raise",
                "equipment": "Pull Up Bar",
                "level": "Intermediate",
                "reps": "12",
                "rest": "30 Seconds",
                "sets": "3",
                "image": "https://wicombit.com/demo/fitpro/images/exercise_1519938568.jpg",
                "video": null,
            },
            {
                "id": 3,
                "title": "90-degree Static Hold",
                "equipment": "Pull Up Bar",
                "level": "Beginner",
                "reps": "12",
                "rest": "45 Seconds",
                "sets": "3",
                "image": "https://wicombit.com/demo/fitpro/images/exercise_1519940878.jpg",
                "video": null,
            },
            {
                "id": 5,
                "title": "Single-arm Medicine Ball Pushup",
                "equipment": "Kettlebells",
                "level": "Elite",
                "reps": "8",
                "rest": "45 Seconds",
                "sets": "3",
                "image": "https://wicombit.com/demo/fitpro/images/exercise_1519940316.jpg",
                "video": null,
                "status": "draft"
            }
        ],
    }
}

I have tried the below implementation but not getting the results I want.

Dart Implementation

class WorkouStartSequenceScreen extends StatefulWidget {
  final exercise;

  WorkouStartSequenceScreen({super.key, required this.exercise});

  @override
  State<WorkouStartSequenceScreen> createState() =>
      _WorkouStartSequenceScreenState();
}

class _WorkouStartSequenceScreenState extends State<WorkouStartSequenceScreen> {
  late Timer _startTimer;
  late Timer _restTimer;
  late int totalNoOfExercisesInDay;
  int currentExerciseIndex = 0;
  late int totalNoOfSets;
  late int totalNoOfReps;
  late int totalRestTime;
  int currentSetNo = 0;
  int currentRepNo = 0;
  int currentRestTime = 0;
  bool dayWorkoutComplete = false;
  int startUpCountdown = 10;
  StreamController<int> _startEvents = BehaviorSubject();
  StreamController<int> _restEvents = BehaviorSubject();

  @override
  void initState() {
    totalNoOfExercisesInDay = widget.exercise.length;
    totalNoOfReps = int.parse(widget.exercise[currentExerciseIndex].reps);
    totalNoOfSets = int.parse(widget.exercise[currentExerciseIndex].sets);
    totalRestTime = int.parse(widget.exercise[currentExerciseIndex].rest
        .replaceAll(new RegExp(r'[^0-9]'), ''));
    currentRestTime = totalRestTime;
    _startEvents.add(startUpCountdown);

    super.initState();
  }

  @override
  void dispose() {
    _startTimer.cancel();
    _restTimer.cancel();
    // _startEvents.close();
    // _restEvents.close();
    super.dispose();
  }

  void _showStartupDialog() async {
    _startTimer = Timer.periodic(Duration(seconds: 1), (timer) {
      (startUpCountdown > 0) ? startUpCountdown-- : _startTimer.cancel();

      _startEvents.add(startUpCountdown);
    });

    showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext builderContext) {
          _startTimer = Timer(Duration(seconds: 10), () {
            Navigator.of(context).pop();
          });

          return AlertDialog(
            backgroundColor: AppStyles.primaryColor,
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text('Your workout starts in',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        color: Colors.white, fontSize: SizeConfig.font20)),
                SizedBox(height: SizeConfig.height20),
                StreamBuilder<int>(
                    stream: _startEvents.stream,
                    builder:
                        (BuildContext context, AsyncSnapshot<int> snapshot) {
                      return Text('${snapshot.data.toString()}',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: SizeConfig.font50));
                    }),
              ],
            ),
          );
        }).then((val) {
      if (_startTimer.isActive) {
        _startTimer.cancel();
      }
    });
  }

  void startRestTimer() async {
    _restTimer = Timer.periodic(Duration(seconds: 1), (timer) {
      (currentRestTime > 0) ? currentRestTime-- : _restTimer.cancel();

      _restEvents.add(currentRestTime);
    });

    showDialog(
        context: context,
        barrierDismissible: false,
        builder: (BuildContext builderContext) {
          _restTimer = Timer(Duration(seconds: totalRestTime), () {
            Navigator.of(context).pop();
          });

          return AlertDialog(
            backgroundColor: AppStyles.primaryColor,
            content: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Text('REST',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                        color: Colors.white, fontSize: SizeConfig.font20)),
                SizedBox(height: SizeConfig.height20),
                StreamBuilder<int>(
                    stream: _restEvents.stream,
                    builder:
                        (BuildContext context, AsyncSnapshot<int> snapshot) {
                      return Text('${snapshot.data.toString()}',
                          textAlign: TextAlign.center,
                          style: TextStyle(
                              color: Colors.white,
                              fontSize: SizeConfig.font50));
                    }),
              ],
            ),
          );
        }).then((_) {
      print("Next Set Starting");
      setState(() {
        currentRepNo = 0;
        currentRestTime = int.parse(widget.exercise[currentExerciseIndex].rest
            .replaceAll(new RegExp(r'[^0-9]'), ''));
        startExercise();
      });
      _restTimer.cancel();
    });
  }

  void startExercise() {
    const oneSec = const Duration(seconds: 2);
    new Timer.periodic(
      oneSec,
      (Timer timer) {
        if (currentRepNo == totalNoOfReps) {
          setState(() {
            timer.cancel();
            startRestTimer();
            currentSetNo++;

            if (currentSetNo == totalNoOfSets) {
              currentExerciseIndex++;
            }
          });
        } else {
          setState(() {
            currentRepNo++;
          });
        }
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.blueGrey[100],
      appBar: AppBar(
        backgroundColor: AppStyles.primaryDark,
        leading: GestureDetector(
            onTap: () => Get.back(),
            child: Icon(FontAwesomeIcons.xmark,
                color: AppStyles.appSecondaryColor)),
      ),
      body: Column(children: [
        Image.network(widget.exercise[currentExerciseIndex].image),
        SizedBox(height: SizeConfig.height20),
        TitleTextWidget(
            titleText: widget.exercise[currentExerciseIndex].title,
            titleSize: SizeConfig.font25,
            titleTextMaxLines: 3),
        SizedBox(height: SizeConfig.height50),
        Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [
          Column(children: [
            Row(children: [
              TitleTextWidget(
                titleText: ("$currentRepNo"),
                titleSize: SizeConfig.font80,
              ),
              Text("/", style: TextStyle(fontSize: SizeConfig.font80)),
              DescriptionTextWidget(
                  descriptionText: widget.exercise[currentExerciseIndex].reps,
                  descriptionSize: SizeConfig.font80,
                  fontFamily: 'Raleway'),
            ]),
            SizedBox(height: SizeConfig.height20),
            DescriptionTextWidget(
                descriptionText: 'Reps',
                fontFamily: 'Raleway',
                descriptionSize: SizeConfig.font30)
          ]),
          Column(children: [
            Row(children: [
              TitleTextWidget(
                titleText: currentSetNo.toString(),
                titleSize: SizeConfig.font80,
              ),
              Text("/", style: TextStyle(fontSize: SizeConfig.font80)),
              DescriptionTextWidget(
                  descriptionText: widget.exercise[currentExerciseIndex].sets,
                  descriptionSize: SizeConfig.font80,
                  fontFamily: 'Raleway'),
            ]),
            SizedBox(height: SizeConfig.height20),
            DescriptionTextWidget(
                descriptionText: 'Sets',
                fontFamily: 'Raleway',
                descriptionSize: SizeConfig.font30)
          ])
        ]),
        SizedBox(height: SizeConfig.height30),
        GestureDetector(
          onTap: () {
            _showStartupDialog();
            Future.delayed(const Duration(seconds: 10), () {
              startExercise();
            });
          },
          child: Container(
            height: SizeConfig.height70,
            width: double.maxFinite,
            margin: EdgeInsets.symmetric(
                horizontal: SizeConfig.width20, vertical: SizeConfig.height5),
            decoration: BoxDecoration(
                color: AppStyles.primaryColor,
                borderRadius: BorderRadius.circular(
                  SizeConfig.radius15,
                )),
            child: Padding(
              padding: EdgeInsets.symmetric(
                  horizontal: SizeConfig.width40,
                  vertical: SizeConfig.height10),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: [
                  Icon(FontAwesomeIcons.play, color: Colors.white),
                  SizedBox(width: SizeConfig.width10),
                  Text(
                    "Start",
                    style: TextStyle(
                        color: Colors.white,
                        fontSize: SizeConfig.font25,
                        fontWeight: FontWeight.w500),
                  ),
                ],
              ),
            ),
          ),
        )
      ]),
    );
  }
}

Sharada Sharma
  • 129
  • 1
  • 11

0 Answers0