Flutter Firebase RTDB issue retrieving specific child - flutter

I have tried to retrieve data from a specific child from Firebase RTDB. The problem is that the following error appears (I don't use int):
Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
The log says that the error appears here
DATA[individualKey]['name'],
DATA[individualKey]['picture'],
DATA[individualKey]['price'],
DATA[individualKey]['id'],
DATA[individualKey]['brand'],
DATA[individualKey]['category'],
// DATA[individualKey]['feature'],
// DATA[individualKey]['sale'],
// DATA[individualKey]['colors'],
// DATA[individualKey]['sizes'],
DATA[individualKey]['quantity'],
The code that I am going to show, I use it on another screen with minimal changes and it works
but in the current one that I use it doesn't work
class PostsDetails extends StatefulWidget {
final value2;
PostsDetails({Key key,#required this.value2}) : super(key : key);
#override
_PostsDetailsState createState() => _PostsDetailsState(value2);
}
class _PostsDetailsState extends State<PostsDetails> {
final value2;
_PostsDetailsState(this.value2);
List<Posts>postsList = [];
#override
void initState() {
// TODO: implement initState
super.initState();
DatabaseReference postsRef = FirebaseDatabase.instance.reference().child("Product").child("Shoes").child("Nike").child(value2);
postsRef.once().then((DataSnapshot snap)
{
var KEYS = snap.value.keys;
var DATA = snap.value;
postsList.clear();
for(var individualKey in KEYS)
{
Posts posts = new Posts
(
DATA[individualKey]['name'],
DATA[individualKey]['picture'],
DATA[individualKey]['price'],
DATA[individualKey]['id'],
DATA[individualKey]['brand'],
DATA[individualKey]['category'],
// DATA[individualKey]['feature'],
// DATA[individualKey]['sale'],
// DATA[individualKey]['colors'],
// DATA[individualKey]['sizes'],
DATA[individualKey]['quantity'],
);
postsList.add(posts);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0.1,
backgroundColor: Colors.red,
title: InkWell(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=> new HomePage()));
},
child: Text("SHOP APP")),
actions: <Widget>[
new IconButton(icon: Icon(Icons.search, color: Colors.white,), onPressed: (){}),
],
),
body: new ListView(
children: <Widget>[
new Container(
child: postsList.length == 0 ? new Text("No Available"):new ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: postsList.length,
itemBuilder: (_, index){
new Container(
height: 300.0,
child: GridTile(
child: Container(
color: Colors.white,
// child: Image.network(postsList[index].picture),
),
footer: new Container(
color: Colors.white70,
child: ListTile(
leading: new Text(postsList[index].name,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16.0),),
title: new Row(
children: <Widget>[
Expanded(
// child: new Text("\$"+postsList[index].price, style: TextStyle(fontWeight: FontWeight.bold, color: Colors.red),)
),
],
),
),
),
),
);
})
),
]
)
);
}
}
postslist.length retrieves 0.
final value2 its a child ID. I have verified that it is received well from the previous screen
and if value2 is not used, data will not be retrieved
Posts Class:
class Posts
{
String name;
String picture;
String price;
String id;
String brand;
String category;
String quantity;
// List<> colors;
// List<> sizes;
// bool feature;
// bool sale;
Posts(this.name, this.picture, this.price, this.id, this.category,this.brand,this.quantity);
}
How could it be solved or is there some way to retrieve a specific child? I know how to show a list but not of a specific child thanks

i fixed it, by some reason the code
postsList.length == 0 ? new Text("No Available"):
was the problem so i deleted it

Related

Choice chip value does not update in flutter

i'm trying to store a value coming from the selected choice chip in a variable called etatLabel, so I can send it alongside other values in a form. The problem is that once I first do the selection, the value gets stored successfully, but then the variable's value do not get settled to "" again. Which means if I hit the add button again it will add the value from the choice chip that was last selected.
here is my code:
String etatLabel = "";
class MyOptions extends StatefulWidget {
final ValueNotifier<String?> notifier;
const MyOptions({super.key, required this.notifier});
#override
State<MyOptions> createState() => _MyOptionsState();
}
class _MyOptionsState extends State<MyOptions> {
static const String failedString = "Echec";
int? _value;
List<String> items = ["Succés", failedString];
#override
Widget build(BuildContext context) {
return Column(
children: [
Wrap(
children: List<Widget>.generate(
items.length,
(int index) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 5),
child: Container(
width: 100,
child: ChoiceChip(
backgroundColor: Colors.deepPurple,
selectedColor: _value == 1 ? Colors.red : Colors.green,
label: Align(
alignment: Alignment.center,
child: Text(
'${items[index]}',
style: TextStyle(color: Colors.white),
),
),
selected: _value == index,
onSelected: (bool selected) {
setState(() {
_value = selected ? index : null;
etatLabel = items[index];
});
widget.notifier.value = items[index];
},
),
),
);
},
).toList(),
),
],
);
}
}
I couldn't find a way to solve this, and I appreciate your suggestions/help.

Update an item on a list in my flutter app without having same item with updated value

When I run the code, the list adds another item instead of updating the old item (still displaying the old item) which the index was found. I have also tried as using keys on my listView.builder() listView.custom(), and on the Custom Widget I created which renders on the listView.builder() all give same result. Is there something I'm not doing right?
using the indexWhere() this way,
void updateProduct(String id, ProductSaver productSaver) {
final prodIndex = _productList.indexWhere((element) => element.id == id);
final newProduct = ProductSaver(
title: productSaver.title,
description: productSaver.description,
imageUrl: productSaver.imageUrl,
price: productSaver.price);
_productList[prodIndex] = newProduct as Product;
notifyListeners();
}
and this way:
void updateProduct(String id, Product newItem){
final pIndex = _productList.indexWhere((element)=>element.id == id);
if(pIndex >= 0){
_productList[pIndex] = newItem;}
notifyListeners();}
I also used the list.contain()
void updateProduct({String? id, required Product newItem}) {
final itemIndex = _productList.indexWhere((prod) => prod.id! == id);
if (_productList.contains(_productList[itemIndex])) {
_productList[itemIndex] = newItem;
}
notifyListeners();
}
Here is the build() of the code:
#override
Widget build(BuildContext context) {
final providerData = Provider.of<Products>(context);
return Scaffold(
appBar: AppBar(
title: const Text('Products'),
actions: [
IconButton(
onPressed: () {
Navigator.of(context).pushNamed(EditProductScreen.routeName);
},
icon: const Icon(
Icons.add,
size: 30,
),
)
],
backgroundColor: MyColor.primaryColor,
),
body: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 0, vertical: 10),
itemCount: providerData.item.length,
itemBuilder: (context, index) {
return Column(
children: [
UserProductItem(
id: providerData.item[index].id!,
imageUrl: providerData.item[index].imageUrl,
title: providerData.item[index].title),
)
],
);
}),
);
}
}
the above UserProductItem() Widget.
class UserProductItem extends StatelessWidget {
const UserProductItem({
Key? key,
required this.imageUrl,
required this.title,
required this.id,
}) : super(key: key);
final String imageUrl;
final String title;
final String? id;
#override
Widget build(BuildContext context) {
final productData = Provider.of<Products>(context);
return ListTile(
key: UniqueKey(),
leading: Image.network(
imageUrl,
),
title: Text(
title,
style: const TextStyle(
color: MyColor.primaryColor,
fontSize: 17,
),
),
trailing: FittedBox(
child: Row(
children: [
IconButton(
icon: const Icon(
Icons.edit,
color: Colors.green,
),
onPressed: () {
Navigator.of(context)
.pushNamed(EditProductScreen.routeName, arguments: id!);
},
),
IconButton(
icon: const Icon(
Icons.delete_outline_outlined,
color: Colors.red,
),
onPressed: () {
productData.removeItem(id!);
},
),
],
),
),
);
}
}
You changed the value at a specific index. Instead you can try adding an item to the list
if (_productList.contains(_productList[itemIndex])) {
_productList.add(newItem);//<--here
}

flutter: fetching folder names and storing them in a list from cloud storage

So I have managed to fetch the names of the folder and store them in a list. But the problem I am facing is is the list gets called twice so I tend to have duplicate items in my list view. I've asked similar questions about this but the solutions given don't work on my side.
I know the problem is me calling the getFolders() in the future(which is a bad practice) but that is the only way my code actually work. When I change my list to a type Future I can't use the .add() functionality.
Below is my code:
Here is where I have declared my list:
class Semester extends StatefulWidget {
final String value;
const Semester({Key? key, required this.value}) : super(key: key);
#override
State<Semester> createState() => _SemesterState();
}
class _SemesterState extends State<Semester> {
late List<String> courses = []; // possible culprit
Future<List<FirebaseFolder>>? listResult;
Future<List<String>> getFolders() async {
final storageRef = FirebaseStorage.instance.ref().child(widget.value);
final listResult = await storageRef.listAll();
for (var prefix in listResult.prefixes) {
courses.add(prefix.name);
}
return courses;
}
#override
void initState() {
// TODO: implement initState
super.initState();
getFolders();
}
So when I change the courses to Future<List> I can't use the courses.add(prefix.name) since it says it is not of type future:
And as you can see below I had to use the getFolder() function on my future for it to display contents on my listview, (NOTE: even if I use it on instantiating the result is still same:)
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
leading: kIconButton(),
elevation: 0,
centerTitle: true,
title: const Text("Semester", style: kTitleStyle),
backgroundColor: Colors.white,
),
body: FutureBuilder(
future: getFolders(), // possible culprit
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const Center(
child: spinkitLines,
);
default:
return Column(
children: [
const SizedBox(
height: 20.0,
),
const Center(
child: Text(
'Tap to choose course',
style: kPlaceholderStyle,
),
),
const SizedBox(
height: 30.0,
),
Expanded(
child: ListView.builder(
itemCount: courses.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: GestureDetector(
onTap: () {
String passedValue = widget.value;
String course = courses[index];
String value = "$passedValue""/""$course";
Get.to(() => CourseContent(value: value, courseChosen: course,));
},
child: Container(
height: 80,
decoration: const BoxDecoration(
color: Colors.black,
borderRadius:
BorderRadius.all(Radius.circular(20)),
boxShadow: [
BoxShadow(
color: Color.fromARGB(75, 0, 0, 0),
blurRadius: 4,
spreadRadius: 0,
offset: Offset(0, 4))
],
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Text(
courses[index],
style: kCardTitleStyle,
),
),
),
),
),
);
}),
),
],
);
}
},
),
);
}
}
So I am looking for a way to fetch the list(folders prefixes) and display them in a list view. What I have tried above works but sometimes it displays duplicates which I can tell the getfolder() is being called multiple times.. Help me solve this.
So I came up with a clever and simple solution.
I wrapped my for loop with if to check if the array is empty. if not it won't run that code!
late List<String> courses = [];
Future<List<FirebaseFolder>>? listResult;
Future<List<String>> getFolders() async {
final storageRef = FirebaseStorage.instance.ref().child(widget.value);
final listResult = await storageRef.listAll();
if(courses.isEmpty){
for (var prefix in listResult.prefixes) {
courses.add(prefix.name);
}
}
return courses;
}
It is possible to make sure you get the data from snapshot like this way as shown on blow.
Note: elements in that child is an example.
if(!snapshot.hasData) {
return Center(
child: const CircularProgressIndicator(
backgroundColor: Colors.lightBlue,
),
);
}

I cannot update UI state with riverpod

I'm working on a quiz app as a personal project and what I want to do is make it possible for the user to name a question set. (Kind of like a folder for questions on a particular subject). I am using Riverpod. (I've worked with the provider package a couple of times) for state management but it seems I've missed a step or two because when I type in the name, I don't see it on the page. I hope I can be pointed in the right direction. Thanks
Class forRiverpod model which shows a list of type QuestionSetConstructor for taking the title. There is also a method for accepting the question title to add to the list
class RiverpodModel extends ChangeNotifier {
final List<QuestionSetConstructor> _questionSetList = [];
UnmodifiableListView<QuestionSetConstructor> get questionSet {
return UnmodifiableListView(_questionSetList);
}
void addTitleT(String title) {
final addQuestionTitle = (QuestionSetConstructor(title: title));
_questionSetList.add(addQuestionTitle);
notifyListeners();
}
int get count{
return questionSet.length;
}
}
`
This is for the alert dialog that will take the question title.
In the elevated button, I stated that I want the contents of the
text field to be added to the list in the Riverpod model.
void setQuestionNameMethod(context) {
showDialog(
context: context,
barrierDismissible: true,
builder: (BuildContext context) {
return SetQuestionNameAlertDialog();
});
}
class SetQuestionNameAlertDialog extends ConsumerStatefulWidget {
#override
_SetQuestionNameAlertDialogState createState() =>
_SetQuestionNameAlertDialogState();
}
class _SetQuestionNameAlertDialogState
extends ConsumerState<SetQuestionNameAlertDialog> {
final TextEditingController questionNameController = TextEditingController();
final riverPodModelProvider2 =
ChangeNotifierProvider((ref) => RiverpodModel());
#override
Widget build(
BuildContext context,
) {
final questionNameRef = ref.watch(riverPodModelProvider2);
return AlertDialog(
title: Text("Name of Question Set",
style: TextStyle(
color: Colors.blue[400],
fontSize: 20,
fontWeight: FontWeight.w600)),
content: TextField(
controller: questionNameController,
),
actions: [
Center(
child: ElevatedButton(
onPressed: () {
setState(() {
questionNameRef.addTitleT(questionNameController.text) ;
});
print(questionNameRef.questionSet.first.title);
Navigator.pop(context);
},
child: const Text("Save"))),
],
);
}
}
`
This is the page where the question title is shown as a list. However, for some reason it is not showing.
class QuestionSetPage extends ConsumerStatefulWidget {
#override
_QuestionSetPageState createState() => _QuestionSetPageState();
}
class _QuestionSetPageState extends ConsumerState<QuestionSetPage> {
final riverPodModelProvider =
ChangeNotifierProvider((ref) => RiverpodModel());
#override
Widget build(BuildContext context) {
final questionSetRef = ref.watch(riverPodModelProvider);
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.grey[50],
centerTitle: true,
actions: [
IconButton(
onPressed: () {
setState(() {
setQuestionNameMethod(context);
// modalSheetMethod(context);
});
},
icon: Icon(
Icons.add,
size: 25,
color: Colors.blue[400],
))
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Question Set List",
style: TextStyle(
color: Colors.blue[400],
fontSize: 30,
fontWeight: FontWeight.w600),
),
),
Expanded(
child: ListView.builder(
itemCount: questionSetRef.count,
itemBuilder: (BuildContext context, int index) {
return Tiles(
title: questionSetRef.questionSet[index].title,
);
}),
)
],
),
);
}
}
class Tiles extends StatelessWidget {
String title;
Tiles({required this.title});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(15, 3, 15, 3),
child: Material(
elevation: 2,
child: GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) {
return QuestionSetsQuestionPage();
}));
},
child: ListTile(
title: Text(
title,
style: TextStyle(
color: Colors.blue[400],
fontSize: 17,
fontWeight: FontWeight.w400),
),
tileColor: Colors.white,
// subtitle: Text(
// "${questionSets[index].numberOfQuestions} number of questions",
// ),
leading: const Icon(
Icons.add_box_outlined,
size: 30,
),
),
),
),
);
}
}

how to display data in flutter firestore provider

I want to display data from firestore using provider in flutter. i got stuck please help. below are my codes
//product display page
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
class Product extends StatefulWidget {
#override
_ProductState createState() => _ProductState();
}
class _ProductState extends State<Product> {
#override
Widget build(BuildContext context) {
final product = Provider.of<AppProvider>(context);
return GridView.builder(
itemCount: productList.length,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
itemBuilder: (BuildContext context, int index){
return Padding(
padding:const EdgeInsets.all(4.0),
child:SingleProd(
//where i want to get the product details
prodName: product.featuredProducts[index].name.toString(),
),
);
}
);
}
}
class SingleProd extends StatelessWidget {
final prodName;
final prodPicture;
final prodOldPrice;
final prodPrice;
SingleProd({this.prodName, this.prodPicture,this.prodOldPrice,this.prodPrice});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(tag: new Text("hero 1"),
child:
Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
//here we are passing the value of the products to Product detail page
productDetailName:prodName,
)
)
),
child:GridTile(
footer: Container(
color: Colors.white,
child: new Row(
children: <Widget>[
new Expanded(
child: new Text(prodName, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
),
new Text(
"\$$prodPrice", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
],
)
),
child: Image.asset(prodPicture,
fit: BoxFit.cover,),
),
),
),
),
);
}
}
//product class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
class Product{
static const ID = "id";
static const CATEGORY = "category";
static const NAME = "name";
static const PRICE = "price";
static const BRAND = "brand";
static const COLORS = "colors";
static const QUANTITY = "quantity";
static const SIZES = "sizes";
static const SALE = "sale";
static const FEATURED = "featured";
static const PICTURE = "picture";
String _id;
String _name;
String _brand;
String _category;
String _picture;
double _price;
int _quantity;
List _colors;
List _sizes;
bool _onSale;
bool _featured;
// getters
String get name => _name;
String get id => _id;
String get category => _category;
String get brand => _brand;
String get picture => _picture;
double get price => _price;
int get quantity => _quantity;
List get colors => _colors;
List get sizes => _sizes;
bool get onSale => _onSale;
bool get featured => _featured;
// named constructure
Product.fromSnapshot(DocumentSnapshot snapshot){
Map data = snapshot.data;
_name = data[NAME];
_id = data[ID];
_category = data[CATEGORY];
_brand = data[BRAND];
_price = data[PRICE];
_quantity = data[QUANTITY];
_colors = data[COLORS];
_onSale = data[SALE];
_featured = data[FEATURED];
_picture = data[PICTURE];
}
}
//provider page for the product
import 'package:flutter/material.dart';
import 'package:shopping/db/product.dart';
import 'package:shopping/models/product.dart';
class AppProvider with ChangeNotifier {
List<Product>_fearturedProducts=[];
//method
void _getFeaturedProducts()async{
_fearturedProducts=await _productService.getFeaturedProducts();
notifyListeners();
}
}
//connection to Firestore to collect data
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/models/product.dart';
class ProductService{
Firestore _firestore=Firestore.instance;
String collection="Products";
Future<List<Product>>getFeaturedProducts(){
_firestore.collection(collection).where('featured', isEqualTo:true).getDocuments()
.then((snap){
List<Product>featuredProducts=[];
snap.documents.map((snapshot)=> featuredProducts.add(Product.fromSnapshot(snapshot)));
return featuredProducts;
});
}
}
guys, I have managed to solve the question. The answer is as follow //product page
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
import 'package:shopping/models/product.dart';
class Products extends StatefulWidget {
#override
ProductsState createState() => ProductsState();
}
class ProductsState extends State<Products> {
List<Product> products;
#override
Widget build(BuildContext context) {
final productProvider = Provider.of<CRUDModel>(context);
return StreamBuilder<QuerySnapshot>(
stream: productProvider.fetchProductsAsStream(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
products = snapshot.data.documents
.map((doc) => Product.fromMap(doc.data, doc.documentID))
.toList();
return GridView.builder(
itemCount: products.length,
gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
itemBuilder: (BuildContext context, index){
return Padding(
padding:const EdgeInsets.all(4.0),
child:SingleProd(
product:products[index]
// prodPicture: productList[index]['picture'],
//prodOldPrice: productList[index]['oldPrice'],
//prodPrice: productList[index]['price'],
),
);
}
);
}
else {
return Text('fetching');
}
}
);
}
}
class SingleProd extends StatelessWidget {
//final prodName;
//final prodPicture;
//final prodOldPrice;
//final prodPrice;
final Product product;
SingleProd({ #required this.product});
//SingleProd({product.picture});
#override
Widget build(BuildContext context) {
return Card(
child: Hero(tag: product.id,
child:
Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
//here we are passing the value of the products to Product detail page
productDetailName:product.name,
productDetailNewPrice:product.price,
productDetailPicture:product.picture,
//productDetailOldPrice:prodOldPrice,
//productDetailNewPrice:prodPrice,
//productDetailPicture: prodPicture,
)
)
),
child:GridTile(
footer: Container(
color: Colors.white,
child: new Row(
children: <Widget>[
new Expanded(
child: new Text(product.name, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
),
new Text(
'${product.price} \$', style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
],
)
),
child: Image.asset('assets/${product.picture}.jpg',
fit: BoxFit.cover,),
),
),
),
),
);
}
}
//product class
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:ui';
class Product {
String id;
String name;
String brand;
String category;
String picture;
double price;
int quantity;
List colors;
List sizes;
bool sale;
bool featured;
Product(
{this.id, this.name, this.brand,
this.category, this.picture,this.price,
this.quantity,this.colors,this.sizes,this.sale,this.featured}
);
Product.fromMap(Map snapshot,String id) :
id = id ?? '',
name= snapshot['name'] ?? '',
brand = snapshot['brand'] ?? '',
category = snapshot['category'] ?? '',
picture= snapshot['picture'] ?? '',
price= snapshot['price'] ?? '',
quantity= snapshot['quantity'] ?? '',
colors= snapshot['colors'] ?? '',
sizes= snapshot['sizes'] ?? '',
sale= snapshot['sale'] ?? '',
featured= snapshot['featured'] ?? '';
toJson() {
return {
"name": name,
"brand": brand,
"category": category,
"picture": picture,
"price": price,
"quantity": quantity,
"colors": colors,
"sizes": sizes,
"sale": sale,
"featured": brand,
};
}
}
//provider class for the product
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/db/Api.dart';
import 'package:shopping/models/product.dart';
class CRUDModel extends ChangeNotifier {
//Api _api = locator<Api>();
String path="Products";
Api _api= Api();
List<Product> products;
Future<List<Product>> fetchProducts() async {
var result = await _api.getDataCollection();
products = result.documents
.map((doc) => Product.fromMap(doc.data, doc.documentID))
.toList();
notifyListeners();
return products;
}
Stream<QuerySnapshot> fetchProductsAsStream() {
notifyListeners();
return _api.streamDataCollection();
}
Future<Product> getProductById(String id) async {
var doc = await _api.getDocumentById(id);
notifyListeners();
return Product.fromMap(doc.data, doc.documentID) ;
}
}
//connection to firestore
import 'package:cloud_firestore/cloud_firestore.dart';
class Api{
final Firestore _db = Firestore.instance;
String ref="Products";
//CollectionReference ref;
/*Api({this.path } ) {
ref = _db.collection(path);
}*/
Future<QuerySnapshot> getDataCollection() {
//return ref.getDocuments() ;
return _db.collection(ref).where('featured', isEqualTo:true).getDocuments();
}
Stream<QuerySnapshot> streamDataCollection() {
// return ref.snapshots() ;
//return _db.snapshots(ref).getDocuments();
return _db.collection(ref).snapshots();
}
Future<DocumentSnapshot> getDocumentById(String id) {
// return ref.document(id).get();
return _db.document(id).get();
}
Future<void> removeDocument(String id){
//return ref.document(id).delete();
return _db.document(id).delete();
}
Future<DocumentReference> addDocument(Map data) {
// return ref.add(data);
return _db.collection(ref).add(data);
}
Future<void> updateDocument(Map data , String id) {
//return ref.document(id).updateData(data) ;
return _db.document(ref).updateData(data);
}
}
//homepage where i displayed the products
import 'package:flutter/material.dart';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:shopping/commons/common.dart';
import 'package:provider/provider.dart';
import 'package:shopping/provider/app_provider.dart';
import '../provider/user_provider.dart';
//My packages imports
import 'package:shopping/componets/horizontal_listview.dart';
import 'package:shopping/componets/product.dart';
import 'package:shopping/pages/cart.dart';
import 'package:shopping/pages/login.dart';
class HomePage extends StatefulWidget {
// List<Product> products;
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
TextEditingController _searchController = new TextEditingController();
//final FirebaseAuth _firebaseAuth=FirebaseAuth.instance;
#override
Widget build(BuildContext context) {
final user = Provider.of<UserProvider>(context);
final productProvider=Provider.of<CRUDModel>(context);
Widget image_carousel = new Container(
height: 200.0,
child: new Carousel(
boxFit: BoxFit.cover,
images: [
AssetImage('images/c1.jpg'),
AssetImage('images/m1.jpeg'),
AssetImage('images/m2.jpg'),
AssetImage('images/w1.jpeg'),
AssetImage('images/w3.jpeg'),
AssetImage('images/w4.jpeg'),
],
autoplay:true,
animationCurve: Curves.fastOutSlowIn,
animationDuration: Duration(milliseconds:1000 ),
dotSize: 4.0,
indicatorBgPadding: 8.0,
dotBgColor: Colors.transparent,
),
);
return Scaffold(
appBar: new AppBar(
iconTheme: IconThemeData(color: blue),
elevation: 0.1,
backgroundColor: white,
title: Material(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[50],
elevation: 0.0,
child: TextFormField(
controller: _searchController,
decoration: InputDecoration(
hintText: "Search",
border: InputBorder.none,
),
validator: (value) {
if (value.isEmpty) {
return "The Search field cannot be empty";
}
return null;
}),
),
actions: <Widget>[
new IconButton(
icon: Icon(
Icons.search,
color: blue,
),
onPressed: () {},
),
new IconButton(
icon: Icon(
Icons.shopping_cart,
color: blue,
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => new Cart()));
}),
],
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
//drawer header
new UserAccountsDrawerHeader(
accountName: Text("Afolabi"),
accountEmail: Text("mtreal62#gmail.com"),
currentAccountPicture: GestureDetector(
child: new CircleAvatar(
backgroundColor: Colors.grey,
child: Icon(
Icons.person,
color: Colors.white,
),
),
),
decoration: BoxDecoration(
color: blue,
),
),
//body
InkWell(
onTap: () {},
child: ListTile(
title: Text("Home Page"),
leading: Icon(
Icons.home,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("My Account"),
leading: Icon(
Icons.person,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("My Orders"),
leading: Icon(
Icons.shopping_basket,
color: blue,
),
),
),
InkWell(
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => new Cart()));
},
child: ListTile(
title: Text("Shopping Cart"),
leading: Icon(
Icons.shopping_cart,
color: blue,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("Favourites"),
leading: Icon(
Icons.favorite,
color: blue,
),
),
),
Divider(),
InkWell(
onTap: () {},
child: ListTile(
title: Text("Settings"),
leading: Icon(
Icons.settings,
),
),
),
InkWell(
onTap: () {},
child: ListTile(
title: Text("About"),
leading: Icon(
Icons.help,
),
),
),
InkWell(
onTap: () {
user.signOut();
// changeScreenReplacement(context, Login());
},
child: ListTile(
title: Text("Log Out"),
leading: Icon(
Icons.transit_enterexit,
),
),
),
],
),
),
body: new Column(
children: <Widget>[
//Image Carousel for the home Page Banner
image_carousel,
//padding widget after carousel
new Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: new Text("Categories"),
),
),
//Horizontal layout start from here
HorizontalList(),
//End of the horizontal layout
//padding widget for Recent products categories
new Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.centerLeft,
child: new Text("Recent Products"),
),
),
// Text(appProvider.featuredProducts.length.toString(),
//style: TextStyle(color: Colors.black),),
Flexible(
child: Products(),
),
//Horizontal layout start from here
],
),
);
}
}
Future _signOut() async {
try {
await FirebaseAuth.instance.signOut();
} catch (e) {
print(e); // TODO: show dialog with error
}
}
You are never calling _getFeaturedProducts() from your AppProvider class. So _fearturedProducts will always be null
In class AppProvider you are calling method on undefined name:
_productService.getFeaturedProducts()
Every IDE should show you this error ex. In my Android Studio it looks like this: