Snapshot from StreamBuilder - flutter

I am working on a ListView inside a Streambuilder with data from Cloud Firestore.
Here you have the code:
//inicio stream
StreamBuilder<List<Evento>>(
stream: eventosProvider
.eventosbares,
builder: (context, snapshot) {
if (snapshot
.data.isNotEmpty) {
return SizedBox(
height: 155,
child: ListView.builder(
scrollDirection:
Axis.horizontal,
itemCount: snapshot
.data.length,
itemBuilder:
(context,
index) {
var dateString =
snapshot
.data[
index]
.fechaEvento;
var date = DateFormat(
'd-M-yyyy HH:mm',
'de_DE')
.parse(
dateString);
return Card(
shape:
RoundedRectangleBorder(
borderRadius:
BorderRadius
.circular(
10),
),
child:
Container(
height: 178,
width: 280,
child: Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 8.0,
right: 8.0,
top: 8.0),
child:
ClipRRect(
borderRadius:
BorderRadius.circular(8),
child:
Image.network(
snapshot.data[index].imagenEvento,
width: 278.0,
height: 80.0,
fit: BoxFit.fill,
),
),
),
Padding(
padding:
const EdgeInsets.all(8.0),
child:
Row(
mainAxisAlignment:
MainAxisAlignment.start,
children: [
CircleAvatar(
radius: 20.0,
backgroundImage: NetworkImage(snapshot.data[index].fotoPerfilAutor),
backgroundColor: Colors.transparent,
),
Padding(
padding: const EdgeInsets.all(2.0),
child: Container(
width: 150,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
snapshot.data[index].tituloEvento,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 13,
),
),
Text(
DateFormat('EEEEE dd MMM yyyy HH:mm', 'es_ES').format(date),
style: TextStyle(fontSize: 10),
),
],
),
),
),
SizedBox(
width: 10,
),
Text(
snapshot.data[index].num_invitados,
style: TextStyle(color: ColoresApp.naranjaTop, fontWeight: FontWeight.bold, fontSize: 14),
),
SizedBox(
width: 5,
),
CircleAvatar(
radius: 10.0,
backgroundImage: AssetImage("assets/friends.png"),
backgroundColor: Colors.transparent,
)
],
),
),
]),
),
);
}),
);
} else {
return Text(
"No hay eventos en bares",
style: TextStyle(
color:
Colors.white),
);
}
}),
I am getting the following exception using this code, the app is not exiting, it only shows a red error background for a moment, but it is not acceptable:
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building StreamBuilder<List<Evento>>(dirty, state: _StreamBuilderBaseState<List<Evento>, AsyncSnapshot<List<Evento>>>#d6fd3):
The getter 'isNotEmpty' was called on null.
Receiver: null
Tried calling: isNotEmpty
I have tried changing the line:
if (snapshot.data.isNotEmpty)
with
if (snaphot.hasData)
but then, the exception is gone, but there is a blank space thrown, not the else part of the if clause.
What should I do to know if the snapshop has really data or is waiting to get them?
EDIT
Here you have the service loading the Stream:
Stream<List<Evento>> getEventosBares(){
return _db
.collection('eventos').where('interes', isEqualTo: 'bares')
.snapshots()
.map((snapshot) => snapshot.docs
.map((doc) => Evento.fromJson(doc.data()))
.toList());
}
And here you have the provider:
Stream<List<Evento>> get eventosbares => firestoreService.getEventosBares();

Try adding a null check:
builder: (context, snapshot) {
if (snapshot.data != null && snapshot.data.isNotEmpty) {
return SizedBox(...);

Related

Future function reloads infinitely? flutter

i am building a simple ecommerce app but i am stuck at a position when my future function reloads infinitely:
Future getCartData() async {
print("function one");
print("this is the token mytoken");
String url = 'https://myurl/apis/getCartItems';
http.Response response = await http.post(Uri.parse(url),
headers: {
'Authorization': "token mytoken",
"Content-Type": "application/json",
},
body: json.encode({
"username": "admin",
}));
print(response.body);
var data = json.decode(response.body);
print("cart data recieved :");
print(data.length);
//set state
setState(() {
lengthData=data.length.toString();
totalPrice=0;
});
return data;
}
i am using set state becouse i need to set this value once the data return but this set state reloading again and again when i remove it future function run only once but it not update the values of "lengthData" and "totalPrice".
my init function:
initState(){
getCartData();
super.initState();
}
and here is my futurebuilder:
child:FutureBuilder(
future: getCartData(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
// still waiting for data to come
return Center(
child: CircularProgressIndicator(),
);
} else if (snapshot.hasData &&
snapshot.data.isEmpty) {
return Center(child: Text("No Products"));
;
} else {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext context, index) {
List list = snapshot.data;
totalPrice = totalPrice + list[index]['price'];
print("this is the total:$totalPrice");
return Container(
margin: EdgeInsets.only(top: 20),
height: 130,
child: Stack(
children: <Widget>[
Align(
alignment: Alignment(0, 0.8),
child: Container(
height: 100,
margin: EdgeInsets.symmetric(
horizontal: 16.0),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: shadow,
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(
10))),
child: Row(
mainAxisAlignment: MainAxisAlignment
.end,
children: <Widget>[
Container(
padding: EdgeInsets.only(
top: 12.0, right: 12.0),
width: 200,
child: Column(
crossAxisAlignment: CrossAxisAlignment
.start,
children: <Widget>[
Text(
'${list[index]['title']}',
textAlign: TextAlign.right,
style: TextStyle(
fontWeight: FontWeight
.bold,
fontSize: 12,
color: darkGrey,
),
),
Align(
alignment: Alignment
.centerRight,
child: Container(
width: 160,
padding: const EdgeInsets
.only(
left: 32.0,
top: 8.0,
bottom: 8.0),
child: Row(
mainAxisAlignment:
MainAxisAlignment
.spaceBetween,
children: <Widget>[
ColorOption(
Colors.red),
Text(
"\₹${list[index]['price']}",
textAlign: TextAlign
.center,
style: TextStyle(
color: darkGrey,
fontWeight: FontWeight
.bold,
fontSize: 18.0),
)
],
),
),
)
],
),
),
Theme(
data: ThemeData(
accentColor: Colors.black,
textTheme: TextTheme(
headline6: TextStyle(
fontFamily: 'Montserrat',
fontSize: 14,
color: Colors.black,
fontWeight: FontWeight
.bold),
bodyText1: TextStyle(
fontFamily: 'Montserrat',
fontSize: 12,
color: Colors.grey[400],
),
)),
child: NumberPicker(
value: 2,
minValue: 1,
maxValue: 10,
onChanged: (value) {
// setState(() {
// quantity = value;
// });
},
))
])),
),
Positioned(
top: 5,
child: SizedBox(
height: 150,
width: 200,
child: Stack(children: <Widget>[
Positioned(
left: 25,
child: SizedBox(
height: 150,
width: 150,
child: Transform.scale(
scale: 1.2,
child: Image.asset('assets/bottom_yellow.png'),
),
),
),
Positioned(
left: 50,
top: 5,
child: SizedBox(
height: 80,
width: 80,
child: Image.network(
'$Imagename',
fit: BoxFit.contain,
)),
),
Positioned(
right: 30,
bottom: 25,
child: Align(
child: IconButton(
icon: Image.asset('assets/red_clear.png'),
onPressed: (){
deleteCartData('${list[index]['id']}');
},
),
),
)
]),
)
),
],
),
);
}
):Center(child: Text("no data"));
}
},
)
can someone please help me and suggest me a better way to solve it <3.
Thanks in Advance <3.
You need to return a Future from your 'getCartData()' method, now you are returning just a Hashmap instead of a Future which the futureBuilder needs. You can do it like this:
return Future.value(data);
One more thing is that you must just pass the reference to the method and not call it, like this:
future: getCartData,
Also please specify the return types, use Future<Map<String, dynamic>> or whatever you are returning (this will help you in the future) :D
And one more, you don't need to call your method in 'initState()' since the FutureBuilder will do it for you :)

two streambuilders gives me RangeError (index): Invalid value: Only valid value is 0: 1 when it supposed to read two docs from 2 different collections

What im trying to do is filling a card with the necessary data it needs which is userImage and UserFirstname from my users collection and also data from my subcollection(carReviews)in my carInfo collection where i store the necessary review data:
subcollection(carReviews)
users collection
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('carInfo')
.doc(snapshot.data!.docs[index]
.get('CaradvId'))
.collection('carReviews')
.snapshots(),
builder: (context, snapshot5) {
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('users')
.where('uid',
isEqualTo: snapshot5
.data!.docs[index]
.get('reviewerId'))
.snapshots(),
builder: (context, snapshot6) {
return Container(
padding: EdgeInsets.symmetric(
horizontal: 5),
height: MediaQuery.of(context)
.size
.height *
0.225,
child: ListView.builder(
shrinkWrap: true,
scrollDirection:
Axis.horizontal,
itemCount: snapshot5
.data!.docs.length,
itemBuilder:
(BuildContext context,
int index) {
DateTime date = snapshot5
.data!.docs[index]
.get('reviewDate')
.toDate();
String dateString =
DateFormat(
'dd MMM yyyy')
.format(date);
return ConstrainedBox(
When i print snapshot5.data!.docs[index].get('reviewerId') i get the two ids who has reviewed which what is expected however the snapshot6.data!.docs.length is 1 which doesn't make any sense!
I have tried using both snapshot6.data!.docs.length & snapshot5.data!.docs.length for the itemcount if i use snapshot6.data!.docs.length i get just one item in list with no errors and if i use snapshot5.data!.docs.length i get range error because it goes through all reviews which are just 2. Me using "hasdata" if statment wont change the output i have tried.
how it looks when i use snapshot5.data!.docs.length
how it looks when i use snapshot6.data!.docs.length
Card(
elevation: 2,
child: Container(
child: Column(
mainAxisAlignment:
MainAxisAlignment
.start,
children: [
Row(
mainAxisAlignment:
MainAxisAlignment
.start,
children: [
Container(
padding: EdgeInsets.only(
left:
12.5,
top:
12.5),
height:
55,
width:
55,
child:
CircleAvatar(
backgroundImage:
NetworkImage(
snapshot6.data!.docs[index].get('userImage'),
), //userimage
radius:
40,
),
),
Container(
padding: EdgeInsets.only(
top:
15),
child:
Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
Container( padding: EdgeInsets.only(
left:
5),child:
RatingBar.builder(
initialRating: double.parse(snapshot5.data!.docs[index].get('reviewRating')),
minRating: 1,
direction: Axis.horizontal,
allowHalfRating: true,
updateOnDrag: false,
itemCount: 5,
itemSize: 14,
itemPadding: EdgeInsets.symmetric(vertical: 0),
itemBuilder: (context, _) => Icon(
Icons.star,
color: Colors.amber,
),
onRatingUpdate: (rating) {
print(rating);
},
),
),
SizedBox(height: 7.5),
Row(
children: [
Container(
padding: EdgeInsets.only(
left: 7.5,
),
child: Text(
snapshot6.data!.docs[index].get('userFirstname'),
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w800,
color: Colors.black87,
),
),
),
Container(
padding: EdgeInsets.only(left: 2.5),
child: Text(
dateString,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: TextStyle(
fontSize: 10,
fontWeight: FontWeight.w800,
color: Colors.black54,
),
))
],
)
],
)),
],
),
Container( padding: EdgeInsets.only(
left:
12.5,
top:
12.5),
height: 130,width: MediaQuery.of(
context)
.size
.width *
0.75,
child: Text(snapshot5
.data!
.docs[
index]
.get(
'reviewContent')),
)
],
),
)),

Flutter - setState() or markNeedsBuild() called during build

Showing Error While loading post from Firebase Cloud.. I am using provider in my Application
setState() or markNeedsBuild() called during build.
Detailed Error
════════ Exception caught by foundation library ════════════════════════════════
The following assertion was thrown while dispatching notifications for PostFunctions:
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<PostFunctions> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
My Code When I Load Post..
Widget feedBody(BuildContext context) {
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.orderBy('time', descending: true)
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: SizedBox(
height: 200.0,
width: 200.0,
child: Lottie.asset('assets/animations/loading.json'),
),
);
} else {
return loadPosts(context, snapshot);
}
},
),
height: MediaQuery.of(context).size.height * 0.80,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: constantColors.darkColor.withOpacity(0.6),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(18.0),
topRight: Radius.circular(18.0),
),
),
),
),
);
}
My Load Post Code
Widget loadPosts(
BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
return ListView(
children: snapshot.data.docs.map((DocumentSnapshot documentSnapshot) {
Provider.of<PostFunctions>(context, listen: false)
.showTimeAgo(documentSnapshot.data()['time']);
return Container(
height: MediaQuery.of(context).size.height * 0.62,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
top: 8.0,
left: 8.0,
),
child: Row(
children: [
GestureDetector(
onTap: () {
if (documentSnapshot.data()['useruid'] !=
Provider.of<Authenticationss>(context, listen: false)
.getUserUid) {
Navigator.pushReplacement(
context,
PageTransition(
child: AltProfile(
userUid: documentSnapshot.data()['useruid'],
),
type: PageTransitionType.bottomToTop,
),
);
}
},
child: CircleAvatar(
backgroundColor: constantColors.blueGreyColor,
radius: 20.0,
backgroundImage:
NetworkImage(documentSnapshot.data()['userimage']),
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Container(
width: MediaQuery.of(context).size.width * 0.6,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Text(
documentSnapshot.data()['caption'],
style: TextStyle(
color: constantColors.greenColor,
fontWeight: FontWeight.bold,
fontSize: 16.0),
),
),
Container(
child: RichText(
text: TextSpan(
text: documentSnapshot.data()['username'],
style: TextStyle(
color: constantColors.blueColor,
fontSize: 14.0,
fontWeight: FontWeight.bold,
),
children: <TextSpan>[
TextSpan(
text:
' , ${Provider.of<PostFunctions>(context, listen: false).getImageTimePosted.toString()}',
style: TextStyle(
color: constantColors.lightColor
.withOpacity(0.8),
),
)
],
),
),
),
],
),
),
),
Container(
width: MediaQuery.of(context).size.width * .2,
height: MediaQuery.of(context).size.height * 0.05,
child: StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.doc(documentSnapshot.data()['caption'])
.collection('awards')
.snapshots(),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return ListView(
scrollDirection: Axis.horizontal,
children: snapshot.data.docs
.map((DocumentSnapshot documentSnapshot) {
return Container(
height: 30.0,
width: 30.0,
child: Image.network(
documentSnapshot.data()['award']),
);
}).toList(),
);
}
},
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Container(
height: MediaQuery.of(context).size.height * 0.45,
width: MediaQuery.of(context).size.width,
child: FittedBox(
child: Image.network(
documentSnapshot.data()['postimage'],
scale: 2,
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Padding(
padding: const EdgeInsets.only(left: 21.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: 80.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onLongPress: () {
Provider.of<PostFunctions>(context, listen: false)
.showLikes(
context,
documentSnapshot.data()['caption'],
);
},
onTap: () {
print('adding like');
Provider.of<PostFunctions>(context, listen: false)
.addLike(
context,
documentSnapshot.data()['caption'],
Provider.of<Authenticationss>(context,
listen: false)
.userUid);
},
child: Icon(
FontAwesomeIcons.heart,
color: constantColors.redColor,
size: 22.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.doc(documentSnapshot.data()['caption'])
.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: Text(
snapshot.data.docs.length.toString(),
style: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
);
}
},
)
],
),
),
Container(
width: 80.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onTap: () {
Provider.of<PostFunctions>(context, listen: false)
.shotCommentSheets(context, documentSnapshot,
documentSnapshot.data()['caption']);
},
child: Icon(
FontAwesomeIcons.comment,
color: constantColors.blueColor,
size: 22.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.doc(documentSnapshot.data()['caption'])
.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: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
);
}
},
)
],
),
),
Container(
width: 80.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
GestureDetector(
onLongPress: () {
Provider.of<PostFunctions>(context, listen: false)
.showAwardPresenter(context,
documentSnapshot.data()['caption']);
},
onTap: () {
Provider.of<PostFunctions>(context, listen: false)
.showReward(context,
documentSnapshot.data()['caption']);
},
child: Icon(
FontAwesomeIcons.award,
color: constantColors.yellowColor,
size: 22.0,
),
),
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection('posts')
.doc(documentSnapshot.data()['caption'])
.collection('awards')
.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: TextStyle(
color: constantColors.whiteColor,
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
);
}
},
)
],
),
),
Spacer(),
Provider.of<Authenticationss>(context, listen: false)
.getUserUid ==
documentSnapshot.data()['useruid']
? IconButton(
icon: Icon(
EvaIcons.moreVertical,
color: constantColors.whiteColor,
),
onPressed: () {
Provider.of<PostFunctions>(context, listen: false)
.showPostOptions(context,
documentSnapshot.data()['caption']);
},
)
: Container(
height: 0.0,
width: 0.0,
),
],
),
),
),
],
),
);
}).toList());
}
}
As the error describes, setState is called even before the build function is completed.
You might not see any issue in you UI when this exception hits on debug or local release mode. But exceptions like these displays a grey screen or something instead of the desired widget on google play release etc.
It means you are try to refresh the page even while the initial widget is already loading.
To prevent calling setState during build method is already in progress, you can check whether your initial widget is mounted properly before calling setState. For doing that just wrap your setState by if statement like this :
if(mounted){
setState((){
});
}
There is also another method with is called after build method is completed. Follow this question to know more : Is there any callback to tell me when "build" function is done in Flutter?

Pass document content from one screen to another in flutter firestore

In the code below, I am trying to pass data from the home screen to the detail screen when user clicks on any of the product listed on the home screen. I seem to be having difficulty here.
Similar Question but does not solve my issue
Excerpt of the code at the home screen.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection("name")
.limit(12)
.orderBy("Published Date", descending: true)
.snapshots(),
builder: (context, snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return GridView.builder(
physics: ScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.docs.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 10.0,
mainAxisSpacing: 10,
),
itemBuilder: (BuildContext context, int index){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: spinkit,
);
}
print("${snapshot.data.documents[index].get('Product Title')}");
return GestureDetector(
onTap: (){
// ===> SEND USER TO THE DETAILS SCREEN <===
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsScreen()),
);
},
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Stack(
children: [
Container(
height: 150,
width: 150,
child: Image.network(
snapshot.data.documents[index].get('image') ?? spinkit,
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
),
Positioned(
left: 0,
bottom: 0,
child: Container(
height: 20,
width: 150,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Colors.black38,
Colors.black38,
],
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
)),
),
),
Positioned(
left: 4,
bottom: 5,
child: Text(
snapshot.data.documents[index].get('name') ?? "Product Name",
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: Palette.whiteColor,
fontSize: 11,
fontWeight: FontWeight.bold),
),
)
],
),
),
);
}
);
},
)
And excerpt of the code at the Details Screen. what you see at the detail screen is data that I have populated manually. it is not coming from firestore.
class ProductDetailsScreen extends StatefulWidget {
#override
_ProductDetailsScreenState createState() => _ProductDetailsScreenState();
}
class _ProductDetailsScreenState extends State<ProductDetailsScreen> {
final productDb = FirebaseFirestore.instance.collection("name");
User user = FirebaseAuth.instance.currentUser;
final spinkit = SpinKitHourGlass(
color: Colors.white,
size: 50.0,
);
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackPressed,
child: Scaffold(
body: SafeArea(
child: Padding(
padding: EdgeInsets.only(left: 15, right: 15, top: 3, bottom: 10),
child: FutureBuilder(
future: productDb.get(),
builder: (context, snapshot){
if(snapshot.connectionState == ConnectionState.waiting){
return Center(
child: spinkit,
);
}
return Container(
child: ListView(
children: [
Column(
children: [
Center(
child: Container(
width: 350,
child: Card(
elevation: 5,
child: Container(
padding: EdgeInsets.all(8),
child: Container(
height: 220,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage("asset/images/headphone.jpg",)
)
),
),
),
),
),
),
SizedBox(height: 10,),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Item Name",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
Text("Item Price",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
],
),
SizedBox(height: 10,),
Text("Item Description",
style: TextStyle(
color: Palette.blackColor,
fontSize: 18,
fontWeight: FontWeight.w300
),),
Container(
height: 1,
width: 100,
color: Colors.black12,
),
SizedBox(height: 10,),
Container(
height: 140,
width: 350,
child: SingleChildScrollView(
child: Wrap(
children: [
Text(
"What is Lorem Ipsum Lorem Ipsum is simply dummy "
"text of the printing and typesetting industry"
" Lorem Ipsum has been the industry's standard"
" dummy text ever since the 1500s when an "
"unknown printer took a galley of type and "
"scrambled it to make a type specimen book "
"it has?",
textAlign: TextAlign.justify,
style: TextStyle(
color: Palette.blackColor,
fontSize: 16,
),),
]
),
),
),
],
),
],
),
);
},
),
)),
),
);
}
}
In your GestureDetector onTap
// ===> SEND USER TO THE DETAILS SCREEN WITH DOC<===
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProductDetailsScreen(snapshot.data.documents[index])),
);
Then
class ProductDetailsScreen extends StatefulWidget {
ProductDetailsScreen(this.doc);
QueryDocumentSnapshot doc;
#override
_ProductDetailsScreenState createState() => _ProductDetailsScreenState();
}
Access in _ProductDetailsScreenState as widget.doc.
The document data will be found at widget.doc.data as a Map<String, dynamic>.

Flutter: How to merge two StreamBuilder and show the output in a card

I'm kinda stuck with what I'm trying to do. I'm trying to merge my two Stream Builder to show the output as one in a card. In my first StreamBuilder thats where I'm getting some infos of the user like the info that he posted, what they need like that. And in my 2nd StreamBuilder thats where I get his/her name, contacts like that. Is it possible to merge it as one? so I'll get the data as one also.
This is how I use my StreamBuilders.
1st stream:
StreamBuilder<QuerySnapshot>(
stream: db.collection('HELP REQUEST').where('Type_OfDisaster', isEqualTo: '[Drought]').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList()
);
} else {
return Container(
child: Center(
child: CircularProgressIndicator()
)
);
}
}
);
2nd Stream:
StreamBuilder<QuerySnapshot>(
stream: db.collection('USERS').where('User_ID', isEqualTo: widget.Uid).snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList()
);
} else {
return Container(
child: Center(
child: CircularProgressIndicator()
)
);
}
}
);
Here is where I output the data I get in the stream builder:
Container buildItem(DocumentSnapshot doc) {
final _width = MediaQuery.of(context).size.width;
final _height = MediaQuery.of(context).size.height;
return Container(
child: Card(
elevation: 5,
child: Padding(
padding: const EdgeInsets.only(top: 20, left: 20, right: 20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(
radius: 30,
backgroundColor: Colors.black,
),
SizedBox(
width: 10,
),
Text('Name: '),
Text(
'${doc.data['Name_ofUser']}',
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w500),
)
],
),
],
),
Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 20,
),
Row(
children: <Widget>[
Text('Date:'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'${doc.data['Help_DatePosted']}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 15, fontWeight: FontWeight.w500),
),
),
],
),
Row(
children: <Widget>[
Text('Location:'),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'${doc.data['Help_Location']}',
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w500),
),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text('Description:'),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'${doc.data['Help_Description']}',
maxLines: 3,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.w500),
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(bottom: 10),
child: Container(
height: _height * 0.05,
width: _width * 0.20,
child: FlatButton(
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.all(Radius.circular(20.0))),
color: Color(0xFF121A21),
onPressed: () {
_viewingRequest(doc.data);
},
child: Text(
'View',
style: TextStyle(
color: Colors.white,
fontSize: 12,
fontWeight: FontWeight.w800),
),
),
),
)
],
),
],
),
),
),
);
}
Is it possible to do it? Please help me.
You can listen to the snapshots without using a StreamBuilder directly, like this:
List<HelpRequestsPlusUsers> helpRequestsPlusUsers = [];
List<User> allUsers = [];
List<HelpRequest> helpRequests = [];
#override
void initState() {
db.collection('USERS').where('User_ID', isEqualTo: widget.Uid).snapshots().listen((snapshot){
allusers = snapshot.data.documents;
mergeUsersWithHelpRequests();
});
db.collection('HELP REQUEST').where('Type_OfDisaster', isEqualTo: '[Drought]').snapshots().listen((snapshot){
helpRequests = snapshot.data.documents;
mergeUsersWithHelpRequests();
});
super.initState();
}
void mergeUsersWithHelpRequests(){
// Run the code to merge your allUsers and helpRequests data into a helpRequestsPlusUsers List
}
Widget
Widget _buildHelpRequestsPlusUsersWidget (){
if (helpRequestsPlusUsers.isNotEmpty) {
return ListView.builder(
itemBuilder: (context, index){
return buildItem(helpRequestsPlusUsers[index]);
}
);
} else {
return Container(
child: Center(
child: CircularProgressIndicator()
)
);
}
}