繁体   English   中英

如何在登陆页面后向小部件树中的所有小部件提供身份验证证书并让导航器仍在工作

[英]How can I provide a authentication certificate to all the widgets in a widget tree after the landing page and have the navigator still working

我正在构建一个应用程序,我想检查用户是否已登录,如果没有,我将构建一个特定的小部件树。 因此,如果用户的身份验证状态发生变化,它将重建整个树。 因此,您登陆启动页面,启动页面会等待,直到知道您是否登录并返回 RegisterPage 或 GroupManagementPage,这基本上是一个页面,您可以在其中查看所有群组,有点像 whatsapp,但您有群组,而不是对话。 问题是我只是不知道如何正确地做到这一点。

我正在使用 firebase auth,我目前所做的是从我的主应用程序外部一直提供一个 AuthenticationProvider 。 在我的启动页面中,我在流构建器中使用了这个提供者的流(它基本上是来自 firebase 的 onAuthChanged 但映射到一个 AuthenticationCertificate)我等到流处于活动状态,然后再构建我的小部件树的其余部分。 如果流处于活动状态,我将我的 AuthenticationCertificate 提供给 GroupManagementPage。

所以这是可行的,但导航器出现了问题。 因为在我的 MainApp() 中,我将启动页面定义为我的主页。 所以现在每当我弹出一条路线时,我都会回到初始页面,这不是我想要的。 我还注意到有些页面没有提供 AuthenticationCertificate。 我不确定为什么还因为 Navigator 也传递了上下文,仍然需要研究一下。

现在我的问题是我怎样才能让它正常工作,以便将 AuthenticationCertificate 传递给从 GroupManagementPage 导航到的所有小部件,并且当用户注销时它会返回到 RegisterPage? 这是正确的方法吗,我怎样才能做到这一点?

主应用

return MultiProvider(
  providers: [
    ChangeNotifierProvider<PreferencesProvider>(
        create: (_) => PreferencesProvider()),
    Provider<AuthenticationProvider>(create: (_) => AuthenticationProvider(),),
    Provider<GroupProvider>(create: (_) => GroupProvider()),
    Provider<UserProvider>(
      create: (_) => UserProvider(),
    ),
  ],
  child: Consumer<PreferencesProvider>(
    builder: (context, preferences, _) => MaterialApp(
      home: TheSplashPage(),
      routes: <String, WidgetBuilder>{
        TheRegisterPage.routeName: (BuildContext context) =>
            TheRegisterPage(),
        TheGroupManagementPage.routeName: (BuildContext context) =>
            TheGroupManagementPage(),
        TheGroupPage.routeName: (BuildContext context) => TheGroupPage(),
        TheSettingsPage.routeName: (BuildContext context) =>
            TheSettingsPage(),
        TheProfilePage.routeName: (BuildContext context) =>
            TheProfilePage(),
        TheGroupCreationPage.routeName: (BuildContext context) =>
            TheGroupCreationPage(),
      },
      theme: preferences.isDarkMode
          ? DarkTheme.themeData
          : LightTheme.themeData,
      debugShowCheckedModeBanner: false,
    ),
  ),
);

启动页面

class TheSplashPage extends StatelessWidget {
  static const int loadTimeInSeconds = 2;

  @override
  Widget build(BuildContext context) {
    AuthenticationProvider authenticationProvider =
        Provider.of<AuthenticationProvider>(context);
    return FutureBuilder(
        future: Future.delayed(new Duration(seconds: loadTimeInSeconds)),
        builder: (context, delaySnapshot) {
          return StreamBuilder<UserAuthenticationCertificate>(
            stream: authenticationProvider.authenticationStream(),
            builder: (context, certificateSnapshot) {
              if (delaySnapshot.connectionState != ConnectionState.done &&
                  certificateSnapshot.connectionState ==
                      ConnectionState.active) {
                return Scaffold(
                  backgroundColor: Theme.of(context).backgroundColor,
                  body: Center(
                    child: Text(
                      'This is the splash page',
                      style: Theme.of(context).textTheme.body1,
                    ),
                  ),
                );
              } else {
                if (certificateSnapshot.hasData) {
                  return Provider<UserAuthenticationCertificate>.value(
                    value: certificateSnapshot.data, 
                    child: TheGroupManagementPage(),
                  );
                } else {
                  return TheRegisterPage();
                }
              }
            },
          );
        });
  }
}

在身份验证提供程序中流式传输

  Stream<UserAuthenticationCertificate> authenticationStream()
  {
    return _authentication.onAuthStateChanged.map((firebaseUser) => UserAuthenticationCertificate.fromFirebase(firebaseUser));
  }

如果要使用 Stream,请使用StreamProvider而不是 Provider。 但是我不知道您为什么要在这种情况下使用 Stream 。 为什么不是 ChangeNotifierProvider?

使用Navigator.of(context)导航到您的页面。 您代码的导航部分很奇怪。 您在 TheSplashPage() 的构建函数中返回 TheGroupManagementPage() 或 TheRegisterPage()。 这不是 Navigator 的工作方式。 您应该使用 Navigator 的方法,如pushpoppushNamed等。

  Navigator.of(context).pushNamed(TheGroupManagementPage.routeName);

所以现在每当我弹出一条路线时,我都会回到初始页面,这不是我想要的。

您可以在登录后从导航树中删除 SplashPage。 这是一种方法,而不是一种坏方法。 在验证后推送页面时,您应该使用pushReplacementpushReplacementNamed 您还可以使用它进行注销以使用 RegisterPage() 替换您的导航树。

或者,如果您有一个主屏幕,例如启动后的根路由,在您的情况下,这可能是 TheGroupManagementPage。 然后将TheGroupManagementPage包装在WillPopScope 中并在onWillPop 中执行您将执行的操作 不过我更喜欢第一种方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM