diff --git a/lib/services/audio_service.dart b/lib/services/audio_service.dart index 2960fe0..ca3909f 100644 --- a/lib/services/audio_service.dart +++ b/lib/services/audio_service.dart @@ -443,11 +443,16 @@ class AudioService extends ChangeNotifier { // ════════════════════════════════════════════════════════════ Future next() async { - if (_queue.isEmpty) return; + debugPrint( + '🎵 [next] CALLED: index=$_currentIndex, total=${_queue.length}, isChangingTrack=$_isChangingTrack'); + + if (_queue.isEmpty) { + debugPrint('⚠️ [next] queue is empty'); + return; + } - // ⭐ 如果正在切换歌曲,忽略本次请求 if (_isChangingTrack) { - debugPrint('⚠️ [AudioService] next() ignored: track switch in progress'); + debugPrint('⚠️ [next] REJECTED: track switch in progress'); return; } @@ -611,38 +616,41 @@ class AudioService extends ChangeNotifier { // ⭐ 完整生命周期校验的 completed 监听 _subscriptions.add( player.stream.completed.listen((_) { + debugPrint( + '🎵 [completed event] RAW: index=$_currentIndex, isChangingTrack=$_isChangingTrack'); + if (_isChangingTrack) { - debugPrint('⚠️ [AudioService] completed ignored during track switch'); + debugPrint('⚠️ [completed] REJECTED: track switch in progress'); return; } if (!_hasStartedCurrentPlayback) { - debugPrint( - '⚠️ [AudioService] completed ignored: playback never started'); + debugPrint('⚠️ [completed] REJECTED: playback never started'); return; } if (_handlingCompletion) { - debugPrint('⚠️ [service] completed ignored: already handling'); + debugPrint('⚠️ [completed] REJECTED: already handling'); return; } final pos = player.state.position; final dur = player.state.duration; + debugPrint('🎵 [completed] pos=$pos, dur=$dur'); + if (dur.inMilliseconds <= 0) { - debugPrint( - '⚠️ [AudioService] completed ignored: invalid duration $dur'); + debugPrint('⚠️ [completed] REJECTED: invalid duration $dur'); return; } - if (pos.inMilliseconds < dur.inMilliseconds - 500) { - debugPrint( - '⚠️ [AudioService] completed ignored: position=$pos, duration=$dur'); + final diff = dur.inMilliseconds - pos.inMilliseconds; + debugPrint('🎵 [completed] diff=${diff}ms'); + if (pos.inMilliseconds < dur.inMilliseconds - 800) { + debugPrint('⚠️ [completed] REJECTED: not at end, diff=${diff}ms'); return; } - debugPrint( - '🎵 [AudioService] valid completed: index=$_currentIndex, pos=$pos, dur=$dur'); + debugPrint('✅ [completed] ACCEPTED: index=$_currentIndex'); _handlingCompletion = true; _onPlaybackCompleted(); }), @@ -658,23 +666,41 @@ class AudioService extends ChangeNotifier { } void _onPlaybackCompleted() { - if (_queue.isEmpty || _currentIndex < 0 || _currentIndex >= _queue.length) { - debugPrint('⚠️ [service] completed ignored: invalid queue'); + debugPrint( + '🎵 [onPlaybackCompleted] ENTERED: index=$_currentIndex, total=${_queue.length}, mode=$_playMode'); + + if (_queue.isEmpty) { + debugPrint('⚠️ [onPlaybackCompleted] queue is empty, returning'); _handlingCompletion = false; return; } - if (_currentIndex + 1 >= _queue.length && _playMode != PlayMode.repeatOne) { - debugPrint('⚠️ [service] completed ignored: last song in queue'); + if (_currentIndex < 0 || _currentIndex >= _queue.length) { + debugPrint( + '⚠️ [onPlaybackCompleted] invalid index: $_currentIndex, total=${_queue.length}'); _handlingCompletion = false; return; } + // ⭐ 关键判断:是否是最后一首 + final isLastSong = _currentIndex + 1 >= _queue.length; + if (isLastSong && _playMode != PlayMode.repeatOne) { + debugPrint( + '⚠️ [onPlaybackCompleted] LAST SONG: index=$_currentIndex, mode=$_playMode, no next()'); + _handlingCompletion = false; + return; + } + + debugPrint( + '🎵 [onPlaybackCompleted] will call next(), index=$_currentIndex'); try { if (_playMode == PlayMode.repeatOne) { + debugPrint( + '🎵 [onPlaybackCompleted] repeatOne mode, calling _playCurrent()'); _playCurrent(); return; } + debugPrint('🎵 [onPlaybackCompleted] calling next()'); next(); } finally { _handlingCompletion = false; diff --git a/pubspec.yaml b/pubspec.yaml index da066de..e79c170 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.4+1 +version: 1.0.5+1 environment: sdk: ^3.0.0