How to acces data from StreamProvider Flutter - firebase

I'm trying to show a list of reminder where user see all their reminders and able to edit it. I'm using StreamProvider so that I'm able to access in child widget. I map the DocumentSnapShot into MedReminder object. The StreamProvider should return List of MedReminder object. But in the ReminderList widget the Provider return null.
Stream:
List<MedReminder> _medReminderListFromSnapshot(QuerySnapshot snapshot) {
print('here is db');
return snapshot.documents.map((doc) {
return MedReminder(
remindId: doc.data['remindId'] ?? '',
howManyTimeDay: doc.data['howManyTimeDay'] ?? '',
frequency: doc.data['frequecy'] ?? '',
hour: doc.data['hour'] ?? '',
min: doc.data['min'] ?? '',
dateStarted: doc.data['dateStarted'] ?? '',
dateEnded: doc.data['dateEnded'] ?? '',
dateRefill: doc.data['dateRefill'] ?? '',
quantityTime: doc.data['quantityTime'] ?? '',
);
}).toList();
}
Stream<List<MedReminder>> get medReminders {
return userCollection.document(uid).collection('medic_reminder').snapshots()
.map(_medReminderListFromSnapshot);
}
Reminder Page:
Widget build(BuildContext context) {
final user = Provider.of<User>(context);
return StreamProvider<List<MedReminder>>.value(
value: DatabaseService(uid: user.uid).medReminders,
child: Scaffold(
body: Container(
child: ReminderList(),
),
),
);
}
Reminder List widget(here the provider returning null):
Widget build(BuildContext context) {
final reminders = Provider.of<List<MedReminder>>(context) ?? [];
reminders.forEach((reminder) {
print(reminder.remindId);
});
return ListView.builder(
itemCount: reminders.length,
itemBuilder: (context, index) {
return ReminderTile();
});
}
Please help me thanks.

Stream<List<MedReminder>> get medReminders {
return userCollection.snapshots()
.map(_medReminderListFromSnapshot);
}
Store Data In userCollection with uid, dont add other collections
like
collectionReference userCollection = Firestore.instance.collection('users');
when saving data in 'users'
userCollection.document(uid).setData()..
then it works

Related

How can i compare fields in firebase with flutter?

I'm building a chat app and I'm trying to build a screen with the user history conversations with other users.
So basically what I am trying to do is taking all the values in the message field map (just the values, not the keys) like shown here:
And I want to compare it with the docs in the chatRoom like shown here:
If I compare them and the result came as true, I want to show the user the data that inside that chatRoom.
I'm really struggling to understand how to compare them
Thanks in advance.
Edit: here is the code:
final String chatId;
Chat({this.chatId});
#override
_ChatState createState() => _ChatState();
}
class _ChatState extends State<Chat> {
// Our own id
final String currentUserId = auth.currentUser?.uid;
// Loading state
bool isLoading = false;
// Query variable
Future<QuerySnapshot> chatHistoryResults;
// All the user rooms will be in this variable
List<String> roomsUserList = [];
// All the chat rooms will be in this variable
List<String> roomsChatList = [];
// All the history chat tickets will be here.
List<QuerySnapshot> tickets = [];
// Getting all the current user rooms in a list of Id rooms.
//TODO: fix the chat history
getRooms() async {
roomsUserList = [];
//roomsChatList = [];
DocumentSnapshot myDocUser = await userRef.doc(currentUserId).get();
Map<dynamic, dynamic> userRoomsMap = await myDocUser.get('messages');
userRoomsMap.forEach((key, value) {
roomsUserList.add(value);
});
print(roomsUserList);
roomsUserList.forEach((element) async {
String chatDoc = chatRef.doc(element).get().toString();
roomsChatList.add(chatDoc.toString());
});
print(roomsChatList);
}
// Build the story tickets here
buildStoryTickets() {
return FutureBuilder(
future: chatRef.get().then((snapshot) {
snapshot.docs.forEach((element) {});
}),
);
}
#override
Widget build(BuildContext context) {
return Provider<AuthService>(
create: (context) => AuthService(),
child: Scaffold(
backgroundColor: Colors.grey[350],
appBar: PreferredSize(
preferredSize: Size.fromHeight(55.0),
child: Header(
title: 'Chat',
),
),
body: ListView(
children: [
//buildStoryTickets(),
Container(
height: 100,
width: 100,
child: FlatButton(onPressed: () {
getRooms(); // Just to check
}),
),
],
),
),
);
}
}
I manage to insert all the values from the "messages" map inside a List called "roomUserList"
First, you can get the all the data from the User and chat room Using the StreamBuilder.
Once you have the messages and Chat room you can compare it by developing code logic.
PFB sample code to get data from firestore:
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('users').snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
//add your comparison logic here
);
}

Getting null on Query snapshot

I ma getting a null return on a stream query. The funny thing is that data came through but on processing it to use it in the app it gets lost somewhere.I know i probably made a silly mistake somewhere yet i've been looking at this issue for three days now. Please help.
Here is the stream
Stream <SellerProfile> get sellerProfile {
return sellerProfileCollection.document(uid).snapshots()
.map(yieldSellerProfile);
}
SellerProfile yieldSellerProfile(DocumentSnapshot snapshot) {
print(snapshot.data['shopName']);
return SellerProfile(
shopName: snapshot.data['shopName'] ?? '',
phone: snapshot.data['phone']??'',
credit: snapshot.data['credit'] ?? '',
posts: snapshot.data['posts'] ?? '',
sales: snapshot.data['sales'] ?? '',
avatarUrl: snapshot.data['avatarUrl'] ?? '',
location:snapshot.data['location'] ?? '',
rating: snapshot.data['rating'] ?? '',
joinedDate: snapshot.data['joinedDate'] ?? '',
);
}
My idea is that after querying the stream sellerProfile i want to map it into a custom model to use it in the app.
As in the code, i print the snapshot.data['shopName'] before it is processed and i get the output
I/flutter ( 1008): Soko
which means the data arrives from firestore but as i try to access the data on my frontend i receive a null
Here is the frontend
Widget build(BuildContext context) {
final AuthService _auth = AuthService();
final user = Provider.of<User>(context);
return StreamBuilder<SellerProfile>(
stream: SellerDatabaseService(uid: user.uid).sellerProfile,
builder: (context, snapshot) {
SellerProfile profile=snapshot.data;
print(profile);
return Scaffold(
backgroundColor: Colors.white,
appBar: header(context,strTitle: "Profile"),
body: SingleChildScrollView(),
);
}
);
}
and here is the output when i try to print the profile
I/flutter ( 1008): null
Where am i going wrong? Thanks in advance!
I go the issue. I was trying to build the stream with stream builder instead of returning it from a provider.
So i changed this...
Widget build(BuildContext context) {
final AuthService _auth = AuthService();
final user = Provider.of<User>(context);
return StreamBuilder<SellerProfile>(
stream: SellerDatabaseService(uid: user.uid).sellerProfile,
builder: (context, snapshot) {
SellerProfile profile=snapshot.data;
print(profile);
return Scaffold(
backgroundColor: Colors.white,
appBar: header(context,strTitle: "Profile"),
body: SingleChildScrollView(),
);
}
);
}
To this...
return StreamProvider<BuyerProfile>.value(
value: BuyerDatabaseService(uid: user.uid).buyerProfile,
builder: (context, snapshot) {
BuyerProfile profile=Provider.of<BuyerProfile>(context);
if(profile!=null){
return Scaffold(...
You're not checking if the snapshot has data yet. Add a check for this with the hasData property of the AsyncSnapshot:
return StreamBuilder<SellerProfile>(
stream: SellerDatabaseService(uid: user.uid).sellerProfile,
builder: (context, snapshot) {
if(snapshot.hasError) {
return Text(snapshot.error.toString());
}
if(!snapshot.hasData) {//Check if the snapshot actually has data
return CircularProgressIndicator();
}
SellerProfile profile=snapshot.data;
print(profile);
return Scaffold(
backgroundColor: Colors.white,
appBar: header(context,strTitle: "Profile"),
body: SingleChildScrollView(),
);
}
);
Ideally you should also check if it hasError as well, and if you want more granular control over what to show, you could use the connectionState.

filter data from firebase in flutter

in my system there are notices which have both status 'approved' and 'unapproved'. I want to display only 'unapproved'notices and I want to convert them 'approved' by using flutter app.
this is the screenshot of my firebase.
by using below codes I can display notice all notice list
Widget build(BuildContext context) {
final notices = Provider.of<List<Notice>>(context) ?? [];
return StreamBuilder<List<Notice>>(
stream: NoticeService().notices,
builder: (context, snapshot) {
if(snapshot.hasData){
return GridView.builder (
itemCount: notices.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 1),
// ignore: missing_return
itemBuilder: (context,index){
return SingleNotice(
notice:notices[index]
);
}
);
}else{
return(Text('No List'));
}
}
);
}
i create notice stream like this
final CollectionReference noticeCollection=Firestore.instance.collection('Notices');
//notice list from snapshot
List<Notice>_noticeListFromSnapshot(QuerySnapshot snapshot){
return snapshot.documents.map((doc){
return Notice(
title:doc.data['title'] ?? '',
url: doc.data['url'] ?? '',
category: doc.data['noticecategory'] ?? 'General',
status: doc.data['status'] ?? 'unapproved',
dateTime: doc.data['dateTime'] ?? '',
noticeId: doc.data['noticeId'] ?? ''
);
}).toList();
}
Stream<List<Notice>>get notices{
return noticeCollection.snapshots().map(_noticeListFromSnapshot);
}
then how can I filter unapproved notices and display them.
To get only the unapproved documents, you can use a query:
final CollectionReference noticeCollection=Firestore.instance.collection('Notices');
final Query unapproved = noticeCollection.where("status", isEqualTo: "unapproved")
And then use that in place of the collection in:
Stream<List<Notice>>get notices{
return unapproved.snapshots().map(_noticeListFromSnapshot);
}

Flutter Stream Builder return only one LisTile from Firestore

I have a stream builder that is supposed to return a multiple LisTile but it returns only one, I have used the same structure with other collections and its work fine but for this collection it doesn't.
Widget build(BuildContext context) {
return StreamBuilder(
stream: DatabaseService().itemsCollection.snapshots(),
builder: ( context, snapshot){
if (!snapshot.hasData){
return Loading();
}
else{
List<Item> myItems= [];
for (int i=0; i<snapshot.data.documents.length; i++){
DocumentSnapshot snap = snapshot.data.documents[i];
myItems.add(
Item(
restaurantId: snap.data['restaurantId'],
id:snap.documentID ?? '',
name:snap.data['name']?? '',
price:double.tryParse(snap.data['price'].toString())?? 0,
calories:double.tryParse(snap.data['calories'].toString())?? 0,
section: MenuSection('','',''),
imageUrl:snap.data['imageUrl']?? '',
describtion: snap.data['describtion']?? '')
);
return
ListView.builder(
itemCount: myItems.length,
itemBuilder: (_, i) => Column(
children: [
ItemListItem(
id: myItems[i].id,
name: myItems[i].name,
describtion: myItems[i].describtion,
price: double.tryParse(myItems[i].price.toString()),
imageUrl: myItems[i].imageUrl,
// branchId: branchId,
restId: myItems[i].restaurantId ,
),
// Divider(),
], ),
);
}
}
}
);
Data in FireStore
If anyone can find where the issue please.
================= UPDATE =================
Issue Solved.
To whom might face this issue later,
I found the issue is that I have put the return statement inside the for loop, while it should after the loop ends!

How to set the value of a model object in flutter and use it in FutureBuilder ListView?

I want to fetch data from the firestore and display it in the form of cards using ListView. I am willing the data fetched from firestore in an object for reusability on the same as well as other screens but, I am unable to do so. I created a model and a database service to serve it;
I tried to create a map which can store HomePage objects in it. Each object of the list creates a new card but, I am not able to assign values in the objects. I tried using the print statement below it but no output came there
Any leads on how to solve this problem would be really appreciated.
model
class HomePage {
bool confirmed;
DriverDetails driverDetail;
HomePage({this.confirmed, this.driverDetails});
}
class DriverDetails {
String driverUID;
String driverName;
String vehicalNumber;
String vehicalName;
String timeOfReporting;
String placeOfReporting;
LatLng reportingCord;
DriverDetails({
this.driverName,
this.driverUID,
this.placeOfReporting,
this.reportingCord,
this.timeOfReporting,
this.vehicalName,
this.vehicalNumber,
});
}
Database Service
class DatabaseService {
final Firestore _db = Firestore.instance;
static DriverDetails driverdetails;
static bool confirmed;
Map homeObject = new Map<String, HomePage>();
HomePage home = new HomePage(
confirmed: confirmed,
driverDetail: driverdetails,
);
/// Query a subcollection
Future streamHomePage(FirebaseUser user) async {
var ref = _db
.collection('homepage')
.document(user.uid)
.collection('h')
.document('28032020');
await ref.get(source: Source.serverAndCache).then((ref) => {
ref.data.forEach((index, value) => {
// Prints "index = WE10203 and value Swargate and null"
print(
"index = $index and value ${value['dd']['p']} and ${home.driverDetail}"),
driverdetails.placeOfReporting = value['dd']['p'],
// The below line prints nothing
print("driverdetails = $driverdetails"),
homeObject[index] = home
}),
});
return homeObject;
}
} }
Home Page screen
FutureBuilder(
future: databaseService(),
builder: (context, snapshot) {
if (snapshot.hasData) {
stringMap = snapshot.data;
}
return ListView.builder(
itemBuilder: (context, index) {
stringMap.forEach((index, value) => {
print("The stringMap is ${stringMap.keys.toList()}"),
});
return HomepageCards(
user: widget.user,
cardDetails: stringMap[stringMap.keys.toList()[index]],
);
},
itemCount: stringMap.length,
scrollDirection: Axis.vertical,
controller: _controller,
shrinkWrap: true,
);
},
)
databaseService() async {
return DatabaseService().streamHomePage(widget.user);
}
Try using models like this :
import 'package:cloud_firestore/cloud_firestore.dart';
class EmployeeData {
final DocumentReference reference;
String address;
String designation;
String email;
EmployeeData.data(
this.reference, [
this.address,
this.designation,
this.email,
]);
factory EmployeeData.from(DocumentSnapshot document) => EmployeeData.data(
document.reference,
document.data['Address'],
document.data['Designation'],
document.data['Email'],
);
void save() {
reference.setData(toMap());
}
Map<String, dynamic> toMap() {
return {
'address': address,
'designation': designation,
'email': email,
};
}
}
so when u got data u can use like this :
return StreamBuilder<QuerySnapshot>(
stream: Firestore().collection('Workers').snapshots(),
builder: (context, snapshot) {
if (snapshot.data != null) {
// Here u will get list of document snapshots
final List<DocumentSnapshot> documents = snapshot.data.documents;
final List<EmployeeData> employeeDataList = documents
.map((snapshot) => EmployeeData.from(snapshot))
.toList();
// now u can access each document by simply specifying its number
// u can also use list view to display every one of them
return ListView.builder(
itemCount: documents.length,
itemBuilder: (context, int index) => Text(employeeDataList[index].email),
);
} else {
// Show loading indicator here
}
},
);

Resources