Flutter - How to do an infinite card feed? - flutter

I want to display one by one each document of a collection from Firestore. A document is a card containing an image and a text with a button to show the next card. Basically, my app should have the same behavior as Tinder: display one card then the next one, and never twice the same.
At the moment, I made a StreamBuilder that call the last 10 cards in a Stack so each card is on top of each other (hiding the next one).
But with this solution I have 2 problems :
I don't know how to display the next item when the user tap on the
next button. The current card has to disappear to let the next one being visible.
The StreamBuilder call only 10 cards, I would like to load 10 more
cards when the user is almost at the end (at the card number 8 for
example) so the user don't even realize the loading in the background.
Maybe the StreamBuilder is not the solution at all. But I have no idea what is the best way to do it.
StreamBuilder(
stream: firestore.collection('Feed').orderBy('date').limit(10).snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
return Center(child: CircularProgressIndicator());
var _docs = snapshot.data.docs;
if (_docs.isEmpty)
return Center(
child: Text("There is no more cards"),
);
return Scaffold(
body: Stack(
children: _docs.map((document) {
return Container(
color: Colors.white,
child: CardItem(...),
);
}).toList(),
),
);
});

Related

Flutter: CircularProgressIndicator not showing even though Stream returns no values

I have a StreamBuilder in order to get data from my user collection in Firestore to get their profile image. This works fine. But when for example I turn off my internet, then instead of showing a CircularProgressIndicator, it just shows my CircularAvatar with the backgroundColor.
Please see my code below. Normally when I turn off the internet, the code below should return the Progress Indicator. Why is that not happening? And when I then turn the internet back on, it does not update and show the correct profile image. Is the stream not working correctly?
StreamBuilder(
stream: DatabaseService(uid: uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: CircleAvatar(
radius: 50,
backgroundImage: NetworkImage(snapshot.data!.photoUrl),
),
);
} else {
return CircularProgressIndicator();

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>( ..

Is there a way to get StreamBuilder to load content slightly before the user scrolls down to it to reduce delay (Flutter)?

Currently my app loads the information (including pictures) into cards from Cloud Firestore, but it only starts loading the information when it appears on the user's screen. I used FadeInImage in _makeCard to make it a bit more usable while loading, but it's still too slow. Is there a way to make StreamBuilder load, for example, the nearest 10 cards that are off the screen? If not, is there a better way to create a list that is loaded from Firestore? This is my code currently:
StreamBuilder(
stream: Firestore.instance.collection('Cards').snapshots(),
builder: (context, snapshot) {
return SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return _makeCard(context, snapshot.data.documents[index]);
},
childCount:
snapshot.hasData ? snapshot.data.documents.length : 0,
),
);
})
I don't have a lot of experience with coding, so let me know if there is anything I can clarify.

next Page stream is not update on Flutter

I used two pages. and I added StreamBuilder in my first page and I passed snapshot.data to next Page. but when value change in 2nd-page value is not changing. How to fix it? I can't call streamBuilder in both pages because it's meaning two read in firebase. Is there any way to create singleton for services and access anywhere?
StreamBuilder(
stream: db.getData(),
builder: (context,snapshot){
return Column(
children: <Widget>[
InkWell(
onTap: ()=> Navigator.pushNamed(context, '/nextPage',arguments: Arguments(
data: snapshot.data
)),
)
],
);
},
)
InkWell(
onTap: ()=> Navigator.pushNamed(context, '/nextPage',arguments: Arguments(
data: snapshot.data
),
),
When using the above code, a data snapshot is only sent when you Tap on the InkWell. Meaning unless tapped on the inkwell it will not provide new data to nextPage.
To resolve this issue, I would suggest the following:
In First page
Create ValueNotifier instance to observe changes in the common reference:
// change Cast to type that you receive from firebase, or you can omit the cast
final ValueNotifier<snapshot_data_type> firebaseDataNotifier = ValueNotifier<snapshot_data_type>();
Update the value of firebaseDataNotifier when you receive data from firebase:
StreamBuilder(
stream: db.getData(),
builder: (context,snapshot){
firebaseDataNotifier.value = snapshot.data;
...
Pass the firebaseDataNotifier as data for the nextPage
In the next Page
Wrap the Next page widgets with ValueListenable
ValueListenableBuilder(
valueListenable: valueNotifier,
builder: (context, firebaseData, child) {
// return your next page widget here and use firebaseData instead of snapshot.data
)
Note: Make sure you keep the ValueNotifier instance outside of both widgets so that they can access it without any dependency.

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