import 'package:audioplayers/audioplayers.dart'; import 'package:flutter/material.dart'; import '../../app_style/colors.dart'; import '../../app_style/sizing.dart'; class ASoundPlayer extends StatefulWidget { final String? audio; const ASoundPlayer({Key? key, this.audio}) : super(key: key); @override ASoundPlayerState createState() => ASoundPlayerState(); } class ASoundPlayerState extends State { //FlutterSoundPlayer _myPlayer = FlutterSoundPlayer(); bool _sliderMoving = false; Duration? _audioTime; Duration? _audioPosition; String? _audio; bool _isLocalFile = false; bool _failedToLoad = false; AudioPlayer? _audioPlayer; Widget _getAudioButton() { switch (_audioPlayer?.state) { case PlayerState.playing: return IconButton( icon: const Icon(Icons.pause_rounded), onPressed: () async { _failedToLoad = false; await _audioPlayer?.pause(); rebuild(); }); case PlayerState.paused: return IconButton( icon: const Icon(Icons.play_arrow_rounded), onPressed: () async { _failedToLoad = false; await _audioPlayer?.resume(); rebuild(); }); case PlayerState.completed: return IconButton( icon: const Icon(Icons.replay_rounded), onPressed: () async { _failedToLoad = false; await _audioPlayer?.stop(); await _audioPlayer?.resume(); rebuild(); }); case PlayerState.stopped: return IconButton( icon: Icon(_isLocalFile ? Icons.play_circle_fill_outlined : Icons.download_rounded), onPressed: () async { _failedToLoad = false; try { await _audioPlayer?.play( _isLocalFile ? DeviceFileSource(_audio ?? '') : UrlSource(_audio ?? ''), ); rebuild(); } on Exception catch (e) { _failedToLoad = true; } }); default: return IconButton( icon: const Icon(Icons.replay_rounded), onPressed: () async { _failedToLoad = false; try { _audioPlayer?.seek(const Duration(milliseconds: 0)); _audioPlayer?.stop(); await _audioPlayer?.play( _isLocalFile ? DeviceFileSource(_audio ?? '') : UrlSource(_audio ?? ''), ); rebuild(); } on Exception catch (e) { _failedToLoad = true; } }); } } String format(Duration? d) { if (d == null) return "00:00"; return d.toString().substring(2, 7); } rebuild() { if (!mounted) return; setState(() {}); } bool _isLocalUrl(String url) { if (url.isEmpty != false) return false; return url.startsWith("/") || url.startsWith("file://") || url.substring(1).startsWith(':\\'); } @override void initState() { super.initState(); _audioPlayer = AudioPlayer(); _audioPlayer?.release(); _audio = widget.audio; _isLocalFile = _isLocalUrl(_audio ?? ''); _audioPlayer?.setReleaseMode(ReleaseMode.stop); if (_isLocalFile) { _audioPlayer?.setSourceDeviceFile(_audio ?? '').then((value) { rebuild(); }); } else { _audioPlayer?.setReleaseMode(ReleaseMode.stop); } // set up listeners _audioPlayer?.onPositionChanged.listen((Duration duration) { if (!_sliderMoving) { _audioPosition = duration; rebuild(); } //setState(() => position = p); }); _audioPlayer?.onPlayerStateChanged.listen((event) { //_audioPosition = _audioTime; rebuild(); }); _audioPlayer?.onDurationChanged.listen((Duration duration) { _audioTime = duration; rebuild(); }); _audioPlayer?.onSeekComplete.listen((event) { rebuild(); }); } @override void dispose() { super.dispose(); // _myPlayer.closeAudioSession(); _audioPlayer?.release(); _audioPlayer?.dispose(); } @override Widget build(BuildContext context) { if (_audio != widget.audio) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { _audio = widget.audio; if (_isLocalFile) { await _audioPlayer?.setSourceDeviceFile(_audio ?? ''); } else { await _audioPlayer?.setSourceUrl(_audio ?? ''); } _audioPlayer?.seek(const Duration(milliseconds: 0)); _audioPlayer?.stop(); rebuild(); }); } return Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Row( children: [ Material(color: Colors.transparent, child: _getAudioButton()), Expanded( child: Slider( value: _audioPosition?.inMilliseconds.toDouble() ?? 0.0, min: 0, max: _audioTime?.inMilliseconds.toDouble() ?? 60.0, onChangeStart: (value) { _sliderMoving = true; }, onChanged: (value) { _audioPosition = Duration(milliseconds: value.round()); rebuild(); }, onChangeEnd: (value) { _sliderMoving = false; _audioPlayer?.seek(Duration(milliseconds: value.round())); rebuild(); }), ), ], ), Row( children: [ Expanded( child: Visibility( visible: _failedToLoad, child: Row( children: [ Text( "Failed to load", style: Theme.of(context) .textTheme .labelSmall ?.copyWith(color: AColors.red), textScaleFactor: AppStyle.getScaleFactor(context), ), ], ), ), ), Visibility( visible: _audioPlayer?.state != PlayerState.stopped, child: Text( "${format(_audioPosition)}/${format(_audioTime)}", style: Theme.of(context).textTheme.labelSmall, textScaleFactor: AppStyle.getScaleFactor(context), ), ), ], ) ], ); } }