Just Audio Flutter Plugin - How to catch song completion event - flutter

I am using just_audio plugin for flutter by Ryan Heise. I am able to get events of buffering, ready, loading, completed, etc.
Is there a way to get an event of a song completing in a playlist? I can't seem to find one in the documentation. We need to update the UI to show the next song is playing.
Thank you for your help with this.

You should be able to use a StreamBuilder which listens to just_audio's currentIndexStream. This way, there will always be up-to-date info: If the state updates, your build triggers and the widget showing the data is rebuilt.
In the setup on pub, different available streams for you to listen to are listed, among which is the currentIndexStream, which I assume solves your problem by streaming the current value (which, in conjunction with your list of songs should be able to get you the info you need)
StreamBuilder(
stream: player.currentIndexStream,
builder: (context, AsyncSnapshot snapshot) {
int currentIndex = snapshot.data ?? 0;
print(currentIndex.toString());
return MySongInfoWidget(song: mySongList[currentIndex]);
}
);
The code above should at least give you an idea of how to approach this problem, take a look at the StreamBuilder docs for more info.
A bit more complete example (to show how a streambuilder could be used inside build):
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(...),
body: Column(children: [
myStaticWidget(...),
StreamBuilder(
stream: player.currentIndexStream,
builder: (context, AsyncSnapshot snapshot) {
int currentIndex = snapshot.data ?? 0;
return Column(children: [
Text('Current song #$currentIndex'),
Text('Song name: ${mySongs[currentIndex].name}');
]);
}
),
]),
);
}

Related

Same streambuilder on next page but it stucks on ConnectionState.waiting

I am using bloc. But I found very rare issue i.e Stream is working well on one page but at the same time when we navigate to another page it is showing in ConnectionState.waiting
Here is my piece of code:
In bloc:
late StreamController<String> _timeRemainingController=StreamController.broadcast();
Stream<String> get timeRemainingStream => _timeRemainingController.stream;
// While adding value:
_timeRemainingController.add("");
Here is streambuilder which I am using
StreamBuilder<String>(
stream: _clockTimerBloc.timeRemainingStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
//code
}
Common code which used everywhere. I am stuck there Please try to check. And thanks for any response.

Need I do pagination for flutter StreamBuilder?

I'm new to flutter, and now I'm creating an app which has a feed page, I'm using StreamBuilder + firestore to do this, the code is like this:
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('posts')
.orderBy('createdAt', descending: true)
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(
color: primaryColor,
),
);
}
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) => Container(
child: createPostViewFromSnapShot(snapshot.data!.docs[index]),// it returns a widget
),
);
},
);
You can see from the code I didn't do pagination, I want to know when the code runs, it fetch all the post from firestore ? Or it will fetch data by block or something like pagination ?
I want to know if it's necessary to do pagination for StreamBuilder?
Avoid creating Widgets in Methods. That way you cause your App to
become I'm-performant. Because the Widget is not sat directly in the
Tree, but a method, every build that methods gets called, no matter
if the resulting widget would have to be actually be rebuilt.
That stream will not always emit events where data is not null. You will most likely get an exception for using snapshot.data! bang operator
Take a closer look at the documentation: https://firebase.flutter.dev/docs/firestore/usage/
FlutterFire provides support for dealing with realtime changes to
collections and documents. A new event is provided on the initial
request, and any subsequent changes to collection/document whenever a
change occurs (modification, deleted or added).
For what you are trying to achieve, it would be better to initially fetch a limited set of documents from your collection.
collectionReference.limit(42).get()
You can than fetch the next elements by using https://firebase.flutter.dev/docs/firestore/usage/#start--end-cursors

How to listen for state changes inside a FutureBuilder widget and reflect the state change?

to demonstrate the problem, let me write down some code for a FutureBuilder.
FutureBuilder(future: _myFuture, builder: (context, snapshot) {
if(snapshot.hasData) {
// !!!! IMPORTANT !!!
// Pay attention to the _isFirstText variable below
return SizedBox(
child: _isFirstText ? Text(snapshot.data.firstText) : Text(snapshot.data.secondText),
);
}
if(snapshot.connectionState == ConnectionState.isWaiting) {
return Text('Waiting!');
}
return Text('Error');
}),
As I have mentioned in a comment in the above code, pay attention to the _isFirstText variable. Suppose that is a state variable. Inside the future builder, how do I get the correct return value that corresponds to the isFirstText state variable change.
I also came across this stack overflow post but could not get the code to work.
I also came across a widget called StatefulBuilder, but I can not figure out to where in my FutureBuilder I should use it.
Can someone please help?
If you want to listen to ongoing changes you can use a Streambuilder. Streams are not only for serverside changes but can also be used locally.
You can build a Stream yourself like this :
StreamController myStreamController = StreamController<int>();
To send a new event through this controller you can do
myStreamController.sink.add(newValue);
You can then listen to changes like this:
#override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: myStreamController.stream,
builder: (context, snapshot) {
final value = snapshot.data;
return Text(value!.toString());
}
If you want to learn more check this Video: https://youtu.be/nQBpOIHE4eE
Let me know if this helped.
You can use ValueNotifier variables and use notifyListeners() to update a specific parts of your code Like this:
ValueListenableBuilder and use that ValueNotifier variable and listen to that.

Two StreamBuilderon on one screen with default empty screen shown when neither has data

I'm trying to create a Split View with two ListViews, one of them showing Tasks which are not completed and the second one containing completed tasks. I managed to make this work with a Column containing two Streambuilder. The problem I don't know how to solve is how to show a single default empty screen when neither of the two Streams have any values, due to the way Flutter works, I can't just return null. So I end up having two Empty default screens in my Column and on my screen.
What would be the right approach to make something like shown in the GIF with Firestore?
If I need to work with a single Stream and filter it inside dart, how can I make it work with ListView ?
I'd highly appreciate an example.
My Job class contains a boolean value jobDone which tells me in which list the Job has to go.
My current code:
return Column(
children: [
StreamBuilder<List<Job>>(
stream: getPendingJobsStream(database),
builder: (context, snapshot) {
return ListItemsBuilder<Job>(
...
);
},
),
ExpansionTile(
title: Text('Completed Tasks'),
children: [
StreamBuilder<List<Job>>(
stream: getCompletedJobsStream(database),
builder: (context, snapshot) {
return ListItemsBuilder<Job>(
...
);
},
),
],
),
],
);
You can check for snapshot state
builder: (context, snapshot) {
if(snapshot.connectionState ==ConnectionState.waiting){
return Center(child:CircularProgressIndicator();
}
if(snapshot.connectionState ==ConnectionState.done){
//check if snapshot has data
if(snapshot.hasData){
return ListItemsBuilder<Job>( ..

Flutter performance drop with FutureBuilder

I might be misunderstanding the usage of this tool but I see the following
which is not good because it goes over 16ms. That piece of red bars happens always the first time that I load a page (widget) that has a FutureBuilder:
#override
Widget build(BuildContext context) {
// Page template is a StatelessWidget that wraps a Scaffold with common widgets, nothing special
return PageTemplate(
child: FutureBuilder(
future: getList(), // <-- this takes about 1 second
builder: (context, snapshot) {
if (snapshot.hasData) {
List<Operator> list = snapshot.data;
return ListView.builder(
itemCount: list.length,
itemBuilder: (context, index) {
return MyWidget();
},
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
);
The app is in Run mode: profile. Sometimes the page with the FutureBuilder might generate even more red bars so I am wondering:
is this fine because I am just misunderstanding the tool? The overlays above the app tell me that on averages I am at GPU 10ms/frame and UI 6 ms/frame so it should be fine. But I can't get why sometimes I get this in the future (taken from android studio; dotted white line is 16fps limit):
I suspect the above "issue" (if we can call it issue) might happen because I am not properly using the FutureBuilder. I read this (I try to put const everywhere and I split widgets as much as I can to optimize when rebuild happens) and I think that futurebuilder rebuilds a lot so this might be the problem. But it has to rebuild to check if the future has finished! So?
thanks