[英]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 的方法,如push
、 pop
、 pushNamed
等。
Navigator.of(context).pushNamed(TheGroupManagementPage.routeName);
所以现在每当我弹出一条路线时,我都会回到初始页面,这不是我想要的。
您可以在登录后从导航树中删除 SplashPage。 这是一种方法,而不是一种坏方法。 在验证后推送页面时,您应该使用pushReplacement
或pushReplacementNamed
。 您还可以使用它进行注销以使用 RegisterPage() 替换您的导航树。
或者,如果您有一个主屏幕,例如启动后的根路由,在您的情况下,这可能是 TheGroupManagementPage。 然后将TheGroupManagementPage包装在WillPopScope 中并在onWillPop 中执行您将执行的操作。 不过我更喜欢第一种方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.