I have a Flutter app in which I'm listening to auth changes from Firebase to display the correct screen, using a StreamProvider. What I would like to do is to map the FirebaseUser to a custom User object, which would be retrieved from Firestore, to have it accessible from anywhere in the widget tree.
Is there any way to achieve this?
What I'm doing right now:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
Stream<FirebaseUser> get user {
return _auth.onAuthStateChanged;
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider<FirebaseUser>.value(
value: AuthService().user,
child: MaterialApp(...)
I used https://pub.dev/packages/rxdart to combine and merge the Firebase auth user and Firestore user streams.
For the auth stream, I'm using userChanges()
to listen to all user updates. flatMap()
takes the auth stream, converts it to a firestore stream and combines it with the firestore stream so now we are listening to both auth changes and firestore changes.
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamProvider<UserModel>.value(
value: FirebaseAuth.instance.userChanges().flatMap(
(firebaseUser) => DatabaseService(uid: firebaseUser.uid).userData)),
child: MaterialApp(...)
database.dart
class DatabaseService {
final String uid;
DatabaseService({this.uid});
// get firestore user stream and convert each item into your user object (UserModel in my example)
Stream<UserModel> get userData {
return FirebaseFirestore.instance.collection('users').doc(uid).snapshots()
.map((snapshot) => UserModel.fromMap(snapshot.data()));
user_model.dart
class UserModel {
String field1;
String field2;
UserModel({this.field1, this.field2});
// using factory to create an instance of UserModel
factory UserModel.fromMap(Map data) {
return UserModel(field1: data['field1'], field2: data['field2']);
}
}