feat: add replay functionality and improve error handling in audio player widget
This commit is contained in:
parent
21e90e1b16
commit
2f1eef5f1a
|
|
@ -27,7 +27,6 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
Duration _position = Duration.zero;
|
||||
bool _isAudioLoaded = false;
|
||||
String? _errorMessage;
|
||||
double _volume = 1.0;
|
||||
bool _isDisposed = false;
|
||||
|
||||
@override
|
||||
|
|
@ -88,6 +87,18 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
setState(() => _position = newPosition);
|
||||
}
|
||||
});
|
||||
|
||||
// Add completion listener
|
||||
_audioPlayer.onPlayerComplete.listen((_) {
|
||||
if (!_isDisposed) {
|
||||
setState(() {
|
||||
_position = Duration.zero;
|
||||
_playerState = PlayerState.stopped;
|
||||
});
|
||||
// Reset source when playback completes
|
||||
_audioPlayer.setSource(UrlSource(_getFullAudioUrl()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
String _getFullAudioUrl() {
|
||||
|
|
@ -96,6 +107,20 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
: '${widget.baseUrl ?? ''}${widget.audioFileName}';
|
||||
}
|
||||
|
||||
Future<void> _replayAudio() async {
|
||||
try {
|
||||
await _audioPlayer.seek(Duration.zero);
|
||||
await _audioPlayer.setSource(UrlSource(_getFullAudioUrl()));
|
||||
await _audioPlayer.resume();
|
||||
} catch (error) {
|
||||
if (!_isDisposed) {
|
||||
setState(() {
|
||||
_errorMessage = "Failed to replay audio: $error";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildErrorWidget() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
|
|
@ -174,7 +199,7 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
_buildVolumeButton(),
|
||||
_buildReplayButton(),
|
||||
],
|
||||
),
|
||||
if (_errorMessage != null)
|
||||
|
|
@ -204,17 +229,36 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
size: 32,
|
||||
),
|
||||
onPressed: _isAudioLoaded
|
||||
? () {
|
||||
? () async {
|
||||
try {
|
||||
if (_playerState == PlayerState.playing) {
|
||||
_audioPlayer.pause();
|
||||
await _audioPlayer.pause();
|
||||
} else {
|
||||
_audioPlayer.resume();
|
||||
await _audioPlayer.resume();
|
||||
}
|
||||
} catch (error) {
|
||||
if (!_isDisposed) {
|
||||
setState(() {
|
||||
_errorMessage = "Failed to control playback: $error";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildReplayButton() {
|
||||
return IconButton(
|
||||
icon: const Icon(
|
||||
Icons.replay,
|
||||
color: Colors.blue,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: _isAudioLoaded ? _replayAudio : null,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTimelineIndicator() {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
|
|
@ -243,9 +287,17 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
min: 0.0,
|
||||
max: _duration.inSeconds.toDouble(),
|
||||
onChanged: _isAudioLoaded
|
||||
? (value) {
|
||||
? (value) async {
|
||||
try {
|
||||
final position = Duration(seconds: value.toInt());
|
||||
_audioPlayer.seek(position);
|
||||
await _audioPlayer.seek(position);
|
||||
} catch (error) {
|
||||
if (!_isDisposed) {
|
||||
setState(() {
|
||||
_errorMessage = "Failed to seek: $error";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
activeColor: Colors.blue,
|
||||
|
|
@ -254,27 +306,6 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildVolumeButton() {
|
||||
return IconButton(
|
||||
icon: Icon(
|
||||
_volume == 0.0 ? Icons.volume_off : Icons.volume_up,
|
||||
color: _volume == 0.0 ? Colors.grey : Colors.blue,
|
||||
size: 24,
|
||||
),
|
||||
onPressed: _isAudioLoaded
|
||||
? () {
|
||||
if (_volume == 0.0) {
|
||||
_audioPlayer.setVolume(1.0);
|
||||
setState(() => _volume = 1.0);
|
||||
} else {
|
||||
_audioPlayer.setVolume(0.0);
|
||||
setState(() => _volume = 0.0);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_errorMessage != null) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user