I'm building a music player, there are two screens - At first screen, list of songs are present in ListView builder and second screen plays the respective music (player screen)
When I play music from the player screen by clicking the play button, the icon changed to pause but the problem is that for other player screen, it also get changed
I'm trying to achieve this using Flutter provider package, I think what happens is that isPlaying boolean is acting up as a global variable in provider class and all of them are consuming the same value, how to tackle this?
//Provider class
class MusicPlayerProvider extends ChangeNotifier {
final AudioPlayer audioPlayer = AudioPlayer();
bool isPlaying = false;
void playMusic(Map<String, dynamic> songMap) async {
await audioPlayer.play(UrlSource(songMap['link']));
isPlaying = true;
notifyListeners();
}
void stopMusic() async {
await audioPlayer.pause();
isPlaying = false;
notifyListeners();
}
}
// Music Listing Screen
class _MusicListScreenState extends State<MusicListScreen> {
List<Map<String, dynamic>> songList = [{'name': 'Helix', 'link': 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-1.mp3', 'singer': 'Alan Walker'}, {'name': 'Lucifer', 'link': 'https://www.soundhelix.com/examples/mp3/SoundHelix-Song-2.mp3', 'singer': 'John Smith'}];
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: songList.length,
itemBuilder: (BuildContext context, int index){
return ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Colors.grey
),
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => MusicPlayerScreen(songMap: songList[index])));
},
child: Text('Go to Player Screen', style: GoogleFonts.oswald(color: Colors.white))
)
},
);
}
}
// Music Player Screen
class MusicPlayerScreen extends StatefulWidget {
final Map<String, dynamic> songMap;
const MusicPlayerScreen({Key? key, required this.songMap}) : super(key: key);
@override
State<MusicPlayerScreen> createState() => _MusicPlayerScreenState();
}
class _MusicPlayerScreenState extends State<MusicPlayerScreen> {
@override
Widget build(BuildContext context) {
return Consumer<MusicPlayerProvider>(
builder: (BuildContext context, value, Widget? widgetValue){
return InkWell(
onTap: (){
if(value.isPlaying){
value.stopMusic();
} else {
value.playMusic(widget.songMap);
}
},
child: Container(
height: 50.0,
width: 50.0,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.grey[300]
),
// Icon changed for other music player screen to - problem
child: Icon(value.isPlaying ? Icons.pause_circle_filled : Icons.play_circle_fill, color: Colors.white, size: 35.0),
),
),
},
);
}
}
CodePudding user response:
In your provider you can track the song that is playing instead of just isPlaying
bool. This way you can tell which song is playing (if any) and show play/pause button accordingly.
UPD: also I would recommend moving song list to provider as well. So screens would just display a state and provider would handle the data.