multiprovider - pass value from first to second provider - firebase

I am trying to setup a MultiProvider but I am struggling to figure out how to pass a value from one to the other. I have a list of data that has a userID in it, my app would previously make a StreamProvider for user info and then another for the list of data. This was fine as I could pass the user.uid to the data and then apply the filter. Something like this...
final user = Provider.of<User>(context);
return StreamProvider<List<UserLevelTwo>>.value(
value: DatabaseService(uid: user.uid).levelTwoSelector,
The problem was that I couldn't access the List throughout the app so after researching it looks like it is meant to be put before the MaterialApp with the other Provider. I have got this setup but only with manually passing the UID.
Widget build(BuildContext context) {
return MultiProvider(
providers: [
StreamProvider<User>.value(value: AuthService().user),
StreamProvider<List<UserLevelTwo>>.value(value: DatabaseService(uid: 'rgDe5I0QgFfa123mIgxo8VQew9T2').levelTwoSelector),
],
child: MaterialApp(
What I need help with is how do I pass the uid from the first provider into the second provider?
The second streamprovider calls my DB service which is as below:
class DatabaseService {
final String uid;
DatabaseService({this.uid});
Query getLevelTwoSelectorData(){
return Firestore.instance.collection('ULTs')
.where("UserID", isEqualTo: uid)
.where("D", isEqualTo: false)
.orderBy("R", descending: true)
.orderBy("Desc");
}
Stream<List<UserLevelTwo>> get levelTwoSelector {
return getLevelTwoSelectorData().snapshots().map(_userLevelTwoListFromSnapshot);
}
}
If anyone could help me that would be greatly appreciated!
Thanks

Thanks for the help. I got this to work by using the same method described here Pass user uid to Firestore stream query in Flutter
More or less it seems that you have one StreamProvider for the user info, then once that isn't null, you create a multiprovider for the list with the uid from the original provider.
Thanks again!

Related

How to convert serverTimestamp to String when using StreamBuilder

What I want
To order ListView based on server timestamp
My code
Adding to firestore collection:
onPressed: () {
FirebaseFirestore.instance.collection('things').add(
{
// some code
'timestamp': FieldValue.serverTimestamp(),
},
);
Get data from the firestore and ordered them based on the server timestamp
return StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collection('things').orderBy('timestamp').snapshots(),
Expected behavior
List View are displayed ordered based on the server timestamp
What I got
This error:
Expected a value of type 'String', but got one of type 'Timestamp'
What I've tried
I've tried adding toString() when sending the data to the firestore: 'timestamp': FieldValue.serverTimestamp().toString(), but then the data on the firestore didn't store timestamp, instead they stored FieldValue(Instance of 'FieldValueWeb').
I know that I probable have to convert them to String when I'm getting the data from the firestore, but I have no idea how to do that. I've tried adding in toString() when getting the data into the stream as such:
stream: FirebaseFirestore.instance.collection('things').orderBy('timestamp').toString().snapshots()
but then it shows below error and won't compile.
The method 'snapshots' isn't defined for the type 'String'.
The official document does not say anything about converting them to String either.
If anybody knows how to solve this please help me, I'm really stuck here.
Full StreamBuilder and ListView code
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('things').orderBy('timestamp').snapshots(),
builder: (context, snapshot) {
List<Text> putDataHere = [];
final things = snapshot.data.docs;
for (var thing in things) {
final myData = Map<String, String>.from(thing.data());
final myThing = myData['dataTitle'];
final thingWidget = Text(myThing);
putDataHere.add(thingWidget);
}
return Expanded(
child: ListView(
children: putDataHere,
),
);
},
);
You can try this:
Firestore.instance
.collection("things")
.orderBy('createdAt', descending: true or false).getDocuments()
And then you can store createdAt on your client side with Timestamp, and you can get current timestamp with Timestamp.now()
Since the expected behaviour is that ListView items are ordered based on the server timestamp, you can just sort the list after you've gotten it from Firestore.
final things = snapshot.data.docs;
things.sort((a, b) {
return (a['timestamp'] as Timestamp).compareTo(b['timestamp'] as Timestamp);
});
The problem was totally different from what I had initially thought.
I honestly forgot that when I retrieve the data from the Firestore to process it, I set my Map to Map<String, String>, it was fine before because I only had String, but now that I have Timestamp type, it doesn't work.
The answer to the question is just simply changing the Map<String, String> to Map<String, dynamic>

How can I load the previous signed in user?

In my application, I happen to have two types of users, hospital, and patients, both are configured to use the same authentication by firebase. What I would like to know is, how do I load the page for the respective user depending on how they were signed in previously? For example, if a hospital had signed in and not logged out, when they run the app, it should display the hospitals' dashboard and not the patients'. How do I configure this?
shared_prefs supports Flutter web. Save a value stating the account type.
See this answer:
https://stackoverflow.com/a/59579821/13714686
SharedPreferences prefs = await SharedPreferences.getInstance();
bool isHospital = (prefs.getBool('isHospitalAccount');
if(isHospital == true){
//hospital navigation
}
else{
//patient navigation
}
First, you need to check whether the user is logged in or not. For this, you can check through the below code.
class MyApp extends StatelessWidget{
#override
Widget build(BuildContext context){
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot){
if (snapshot.hasData){
FirebaseUser user = snapshot.data; // this is your user
/// is because there is a user already logged, So route them to a Screen of Dashboard directly.
return MainScreen();
}
/// other way there is no user logged.
return LoginScreen();
}
);
}
}
Now, you need to maintain a list of users in FireStore where the user's metadata like the last login, User Type information will be stored. Using this information you can Route the user accordingly.

Error: Can't access 'this' in a field initializer to read 'uid' [duplicate]

This question already has answers here:
Error: The instance member ... can't be accessed in an initializer
(4 answers)
Closed 1 year ago.
Hoping someone can help me with this. I have a StreamProvider which works great with this:
class DatabaseService {
final String uid;
DatabaseService({this.uid});
final Query flashCardWordsCollection = Firestore.instance.collection('MyWords')
.where("SelectedToStudy", isEqualTo: true)
.where("DocBelongsTo", isEqualTo: "rgDe5I0QgFfax123Igxo8VQew9T2")
.orderBy("LastFlashCard", descending: false);
However, I need to change the DocBelongsTo filter to be based on the user that is currently logged into the app. When I try this:
class DatabaseService {
final String uid;
DatabaseService({this.uid});
final Query flashCardWordsCollection = Firestore.instance.collection('MyWords')
.where("SelectedToStudy", isEqualTo: true)
.where("DocBelongsTo", isEqualTo: uid)
.orderBy("LastFlashCard", descending: false);
Where on the home_screen.dart I called the StreamProvider like this:
final user = Provider.of<User>(context);
return StreamProvider<List<VoBuWord>>.value(
value: DatabaseService(uid: user.uid).flashCardWords ,
I get an error of:
lib/services/database.dart:11:41: Error: Can't access 'this' in a field initializer to read 'uid'.
.where("DocBelongsTo", isEqualTo: uid)
From the research I have been doing I understand it is due to the fact that uid may or may not have been set when this is called, therefore I get the error. But I have no idea how to fix this.
Users are not able to use the app without signing in first so in theory the uid should never be blank, however, I don't know how to tell the class this.
Any help would be greatly appreciated.
Thanks
You need to use a method or constructor to access instance fields of a class, for example:
Query getData(){
return Firestore.instance.collection('MyWords')
.where("SelectedToStudy", isEqualTo: true)
.where("DocBelongsTo", isEqualTo: uid)
.orderBy("LastFlashCard", descending: false);
}
Then to call it just do:
Stream<List<VoBuWord>> get flashCardWords {
return getData().snapshots().map(_vobuWordListFromSnapshot);
}

Flutter, Firebase Auth How to access uid everywhere in the app?

it's my first app I try to code.
I am using Firebase Auth and Cloud Firestore in my app. How can I make the uid of the logged-in User available on every screen without using await?
I know I can get it that way:
final FirebaseUser user = await _auth.currentUser();
String id = user.uid;
but I need to access the uid without awaiting it, for example here:
Stream<QuerySnapshot> get groups {
return Firestore.instance.collection("userGroups")
.where("userId", isEqualTo: " uid ").snapshots();
}
As I am using the provider package I thought I can make it available through it. But how is the best way to do it?
Thank You!
You can provide the firebase auth stream above your app:
StreamProvider<FirebaseUser>.value(
value: FirebaseAuth.instance.onAuthStateChanged,
lazy: false,
child: YourApp(),
)
and when want to get the user you can:
final user = Provider.of<FirebaseUser>(context);
Note, this will not listen to changes to the user object beyond signins and sign outs. To listen to actual user changes on the user (such as isVerified or photoUrl changes) you'll want to use a package like firebase_user_stream and replace the previous stream with something like:
StreamProvider<FirebaseUser>.value(
value: FirebaseUserReloader.onAuthStateChangedOrReloaded.asBroadcastStream(),
lazy: false,
),

Flutter Firebase how would I go about getting specific data from snapshot

I am currently using a realtime database for my application. I am having trouble reading specific user data from a snapshot.
My code:
final databaseReference = FirebaseDatabase.instance.reference();
void getData() {
databaseReference.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> values = snapshot.value;
//print(snapshot.value['name']);
print('Data : ${snapshot.value}');
});
}
My database layout:
Users:
userId:
name: TEST
email: TESTEmail#gmail.com
bio: TESTBio
I want to be able to read the name of an individual with a specific userId (for example Bdhsaiweuy2731319238121shda), how would I go about doing so? Thank you for your time, I really appreciate it.
If you know their UID, you can look up that user directly with databaseReference.child("Users/Bdhsaiweuy2731319238121shda") and then read the data from there. Something like:
databaseReference.child("Users/Bdhsaiweuy2731319238121shda").once().then((DataSnapshot snapshot) {
print(snapshot.value['name']);
});
values is a variable of type map and it will contain all the retrieved data. If you want access only to the name value, then you need to iterate inside this map and use the get [] operator to get the value of the name. Example:
values.forEach((key,values) {
print(values["name"]);
String name = values["names"];
});
https://api.dartlang.org/stable/2.7.0/dart-core/Map-class.html

Resources