使用Streambuilder与Flutter和GoRouter持久化用户状态

w41d8nur  于 2022-11-26  发布在  Flutter
关注(0)|答案(1)|浏览(128)

以前有没有人用过Streambuilder和Flutter和GoRouter来持久化用户状态?
目前,我正在使用默认的Flutter导航,它工作正常(见下文),但我现在正尝试用GoRouter替换
我以前使用默认Flutter导航的导航设置

home: StreamBuilder(
           stream: AuthMethods().authChanges,
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(
              child: CircularProgressIndicator(),
               );
             }

             if (snapshot.hasData) {
               return const TabsScreen();
            }

            return const AuthScreen();
           }),
    );
   }

我目前的goRouter代码。我想知道我可以在哪里使用Streambuilder在下面的d代码为我的应用程序持久化用户状态(或者是否Streambuilder可以在所有与go路由器一起使用)

GoRouter routeConstruct() {
  return GoRouter(
    routes: <RouteBase>[
      GoRoute(
          path: '/',
          builder: (BuildContext context, GoRouterState state) {
            return const PublicScreen();
          },
          routes: <RouteBase>[
            GoRoute(
              path: Events_Screen,
              builder: (BuildContext context, GoRouterState state) {
                return const EventsScreen();
              },
            ),
            GoRoute(
              path: "$EventDetail_Screen/:eventId",
              builder: (BuildContext context, GoRouterState state) {
                return EventDetailScreen(eventId: state.params['eventId']!);
              },
            ),
            ...
          ]),
    ],
  );

我可以使用Streambuilder与Flutter和GoRouter来保持用户身份验证状态吗?如果可以,在goRouter代码中的什么地方我可以使用Streambuilder来根据身份验证状态确定要显示哪个小部件?谢谢

###########################

类身份验证方法

class AuthMethods {
  final FirebaseAuth _auth = FirebaseAuth.instance;
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  Stream<User?> get authChanges => _auth.authStateChanges();
// --> use of bang ! operator here
  User get user => _auth.currentUser!;

  Future<bool> signInWithGoogle(BuildContext context) async {
    bool res = false;

    try {
      final GoogleSignInAccount? googleUser = await GoogleSignIn().signIn();
      final GoogleSignInAuthentication? googleAuth =
          await googleUser?.authentication;

      final credential = GoogleAuthProvider.credential(
          accessToken: googleAuth?.accessToken, idToken: googleAuth?.idToken);

      UserCredential userCredential =
          await _auth.signInWithCredential(credential);

      User? user = userCredential.user;

      if (user != null) {
        if (userCredential.additionalUserInfo!.isNewUser) {
          await _firestore.collection('users').doc(user.uid).set({
            'username': user.displayName,
            'uid': user.uid,
            'profilePhoto': user.photoURL,
          });
        }
        res = true;
      }
    } on FirebaseAuthException catch (e) {
      showSnackBar(context, e.message!);
      res = false;
    }
    return res;
  }

类路由通告程序

class RouterNotifier extends ChangeNotifier {
  RouterNotifier(this._authMethods) {
    _authMethods.authChanges.listen((event) {
      notifyListeners();
    });
  }

  final AuthMethods _authMethods;

  String? redirect(BuildContext context, GoRouterState state) {
    final onLoginPage = state.location == '/$AuthScreen';
    final onHomePage = state.location == '/$Tabs_Screen';

// --> The getter 'isEmpty' isn't defined for the type 'User'.
// --> User get user => _auth.currentUser!; used a bang operator
    if (_authMethods.user.isEmpty && onHomePage) {
      return '/$AuthScreen';
    }

// --> The getter 'isEmpty' isn't defined for the type 'User'.
    if (_authMethods.currentUser.isNotEmpty && onLoginPage) {
      return '/$Tabs_Screen';
    }

    return null;
  }
}

router.dart

GoRouter routeConstruct() {
  return GoRouter(
    refreshListenable: router,

    routes: <RouteBase>[
      GoRoute(
          path: '/',
          builder: (BuildContext context, GoRouterState state) {
            return const PublicScreen();
          },
          routes: <RouteBase>[
            GoRoute(
              path: Events_Screen,
              builder: (BuildContext context, GoRouterState state) {
                return const EventsScreen();
              },
            ),
            GoRoute(
              path: "$EventDetail_Screen/:eventId",
              builder: (BuildContext context, GoRouterState state) {
                return EventDetailScreen(eventId: state.params['eventId']!);
              },
            ),
          ]),
    ],
  );
}
a64a0gku

a64a0gku1#

在使用路由器5.0.0之前:
Go路由器有一个名为GoRouterRefreshStream的类,因此在Go路由器中

GoRouter (
....
refreshListenable: GoRouterRefreshStream(AuthMethods().authChanges),

但是在使用路由器5.0.0之后,它们remove it
因此您必须创建自己通告程序:

class RouterNotifier extends ChangeNotifier {

  RouterNotifier(this._authMethods) {
    _authMethods.authChanges.listen((event) {
      notifyListeners();
    });
  }

  final AuthMethods _authMethods;
}

移动路由器:

GoRouter(
      debugLogDiagnostics: false,
      ....
      ...
      refreshListenable: RouterNotifier(AuthMethods()),
      ...
      );

那么路由器如何能够像您以前使用流构建器一样工作呢?
重定向非常有用:

final router  = RouterNotifier(AuthMethods());

GoRouter (
...
refreshListenable: router,
redirect: router.redirect,

RouterNotifier类中:

class RouterNotifier extends ChangeNotifier {
    
    
      RouterNotifier(this._authMethods) {
        _authMethods.authChanges.listen((event) {
          notifyListeners();
        });
      }
    
      final AuthMethods _authMethods;

    String? redirect(BuildContext context, GoRouterState state) {

    final onLoginPage = state.location == '/login';
    final onHomePage = state.location == '/';

    if (_authMethods.currentUser.isEmpty && onHomePage) {

      return '/login';
    }

    if (_authMethods.currentUser.isNotEmpty && onLoginPage) {

      return '/';
    }

    return null;
  }

}
类用户模型:

class User {

String id;
.........
some variable i need from db;

static const empty = User(id: '');

bool get isEmpty => this == User.empty;
bool get isNotEmpty => this != User.empty;

}

数据流:

Stream<User> get user {
    // map the user if user null is mean empty
    return _firebaseAuth.authStateChanges().asyncMap((fUser) async {
      
      if (fUser == null) {
      const User user = User.empty;
      return user;
      } else {
      // in my case i need to take some data from Firestore 
      .... 
      await datafromDb() // if you dont need to wait future, remove async map, just use normal map
      return fUser.withBiodata();

相关问题