diff --git a/lib/screens/queue_tab.dart b/lib/screens/queue_tab.dart index e76e0ad9..e872be71 100644 --- a/lib/screens/queue_tab.dart +++ b/lib/screens/queue_tab.dart @@ -9,6 +9,7 @@ import 'package:spotiflac_android/services/platform_bridge.dart'; import 'package:spotiflac_android/l10n/l10n.dart'; import 'package:spotiflac_android/utils/adaptive_layout.dart'; import 'package:spotiflac_android/utils/app_bar_layout.dart'; +import 'package:spotiflac_android/utils/audio_quality_badge_policy.dart'; import 'package:spotiflac_android/utils/nav_bar_inset.dart'; import 'package:spotiflac_android/utils/re_enrich_release_policy.dart'; import 'package:spotiflac_android/widgets/settings_group.dart'; diff --git a/lib/screens/queue_tab_collection_items.dart b/lib/screens/queue_tab_collection_items.dart index fdebed9c..19aa1bf1 100644 --- a/lib/screens/queue_tab_collection_items.dart +++ b/lib/screens/queue_tab_collection_items.dart @@ -336,11 +336,11 @@ extension _QueueTabCollectionItemWidgets on _QueueTabState { String quality, { bool listStyle = false, }) { - final isHighResolution = quality.startsWith('24'); + final isHighlightedQuality = shouldHighlightAudioQualityBadge(quality); return Container( padding: EdgeInsets.symmetric(horizontal: listStyle ? 6 : 4, vertical: 2), decoration: BoxDecoration( - color: isHighResolution + color: isHighlightedQuality ? listStyle ? colorScheme.primaryContainer : colorScheme.primary @@ -350,7 +350,7 @@ extension _QueueTabCollectionItemWidgets on _QueueTabState { child: Text( listStyle ? quality : _getQualityBadgeText(quality), style: Theme.of(context).textTheme.labelSmall?.copyWith( - color: isHighResolution + color: isHighlightedQuality ? listStyle ? colorScheme.onPrimaryContainer : colorScheme.onPrimary diff --git a/lib/utils/audio_quality_badge_policy.dart b/lib/utils/audio_quality_badge_policy.dart new file mode 100644 index 00000000..5da8f2dc --- /dev/null +++ b/lib/utils/audio_quality_badge_policy.dart @@ -0,0 +1,24 @@ +const highQualityBadgeBitrateThresholdKbps = 900; + +/// Preserves the highlighted color used by legacy 24-bit Library badges while +/// also supporting newer labels that display a measured bitrate instead. +bool shouldHighlightAudioQualityBadge(String quality) { + final normalized = quality.trim().toLowerCase(); + if (RegExp(r'\b24(?:\s*[- ]?\s*bit|/)').hasMatch(normalized)) { + return true; + } + + final kbpsMatch = RegExp( + r'\b(\d+(?:\.\d+)?)\s*k(?:bps)?\b', + ).firstMatch(normalized); + final kbps = double.tryParse(kbpsMatch?.group(1) ?? ''); + if (kbps != null) { + return kbps > highQualityBadgeBitrateThresholdKbps; + } + + final mbpsMatch = RegExp( + r'\b(\d+(?:\.\d+)?)\s*mbps\b', + ).firstMatch(normalized); + final mbps = double.tryParse(mbpsMatch?.group(1) ?? ''); + return mbps != null && mbps * 1000 > highQualityBadgeBitrateThresholdKbps; +} diff --git a/test/audio_quality_badge_policy_test.dart b/test/audio_quality_badge_policy_test.dart new file mode 100644 index 00000000..46ea2357 --- /dev/null +++ b/test/audio_quality_badge_policy_test.dart @@ -0,0 +1,25 @@ +import 'package:flutter_test/flutter_test.dart'; +import 'package:spotiflac_android/utils/audio_quality_badge_policy.dart'; + +void main() { + group('Library audio quality badge color', () { + test('keeps legacy 24-bit labels highlighted', () { + expect(shouldHighlightAudioQualityBadge('24-bit/96kHz'), isTrue); + expect(shouldHighlightAudioQualityBadge('FLAC 24bit-48kHz'), isTrue); + expect(shouldHighlightAudioQualityBadge('24/192kHz'), isTrue); + }); + + test('highlights only measured bitrates above 900 kbps', () { + expect(shouldHighlightAudioQualityBadge('900kbps'), isFalse); + expect(shouldHighlightAudioQualityBadge('901kbps'), isTrue); + expect(shouldHighlightAudioQualityBadge('FLAC 1760 kbps'), isTrue); + expect(shouldHighlightAudioQualityBadge('1.76 Mbps'), isTrue); + }); + + test('leaves normal lossy bitrate labels neutral', () { + expect(shouldHighlightAudioQualityBadge('AAC 320kbps'), isFalse); + expect(shouldHighlightAudioQualityBadge('OPUS 256k'), isFalse); + expect(shouldHighlightAudioQualityBadge('16-bit/44.1kHz'), isFalse); + }); + }); +}