Skip to content

Highlight currently playing radio station#149

Merged
phanan merged 1 commit into
masterfrom
feat/radio-now-playing-highlight
Mar 29, 2026
Merged

Highlight currently playing radio station#149
phanan merged 1 commit into
masterfrom
feat/radio-now-playing-highlight

Conversation

@phanan
Copy link
Copy Markdown
Member

@phanan phanan commented Mar 29, 2026

Summary

  • Radio station rows now highlight when they are the currently playing station
  • The leading thumbnail gets a dark overlay with the playback animation (matching song playable rows), shown only when actively playing or loading — no icon when paused
  • Station name and trailing icon turn highlight pink when active
  • Thumbnail shape changed from circle to rounded square (squircle) for consistency

Test plan

  • Play a radio station and verify the row highlights with overlay animation, pink title, and pink antenna icon
  • Pause the radio and verify the overlay remains but the animation disappears
  • Switch to a different station and verify the previous row unhighlights and the new one highlights
  • Stop radio playback entirely and verify no rows are highlighted
  • Run flutter test test/ui/screens/radio_stations_test.dart

Summary by CodeRabbit

Release Notes

New Features

  • Enhanced radio station list interface with improved visual feedback when a station is playing, featuring a loading animation overlay, dynamic highlighting for the active station, and refined card design styling

Tests

  • Added comprehensive test coverage for radio station selection highlighting and playback state indicators

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 29, 2026

📝 Walkthrough

Walkthrough

The radio stations screen's row widget now subscribes to RadioPlayerProvider for state-driven rendering. The logo presentation updates from ClipOval to ClipSmoothRect, and when a station is actively playing, a semi-transparent overlay and optional loading animation appear. Title styling and icon colors adapt based on playback state. Comprehensive tests validate the highlighting and overlay logic.

Changes

Cohort / File(s) Summary
Radio Station UI Updates
lib/ui/screens/radio_stations.dart
_RadioStationRow now consumes RadioPlayerProvider via Consumer for reactive state updates. Logo changed from ClipOval to ClipSmoothRect with smooth borders wrapped in a Stack. Conditional overlay and loading animation display when station is active. Title text and trailing icon colors dynamically update based on isPlaying state. Added figma_squircle import.
Radio Stations Test Coverage
test/ui/screens/radio_stations_test.dart
New test file with two groups: highlighting tests validating whether a station matches the currently playing station by id, and overlay logic tests covering isPlaying, loading, and playing flag combinations to ensure correct visual behavior in all playback states.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • Add radio station support #138: Added RadioStationsScreen and RadioPlayerProvider foundation that this PR builds upon by implementing state-driven UI updates in the same _RadioStationRow widget.

Poem

🐰 Smooth corners now dance with a gentle glow,
Loading spinners twirl where the stations flow,
Consumer whispers state to our UI row—
Polish and signals in harmony grow!

🚥 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 'Highlight currently playing radio station' directly and accurately summarizes the main change: adding visual highlighting to the currently active radio station in the UI.
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 feat/radio-now-playing-highlight

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 (3)
test/ui/screens/radio_stations_test.dart (2)

88-95: Test covers an important edge case but assertion is incomplete.

This test verifies the scenario where a different station is actively playing (playing = true but isPlaying = false). The assertion only checks isPlaying, but doesn't verify that loading || playing is intentionally ignored when isPlaying is false.

Consider adding a clarifying comment or assertion:

// Animation condition is true, but overlay is not shown because station is not active
expect(loading || playing, isTrue); // Would show animation IF this were the active station
expect(isPlaying, isFalse); // But it's not, so no overlay at all
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/ui/screens/radio_stations_test.dart` around lines 88 - 95, The test "no
overlay when station is not active" currently only asserts isPlaying is false;
update the test to also assert that the animation condition is true by adding an
expectation for (loading || playing) to be true (and include a short comment
noting "Animation condition is true, but overlay is not shown because station is
not active") so the test verifies that loading || playing would trigger an
animation for an active station but that no overlay appears when isPlaying is
false; refer to the test name and the variables isPlaying, loading, and playing
when making the changes.

4-96: These tests verify boolean/string semantics, not widget behavior.

The current tests only validate that == works on String IDs and || works on booleans—essentially testing Dart language primitives. They don't actually test the _RadioStationRow widget implementation.

Consider adding widget tests that:

  1. Pump _RadioStationRow with a mocked RadioPlayerProvider
  2. Verify the overlay Container appears when the station is active
  3. Verify the animation Image.asset appears when playing || loading
  4. Verify AppColors.highlight is applied to title/icon when active
  5. Verify state changes trigger rebuilds correctly
Example widget test structure
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mockito/mockito.dart';
import 'package:provider/provider.dart';
// ... other imports

class MockRadioPlayerProvider extends Mock implements RadioPlayerProvider {}

void main() {
  group('_RadioStationRow widget', () {
    testWidgets('shows overlay and animation when station is playing', (tester) async {
      final mockProvider = MockRadioPlayerProvider();
      final station = RadioStation.fake(id: 'station-1');
      
      when(mockProvider.currentStation).thenReturn(station);
      when(mockProvider.playing).thenReturn(true);
      when(mockProvider.loading).thenReturn(false);

      await tester.pumpWidget(
        MaterialApp(
          home: ChangeNotifierProvider<RadioPlayerProvider>.value(
            value: mockProvider,
            child: Scaffold(
              body: _RadioStationRow(station: station, onTap: () {}),
            ),
          ),
        ),
      );

      // Verify overlay container exists
      expect(find.byType(Container), findsWidgets);
      // Verify animation asset is shown
      expect(find.byType(Image), findsOneWidget);
    });
  });
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/ui/screens/radio_stations_test.dart` around lines 4 - 96, Replace the
primitive boolean/string assertions with real widget tests: pump the
_RadioStationRow widget inside a MaterialApp and a
ChangeNotifierProvider<RadioPlayerProvider> backed by a mocked provider (mock
methods: currentStation, playing, loading), then assert the overlay Container is
present when currentStation matches the row's RadioStation, assert the animation
Image.asset is present when (playing || loading) is true, assert title/icon
Text/Icon widgets use AppColors.highlight when active, and verify changing the
mocked provider state and calling tester.pump()/pumpAndSettle() triggers the row
to rebuild and update visibility/styles accordingly.
lib/ui/screens/radio_stations.dart (1)

424-426: Consider renaming isPlaying to isActive for clarity.

The variable isPlaying is misleading—it represents whether this station is the currently selected station, not whether audio is actively playing. The actual playback state is accessed via radioPlayer.playing. This naming confusion could lead to maintenance issues.

Suggested rename
     return Consumer<RadioPlayerProvider>(
       builder: (context, radioPlayer, _) {
-        final isPlaying = radioPlayer.currentStation?.id == station.id;
+        final isActive = radioPlayer.currentStation?.id == station.id;

Then update all references to isPlayingisActive within this builder (lines 452, 458, 474, 489).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/ui/screens/radio_stations.dart` around lines 424 - 426, Rename the local
boolean variable isPlaying to isActive in the Consumer<RadioPlayerProvider>
builder where it's set as radioPlayer.currentStation?.id == station.id, and
update all uses of isPlaying within that builder to isActive (while keeping the
actual playback flag radioPlayer.playing untouched) so the name reflects
"currently selected station" rather than playback state.
🤖 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/ui/screens/radio_stations.dart`:
- Around line 424-426: Rename the local boolean variable isPlaying to isActive
in the Consumer<RadioPlayerProvider> builder where it's set as
radioPlayer.currentStation?.id == station.id, and update all uses of isPlaying
within that builder to isActive (while keeping the actual playback flag
radioPlayer.playing untouched) so the name reflects "currently selected station"
rather than playback state.

In `@test/ui/screens/radio_stations_test.dart`:
- Around line 88-95: The test "no overlay when station is not active" currently
only asserts isPlaying is false; update the test to also assert that the
animation condition is true by adding an expectation for (loading || playing) to
be true (and include a short comment noting "Animation condition is true, but
overlay is not shown because station is not active") so the test verifies that
loading || playing would trigger an animation for an active station but that no
overlay appears when isPlaying is false; refer to the test name and the
variables isPlaying, loading, and playing when making the changes.
- Around line 4-96: Replace the primitive boolean/string assertions with real
widget tests: pump the _RadioStationRow widget inside a MaterialApp and a
ChangeNotifierProvider<RadioPlayerProvider> backed by a mocked provider (mock
methods: currentStation, playing, loading), then assert the overlay Container is
present when currentStation matches the row's RadioStation, assert the animation
Image.asset is present when (playing || loading) is true, assert title/icon
Text/Icon widgets use AppColors.highlight when active, and verify changing the
mocked provider state and calling tester.pump()/pumpAndSettle() triggers the row
to rebuild and update visibility/styles accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: eeb23f2b-eac1-4678-9a0f-13356abfe7bf

📥 Commits

Reviewing files that changed from the base of the PR and between 4980405 and 2db7781.

📒 Files selected for processing (2)
  • lib/ui/screens/radio_stations.dart
  • test/ui/screens/radio_stations_test.dart

@phanan phanan merged commit e1473ab into master Mar 29, 2026
2 checks passed
@phanan phanan deleted the feat/radio-now-playing-highlight branch March 29, 2026 12:44
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