CH05 Firebase Authentication App
Provider ์์ ๊ตฌํํ ์ฑ๊ณผ ๋์ผํ๊ณ , Bloc ํ์ฉ ๋ฒ์๋ TODO ์์ ๋ค๋ค๋ ๋ฒ์ ๋ด์์ ๋ค๋ค๋ค.
๋จ, WillPopScope ํ์ฉ์ ๋ํด์ ๋ด๊ฐ ์์ ์ ์ด ์ฑ์ ๋ง๋ค๋ ๋ค์ ์ ์ฌํ ๋ณด์ง ์์๋ ๊ฒ ๊ฐ์์ ๋ฐ๋ก ๋ค์ ์ ๋ฆฌํด๋๋ค.
WillPopScope ์์ ฏ์ ์ฌ์ฉ์๊ฐ ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ๋๋ฅผ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ ์์ ฏ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ์คํ ๋ด์์ ์ด์ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ ค๋ ๊ฒฝ์ฐ ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ๋๋ฆ ๋๋ค. ์ด๋ WillPopScope ์์ ฏ์ด ์ฌ์ฉ๋๋ฉด, ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ ์ด๋ฒคํธ๋ฅผ ์บ์นํ์ฌ ์ปค์คํ ํ ์์ ์ ์ํํ ์ ์์ต๋๋ค.
WillPopScope ์์ ฏ์ onWillPop ์์ฑ์ ๊ฐ์ง๋ฉฐ, ์ด ์์ฑ์ Future์ ๋ฐํํฉ๋๋ค. ๋ง์ฝ onWillPop์ด true๋ฅผ ๋ฐํํ๋ฉด ์ด๋ฒคํธ๋ ๋ฌด์๋๊ณ ์ฑ์ ์ด์ ํ๋ฉด์ผ๋ก ์ด๋ํฉ๋๋ค. ๋ฐ๋ฉด์, false๋ฅผ ๋ฐํํ๋ฉด ์ด๋ฒคํธ๊ฐ ์ทจ์๋๊ณ ์ฑ์ ํ์ฌ ํ๋ฉด์ ๋จธ๋ฌด๋ฅด๊ฒ ๋ฉ๋๋ค.
WillPopScope๋ ์ผ๋ฐ์ ์ผ๋ก Scaffold๋ AppBar์ ๊ฐ์ ์์ ฏ์ ์ฌ์ฉํ ๋ ์ ์ฉ๋ฉ๋๋ค. ์ด๋ฌํ ์์ ฏ์ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ๋๋ฅด๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ฌ ํ๋ฉด์ด ์ข ๋ฃ๋์ด์ผ ํ์ง๋ง, WillPopScope๋ฅผ ์ฌ์ฉํ๋ฉด ์ด๋ฒคํธ๋ฅผ ์บ์นํ์ฌ ๋ค๋ฅธ ์์ ์ ์ํํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, ์ฌ์ฉ์๊ฐ ๋ค๋ก ๊ฐ๊ธฐ ๋ฒํผ์ ๋๋ ์ ๋ ๊ฒฝ๊ณ ๋ฉ์์ง๋ฅผ ๋์ธ ์ ์์ต๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ฆฌ์ค๋์ ๋ค์ด์ผ๋ก๊ทธ๋ฅผ ์ค์ ํด๋์๋ ๋ค์ด์ผ๋ก๊ทธ๊ฐ ์ฌ๋ฌ๋ฒ ํธ์ถ๋๋ ๋ฌธ์ ๋ ์๋์ ๊ฐ์ด ํด๊ฒฐํ๋ค.
class SplashPage extends StatelessWidget {
static const String routeName = '/';
const SplashPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state.authStatus == AuthStatus.unauthenticated) {
Navigator.pushNamedAndRemoveUntil(
context,
SigninPage.routeName,
(route) {
print('route.settings.name: ${route.settings.name}');
print('ModalRoute: ${ModalRoute.of(context)!.settings.name}');
return route.settings.name ==
ModalRoute.of(context)!.settings.name
? true
: false;
},
);
} else if (state.authStatus == AuthStatus.authenticated) {
Navigator.pushNamed(context, HomePage.routeName);
}
},
builder: (context, state) {
return Scaffold(
body: Center(
child: CircularProgressIndicator(),
),
);
},
);
}
}
๋ก๊ทธ์ธ ์ฑ๊ณต ํ ๋ก๊ทธ์์์ ํ ๋ค ๋ก๊ทธ์ธ์ ์๋์ ์ผ๋ก ์คํจํ๋ฉด ์๋ ํ ๋ฒ ๋ ์ผํ ๋ค์ด์ผ๋ก๊ทธ๊ฐ ์ค์ฒฉํด์ ๋ ๊ฐ ๋จ๋ ํ์์ ํด๊ฒฐํ๋ ๊ฒ์ด๋ค. ๋ค์ด์ผ๋ก๊ทธ๋ ์๋์ ๊ฐ์ด ๋ฆฌ์ค๋์ ๊ฑธ๋ ค์๋ค.
child: BlocConsumer<SigninCubit, SigninState>(
listener: (context, state) {
if (state.signinStatus == SigninStatus.error) {
errorDialog(context, state.error);
}
},
...
),
์ํ๊ฐ ์ค์ ๋ก ๋ ๋ฒ ๋ฐ๋์๊ฑฐ๋
๋ฆฌ์ค๋๊ฐ ๋ ๊ฐ ๋ฑ๋ก๋์ด์๊ฑฐ๋
์ธ๋ฐ ์ด ๊ฒฝ์ฐ 2๋ฒ์ ๊ฒฝ์ฐ๋ก ์ธํด ๋ค์ด์ผ๋ก๊ทธ๊ฐ ๋ ๊ฐ ๋จ๋ ๊ฒ์ด๋ค. ์๋ํ๋ฉด Splash ์์ pushNamed ๋ก Signin Page ๋ก ๋ณด๋์๊ธฐ ๋๋ฌธ์, ์ฒซ ๋ก๊ทธ์ธ ์ง์ ์ ํ๋์ Home ์์ ๋ก๊ทธ์์ํ ํ Splash ์์ ๋ถ๊ธฐ๋ฅผ ํ๋ฉด์ Splash ๋ก ๋ณด๋ธ ๊ฒ ๋ ๊ฐ๊ฐ ์ค์ฒฉ๋์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด๋ฅผ ๋ฐฉ์งํ๊ณ ์ signin ์์ ์์ธ ๋ผ์ฐํธ๋ฅผ ๊ฒ์ฌํด์ splash ์ธ์ ๋ชจ๋ ๊ฒ์ ์์ ๋ ์์ ์ ํด์ค ๊ฒ์ด๋ค.
Navigator.pushNamedAndRemoveUntil ์ ๋ํด์ ์ ๊น ์์๋ณด์.
Navigator.pushNamedAndRemoveUntil
Navigator.pushNamedAndRemoveUntil์ ํ์ฌ ํ์ด์ง์์ ์ง์ ํ ๊ฒฝ๋ก ์ด๋ฆ์ ํ์ด์ง๋ก ์ด๋ํ๋ฉด์, ์ด์ ํ์ด์ง ์คํ์์ ํน์ ์กฐ๊ฑด์ ๋ง์กฑํ๋ ๋ชจ๋ ํ์ด์ง๋ฅผ ์ ๊ฑฐํ๋ ํจ์์ ๋๋ค.
Navigator.pushNamedAndRemoveUntil์ ์ธ์๋ก๋ 1) ์ด๋ํ ๊ฒฝ๋ก ์ด๋ฆ๊ณผ 2) ์ด์ ํ์ด์ง ์คํ์์ ์ ๊ฑฐํ ํ์ด์ง๋ฅผ ๊ฒฐ์ ํ๋ ์ฝ๋ฐฑ ํจ์๊ฐ ๋ค์ด๊ฐ๋๋ค. ์ฝ๋ฐฑ ํจ์๋ ์ด์ ํ์ด์ง ์คํ์์ ๊ฐ ํ์ด์ง๋ฅผ ๊ฒ์ฌํ์ฌ ํ์ด์ง๋ฅผ ์ ๊ฑฐํ ์ง ๋ง์ง๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๋ฅผ ์ฌ์ฉํ์ฌ โ/Aโ ๊ฒฝ๋ก๋ก ์ด๋ํ๋ฉด์ ์ด์ ํ์ด์ง ์คํ์์ โ/โ (๋ฃจํธ) ๊ฒฝ๋ก๋ฅผ ์ ์ธํ ๋ชจ๋ ํ์ด์ง๋ฅผ ์ ๊ฑฐํ ์ ์์ต๋๋ค.
Navigator.pushNamedAndRemoveUntil(
context,
'/A',
(route) => route.settings.name == '/',
);
๋ํ๋จผํธ๋ฅผ ๋ณด๋ฉด ์๋์ ๊ฐ์ด ๋์์๋ค.
/// Push the route with the given name onto the navigator, and then remove all
/// the previous routes until the `predicate` returns true.
///
/// {@macro flutter.widgets.navigator.pushNamedAndRemoveUntil}
///
/// {@macro flutter.widgets.navigator.pushNamed.returnValue}
///
/// {@macro flutter.widgets.Navigator.pushNamed}
///
/// {@tool snippet}
///
/// Typical usage is as follows:
///
/// ```dart
/// void _handleOpenCalendar() {
/// navigator.pushNamedAndRemoveUntil('/calendar', ModalRoute.withName('/'));
/// }
/// ```
/// {@end-tool}
///
/// See also:
///
/// * [restorablePushNamedAndRemoveUntil], which pushes a new route that can
/// be restored during state restoration.
@optionalTypeArgs
Future<T?> pushNamedAndRemoveUntil<T extends Object?>(
String newRouteName,
RoutePredicate predicate, {
Object? arguments,
}) {
return pushAndRemoveUntil<T>(_routeNamed<T>(newRouteName, arguments: arguments)!, predicate);
}
Push the route with the given name onto the navigator, and then remove all the previous routes until the
predicate returns true.
์ด๊ฑธ ๋ณด๋ฉด ์ ์ ์๋ฏ์ด โ๋ฌด์กฐ๊ฑด ์ง์ด๋ค. predicate ์ด true ๋ฅผ return ํ ๋ ๊น์งโ ๋ก ๋์ํ๋ค. ๊ทธ๋์ pushNamedAndRemoveUntil ๊ฐ ์คํ๋๋ฉด predicate ์์ ํ์ฌ ์คํ์ ์์ธ ๋ชจ๋ route ๋ฅผ ์ํํ๋ฉฐ predicate ์ ์ฉ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌํ๊ฒ ๋๋ ๊ฒ์ด๋ค.
Last updated