Сопоставьте FirebaseUser с настраиваемым объектом User

У меня есть приложение Flutter, в котором я слушаю изменения аутентификации из Firebase для отображения правильного экрана с помощью StreamProvider. Что я хотел бы сделать, так это сопоставить FirebaseUser с настраиваемым объектом User, который будет извлекаться из Firestore, чтобы он был доступен из любого места в дереве виджетов.

Есть ли способ добиться этого?

Что я сейчас делаю:

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

person Merig    schedule 11.06.2020    source источник
comment
Создайте модели для преобразования данных в объект Dart, и вы используете Provider для управления состоянием, поэтому просто расширяйте модели с помощью ChangeNotifier и получайте данные, когда захотите: D   -  person Chinky Sight    schedule 11.06.2020
comment
интересно, нашли ли вы когда-нибудь решение!   -  person Karen    schedule 11.02.2021
comment
@Karen, к сожалению, нет, это был небольшой проект, который отложили в сторону ^^   -  person Merig    schedule 11.02.2021
comment
не беспокойтесь, это заняло у меня несколько дней и ночей, но я наконец понял это. Я немного напишу решение, чтобы помочь другим, и если вы когда-нибудь вернетесь к своему проекту   -  person Karen    schedule 11.02.2021


Ответы (2)


Я использовал https://pub.dev/packages/rxdart, чтобы объединить и объединить пользователя аутентификации Firebase и Пользовательские потоки Firestore.

Для потока аутентификации я использую userChanges() для прослушивания всех обновлений пользователей. flatMap() принимает поток аутентификации, преобразует его в поток хранилища данных и объединяет его с потоком хранилища данных, поэтому теперь мы слушаем как изменения аутентификации, так и изменения хранилища данных.

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']);
    }
}
person Karen    schedule 17.02.2021

Во-первых, начните с пользовательской модели и решите, что вы хотели бы иметь, в этом случае у меня будет просто uid

### Модель пользователя ###

 class CurrentUser {
      final String uid;
    
      CurrentUser ({ this.uid });
    }

### AuthService ###

// Create user object based on FirebaseUser
  CurrentUser _customModelForFirebaseUser(User user) {
    return user != null ? CurrentUser (uid: user.uid) : null;
  }

  // auth changed user stream
  Stream<CurrentUser > get user {
    return _auth.onAuthStateChanged
      .map(_customModelForFirebaseUser)
  }

### Мое приложение ###

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamProvider<CurrentUser >.value(
      value: AuthService().user,
      child: MaterialApp(
        home: Wrapper(),
      ),
    );
  }
}

Затем вы можете получить к нему доступ из любого места, например:

 @override
      Widget build(BuildContext context) {
    
        final user = Provider.of<CurrentUser>(context);
}
person Unbreachable    schedule 11.06.2020
comment
Я понимаю, но моя модель User построена на основе результата запроса Firestore для данного UID Firebase. Как сделать так, чтобы при изменении статуса аутентификации поток сопоставлялся с некоторым асинхронным значением? - person Merig; 12.06.2020
comment
Вы можете проверить с помощью if / else всякий раз, когда есть изменение аутентификации, например if (user == null) {} else { map (stream) } - person Unbreachable; 12.06.2020
comment
попытка выполнения кода в AuthService вызывает ошибку. Класс «Пользователь» не имеет конструктора по умолчанию. Попробуйте использовать один из названных конструкторов, определенных в «Пользователь». Как решить такую ​​ошибку. Заранее спасибо. - person olammy; 01.06.2021
comment
Что ж, вы больше не можете использовать User, потому что теперь это тип по умолчанию в Firebase Service. User раньше было FirebaseUser, поэтому теперь просто измените имя. - person Unbreachable; 01.06.2021