Fix radio stream title not updating on first play#158
Conversation
The first now-playing poll fired before the playing state propagated to the UI, so the title update was lost. Delay the first poll by 2 seconds to let the mini player settle into radio mode.
📝 WalkthroughWalkthroughRadioPlayerProvider.play() now defers the initial now-playing metadata polling by 2 seconds using Future.delayed instead of invoking it immediately. The delayed call only executes if the provider remains active and the station hasn't changed, preventing stale polling after user interactions. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
lib/providers/radio_player_provider.dart (1)
107-113: The fix addresses the timing issue correctly with appropriate guards.The delayed callback with station-matching guard prevents stale polling when the station changes during the delay. Since
_startNowPlayingPollingalready calls_stopNowPlayingPolling()first, concurrent callbacks for the same station won't create duplicate timers.One minor consideration: the
Future.delayedcallback isn't tracked, so ifdispose()is called during the 2-second window, the callback could still fire on a disposed provider. In practice this is low-risk since the guard checksactive, but for extra safety you could track and cancel it.🔧 Optional: Track the delayed Future for cancellation on dispose
Timer? _nowPlayingTimer; + Completer<void>? _initialPollCompleter; ... await _player.play(); // Delay the first poll briefly to let the playing state propagate // so the UI is ready to display the stream title. + _initialPollCompleter = Completer<void>(); + final completer = _initialPollCompleter; Future.delayed(const Duration(seconds: 2), () { + if (completer?.isCompleted == true) return; if (active && _currentStation?.id == station.id) { _startNowPlayingPolling(station); } });And in
dispose():`@override` void dispose() { _stopNowPlayingPolling(); + _initialPollCompleter?.complete(); + _initialPollCompleter = null; _playingSubscription?.cancel();🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/providers/radio_player_provider.dart` around lines 107 - 113, Replace the untracked Future.delayed with a cancelable Timer so the delayed callback can be cancelled on dispose: store the Timer in a field (e.g. _startPollingTimer), create it instead of calling Future.delayed, keep the existing guard that checks active and _currentStation?.id == station.id before calling _startNowPlayingPolling(station), and cancel and null out _startPollingTimer in dispose (and when starting/stopping polling) to prevent the callback from firing after the provider is disposed; note _startNowPlayingPolling already calls _stopNowPlayingPolling(), so keep that behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@lib/providers/radio_player_provider.dart`:
- Around line 107-113: Replace the untracked Future.delayed with a cancelable
Timer so the delayed callback can be cancelled on dispose: store the Timer in a
field (e.g. _startPollingTimer), create it instead of calling Future.delayed,
keep the existing guard that checks active and _currentStation?.id == station.id
before calling _startNowPlayingPolling(station), and cancel and null out
_startPollingTimer in dispose (and when starting/stopping polling) to prevent
the callback from firing after the provider is disposed; note
_startNowPlayingPolling already calls _stopNowPlayingPolling(), so keep that
behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 83494fb8-66b4-4420-84f3-7f15f33f5b86
📒 Files selected for processing (1)
lib/providers/radio_player_provider.dart
Summary
play(), before the playing state had propagated through streams to the UITest plan
flutter testSummary by CodeRabbit