import 'dart:async'; import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:wakelock/wakelock.dart'; class UniversalPage extends StatefulWidget { const UniversalPage({super.key}); @override State createState() => _UniversalPageState(); } class _UniversalPageState extends State { Duration exerciseDuration = const Duration(minutes: 4); Duration shavasanaDuration = const Duration(minutes: 10); late int exNumber = 5; late int totalDuration = exerciseDuration.inSeconds * exNumber + shavasanaDuration.inSeconds; late Timer _timer; late String startText = 'Старт'; final player = AudioPlayer(); bool isStarted() { if (totalDuration == exerciseDuration.inSeconds * exNumber + shavasanaDuration.inSeconds) { return false; } return true; } void startTimer() { Wakelock.enable(); if (startText == 'Пауза') { setState(() { player.dispose(); startText = 'Возобновить'; _timer.cancel(); }); } else { startText = 'Пауза'; const oneSec = Duration(seconds: 1); _timer = Timer.periodic( oneSec, (Timer timer) { if (totalDuration == 0) { player.play(AssetSource('audio/finish.mp3')); stopTimer(); } else if (totalDuration == shavasanaDuration.inSeconds) { player.play(AssetSource('audio/relax.mp3')); setState(() { totalDuration--; }); } else if ((totalDuration - shavasanaDuration.inSeconds) % exerciseDuration.inSeconds == 0 && (totalDuration - shavasanaDuration.inSeconds) > 0) { player.play(AssetSource('audio/start.mp3')); setState(() { totalDuration--; }); } else { setState(() { totalDuration--; }); } }, ); } } void stopTimer() { setState(() { Wakelock.disable(); player.dispose(); _timer.cancel(); startText = 'Старт'; totalDuration = exerciseDuration.inSeconds * exNumber + shavasanaDuration.inSeconds; }); } void setTotalDuration(value) { setState(() { exNumber = value!; totalDuration = exerciseDuration.inSeconds * exNumber + shavasanaDuration.inSeconds; }); } void _showDialog(Widget child) { showCupertinoModalPopup( context: context, builder: (BuildContext context) => Container( height: 216, padding: const EdgeInsets.only(top: 6.0), margin: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, ), color: CupertinoColors.systemBackground.resolveFrom(context), child: SafeArea( top: false, child: child, ), )); } format(Duration duration) { final splitDuration = duration.toString().split(":"); final hours = splitDuration[0]; final minutes = splitDuration[1]; final seconds = splitDuration[2].split('.')[0]; return [hours, minutes, seconds]; } @override void dispose() { _timer.cancel(); player.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Универсальный таймер'), ), body: ListView( padding: const EdgeInsets.all(16.0), children: [ const Center( child: Text( "Количество упражнений", style: TextStyle(fontSize: 22.0), )), const Divider(), CupertinoButton( onPressed: isStarted() ? null : () => _showDialog( CupertinoPicker( backgroundColor: Colors.white, itemExtent: 30, scrollController: FixedExtentScrollController(initialItem: 1), children: [ Text('0'), Text('1'), Text('2'), Text('3'), Text('4'), Text('5'), Text('6'), Text('7'), Text('8'), Text('9'), Text('10'), Text('11'), Text('12'), Text('13'), Text('14'), Text('15'), Text('16'), Text('17'), Text('18'), Text('19'), Text('20'), Text('21'), Text('22'), Text('23'), Text('24'), Text('25') ], onSelectedItemChanged: isStarted() ? null : (value) => setTotalDuration(value), ), ), child: Text( exNumber.toString(), style: const TextStyle( fontSize: 22.0, ), ), ), const Divider(), const Center( child: Text( "Продолжительность каждого упражнения", style: TextStyle(fontSize: 22.0), )), CupertinoButton( onPressed: isStarted() ? null : () => _showDialog( CupertinoTimerPicker( mode: CupertinoTimerPickerMode.ms, initialTimerDuration: exerciseDuration, onTimerDurationChanged: (Duration newDuration) { setState(() { exerciseDuration = newDuration; totalDuration = exerciseDuration.inSeconds * exNumber + shavasanaDuration.inSeconds; }); }, ), ), child: Text( format(exerciseDuration)[1] + ":" + format(exerciseDuration)[2], style: const TextStyle( fontSize: 22.0, ), ), ), const Divider(), const Center( child: Text( "Продолжительность шавасаны", style: TextStyle(fontSize: 22.0), )), CupertinoButton( onPressed: isStarted() ? null : () => _showDialog( CupertinoTimerPicker( mode: CupertinoTimerPickerMode.ms, initialTimerDuration: shavasanaDuration, onTimerDurationChanged: (Duration newDuration) { setState(() { shavasanaDuration = newDuration; totalDuration = exerciseDuration.inSeconds * exNumber + shavasanaDuration.inSeconds; }); }, ), ), child: Text( format(shavasanaDuration)[1] + ":" + format(shavasanaDuration)[2], style: const TextStyle( fontSize: 22.0, ), ), ), const Divider(), Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ ElevatedButton( onPressed: () => startTimer(), child: Text(startText)), const SizedBox(width: 50), ElevatedButton( onPressed: isStarted() ? () => stopTimer() : null, child: const Text('Стоп')) ]), const Divider(), const Center( child: Text( "Осталось практиковать:", style: TextStyle(fontSize: 22.0), )), const Divider(), Center( child: Text( "${format(Duration(seconds: totalDuration)).join(':')}", style: const TextStyle(fontSize: 22.0))) ], )); } }