import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:spotify_sdk/models/image_uri.dart'; import 'package:spotify_sdk/models/player_state.dart'; import 'package:spotify_sdk/spotify_sdk.dart'; /// InheritedWidget that holds the state of your MusicPlayer /// the rebuild stream builds the hole body /// the playStatedStream only rebuild the Image, SongInfo and the ControlsButtons class MusicPlayerState extends InheritedWidget { MusicPlayerState({super.key, required super.child}); bool loading = false; bool connected = false; StreamController<void> rebuildStream = StreamController.broadcast(); StreamController<void> playStatedStream = StreamController.broadcast(); PlayerState? playerState; late ImageUri? currentTrackImageUri; Image? albumImage; static MusicPlayerState? maybeOf(BuildContext context) => context.dependOnInheritedWidgetOfExactType<MusicPlayerState>(); static MusicPlayerState of(BuildContext context) { final MusicPlayerState? result = maybeOf(context); assert(result != null, 'No PlayerState found in context'); return result!; } void setLoading(bool loading) { this.loading = loading; rebuildStream.sink.add(null); } /// will be called on PlayStateChange /// load new Imag e void updatePlayerState() async { playerState = await getPlayerState(); loadAlbumImage().then((value) => playStatedStream.sink.add(null)); } ///disconnect your app from your local spotify app Future<void> disconnect() async { try { setLoading(true); var result = await SpotifySdk.disconnect(); setStatus(result ? 'disconnect successful' : 'disconnect failed'); setLoading(false); } on PlatformException catch (e) { setLoading(false); setStatus(e.code, message: e.message); } on MissingPluginException { setLoading(false); setStatus('not implemented'); } } /// establish connection to local spotify app /// connection data will be loaded in main from dotenv.env /// if connection successful /// connection will be set to true and loading to false Future<bool> connectToSpotifyRemote() async { try { setLoading(true); var result = await SpotifySdk.connectToSpotifyRemote( clientId: dotenv.env['CLIENT_ID'].toString(), redirectUrl: dotenv.env['REDIRECT_URL'].toString()); setStatus(result ? 'connect to spotify successful' : 'connect to spotify failed'); if (result) { playerState = await getPlayerState(); setLoading(false); } connected = result; } on PlatformException catch (e) { setLoading(false); setStatus(e.code, message: e.message); } on MissingPluginException { setLoading(false); setStatus('not implemented'); } return connected; } Widget spotifyImageWidget(ImageUri imageUri) { return FutureBuilder( future: SpotifySdk.getImage( imageUri: imageUri, dimension: ImageDimension.large, ), builder: (BuildContext context, AsyncSnapshot<Uint8List?> snapshot) { if (snapshot.hasData) { albumImage = Image.memory(snapshot.data!); rebuildStream.sink.add(null); return const Center(child: Text('Getting image...')); } else if (snapshot.hasError) { setStatus(snapshot.error.toString()); return SizedBox( width: ImageDimension.small.value.toDouble(), height: ImageDimension.small.value.toDouble(), child: const Center(child: Text('Error getting image')), ); } else { return SizedBox( width: ImageDimension.small.value.toDouble(), height: ImageDimension.small.value.toDouble(), child: const Center(child: Text('Getting image...')), ); } }); } ///loads the Album image via spotify.sdk and saves the image in MusicPlayState ///for global access Future<void> loadAlbumImage() async { currentTrackImageUri = playerState?.track?.imageUri; albumImage = Image.memory((await SpotifySdk.getImage( imageUri: currentTrackImageUri!, dimension: ImageDimension.large, ))!); } void setStatus(String code, {String? message}) { var text = message ?? ''; print(text); } //get PlayState from local spotify app Future<PlayerState?> getPlayerState() async { try { return await SpotifySdk.getPlayerState(); } on PlatformException catch (e) { setStatus(e.code, message: e.message); } on MissingPluginException { setStatus('not implemented'); } } @override bool updateShouldNotify(covariant MusicPlayerState oldWidget) { return loading != oldWidget.loading && connected != oldWidget.connected; } }