Skip to content

Fix radio stream title not updating on first play#158

Merged
phanan merged 1 commit into
masterfrom
fix/radio-stream-title-first-update
Mar 29, 2026
Merged

Fix radio stream title not updating on first play#158
phanan merged 1 commit into
masterfrom
fix/radio-stream-title-first-update

Conversation

@phanan
Copy link
Copy Markdown
Member

@phanan phanan commented Mar 29, 2026

Summary

  • The first now-playing API poll fired immediately after play(), before the playing state had propagated through streams to the UI
  • The title update was lost because the mini player hadn't settled into radio mode yet
  • Delay the first poll by 2 seconds with a guard to skip if the station changed

Test plan

  • Play a radio station — verify the stream title appears in the mini player within a few seconds
  • Verify the stream title also updates on the lock screen
  • Stop and replay — verify title still appears
  • Run flutter test

Summary by CodeRabbit

  • Bug Fixes
    • Fixed radio player station switching to properly synchronize metadata updates. Now-playing information polling is now intelligently timed with a brief delay to prevent stale or incorrect data from displaying when transitioning between stations. This ensures smooth and reliable station switching with improved alignment between player state and the user interface.

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.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

RadioPlayerProvider.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

Cohort / File(s) Summary
Radio Player Polling Scheduling
lib/providers/radio_player_provider.dart
Modified play() method to schedule initial _startNowPlayingPolling(station) call with a 2-second delay and added guard conditions to prevent polling if provider is inactive or station has changed.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • Poll now-playing metadata for radio stations #151: Introduced the now-playing polling mechanism (_startNowPlayingPolling and _stopNowPlayingPolling methods) that this PR modifies by changing its invocation timing and adding stale-call prevention guards.

Poem

🎙️ A rabbit tuned the frequency just right,
Delayed the polling two seconds bright,
No stale stations in the stream,
Just fresh metadata in the dream! 🐰✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix radio stream title not updating on first play' directly and accurately summarizes the main change: deferring the now-playing poll to ensure stream titles update correctly on initial playback.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/radio-stream-title-first-update

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 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 _startNowPlayingPolling already calls _stopNowPlayingPolling() first, concurrent callbacks for the same station won't create duplicate timers.

One minor consideration: the Future.delayed callback isn't tracked, so if dispose() 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 checks active, 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

📥 Commits

Reviewing files that changed from the base of the PR and between 64a293e and 08ee31a.

📒 Files selected for processing (1)
  • lib/providers/radio_player_provider.dart

@phanan phanan merged commit 86ce54e into master Mar 29, 2026
2 checks passed
@phanan phanan deleted the fix/radio-stream-title-first-update branch March 29, 2026 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant