diff --git a/lib/widgets/open_on_platform_sheet.dart b/lib/widgets/open_on_platform_sheet.dart index 471075f8..5af332db 100644 --- a/lib/widgets/open_on_platform_sheet.dart +++ b/lib/widgets/open_on_platform_sheet.dart @@ -9,7 +9,7 @@ import 'package:url_launcher/url_launcher.dart'; /// Bottom sheet listing every streaming platform song.link resolves for a /// track. Data-driven from the generic platform-link map so the app core /// stays service-agnostic; tapping a row opens the link externally. -class OpenOnPlatformSheet extends StatelessWidget { +class OpenOnPlatformSheet extends StatefulWidget { final String spotifyId; final String isrc; @@ -31,6 +31,35 @@ class OpenOnPlatformSheet extends StatelessWidget { ); } + @override + State createState() => _OpenOnPlatformSheetState(); +} + +class _OpenOnPlatformSheetState extends State { + late Future> _links; + + @override + void initState() { + super.initState(); + _loadLinks(); + } + + @override + void didUpdateWidget(OpenOnPlatformSheet oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.spotifyId != widget.spotifyId || + oldWidget.isrc != widget.isrc) { + _loadLinks(); + } + } + + void _loadLinks() { + _links = PlatformBridge.getTrackPlatformLinks( + spotifyId: widget.spotifyId, + isrc: widget.isrc, + ); + } + static const Map _platformNames = { 'spotify': 'Spotify', 'appleMusic': 'Apple Music', @@ -83,10 +112,7 @@ class OpenOnPlatformSheet extends StatelessWidget { Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; return FutureBuilder>( - future: PlatformBridge.getTrackPlatformLinks( - spotifyId: spotifyId, - isrc: isrc, - ), + future: _links, builder: (context, snapshot) { if (snapshot.connectionState != ConnectionState.done) { return const Padding( diff --git a/test/open_on_platform_sheet_test.dart b/test/open_on_platform_sheet_test.dart new file mode 100644 index 00000000..76e83f89 --- /dev/null +++ b/test/open_on_platform_sheet_test.dart @@ -0,0 +1,60 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:spotiflac_android/l10n/app_localizations.dart'; +import 'package:spotiflac_android/widgets/open_on_platform_sheet.dart'; + +void main() { + TestWidgetsFlutterBinding.ensureInitialized(); + testWidgets( + 'theme rebuild retains completed lookup; identifiers replace it', + (tester) async { + const channel = MethodChannel('com.zarz.spotiflac/backend'); + final calls = []; + final pending = Completer>(); + tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(channel, ( + call, + ) async { + calls.add(call); + if (calls.length == 1) { + return { + 'platforms': {'spotify': 'https://example.test/one'}, + }; + } + return pending.future; + }); + addTearDown( + () => tester.binding.defaultBinaryMessenger.setMockMethodCallHandler( + channel, + null, + ), + ); + Widget app(Brightness brightness, String id) => MaterialApp( + theme: ThemeData(brightness: brightness), + localizationsDelegates: AppLocalizations.localizationsDelegates, + supportedLocales: AppLocalizations.supportedLocales, + home: Scaffold(body: OpenOnPlatformSheet(spotifyId: id)), + ); + await tester.pumpWidget(app(Brightness.light, 'one')); + await tester.pumpAndSettle(); + expect(find.text('Spotify'), findsOneWidget); + await tester.pumpWidget(app(Brightness.dark, 'one')); + await tester.pumpAndSettle(); + expect(calls.length, 1); + expect(find.text('Spotify'), findsOneWidget); + expect(find.byType(CircularProgressIndicator), findsNothing); + await tester.pumpWidget(app(Brightness.dark, 'two')); + await tester.pump(); + expect(calls.length, 2); + expect(calls.last.arguments, {'spotify_id': 'two', 'isrc': ''}); + expect(find.byType(CircularProgressIndicator), findsOneWidget); + pending.complete({ + 'platforms': {'appleMusic': 'https://example.test/two'}, + }); + await tester.pumpAndSettle(); + expect(find.text('Apple Music'), findsOneWidget); + expect(find.text('Spotify'), findsNothing); + }, + ); +}