mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-28 20:32:15 +02:00
perf(player): rebuild preview buttons only on status changes
This commit is contained in:
@@ -39,8 +39,12 @@ class PreviewButton extends ConsumerWidget {
|
||||
|
||||
// When the built-in player is currently on this track, mirror and control
|
||||
// it (consistent with the mini player) rather than the preview snippet.
|
||||
final mainItem = ref.watch(currentMediaItemProvider).value;
|
||||
if (_isCurrentMainTrack(mainItem)) {
|
||||
final isCurrentMainTrack = ref.watch(
|
||||
currentMediaItemProvider.select(
|
||||
(item) => _isCurrentMainTrack(item.value),
|
||||
),
|
||||
);
|
||||
if (isCurrentMainTrack) {
|
||||
final isPlaying = ref.watch(playbackPlayingProvider);
|
||||
return IconButton(
|
||||
iconSize: size,
|
||||
@@ -62,9 +66,13 @@ class PreviewButton extends ConsumerWidget {
|
||||
|
||||
if (!track.hasPreview) return const SizedBox.shrink();
|
||||
|
||||
final previewState = ref.watch(previewPlayerProvider);
|
||||
final isActive = previewState.isActiveUrl(track.previewUrl);
|
||||
final status = isActive ? previewState.status : PreviewStatus.idle;
|
||||
final status = ref.watch(
|
||||
previewPlayerProvider.select(
|
||||
(state) => state.isActiveUrl(track.previewUrl)
|
||||
? state.status
|
||||
: PreviewStatus.idle,
|
||||
),
|
||||
);
|
||||
|
||||
final Widget icon;
|
||||
final String tooltip;
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:spotiflac_android/models/settings.dart';
|
||||
import 'package:spotiflac_android/models/track.dart';
|
||||
import 'package:spotiflac_android/providers/library_collections_provider.dart';
|
||||
import 'package:spotiflac_android/providers/music_player_provider.dart';
|
||||
import 'package:spotiflac_android/providers/preview_player_provider.dart';
|
||||
import 'package:spotiflac_android/providers/settings_provider.dart';
|
||||
import 'package:spotiflac_android/widgets/preview_button.dart';
|
||||
import 'package:spotiflac_android/widgets/track_collection_quick_actions.dart';
|
||||
@@ -79,6 +80,69 @@ void main() {
|
||||
expectCenteredHitbox(tester, Icons.play_circle_fill_rounded);
|
||||
});
|
||||
|
||||
testWidgets('preview progress does not rebuild track buttons', (
|
||||
tester,
|
||||
) async {
|
||||
final player = _TestPreviewPlayer();
|
||||
var builds = 0;
|
||||
await tester.pumpWidget(
|
||||
ProviderScope(
|
||||
overrides: [
|
||||
currentMediaItemProvider.overrideWith((ref) => Stream.value(null)),
|
||||
previewPlayerProvider.overrideWith(() => player),
|
||||
],
|
||||
child: MaterialApp(
|
||||
localizationsDelegates: AppLocalizations.localizationsDelegates,
|
||||
supportedLocales: AppLocalizations.supportedLocales,
|
||||
home: Scaffold(
|
||||
body: _CountingPreviewButton(track: track, onBuild: () => builds++),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
await tester.pumpAndSettle();
|
||||
player.emit(
|
||||
PreviewPlayerState(
|
||||
activeUrl: track.previewUrl,
|
||||
status: PreviewStatus.playing,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(find.byIcon(Icons.pause_circle_filled_rounded), findsOneWidget);
|
||||
final playingBuilds = builds;
|
||||
for (var second = 1; second <= 3; second++) {
|
||||
player.emit(
|
||||
PreviewPlayerState(
|
||||
activeUrl: track.previewUrl,
|
||||
status: PreviewStatus.playing,
|
||||
position: Duration(seconds: second),
|
||||
duration: const Duration(seconds: 30),
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
}
|
||||
expect(builds, playingBuilds);
|
||||
|
||||
player.emit(
|
||||
PreviewPlayerState(
|
||||
activeUrl: track.previewUrl,
|
||||
status: PreviewStatus.paused,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(find.byIcon(Icons.play_circle_fill_rounded), findsOneWidget);
|
||||
expect(builds, playingBuilds + 1);
|
||||
|
||||
player.emit(
|
||||
const PreviewPlayerState(
|
||||
activeUrl: 'https://example.com/another-preview.mp3',
|
||||
status: PreviewStatus.playing,
|
||||
),
|
||||
);
|
||||
await tester.pump();
|
||||
expect(find.byIcon(Icons.play_circle_outline_rounded), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('overflow menu icon is centered in its adjacent hitbox', (
|
||||
tester,
|
||||
) async {
|
||||
@@ -157,6 +221,25 @@ class _TestSettingsNotifier extends SettingsNotifier {
|
||||
AppSettings build() => const AppSettings();
|
||||
}
|
||||
|
||||
class _TestPreviewPlayer extends PreviewPlayerController {
|
||||
@override
|
||||
PreviewPlayerState build() => const PreviewPlayerState();
|
||||
|
||||
void emit(PreviewPlayerState next) => state = next;
|
||||
}
|
||||
|
||||
class _CountingPreviewButton extends PreviewButton {
|
||||
const _CountingPreviewButton({required super.track, required this.onBuild});
|
||||
|
||||
final VoidCallback onBuild;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
onBuild();
|
||||
return super.build(context, ref);
|
||||
}
|
||||
}
|
||||
|
||||
class _TestLibraryCollectionsNotifier extends LibraryCollectionsNotifier {
|
||||
@override
|
||||
LibraryCollectionsState build() => LibraryCollectionsState(isLoaded: true);
|
||||
|
||||
Reference in New Issue
Block a user