import 'dart:async'; import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.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(seconds: 35); 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() { _isPaused = false; _timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick()); } void _pauseTimer() { _isPaused = true; _timer?.cancel(); } void _resetTimer() { _isPaused = true; _timer?.cancel(); _currentBlock = 0; _currentDuration = _warmupDuration; _totalDuration = const Duration(minutes: 35); setState(() {}); } Future _playSoundEffect() async { final player = AudioPlayer(); await player.play(UrlSource('assets/beep.mp3')); } void _tick() { setState(() { _currentDuration = Duration( seconds: _currentDuration.inSeconds - 1, ); _totalDuration = Duration( seconds: _totalDuration.inSeconds - 1, ); if (_currentDuration.inSeconds == 0) { _playSoundEffect(); } if (_currentDuration.inSeconds < 0) { if (_currentBlock == 0) { // Start high intensity blocks. _currentBlock++; _currentDuration = _highIntensityDuration; } else if (_currentBlock <= _numHighIntensityBlocks) { // Start low intensity blocks. _currentBlock++; _currentDuration = _lowIntensityDuration; } else if (_currentBlock <= _numHighIntensityBlocks + _numLowIntensityBlocks) { // Start high intensity blocks again. _currentBlock++; _currentDuration = _highIntensityDuration; } else { // End workout. _currentDuration = _cooldownDuration; _pauseTimer(); } } }); } 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) { return Scaffold( appBar: AppBar( title: const Text('Interval Timer'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( _currentBlock == 0 ? 'Warm-up' : _currentBlock <= _numHighIntensityBlocks ? 'High Intensity' : 'Low Intensity', 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 { _pauseTimer(); _resetTimer(); } }, ), // ), ], ), ], ))); } }