import 'dart:async'; import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:smoke_cess_app/providers/timer_provider.dart'; import 'package:smoke_cess_app/providers/workout_provider.dart'; import 'package:smoke_cess_app/widgets/popup_for_start_and_stop.dart'; import 'package:smoke_cess_app/widgets/timer_widget.dart'; import 'package:smoke_cess_app/widgets/workout_timer_widget.dart'; import '../providers/input_provider.dart'; class IntervalTimerPage extends StatefulWidget { const IntervalTimerPage({Key? key}) : super(key: key); @override _IntervalTimerPageState createState() => _IntervalTimerPageState(); } class _IntervalTimerPageState extends State { final Duration _warmupDuration = const Duration(seconds: 5); final Duration _cooldownDuration = const Duration(seconds: 5); final Duration _highIntensityDuration = const Duration(seconds: 4); final Duration _lowIntensityDuration = const Duration(seconds: 3); late Duration _totalDuration = const Duration(minutes: 35); AudioPlayer warmUpPlayer = AudioPlayer(); AudioPlayer workoutPlayer = AudioPlayer(); AudioPlayer coolDownPlayer = AudioPlayer(); final AudioCache _audioCache = AudioCache(); final int _numHighIntensityBlocks = 4; final int _numLowIntensityBlocks = 3; Timer? _timer; int _currentBlock = 0; Duration _currentDuration = const Duration(); bool _isPaused = true; @override void initState() { _currentDuration = _warmupDuration; super.initState(); } @override void dispose() { _timer?.cancel(); super.dispose(); } void _startTimer() async { await showDialog( context: context, builder: (BuildContext context) { return ChangeNotifierProvider( create: (context) => InputProvider(), child: const TimerStartStopPopup( title: 'Motivation vor dem Training', )); }, ); _isPaused = false; Source source = AssetSource('go.mp3'); await AudioPlayer().play(source); _timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick()); Future.delayed(const Duration(seconds: 1)).then((value) { _playWarmUpMusic(); }); } void _resetTimer() { () async { await coolDownPlayer.stop(); await warmUpPlayer.stop(); await workoutPlayer.stop(); }(); _isPaused = true; _timer?.cancel(); _currentBlock = 0; _currentDuration = _warmupDuration; _totalDuration = const Duration(minutes: 35); setState(() {}); showDialog( context: context, builder: (BuildContext context) { return const TimerStartStopPopup( title: 'Motivation nach dem Training', ); }, ); } Future _playWarmUpMusic() async { Source source = AssetSource('warmUp.mp3'); await warmUpPlayer.setReleaseMode(ReleaseMode.loop); await warmUpPlayer.play(source); } Future _playWorkoutMusic() async { await warmUpPlayer.stop(); Future.delayed(const Duration(microseconds: 600)).then((value) async { Source source = AssetSource('workout.mp3'); await workoutPlayer.setReleaseMode(ReleaseMode.loop); await workoutPlayer.play(source); }); } Future _intervalChange() async { Source source = AssetSource('beep.mp3'); await AudioPlayer().play(source); } void _tick() { setState(() { _currentDuration = Duration( seconds: _currentDuration.inSeconds - 1, ); _totalDuration = Duration( seconds: _totalDuration.inSeconds - 1, ); if (_currentDuration.inSeconds < 1) { if (_currentBlock < _numHighIntensityBlocks + _numLowIntensityBlocks) { _intervalChange(); if (_currentBlock == 0) { _playWorkoutMusic(); } _currentBlock++; if (_currentBlock % 2 == 1) { _currentDuration = _highIntensityDuration; } else { _currentDuration = _lowIntensityDuration; } } else if (_currentBlock < _numHighIntensityBlocks * 2) { _intervalChange(); _currentBlock++; _currentDuration = _cooldownDuration; () async { await workoutPlayer.stop(); Source source = AssetSource('cool_down.mp3'); await coolDownPlayer.setReleaseMode(ReleaseMode.loop); await coolDownPlayer.play(source); }(); } else { () async { Future.delayed(const Duration(microseconds: 900)) .then((value) async { Source source = AssetSource('finish.mp3'); await AudioPlayer().play(source); }); }(); _resetTimer(); } } }); } String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, '0'); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); return '$minutes:$seconds'; } String _formatTotalDuration(Duration duration) { final minutes = duration.inMinutes; final seconds = duration.inSeconds.remainder(60); return _formatDuration(Duration(minutes: minutes, seconds: seconds)); } @override Widget build(BuildContext context) { TimerProvider timerProvider = TimerProvider(); return MultiProvider( providers: [ ChangeNotifierProvider(create: (context) => timerProvider), ChangeNotifierProvider( create: (context) => WorkoutProvider(timerProvider)) ], child: WorkoutTimerWidget(), ); ChangeNotifierProvider( create: (context) => TimerProvider(), child: TimerWidget( duration: Duration(seconds: 5), )); return Center( child: ChangeNotifierProvider( create: (context) => InputProvider(), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( _currentBlock == 0 ? 'Warm-up' : _currentBlock % 2 == 1 ? 'High Intensity' : _currentBlock < _numHighIntensityBlocks * 2 ? 'Low Intensity' : 'Cool-down', style: const TextStyle(fontSize: 32.0), ), const SizedBox(height: 16.0), Text( _formatDuration(_currentDuration), style: const TextStyle(fontSize: 80.0), ), const SizedBox(height: 32.0), Text( 'Total: ${_formatTotalDuration(_totalDuration)}', style: const TextStyle(fontSize: 24.0), ), const SizedBox(height: 32.0), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: Icon(_isPaused ? Icons.play_arrow_rounded : Icons.stop_rounded), iconSize: 48.0, onPressed: () { if (_isPaused) { _startTimer(); } else { _resetTimer(); } }, ), // ), ], ), ], ))); } }