Map FirebaseUser to custom User object

Issue

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(...)

Solution

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']);
    }
}

Answered By – Karen

Answer Checked By – Senaida (FlutterFixes Volunteer)

Leave a Reply

Your email address will not be published.