When I login using the form in the signin_content.dart, I navigate to the home page. And then I can logout because I didn't push to another screen, so it works perfectly.
The problem is when I start the app, I see the first page that is signin_content.dart.
And then, if I push to signup_content.dart and I back to signin_content.dart and try to login, the context in the provider doesn't work.
BlocProvider.of<AuthenticationBloc>(context).add(LoggedIn()),
I already tried this solution but I need to see how to locate the code:
I tried to use the the provider as a parent of MaterialApp but how?
I am using this library:
main.dart
// imports ..
class SimpleBlocDelegate extends BlocDelegate {
@override
void onEvent(Bloc bloc, Object event) {
super.onEvent(bloc, event);
print(event);
}
@override
void onTransition(Bloc bloc, Transition transition) {
super.onTransition(bloc, transition);
print(transition);
}
@override
void onError(Bloc bloc, Object error, StackTrace stacktrace) {
super.onError(bloc, error, stacktrace);
print(error);
}
}
void main() {
BlocSupervisor.delegate = SimpleBlocDelegate();
final userRepository = UserRepository();
runApp(
BlocProvider<AuthenticationBloc>(
create: (context) {
return AuthenticationBloc(userRepository: userRepository)
..add(AppStarted());
},
child: App(userRepository: userRepository),
),
);
}
app.dart
// imports..
class App extends StatelessWidget {
final UserRepository userRepository;
const App({
Key key,
@required this.userRepository,
}) : assert(userRepository != null),
super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: fitnessTheme(),
routes: Routes.appRoutes,
home: BlocBuilder<AuthenticationBloc, AuthenticationState>(
builder: (context, state) {
if (state is AuthenticationLoading) {
return LoadingIndicator();
}
if (state is AuthenticationUnauthenticated) {
return SigninScreen();
}
if (state is AuthenticationProfileInactive) {
return WelcomeScreen();
}
if (state is AuthenticationAuthenticated) {
return HomeScreen();
}
return Splash();
},
),
);
}
}
signin_content.dart
//imports..
class SigninContent extends StatefulWidget {
SigninContent({Key key}) : super(key: key);
_SigninContentState createState() => _SigninContentState();
}
class _SigninContentState extends State<SigninContent> {
SigninFormBloc _signinFormBloc;
final TextEditingController _emailController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final UserProvider _userProvider = UserProvider();
@override
void initState() {
super.initState();
_signinFormBloc = BlocProvider.of<SigninFormBloc>(context);
_emailController.addListener(_onEmailChanged);
_passwordController.addListener(_onPasswordChanged);
}
@override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
print(BlocProvider.of<AuthenticationBloc>(context).state);
return BlocBuilder<SigninFormBloc, SigninFormState>(
builder: (context, state) {
if (state.formSubmittedSuccessfully) {
final authData = {
'email': _emailController.value.text,
'password': _passwordController.value.text,
};
_userProvider.signin(
data: authData,
success: () =>
BlocProvider.of<AuthenticationBloc>(context).add(LoggedIn()),
error: (message) {
Scaffold.of(context).showSnackBar(
buildSnackbar(
message,
Colors.red[700],
Colors.white,
Duration(seconds: 2),
),
);
},
);
// _emailController.clear();
// _passwordController.clear();
_signinFormBloc.add(FormReset());
}
return Column(
children: <Widget>[
Expanded(
child: SingleChildScrollView(
child: Container(
margin: EdgeInsets.only(top: 16.0),
padding: EdgeInsets.only(
top: 29.0,
left: 14.0,
right: 14.0,
),
child: Column(
children: <Widget>[
textInputWidget(
controller: _emailController,
labelText: "Email",
hintText: 'Enter a valid email',
autovalidate: state.email.isEmpty ? false : true,
validator: (_) {
return state.isEmailValid ? null : 'Invalid Email';
},
),
SizedBox(height: 20.0),
textInputWidget(
controller: _passwordController,
labelText: "Password",
hintText: 'Enter a valid password',
obscureText: true,
autovalidate: state.password.isEmpty ? false : true,
validator: (_) {
return state.isPasswordValid
? null
: 'Invalid Password';
},
),
SizedBox(height: 20.0),
primaryButton(
caption: "sign in",
context: context,
submit: state.isFormValid ? _onSubmitPressed : null,
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Text("Need an account?"),
FlatButton(
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
textColor: Color(0xFF32AEE2),
child: Text(
"Sign up",
style: TextStyle(
fontSize: 14.0,
fontFamily: "SF Pro Text",
),
),
onPressed: () => Navigator.pushReplacementNamed(
context,
SignupScreen.routeName,
),
)
],
),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Text("Forgot your password?"),
FlatButton(
padding: EdgeInsets.all(0),
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
textColor: Color(0xFF32AEE2),
child: Text(
"Reset",
style: TextStyle(
fontSize: 14.0,
fontFamily: "SF Pro Text",
),
),
onPressed: () => Navigator.pushReplacementNamed(
context,
PasswordResetScreen.routeName,
),
)
],
),
),
],
),
),
),
),
],
);
},
);
}
@override
void dispose() {
_emailController.dispose();
_passwordController.dispose();
super.dispose();
}
void _onEmailChanged() {
_signinFormBloc.add(EmailChanged(email: _emailController.text));
}
void _onPasswordChanged() {
_signinFormBloc.add(PasswordChanged(password: _passwordController.text));
}
void _onSubmitPressed() {
_signinFormBloc.add(FormSubmitted());
}
}
signup_content.dart
// imports..
class SignupContent extends StatefulWidget {
SignupContent({Key key}) : super(key: key);
_SignupContentState createState() => _SignupContentState();
}
class _SignupContentState extends State<SignupContent> {
SignupFormBloc _signupFormBloc;
final TextEditingController _nameController = TextEditingController();
final TextEditingController _emailController = TextEditingController();
final TextEditingController _dobController = TextEditingController();
final TextEditingController _passwordController = TextEditingController();
final TextEditingController _passwordConfirmationController =
TextEditingController();
final UserProvider _userProvider = UserProvider();
@override
void initState() {
super.initState();
_signupFormBloc = BlocProvider.of<SignupFormBloc>(context);
_nameController.addListener(_onNameChanged);
_emailController.addListener(_onEmailChanged);
_dobController.addListener(_onDobChanged);
_passwordController.addListener(_onPasswordChanged);
_passwordConfirmationController.addListener(_onPasswordConfirmationChanged);
}
@override
Widget build(BuildContext context) {
final Size _size = MediaQuery.of(context).size;
print(BlocProvider.of<AuthenticationBloc>(context).state);
return BlocBuilder<SignupFormBloc, SignupFormState>(
builder: (context, state) {
if (state.formSubmittedSuccessfully) {
final userData = {
'name': _nameController.value.text,
'email': _emailController.value.text,
'password': _passwordController.value.text,
};
_userProvider.signup(
userData: userData,
success: () {
BlocProvider.of<AuthenticationBloc>(context).add(
SignedUp(
email: userData["email"],
password: userData["password"],
),
);
},
error: (message) {
Scaffold.of(context).showSnackBar(
buildSnackbar(
message,
Colors.red[700],
Colors.white,
Duration(seconds: 2),
),
);
},
);
_signupFormBloc.add(FormReset());
}
return Column(
children: <Widget>[
authHeader(_size),
Expanded(
child: SingleChildScrollView(
child: Container(
margin: EdgeInsets.only(top: 16.0),
padding: EdgeInsets.only(
top: 29.0,
left: 14.0,
right: 14.0,
),
child: Column(
children: <Widget>[
textInputWidget(
controller: _nameController,
labelText: "Name",
hintText: 'Enter a valid name',
autovalidate: state.name.isEmpty ? false : true,
validator: (_) {
return state.isNameValid
? null
: 'At least 6 characters long.';
},
),
SizedBox(height: 20.0),
textInputWidget(
controller: _emailController,
labelText: "Email",
hintText: 'Enter a valid email',
autovalidate: state.email.isEmpty ? false : true,
validator: (_) {
return state.isEmailValid ? null : 'Invalid Email';
},
),
SizedBox(height: 20.0),
textInputWidget(
controller: _passwordController,
labelText: "Password",
hintText: 'Enter a valid password',
obscureText: true,
autovalidate: state.password.isEmpty ? false : true,
validator: (_) {
return state.isPasswordValid
? null
: 'Invalid Password';
},
),
SizedBox(height: 20.0),
textInputWidget(
controller: _passwordConfirmationController,
labelText: "Password Confirmation",
hintText: 'Enter a valid password',
autovalidate:
state.passwordConfirmation.isEmpty ? false : true,
validator: (_) {
return state.isPasswordConfirmationValid
? null
: 'Invalid Password';
},
obscureText: true,
),
SizedBox(height: 20.0),
primaryButton(
caption: "sign up",
context: context,
submit: state.isFormValid ? _onSubmitPressed : null,
),
SizedBox(height: 10.0),
Row(
children: <Widget>[
Text("Already Registered?"),
FlatButton(
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
textColor: Color(0xFF32AEE2),
child: Text(
"Sign in",
style: TextStyle(
fontSize: 14.0,
fontFamily: "SF Pro Text",
),
),
onPressed: () => Navigator.pushReplacementNamed(
context,
SigninScreen.routeName,
),
)
],
),
],
),
),
),
),
],
);
},
);
}
@override
void dispose() {
_nameController.dispose();
_emailController.dispose();
_passwordController.dispose();
_passwordConfirmationController.dispose();
super.dispose();
}
void _onNameChanged() {
_signupFormBloc.add(NameChanged(name: _nameController.text));
}
void _onEmailChanged() {
_signupFormBloc.add(EmailChanged(email: _emailController.text));
}
void _onPasswordChanged() {
_signupFormBloc.add(PasswordChanged(password: _passwordController.text));
}
void _onPasswordConfirmationChanged() {
_signupFormBloc.add(
PasswordConfirmationChanged(
password: _passwordController.text,
passwordConfirmation: _passwordConfirmationController.text,
),
);
}
void _onSubmitPressed() {
_signupFormBloc.add(
FormSubmitted(),
);
}
}
This is because in the SignupContent
you are replacement the home of your MaterialApp
, so the BlocBuilder
is removed and the widget does not change even if the authentication state changes.
To fix it, I recommend that you delete the BlocBuilder
and use a BlocListener
in each screen instead, in this way you can use the Navigator
without any problem.
So change your main
to
void main() {
BlocSupervisor.delegate = SimpleBlocDelegate();
final userRepository = UserRepository();
final authenticationBloc = AuthenticationBloc(userRepository: userRepository);
authenticationBloc
.firstWhere((state) =>
state is! AuthenticationUninitialized &&
state is! AuthenticationLoading)
.then((state) => runApp(App(
authenticationBloc: authenticationBloc,
home: state is AuthenticationUnauthenticated
? SigninScreen()
: HomeScreen(),
)));
authenticationBloc.add(AppStarted());
}
Also change your App
widget
class App extends StatelessWidget {
const App({
Key key,
@required this.home,
@required this.authenticationBloc,
}) : super(key: key);
final Widget home;
final AuthenticationBloc authenticationBloc;
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
providers: <BlocProvider>[
BlocProvider<AuthenticationBloc>.value(value: authenticationBloc),
],
child: MaterialApp(
debugShowCheckedModeBanner: false,
theme: fitnessTheme(),
routes: Routes.appRoutes,
home: home,
),
);
}
}
Then use a BlocListener
in your SigninScreen
and SignupScreen
for navigate, and show loading dialog when the authentication state changes.
class SigninScreen extends StatelessWidget {
static const String routeName = "signin";
const SigninScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
ScreenRatio.setScreenRatio(
MediaQuery.of(context).size.height,
MediaQuery.of(context).size.width,
);
return BlocProvider(
create: (context) => SigninFormBloc(),
child: BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is AuthenticationLoading) {
LoadingDialog.show(context);
} else if (state is AuthenticationUnauthenticated) {
LoadingDialog.hide(context);
} else if (state is AuthenticationAuthenticated) {
LoadingDialog.hide(context);
Navigator.of(context).pushNamedAndRemoveUntil(
HomeScreen.routeName, (route) => false);
}
},
child: Scaffold(
body: SafeArea(
child: SigninContent(),
),
),
));
}
}
class SignupScreen extends StatelessWidget {
static const String routeName = "signup";
const SignupScreen({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
ScreenRatio.setScreenRatio(
MediaQuery.of(context).size.height, MediaQuery.of(context).size.width);
return BlocProvider(
create: (context) => SigninFormBloc(),
child: BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is AuthenticationLoading) {
LoadingDialog.show(context);
} else if (state is AuthenticationUnauthenticated) {
LoadingDialog.hide(context);
} else if (state is AuthenticationAuthenticated) {
LoadingDialog.hide(context);
Navigator.of(context).pushNamedAndRemoveUntil(
HomeScreen.routeName, (route) => false);
}
},
child: Scaffold(
body: SafeArea(
child: SignupContent(),
),
),
));
}
}
class LoadingDialog extends StatelessWidget {
static void show(BuildContext context, {Key key}) {
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (_) => LoadingDialog(key: key),
);
}
static void hide(BuildContext context) {
Navigator.pop(context);
}
LoadingDialog({Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async => false,
child: Center(
child: Card(
child: Container(
width: 80,
height: 80,
padding: EdgeInsets.all(12.0),
child: CircularProgressIndicator(),
),
),
),
);
}
}
And finally in your HomeScreen
use a BlocListener
to navigate when the user has signed out
return BlocListener<AuthenticationBloc, AuthenticationState>(
listener: (context, state) {
if (state is AuthenticationUnauthenticated) {
Navigator.of(context).pushNamedAndRemoveUntil(
SigninScreen.routeName, (route) => false);
}
},
child: Scaffold(
body: Center(
child: RaisedButton(
onPressed: () {
BlocProvider.of<AuthenticationBloc>(context).add(LoggedOut());
},
child: Text("Sign out"),
),
),
),
);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.