diff --git a/lib/features/home/screens/page_view.dart b/lib/features/home/screens/page_view.dart deleted file mode 100644 index e69de29..0000000 diff --git a/lib/features/learning/modules/material/widgets/audio_player_widget.dart b/lib/features/learning/modules/material/widgets/audio_player_widget.dart index b1502f9..b168b95 100644 --- a/lib/features/learning/modules/material/widgets/audio_player_widget.dart +++ b/lib/features/learning/modules/material/widgets/audio_player_widget.dart @@ -27,7 +27,6 @@ class AudioPlayerWidgetState extends State 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 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 : '${widget.baseUrl ?? ''}${widget.audioFileName}'; } + Future _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 ), ), const SizedBox(width: 12), - _buildVolumeButton(), + _buildReplayButton(), ], ), if (_errorMessage != null) @@ -204,17 +229,36 @@ class AudioPlayerWidgetState extends State size: 32, ), onPressed: _isAudioLoaded - ? () { - if (_playerState == PlayerState.playing) { - _audioPlayer.pause(); - } else { - _audioPlayer.resume(); + ? () async { + try { + if (_playerState == PlayerState.playing) { + await _audioPlayer.pause(); + } else { + 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 min: 0.0, max: _duration.inSeconds.toDouble(), onChanged: _isAudioLoaded - ? (value) { - final position = Duration(seconds: value.toInt()); - _audioPlayer.seek(position); + ? (value) async { + try { + final position = Duration(seconds: value.toInt()); + 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 ); } - 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) {