How to use Variables Cloud Firestore in Flutter (Dart) while doing query - firebase

This is my working code:
final Stream<QuerySnapshot> products = FirebaseFirestore.instance
.collection('products')
.doc('men')
.collection('tshirts')
.snapshots();
This is the code I want but not working:
String val = 'tshirts';
final Stream<QuerySnapshot> products = FirebaseFirestore.instance
.collection('products')
.doc('men')
.collection(val)
.snapshots();
Error: The instance member 'val' can't be accessed in an initializer.
Try replacing the reference to the instance member with a different expression
The bellow code I am using in build widget to show database query results & working fine:
GridView.count(
physics: const BouncingScrollPhysics(),
crossAxisCount: 2,
childAspectRatio: 0.5,
mainAxisSpacing: 30,
crossAxisSpacing: 10,
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return Visibility(
child: GestureDetector(
onTap: () {
Navigator.push(
context,
PageTransition(
type: PageTransitionType.bottomToTop,
child: const ProductView(productId: '3453245'),
));
},
child: Stack(
children: [
Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage('${data['img']}'),
fit: BoxFit.cover)),
),
Align(
alignment: Alignment.bottomLeft,
child: SizedBox(
height: 70,
width: double.infinity,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: const EdgeInsets.only(
right: 18, top: 15, left: 5),
child: Text(
data['name'].toUpperCase(),
textAlign: TextAlign.left,
style: GoogleFonts.oswald(
color: Colors.black,
fontSize: 15,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
softWrap: false,
),
),
Container(
margin: const EdgeInsets.only(left: 5),
child: Text(
'\u{20B9} ${data['price']}',
textAlign: TextAlign.left,
style: const TextStyle(
color: Colors.black,
fontSize: 14,
),
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
)
],
),
).frosted(
blur: 7,
),
),
],
)),
visible: true,
);
}).toList(),
)

You are trying to use val before even initializing the class that is used.
You can only access it inside a method or the constructor, example:
#override
void initState() {
super.initState();
final Stream<QuerySnapshot> products = FirebaseFirestore.instance.collection('products').doc('men').collection(val).snapshots();
}

Related

How to put different images and redirect users to other pages in ListView Builder?

Writing a code in Flutter right now and I can display a database with ListView.
However, I want to put pictures of the destination according to its location so I was wondering how to put different images for each different item? The same goes for the onTap void callback function as well. I want each list item to go to different pages where further details of the destination is given.
Code:
class _DispDestState extends State<DispDest> {
List<AllDestinations> destinationsList = [];
#override
void initState() {
super.initState();
DatabaseReference referenceAllCourses = FirebaseDatabase.instance
.reference()
.child('Database')
.child('Destinations');
referenceAllCourses.once().then(((DataSnapshot dataSnapshot) {
destinationsList.clear();
var keys = dataSnapshot.value.keys;
var values = dataSnapshot.value;
for (var key in keys) {
AllDestinations allDestinations = new AllDestinations(
values[key]['name'],
values[key]['description'],
values[key]['category'],
);
if (allDestinations.category.toString() == 'Destination')
destinationsList.add(allDestinations);
}
setState(() {});
}));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.fromLTRB(20, 5, 20, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
"Come and Explore",
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 14,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.w500,
letterSpacing: 0.5,
),
),
SizedBox(height: 15),
Expanded(
child: SingleChildScrollView(
child: Column(children: <Widget>[
destinationsList.length == 0
? Center(
child: Text(
"Loading...",
style: TextStyle(fontSize: 15),
))
: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: destinationsList.length,
itemBuilder: (_, index) {
return DestinationCard(
title: destinationsList[index].destname,
onTap: () {},
img: 'assets/icons/temp.png');
})
]),
),
),
])));
}
}
class DestinationCard extends StatelessWidget {
final String title, img;
final VoidCallback onTap;
const DestinationCard({
Key? key,
required this.title,
required this.img,
required this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 400,
height: 190,
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
child: Column(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(15, 155, 0, 0),
width: 350,
height: 190,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
image: AssetImage(img), fit: BoxFit.cover),
),
child: Text(
title,
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
);
}
}
You should add a parameter named imagePath to AllDestinations class. So when you use DestinationCard in ListView.builder, you can add:
return DestinationCard(
title: destinationsList[index].destname,
onTap: () {},
img: destinationsList[index].imagePath,
);

i want to create a listview with firebase in flutter that will show title subtitle and image and when user click on listview that will open a webview

I sm creating a flutter app where i want to create a listview with firebase in flutter that will show title subtitle and image and when user click on listview that will open a webview but I want the web view URL should come from the firebase title subtitle and the image part already working I stuck in the URL part please help how to do this
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:watched_movie_list/Widget/webviewx.dart';
class ListviewPage extends StatefulWidget {
final firBaseLists;
final String webviewTitle;
final String weburl;
ListviewPage(
{this.firBaseLists, required this.webviewTitle, required this.weburl});
#override
_ListviewPageState createState() => _ListviewPageState();
}
class _ListviewPageState extends State<ListviewPage> {
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: FirebaseFirestore.instance.collection('listview').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CupertinoActivityIndicator(
radius: 20,
),
);
}
return Scaffold(
appBar: AppBar(
title: Text(
' नवीनतम सूचनाएं',
style: TextStyle(color: Colors.black),
),
leading: BackButton(color: Colors.black),
backgroundColor: Colors.white,
),
body: Container(
height: 800,
color: Color(0xfff5f5f5),
child: ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InAppWebViewx(
title: widget
.firBaseLists["${data['titletext']}"],
url: widget.firBaseLists("${data['url']}"),
)));
},
child: Container(
height: 150,
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.circular(18)),
margin:
EdgeInsets.only(top: 8, right: 12, left: 12, bottom: 2),
child: Row(
children: [
Container(
padding: const EdgeInsets.only(top: 15, left: 20),
height: 150,
width: 330,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.network(
"${data['img']}",
height: 40,
width: 40,
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"${data['titletext']}",
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
"${data['subtitle']}",
maxLines: 2,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.white,
),
),
),
],
),
),
],
),
),
);
}).toList(),
),
),
);
},
);
}
}```
You should use Listview.builder instead of Listview. Inside the Listview.builder you could capture the data with index of the itemBuilder and pass it to the WebView. Here's the link to get started on Listview.builder https://www.geeksforgeeks.org/listview-builder-in-flutter/

Error is not showing after scanning a item thats not on the firestore database

I did this personal project of mine where a barcode scanner would scan for data inside firestore database. I have this problem when I scanned a barcode thats not on the database it wont show the error message is just shows a empty scan item container which I made. Let me know if someone can figure why. I tried everything still couldnt fix it.
StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance
.collection("products")
.where("barcode", isEqualTo: '$barcodeScanRes')
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Dialog(
child: Container(
height: 300,
child: Text('Product Not Found'),
),
);
} else {
return Dialog(
child: Container(
height: 350,
child: Column(children: [
Container(
height: 350,
width: 165,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot products =
snapshot.data!.docs[index];
return ScanCard(products: products);
},
)),
]),
),
);
#Scan Card
class ScanCard extends StatelessWidget {
const ScanCard({
Key? key,
required this.products,
}) : super(key: key);
final DocumentSnapshot products;
#override
Widget build(BuildContext context) {
final user = FirebaseAuth.instance.currentUser;
String _userId = user!.uid;
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.all(10.0),
height: 180,
width: 160,
decoration: BoxDecoration(
color: Colors.blueAccent,
borderRadius: BorderRadius.circular(16)),
child: Image.network(products['img']),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 20.0 / 4),
child: Text(
products['name'],
style: TextStyle(
color: Colors.blueGrey,
fontSize: 18,
),
),
),
Column(
children: [
Text(
"Size: " + products['size'],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14, color: Colors.brown),
),
SizedBox(
width: 30,
),
],
),
Row(
children: [
Text(
"\tRs. " + products['price'],
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
SizedBox(
width: 40,
),
Icon(
Icons.add_shopping_cart,
color: Colors.black,
size: 25,
),
],
),
SizedBox(
width: 10,
),
SizedBox(
child: Padding(
padding: const EdgeInsets.all(10),
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Colors.red,
child: Text(
"Add to cart",
style: TextStyle(color: Colors.white),
),
onPressed: () {
DocumentReference documentReference = FirebaseFirestore.instance
.collection('userData')
.doc(_userId)
.collection('cartData')
.doc();
documentReference.set({
'uid': FirebaseAuth.instance.currentUser!.uid,
'barcode': products['barcode'],
'img': products['img'],
'name': products['name'],
'size': products['size'],
'price': products['price'],
'id': documentReference.id
}).then((result) {
addToCartMessage(context).then((value) => {
Navigator.pop(context)
});
}).catchError((e) {
print(e);
});
},
),
),
)
],
);
}
}
The thing is you are showing Product not found based on the condition:- !snapshot.hasData but this conditon means that data is being fetched so at this time rather show a progress indicator.
And to handle when data is not present in backend then add another condition:- if(snapshot.data.docs.isEmpty) and here show your dialogbox of Product not found...
Final Code Snippet will look like:-
if (!snapshot.hasData)
return Center(child:CircularProgressIndicator));//or return a black container if you don't want to show anything while fetching data from firestore
else if (snapshot.data.docs.isEmpty) {
return Dialog(
child: Container(
height: 300,
child: Text('Product Not Found'),
),
);
} else {
return Dialog(
child: Container(
height: 350,
child: Column(children: [
Container(
height: 350,
width: 165,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot products =
snapshot.data!.docs[index];
return ScanCard(products: products);
},
)),
]),
),
);
}

type 'Future<dynamic>' is not a subtype of type 'Widget?'

IM trying to call on Tap method, what I want now is change it to a future method because on Tap the method is not ready because im calling a firebase query . So heres first my method
where the onTap function is
child: InkWell(
onTap: () async {
setState(() {
israting = true;
});
},
child: israting
? buildBody(videos.data()['likes'], videos.data()['id'])
: Icon(
Icons.star,
size: 37,
color: videos.data()['likes'].contains(uid)
? Colors.yellow
: Colors.white,
),
),
So im giving the buildBody 2 parameters from a streambuilder
and then thats the function
buildBody(videoid, video) async {
if (videoid.contains(uid)) {
await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get()
.then((value) {
votefromfirebase = value.data()["rating"];
});
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: votefromfirebase,
itemBuilder: (context, index) => InkWell(
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
print(video);
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
));
} else {
return Container(
child: Stack(
children: [
Padding(
padding: const EdgeInsets.fromLTRB(3, 7, 0, 0),
child: Align(
alignment: Alignment.topLeft,
child: RatingBarIndicator(
rating: _userRating,
itemBuilder: (context, index) => InkWell(
onTap: () {
setState(() {
_userRating = index + 1.toDouble();
});
likevideo(video, _userRating);
},
child: Icon(
Icons.star,
color: Colors.amber,
),
),
itemCount: 5,
itemSize: 31.0,
direction: Axis.horizontal,
),
),
),
Align(
alignment: Alignment.topRight,
child: TextButton(
onPressed: () {
letuservoting = true;
setState(() {
_userRating = 0.0;
israting = false;
});
dislike(idovvideo, _userRating);
},
child: Text(
"Clear",
style: TextStyle(color: Colors.white, fontSize: 20),
),
),
),
],
),
);
}
}
buildprofile(String url) {
return Container(
width: 50,
height: 50,
child: Stack(
children: [
Positioned(
left: (50 / 2) - (50 / 2),
child: Container(
width: 50,
height: 50,
padding: EdgeInsets.all(1),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(25),
),
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(60),
child: Container(
height: 110,
width: 110,
decoration: BoxDecoration(
color: Colors.white,
),
child: url != null && url != "profilepictureer"
? Image.network(
url,
fit: BoxFit.cover,
)
: Image.asset(
'assets/profilepictureer.png') // Your widget is here when image is no available.
),
),
decoration: new BoxDecoration(
shape: BoxShape.circle,
border: new Border.all(color: Colors.black, width: 4)),
),
),
),
],
),
);
}
}
At the moment im getting this error
The following _TypeError was thrown building:
type 'Future<dynamic>' is not a subtype of type 'Widget?'
When the exception was thrown, this was the stack
#0 _VideopageofcurrentuserState.build.<anonymous closure>.<anonymous closure> (package:wichtigdenyady/taking%20videos/currentuservideos.dart:310:47)
#1 SliverChildBuilderDelegate.build
package:flutter/…/widgets/sliver.dart:455
#2 SliverMultiBoxAdaptorElement._build
package:flutter/…/widgets/sliver.dart:1201
#3 SliverMultiBoxAdaptorElement.performRebuild.processElement
package:flutter/…/widgets/sliver.dart:1145
#4 Iterable.forEach (dart:core/iterable.dart:257:30)
The error throws in the onTap function
The buildBody function cannot be an async function.
You should move the call to Firebase out of this function and use the result of it in state, instead.
An async function always returns a Future. Because the return type isn't defined, it assumes it will return a Future<dynamic>. If you defined the return type as Widget buildBody(videoid, video) async, the IDE would show an error.
In your onTap function, you can make the call:
onTap: () async {
setState(() {
israting = true;
});
if(!videos.data()['likes'].contains(uid)) return; // don't call firebase if uid is not in videoid
final value = await FirebaseFirestore.instance
.collection("videos")
.doc(video)
.collection("uservotes")
.doc(uid)
.get();
setState(() {
votefromfirebase = value.data()["rating"];
});
},
Next, change the buildBody function to a non-async function and check if votefromfirebase is in the state
Widget buildBody(videoid, video) {
if (votefromfirebase == null) {
return Container(); // return empty container, progress indicator, or anything else
}
// else return the normal body
return Container(
child: Stack(
// rest of this widget

Fetch user data from firestore and show them in profile screen using flutter

The issue here is that when I fetch the data, I am suppose to fetch it for the current user but it is rather fetching data for all users within that collection.
I have done reading and watched a number of videos for a possible solution but I can't seem to find how to do this. Your help is needed please. Thanks.
A excerpt of the bode is below.
File image;
TextEditingController loginNameController = TextEditingController();
TextEditingController loginPhoneController = TextEditingController();
TextEditingController loginAddressController = TextEditingController();
clearForm() {
setState(() {
image = null;
loginNameController.clear();
loginPhoneController.clear();
loginAddressController.clear();
});
}
//=====> FOR INSTANCES OF FIREBASE <=====
final auth = FirebaseAuth.instance;
final db = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
body: Padding(
padding: EdgeInsets.only(left: 20, right: 20),
child: StreamBuilder(
stream: db.collection("collection name").snapshots(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if (!snapshot.hasData) {
return Center(
child: spinkit,
);
}
return ListView.builder (
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, int index){
return Stack(
children: [
Column(
children: [
Stack(
children: [
// ===> RETRIEVING USER DETAILS AND SHOWING IT IN A ROW <===
Container(
padding : EdgeInsets.only(top: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
CircleAvatar(
backgroundColor: Palette.mainColor,
radius: 50,
child: ClipOval(
child: SizedBox(
height: 150,
width: 150,
child: image == null ? Center(
// child: Image.asset("asset/images/placeholder.png", fit: BoxFit.cover,),
child: Image.network(snapshot.data.documents[index].get("image")),
):
Image.file(image, fit: BoxFit.cover,),
),
),
),
SizedBox(width: 16,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: EdgeInsets.only(left: 0),
child: Text(snapshot.data.documents[index].get("Name"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),),
),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Address"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
SizedBox(height: 5,),
Text(snapshot.data.documents[index].get("Number"),
style: TextStyle(
letterSpacing: 2,
color: Colors.black54,
fontSize: 16,
),),
],
),
),
Padding(
padding: EdgeInsets.only(left: 0, bottom: 15),
child: IconButton(
icon:Icon(Icons.edit, color: Palette.mainColor, ),
onPressed: () { },
),
),
],
),
),
],
),
],
),
],
);
},
);
},
),
)
The collection name is members
Try like this, stream of your widget should be like this, as said above.
db.collection("Users").document(user.uid).snapshots();
for length in Listview.builder, change it too
snapshot.data.length;
And last, All the data which you fetch data like this should change into
from:
snapshot.data.documents[index].get("image")
To:
snapshot.data["image"]
Note I didn't test it. So, it might or might not work.
First of All use a DocumentSnapshot Shown below:
StreamBuilder<DocumentSnapshot>
Make a collection to get current user Profile data.
db.collection("Users").doc(user.uid).snapshots();
Remove ListView.builder
To get an Email Address use the below Line
Text('${streamSnapshot.data['Email Address']}'),
Here is the complete Article https://medium.com/#kamranktk807/fetch-user-data-from-firestore-and-show-them-in-profile-screen-using-flutter-609d2533e703
By the way I sol this problem with the help of a Professional Flutter Developer SHAKIR ZAHID [shakirzahid191#gmail.com].

Resources