187 lines
5.4 KiB
Dart
187 lines
5.4 KiB
Dart
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<IntervalTimerPage> {
|
|
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 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;
|
|
() async {
|
|
await AudioPlayer().play(UrlSource('assets/go.mp3'));
|
|
}();
|
|
_timer = Timer.periodic(const Duration(seconds: 1), (_) => _tick());
|
|
Future.delayed(const Duration(seconds: 1)).then((value) {
|
|
_playWarmUpMusic();
|
|
});
|
|
}
|
|
|
|
void _resetTimer() {
|
|
() async {
|
|
await coolDownPlayer.dispose();
|
|
await warmUpPlayer.dispose();
|
|
await workoutPlayer.dispose();
|
|
}();
|
|
_isPaused = true;
|
|
_timer?.cancel();
|
|
_currentBlock = 0;
|
|
_currentDuration = _warmupDuration;
|
|
_totalDuration = const Duration(minutes: 35);
|
|
setState(() {});
|
|
}
|
|
|
|
Future<void> _playWarmUpMusic() async {
|
|
await warmUpPlayer.setReleaseMode(ReleaseMode.loop);
|
|
await warmUpPlayer.play(UrlSource('assets/warmUp.mp3'));
|
|
}
|
|
|
|
Future<void> _playWorkoutMusic() async {
|
|
await warmUpPlayer.dispose();
|
|
Future.delayed(const Duration(microseconds: 600)).then((value) async {
|
|
await workoutPlayer.play(UrlSource('assets/workout.mp3'));
|
|
});
|
|
}
|
|
|
|
Future<void> _intervalChange() async {
|
|
await AudioPlayer().play(UrlSource('assets/beep.mp3'));
|
|
}
|
|
|
|
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.dispose();
|
|
await coolDownPlayer.play(UrlSource('assets/cool_down.mp3'));
|
|
}();
|
|
} else {
|
|
() async {
|
|
Future.delayed(const Duration(microseconds: 900))
|
|
.then((value) async {
|
|
await AudioPlayer().play(UrlSource('assets/finish.mp3'));
|
|
});
|
|
}();
|
|
_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) {
|
|
return Scaffold(
|
|
body: Center(
|
|
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();
|
|
}
|
|
},
|
|
),
|
|
// ),
|
|
],
|
|
),
|
|
],
|
|
)));
|
|
}
|
|
}
|