Merge branch 'fix/level-list' into 'master'

feat: add replay functionality and improve error handling in audio player widget

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!31
This commit is contained in:
Naresh Pratista 2024-12-19 06:23:45 +00:00
commit e6ce79528b
2 changed files with 62 additions and 31 deletions

View File

@ -27,7 +27,6 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
Duration _position = Duration.zero; Duration _position = Duration.zero;
bool _isAudioLoaded = false; bool _isAudioLoaded = false;
String? _errorMessage; String? _errorMessage;
double _volume = 1.0;
bool _isDisposed = false; bool _isDisposed = false;
@override @override
@ -88,6 +87,18 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
setState(() => _position = newPosition); 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() { String _getFullAudioUrl() {
@ -96,6 +107,20 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
: '${widget.baseUrl ?? ''}${widget.audioFileName}'; : '${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() { Widget _buildErrorWidget() {
return Container( return Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
@ -174,7 +199,7 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
), ),
), ),
const SizedBox(width: 12), const SizedBox(width: 12),
_buildVolumeButton(), _buildReplayButton(),
], ],
), ),
if (_errorMessage != null) if (_errorMessage != null)
@ -204,17 +229,36 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
size: 32, size: 32,
), ),
onPressed: _isAudioLoaded onPressed: _isAudioLoaded
? () { ? () async {
try {
if (_playerState == PlayerState.playing) { if (_playerState == PlayerState.playing) {
_audioPlayer.pause(); await _audioPlayer.pause();
} else { } else {
_audioPlayer.resume(); await _audioPlayer.resume();
}
} catch (error) {
if (!_isDisposed) {
setState(() {
_errorMessage = "Failed to control playback: $error";
});
}
} }
} }
: null, : null,
); );
} }
Widget _buildReplayButton() {
return IconButton(
icon: const Icon(
Icons.replay,
color: Colors.blue,
size: 24,
),
onPressed: _isAudioLoaded ? _replayAudio : null,
);
}
Widget _buildTimelineIndicator() { Widget _buildTimelineIndicator() {
return Row( return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@ -243,9 +287,17 @@ class AudioPlayerWidgetState extends State<AudioPlayerWidget>
min: 0.0, min: 0.0,
max: _duration.inSeconds.toDouble(), max: _duration.inSeconds.toDouble(),
onChanged: _isAudioLoaded onChanged: _isAudioLoaded
? (value) { ? (value) async {
try {
final position = Duration(seconds: value.toInt()); final position = Duration(seconds: value.toInt());
_audioPlayer.seek(position); await _audioPlayer.seek(position);
} catch (error) {
if (!_isDisposed) {
setState(() {
_errorMessage = "Failed to seek: $error";
});
}
}
} }
: null, : null,
activeColor: Colors.blue, 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (_errorMessage != null) { if (_errorMessage != null) {