前言
Hi, 今天就是把之前寫的一堆功能放到Screen裡面,由於是UI的部分所以程式碼會很長,有些地方我只會擷取片段,建議大家看完整程式碼。
完整程式碼
需要具備知識
Splash Screen
把首頁的MultiBlocProvider加上AuthenticationBloc,並觸發事件AppStarted()來檢查是否有登入過。
1 2 3 4 5 6 7
   | 
  BlocProvider(   create: (context) => AuthenticationBloc(     authRepository: authRepository,   )..add(AppStarted()), ),
 
  | 
 
把這個畫面設置成初始畫面,然後當事件觸發後BlocListener會監聽AuthenticationBloc現在的狀態進行頁面切換。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | class SplashScreen extends StatelessWidget {   const SplashScreen({Key? key}) : super(key: key);
    @override   Widget build(BuildContext context) {     return BlocListener<AuthenticationBloc, AuthenticationState>(       listener: (context, state) {         if (state is Unauthenticated) {           context.replaceRoute(LoginScreen());         }         if (state is Authenticated) {           context.replaceRoute(HomeScreen());         }       },       child: Scaffold(         backgroundColor: Theme.of(context).backgroundColor,       ),     );   } }
 
  | 
 
Login Screen
在LoginScreen這邊一樣加一個AuthenticationBloc監聽器,檢查是否登入成功取得驗證。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   | class LoginScreen extends StatelessWidget {   const LoginScreen({Key? key}) : super(key: key);
    @override   Widget build(BuildContext context) {     return BlocListener<AuthenticationBloc, AuthenticationState>(       listener: (context, state) {         if (state is Authenticated) {           context.replaceRoute(HomeScreen());         }       },       child: Scaffold(         backgroundColor: Theme.of(context).backgroundColor,         body: Container(           width: MediaQuery.of(context).size.width,           height: MediaQuery.of(context).size.height,           child: Stack(             alignment: Alignment.center,             children: [               Positioned(                 top: 200,                 child: Text(                   "Hello",                   style: Theme.of(context).textTheme.bodyText1,                 ),               ),               Positioned(                 top: 370,                 child: BlocProvider(                   create: (context) =>                       SignInBloc(authRepository: AuthRepository()),                   child: LoginFrom(),                 ),               ),             ],           ),         ),       ),     );   } }
  | 
 
Login From
創建SignInBloc然後在LoginForm裡面寫一個SignInBloc的監聽器來檢查登入成功或失敗,如果登入成功的話就觸法LoggedIn的事件。
1 2 3 4 5 6 7 8
   | Positioned(     top: 370,     child: BlocProvider(       create: (context) =>           SignInBloc(authRepository: AuthRepository()),       child: LoginFrom(),     ), ),
   | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
   | class LoginFrom extends StatelessWidget {   const LoginFrom({Key? key}) : super(key: key);
    @override   Widget build(BuildContext context) {     return BlocListener<SignInBloc, SignInState>(       listener: (context, state) {         if (state is SignInStateSuccess) {           BlocProvider.of<AuthenticationBloc>(context).add(LoggedIn());         }         if (state is SignInStateFailure) {                    }       },       child: Column(         children: [           GoogleSignInButton(),         ],       ),     );   } }
  | 
 

Home Screen
在首頁檢查驗證登入狀態,然後在登出按鈕(左上角的小啤酒)新增LoggedOut事件。
1 2 3 4 5 6
   | return BlocListener<AuthenticationBloc, AuthenticationState>(   listener: (context, state) {     if (state is Unauthenticated) {       context.replaceRoute(LoginScreen());     }   },
   | 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
   | class SignOutButton extends StatelessWidget {   @override   Widget build(BuildContext context) {     return IconButton(       onPressed: () {         BlocProvider.of<AuthenticationBloc>(context).add(LoggedOut());       },       icon: Icon(         Icons.sports_bar_rounded,         color: Theme.of(context).shadowColor,         size: 30,       ),     );   } }
  | 
 
