I'm trying to validate the input data entered by the user for signing up and getting this error [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: type 'Null' is not a subtype of type 'BuildContext'
Here is my code:
class _LoginState extends State<Login> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
GoogleSignIn _googleSignIn = GoogleSignIn(scopes: ['email']);
late String _email, _password;
String error = "";
@override
void initState() {
super.initState();
}
bool _isObscure = true;
@override
Widget build(BuildContext context) {
MediaQueryData mediaQueryData = MediaQuery.of(context);
GoogleSignInAccount? user = _googleSignIn.currentUser;
final isKeyboard = MediaQuery.of(context).viewInsets.bottom != 0;
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: !isKeyboard
? AppBar(
titleSpacing: 12,
leading: ModalRoute.of(context)?.canPop == true
? IconButton(
splashColor: Colors.transparent,
padding: const EdgeInsets.only(left: 30.0, bottom: 15.0),
icon: Icon(
Icons.arrow_back,
size: 35,
),
onPressed: () => Navigator.of(context).pop(),
color: Colors.black,
)
: null,
title: Image.asset('images/logo-name.png'),
backgroundColor: new Color(0xffff),
shadowColor: Colors.transparent,
elevation: 0,
toolbarHeight: 90.0,
)
: null,
body: Center(
child: Column(
children: <Widget>[
if (!isKeyboard)
Container(
child: RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: "Made e-Groceries easier",
style: TextStyle(
fontSize: mediaQueryData.textScaleFactor /
mediaQueryData.textScaleFactor *
33,
fontFamily: 'Inter',
fontWeight: FontWeight.w600,
color: Colors.black)),
),
width: mediaQueryData.size.width * 0.8,
),
Container(
child: Image(
image: AssetImage("images/login.png"), fit: BoxFit.contain),
),
Container(
width: mediaQueryData.size.width * 0.85,
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
controller: _emailController,
validator: (input) {
if (input!.isEmpty)
return 'Pleas enter a valid Email';
},
decoration: InputDecoration(
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
errorStyle: TextStyle(height: 0.4),
contentPadding:
const EdgeInsets.symmetric(vertical: 20.0),
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xff2C6846))),
focusColor: Color(0xff2C6846),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Color(0xff2C6846),
)),
labelStyle: TextStyle(color: Color(0xff2C6846)),
labelText: "Email",
prefixIcon:
Icon(Icons.mail, color: Color(0xff2C6846)),
),
onSaved: (input) => _email = input!),
SizedBox(height: 20),
TextFormField(
obscureText: _isObscure,
enableSuggestions: false,
autocorrect: false,
controller: _passwordController,
validator: (input) {
if (input!.length < 6)
return 'Provide minimum 6 character';
},
decoration: InputDecoration(
focusedErrorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
errorBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.red),
),
errorStyle: TextStyle(height: 0.4),
contentPadding: const EdgeInsets.symmetric(
vertical: 20.0),
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xff2C6846))),
focusColor: Color(0xff2C6846),
focusedBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Color(0xff2C6846))),
labelStyle:
TextStyle(color: Color(0xff2C6846)),
labelText: "Password",
suffixIcon: IconButton(
icon: Icon(
_isObscure
? Icons.visibility
: Icons.visibility_off,
color: Color(0xff2C6846),
),
onPressed: () {
setState(() {
_isObscure = !_isObscure;
});
},
),
prefixIcon: Icon(Icons.lock,
color: Color(0xff2C6846))),
onSaved: (input) => _password = input!),
])))),
SizedBox(height: 20),
ButtonTheme(
buttonColor: Color(0xff2C6846),
minWidth: mediaQueryData.size.width * 0.85,
height: 60.0,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(5.0),
),
padding: EdgeInsets.fromLTRB(70, 10, 70, 10),
onPressed: () {
if (_formKey.currentState!.validate()) {
signInUser();
}
},
child: Text('Log In',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w600))),
)
],
),
),
);
}
void signInUser() async {
dynamic authResult = await _auth.loginUser(
_emailController.text, _passwordController.text);
if (authResult == null) {
print("Sign in error. Could not be able to login");
} else {
_emailController.clear();
_passwordController.clear();
print('Sign in Successful');
Navigator.push(
context, MaterialPageRoute(builder: (context) => HomePage()));
}
}
}
The above code is for AuthService.dart:
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
showError(Object errormessage) {
var context;
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Note'),
content: Text(errormessage.toString()),
actions: <Widget>[
FlatButton(
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'))
],
);
});
}
Future loginUser(String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(
email: email.toString(), password: password.toString());
return result.user;
} catch (e) {
showError(e);
}
}
}
Ignore the messy indentation as this is my first time using stack overflow.
CodePudding user response:
Probably the issue is coming from
Navigator.push(
context, MaterialPageRoute(builder: (context) => HomePage()));
So make the global BuildContext variable and initial it from the build method. Or send context as a parameter. Like
signInUser(BuildContext context)
CodePudding user response:
...
showError(Object errormessage) {
var context;
showDialog(
context: context,
...
the showDialog method takes a context parameter, it uses this context to find some special useful information about your application in order to properly show the dialog, you are not passing a proper context.
What you are doing is first declaring a variable context
and then passing that, the variable's value is null by default, so you get an error.
To fix this, you need to pass the real context used by your app:
...
showError(BuildContext context, Object errormessage) {
showDialog(
context: context,
...
and then:
Future loginUser(BuildContext context, String email, String password) async {
try {
UserCredential result = await _auth.signInWithEmailAndPassword(
email: email.toString(), password: password.toString());
return result.user;
} catch (e) {
showError(context, e);
}
}
And finally:
...
void signInUser() async {
dynamic authResult = await _auth.loginUser(context, _emailController.text, _passwordController.text);
...
CodePudding user response:
'Null' is not a subtype of type 'BuildContext' error means the code wants from you BuildContext but probably you give null. So you should check the BuildContext using parts. When i review your code i see the error line. Error is you define the context and not setting anything. So it's value is null. You should pass the context with parameter. If you pass the context your problem will be solve.
showError(Object errormessage) {
var context;
showDialog(
context: context,