How can I update Listview in Streambuilder in flutter - firebase

I have a streambuidler widget that contains a listview to display whom the current user has recently chatted with. When the current user receives a message that message should be pushed to the top of the listview, however that message is always display at the bottom of the list view, it's only display on the top if I refresh my screen.
NoSearchResultScreen() {
final Orientation orientation = MediaQuery.of(context).orientation;
print("hasAlreadyChatWithSomeone: $hasAlreadyChatWithSomeone");
return hasAlreadyChatWithSomeone
? StreamBuilder<QuerySnapshot>(
stream: (FirebaseFirestore.instance
.collection("user")
.where("id", isEqualTo: currentUserId)
.snapshots()),
builder: (context, snapshot) {
List<ProfileChatWith> chatWithList = [];
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: circularProgress(),
);
}
if (snapshot.hasData) {
final chatWithSnapshot = snapshot.data?.docs.first['chatWith'];
//print("chatWithSnapshot: $chatWithSnapshot");
for (var userChatWith in chatWithSnapshot) {
final user = ProfileChatWith(
userId: userChatWith,
currentUserId: currentUserId,
);
chatWithList.add(user);
//print("I have chatted with: $userChatWith");
}
return Container(
width: MediaQuery.of(context).size.width,
child: ListView(
//shrinkWrap: true,
children: chatWithList,
),
);
} else {
return Center(
child: circularProgress(),
);
}
},
)
: Container(
child: Center(
child: ListView(
shrinkWrap: true,
children: <Widget>[
Icon(
Icons.group,
color: Colors.greenAccent,
size: 200.0,
),
Text(
"Search Users",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.greenAccent,
fontSize: 50.0,
fontWeight: FontWeight.bold),
)
],
),
),
);
}

Try reverse: true,
return SizedBox(
width: MediaQuery.of(context).size.width,
child: ListView(
reverse: true,
children: chatWithList,
),
);
Use Listview.builder for performance optimization
return SizedBox(
width: MediaQuery.of(context).size.width,
child: ListView.builder(
reverse: true,
itemBuilder: (BuildContext context, int index) => chatWithList[index],
),
);

The solution which worked is as below, #Leo Tran own words
I found a way to solve my question is that I will rebuild my widget whenever the data got updated.

Related

Flutter - How to make a call on Flutter Firestore, return value if it contains?

I'm building a system. Purpose product search. But I'm having a problem with this search. I want this search system like this: If what the person is looking for is in any value, it should be returned as a result. For example, if the person is looking for shoes as a product, when I type sho, I want it to come to the listView.
Or let me give you another example: Finding the glass when typing gla for glass. How can I make this search system?
Firestore:
I tried a code like this:
Container(
height: 200,
child: StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection("bolatAktar").where("urunAdi", isEqualTo: _arananUrun).snapshots(), // !!!!!!!!!!!!!!<<<<<<<<<<<<<<<<<<<<<
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
else {
return ListView.builder(
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return InkWell(
child: ListTile(
leading: Icon(Icons.label),
title: Text(snapshot.data!.docs[index].data()["urunAdi"], style: TextStyle(fontSize: 20),),
),
onTap: () {
showModalBottomSheet(
isScrollControlled:true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
),
context: context,
builder: (context) {
return FractionallySizedBox(
heightFactor: 0.93,
child: Container(
padding: EdgeInsets.all(25),
height: MediaQuery.of(context).size.height * 0.5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("Product name:", style: TextStyle(fontSize: 20)),
SizedBox(height: 10),
TextFormField(
style: TextStyle(fontSize: 19),
decoration: InputDecoration(
border: OutlineInputBorder(),
),
initialValue: snapshot.data!.docs[index].data()["urunAdi"],
),
]
)
),
);
}
);
},
);
},
);
}
},
),
),
Result:
Thank you in advance for your help and valuable information.
Google Firestore: Query on substring of a property value (text search)
Is there a way to search sub string at Firestore?
Firestore Comparison Operators - contains, does not contain, starts with
I have reviewed the above topics, but they did not contribute because they are not up to date.

snapshot.data.docs.length not working on flutter

I make some listview and it have likes and comments section. I want to show how many likes and comments that post had. The like section works by displaying the number of users who like it, i try to show it with snapshot.data.docs.length.toString() from firestore but when i try to show how many comments with same code as like section it not working and only get 0.
this is inside comments field
Padding(
padding: const EdgeInsets.only(top: 8),
child: Padding(
padding: const EdgeInsets.only(left: 15),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 80.0,
child: Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
onLongPress: () {
Provider.of<PostFunction>(context,
listen: false)
.showLikes(
context,
documentSnapshot
.data()['title']);
},
onTap: () {
print('Adding like...');
Provider.of<PostFunction>(context,
listen: false)
.addLike(
context,
documentSnapshot
.data()['title'],
Provider.of<AuthenticationService>(
context,
listen: false)
.getUserUid);
},
child: Icon(
FontAwesomeIcons.arrowAltCircleUp,
color: kGreyColor,
size: 18.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.doc(documentSnapshot
.data()['title'])
.collection('likes')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child:
CircularProgressIndicator());
} else {
return Padding(
padding:
const EdgeInsets.only(
left: 8.0),
child: RichText(
text: TextSpan(
text: snapshot
.data.docs.length
.toString(),
style: GoogleFonts
.openSans(
color:
kGreyColor,
fontSize: 16.0),
children: <TextSpan>[
TextSpan(
text: ' votes',
style: GoogleFonts
.openSans(
color:
kGreyColor,
fontSize: 16.0,
)),
]),
),
);
}
})
],
),
),
SizedBox(width: 20),
Container(
width: 150.0,
child: Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
Provider.of<PostFunction>(context,
listen: false)
.showComments(
context,
documentSnapshot,
documentSnapshot
.data()['title']);
},
child: Icon(
FontAwesomeIcons.solidComments,
color: kGreyColor,
size: 16.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection(' posts')
.doc(documentSnapshot
.data()['title'])
.collection('comments')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child:
CircularProgressIndicator());
} else {
return Padding(
padding:
const EdgeInsets.only(
left: 8.0),
child: Text(
snapshot.data.docs.length
.toString(),
style: GoogleFonts.openSans(
color: kGreyColor,
fontSize: 16.0),
),
);
}
}),
],
),
),
Spacer(),
Provider.of<AuthenticationService>(context,
listen: false)
.getUserUid ==
documentSnapshot.data()['useruid']
? IconButton(
icon: Icon(EvaIcons.moreVertical,
color: kGreyColor, size: 16),
onPressed: () {
Provider.of<PostFunction>(context,
listen: false)
.showPostOptions(
context,
documentSnapshot
.data()['title']);
})
: Container(width: 0.0, height: 0.0)
],
),
),
),
Replace
.collection(' posts')
with
.collection('posts')
in the “comments” section of the Streambuilder.
Your stream data is coming as empty as the database cannot find a collection with name (“ posts”).
So when you try to show how many comments the post had with the same code as the “likes” section it is not working and only getting 0 each time.
just declare the dataType of builder's arguments..i mean, builder:(BuildContext context,AsyncSnapshot snapShot).check the image
Could you please try this one?
StreamBuilder(
stream: firestoreDB,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data!.size,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(snapshot.data!.docs[index]['name']),
subtitle: Text(snapshot.data!.docs[index]['description']),
),
);
},
);
},
),

Is there any problem in this code while implementing ListView.builder()

Why ListView.builder only showing 2 data, I have so many documents in cloud_firestore and I want to retrieve those data and show it in the ListView but exactly what is happening is it doesn't matter how many documents are there it is returning all the documents but when I am using ListView.builder to show that data using widgets it is showing only 2 Widget.
Future<List<DocumentSnapshot>> getData() async {
var firestore = Firestore.instance;
QuerySnapshot qn =
await firestore.collection("LiveProducts").getDocuments();
return qn.documents;
}
Widget build(BuildContext context) {
return Container(
child: FutureBuilder(
future: getData(),
builder: (_, AsyncSnapshot<List<DocumentSnapshot>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Padding(
padding: const EdgeInsets.only(
top: 295,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Center(
child: SpinKitCircle(
color: Color.fromRGBO(91, 74, 127,10),
size: 50.0,
),
),
],
),
);
} else {
return ListView.builder(
// title: Text(snapshot.data[index].data["ProductName"]),
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
// if (snapshot.data[index].data["live"] == true) {
print(snapshot.data.length);
return Container(
margin: EdgeInsets.all(15),
height: 300,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.green,
),
child: Center(child: Text('$index'),),
);
// }
},
);
}
}));
}
One horrible thing is hapenning i am using Text Widget instead of Container Widget it is showing perfectly all the documents. like this
return Center(child:Text(snapshot.data[index].data["ProductName"])),
Try the following:
else if(snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
// title: Text(snapshot.data[index].data["ProductName"]),
shrinkWrap: true,
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
// if (snapshot.data[index].data["live"] == true) {
print(snapshot.data.length);
return Container(
margin: EdgeInsets.all(15),
height: 300,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.green,
),
child: Center(child: Text('$index'),),
);
// }
},
);
}
done → const ConnectionState
Connected to a terminated asynchronous computation.

How to load image to the Card from data retrieved from async task in flutter?

I'm new to flutter development. I need to load images into a card depending on data loaded via async task.
I have an async task which returns Future> user data quired from the sqlite local database. With retrieved data, I build a ListView to show users using Card. But inside the card, I'm trying to show an image which will be downloaded from Firebase Storage depending on the data retrieved from the local database. But the image URL is null.
Widget build(BuildContext context) {
var allCards = DBProvider.db.getAllCards();
return FutureBuilder<List<User>>(
future: DBProvider.db.getAllCards(),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
User user = snapshot.data[index];
return Card(
elevation: 8.0,
margin:
new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
child: Image(
image: CachedNetworkImageProvider(FirebaseStorage().ref().child('employer_logo').child('00001').child('google-banner.jpg').getDownloadURL().toString()),
fit: BoxFit.cover,
),
),
Positioned(
bottom: 0,
left: 0,
child: Container(
padding: EdgeInsets.all(10),
child: Text(
'Google Incorperation',
style: TextStyle(
fontSize: 20, color: Colors.white),
),
),
)
],
),
Container(
decoration: BoxDecoration(
color: Colors.white10,
),
child: ListTile(
title: Text(user.fname + " " + user.lname,
style: TextStyle(
color: Colors.blue[400], fontSize: 20)),
subtitle: Text(user.designation,
style: TextStyle(
color: Colors.blue[300], fontSize: 16)),
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(
user.fname,
user.lname,
user.uid,
user.designation,
user.mobile,
user.employerId)))
},
),
)
],
),
);
},
);
}
},
);
}
I expect to show images downloaded from firebase storage
This would be my first answer, and there are probably many ways to improve my answer here. But I will give it a go: Actually, you will have to look up a lot on Futuresand Streams, because it is quite a big part in many a app. If your app needs any content on the web, it will need Futures, or it's bigger counterpart Stream. In this case, where you want to set up a Listview with probably multiple images, I would go for a Stream. Also, I would save all my database logic in a seperate file. However, if you don't want to modify your code too much now, I would use a FutureBuilder.
I've seen you already use one of them in your code. But in this case, use:
...
int maxsize = 10e6.round(); // This is needed for getData. 10e^6 is usually big enough.
return new Card (
FutureBuilder<UInt8List> ( // I also think getting Data, instead of a DownloadUrl is more practical here. It keeps the data more secure, instead of generating a DownloadUrl which is accesible for everyone who knows it.
future: FirebaseStorage().ref().child('entire/path/can/go/here')
.getData(maxsize),
builder: (BuildContext context, AsyncSnapshot<UInt8List> snapshot) {
// When this builder is called, the Future is already resolved into snapshot.data
// So snapshot.data contains the not-yet-correctly formatted Image.
return Image.memory(data, fit: BoxFit.Cover);
},
),
Widget build(BuildContext context) {
var allCards = DBProvider.db.getAllCards();
return FutureBuilder<List<User>>(
future: DBProvider.db.getAllCards(),
builder: (BuildContext context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) return new Text('Error: ${snapshot.error}');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
User user = snapshot.data[index];
int maxsize = 10e6.round();
return Card(
elevation: 8.0,
margin:
new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Column(
children: <Widget>[
Stack(
children: <Widget>[
Container(
child: FutureBuilder<dynamic>(
future: FirebaseStorage()
.ref()
.child('employer_logo')
.child('00001')
.child('google-banner.jpg')
.getDownloadURL(),
builder: (BuildContext context,
AsyncSnapshot<dynamic> snapshot) {
if (snapshot.connectionState !=
ConnectionState.waiting) {
return Image(
image: CachedNetworkImageProvider(
snapshot.data.toString()),
fit: BoxFit.cover,
);
}
else {
return Text('Loading image....');
}
},
),
),
Positioned(
bottom: 0,
left: 0,
child: Container(
padding: EdgeInsets.all(10),
child: Text(
'Google Incorperation',
style: TextStyle(
fontSize: 20, color: Colors.white),
),
),
)
],
),
Container(
decoration: BoxDecoration(
color: Colors.white10,
),
child: ListTile(
title: Text(user.fname + " " + user.lname,
style: TextStyle(
color: Colors.blue[400], fontSize: 20)),
subtitle: Text(user.designation,
style: TextStyle(
color: Colors.blue[300], fontSize: 16)),
onTap: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Profile(
user.fname,
user.lname,
user.uid,
user.designation,
user.mobile,
user.employerId)))
},
),
)
],
),
);
},
);
}
},
);
}

Displaying Firebase Firestore Listview Data as a list Flutter

I am currently able to display a Listview filled with data from my Firestore database. My current problem is, that I want to make it dissmissable, so I need to be able to use functions such as:
setState(() {
items.removeAt(index);
});
Now, I read up on how to generate a list, but none of the examples mention a firebase Streambuilder like I am using. So I was just wondering if it was possible to make the data into a list? And if not, if there are any other ways to make a firestore listview dissmissable? Here is how I currently get the data:
Container(
child: StreamBuilder(
stream: Firestore.instance.collection('users').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(themeColor),
),
);
} else {
return ListView.builder(
scrollDirection: Axis.vertical,
padding: EdgeInsets.all(10.0),
itemBuilder: (context, index) => buildItem(context, snapshot.data.documents[index]),
itemCount: snapshot.data.documents.length,
);
}
},
),
),
Thanks in advance, any help is appreciated.
Builditem looks like this:
Widget buildItem(BuildContext context, DocumentSnapshot document) {
if (document['id'] == currentUserId || document['gender'] == null) {
return Container();
}
if (currentUserPreference == 'male' && currentUserGender == 'male') {
return showGayMales(document);
}
And the ShowGayMales method looks like this:
Widget showGayMales(DocumentSnapshot document) {
if (document['id'] == currentUserId || document['id'] == nopeId || ) {
return Container();
} else {
return Container(
child: Slidable(
delegate: new SlidableScrollDelegate(),
actionExtentRatio: 0.3,
child: Card(
child: Padding(
padding:EdgeInsets.fromLTRB(20.0, 10.0, 25.0, 10.0),
child: Row(
children: <Widget>[
Material(
color: Colors.transparent,
child: Icon(
FontAwesomeIcons.male,
color: textColor,
),
),
new Flexible(
child: Container(
child: new Column(
children: <Widget>[
new Container(
child: Text(
'${document['aboutMe']}',
style: TextStyle(color: textColor, fontSize: 30.0),
),
alignment: Alignment.centerLeft,
margin: new EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 5.0),
),
new Container(
child: Row(
children: <Widget>[
Text(
'-'+'${document['nickname'] ?? 'Not available'}',
style: TextStyle(color: textColor, fontSize: 15.0, fontWeight: FontWeight.bold),
),
Text(
','+' ${document['age'] ?? ''}'
)
],
),
alignment: Alignment.centerLeft,
margin: new EdgeInsets.fromLTRB(10.0, 0.0, 0.0, 0.0),
)
],
),
margin: EdgeInsets.only(left: 20.0),
),
),
],
),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
),
actions: <Widget>[
new IconSlideAction(
caption: 'Not interested!',
color: errorColor,
icon: Icons.clear,
onTap: () => notinterested('${document['id']}'),
),
],
secondaryActions: <Widget>[
new IconSlideAction(
caption: "Interested!",
color: primaryColor,
icon: Icons.check,
onTap: () => interested('${document['nickname']}', '${document['id']}', '${document['gender']}', '${document['aboutMe']}', '${document['age']}', '${document['preference']}'),
),
],
),
margin: EdgeInsets.only(bottom: 10.0, left: 5.0, right: 5.0),
);
}
}
You can fetch Firestore data and add it to a List by mapping it to an Object first.
List<Users> userList;
Future<void> getUsers() async {
userList = [];
var collection = FirebaseFirestore.instance.collection('users');
collection.get().then((value) {
value.docs.forEach((users) {
debugPrint('get Users ${users.data()}');
setState(() {
// Map users.data to your User object and add it to the List
userList.add(User(User.setUserDetails(users.data())));
});
});
});
}
// Let's say this is User object
class User {
var username;
User(User doc) {
this.username = doc.getUsername();
}
getUsername() => username;
// fetch name using Firestore field name
User.setUserDetails(Map<dynamic, dynamic> doc)
: username = doc['name'];
}

Resources