AlertDialog is not working on onPressed() - flutter

trying to do simple login form and want to test the result.
I want to show a message on dialog box but when I am trying to use showDialog and AlertDialog but, it is not working. I have tried debugPrint/Print/log and other functions but nothing worked . it will not print it on console as well.
can anyone please help me?
I want to print message on dialog box.
import 'package:flutter/material.dart';
class Login extends StatefulWidget {
const Login({super.key});
#override
State<Login> createState() => _LoginState();
}
class _LoginState extends State<Login> {
late bool _autovalidate = false;
// Message Stored
late String message;
// login credentials var
late String userName = 'admin';
late String passWord = '123';
// TextEditingController initiated
final name = TextEditingController();
final password = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Expense Manager',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
body: SingleChildScrollView(
child: Form(
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
),
Image(
image: AssetImage('images/logo.png'),
height: 100.0,
width: 100.0,
),
ListTile(
leading: Icon(Icons.person),
title: TextFormField(
controller: name,
validator: (input) {
if (input!.isEmpty) {
return 'Enter Username';
}
},
decoration: InputDecoration(labelText: 'Username'),
),
),
ListTile(
leading: Icon(Icons.password),
title: TextFormField(
controller: password,
obscureText: true,
validator: (input) {
if (input!.isEmpty) {
return 'Enter Password';
}
},
decoration: InputDecoration(labelText: 'Password'),
),
),
Container(
padding: EdgeInsets.all(20.0),
child: ButtonTheme(
height: 40.0,
minWidth: 200.0,
child: ElevatedButton(
onPressed: () {
_showAppLogin();
},
child: Text(
'Login',
style: TextStyle(
color: Colors.white,
),
),
style: ElevatedButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
backgroundColor: Colors.redAccent,
padding: EdgeInsets.zero,
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
),
),
],
),
),
),
),
);
}
_showAppLogin() {
if (name.text == null && password.text == null) {
if (name.text == userName && password.text == passWord) {
_showAlertDialog('Login Successful');
} else {
setState(() {
_autovalidate = true;
});
_showAlertDialog('Invalid Credentials');
}
}
}
void _showAlertDialog(String message) {
AlertDialog alertDialog = AlertDialog(
icon: Icon(Icons.message_outlined),
content: Text(message),
);
showDialog(context: context, builder: (_) => alertDialog);
}
}

TextEditingControler text cant be null, you can do empty check
_showAppLogin() {
if (name.text.isNotEmpty && password.text.isNotEmpty) {
if (name.text == userName && password.text == passWord) {
_showAlertDialog('Login Successful');
} else {
setState(() {
_autovalidate = true;
});
_showAlertDialog('Invalid Credentials');
}
}
}

_showAppLogin() {
if (name.text == null && password.text == null) {
if (name.text == userName && password.text == passWord) {
This is not going to work. The first if checks if both name.text and password.text are null, then the second if checks if they are equal to your desired values. It is impossible for both if conditions to pass.
I think you meant to check != null rather than == null

Remove the unnecessary null check from if (name.text == null && password.text == null) TextEditingController cannot be null because of Sound null safty.
And both of the if conditions Never satisfied
if (name.text == null && password.text == null) {
if (name.text == userName && password.text == passWord) {
...
}
}
You have to check if the TextEditingController .isNotEmpty instead of name.text == null
Change your function to this
if (name.text.isNotEmpty && password.text.isNotEmpty) {
....
}

I think the issue is with the condition you have given,
if (name.text == null && password.text == null) {
The bottom condition will only be checked if the value is null;
if name.text is null then it will not go inside and check if the value is equal to userName' and hence if it's null then there is no value to check.
if (name.text == userName && password.text == passWord) {
} else {
...
}
Try changing the condition to:
if (name.text != null && password.text != null) {
if (name.text == userName && password.text == passWord) {
} else {
...
}
Correct me if i am worng.
Thank you.

Related

I am new to programming can someone help me what's the problem here, I was doing a login page and this happens

If password and username is same, I want to print 'username and password is same' statement in the terminal .But it is only printing the second statement 'username and password does not match even if username and password is same or not . I don't understand why this happened somebody help, I am new here' ( NB : problem is inside the function named checkLogin)
class ScreenLogin extends StatefulWidget {
ScreenLogin({Key? key}) : super(key: key);
#override
State<ScreenLogin> createState() => _ScreenLoginState();
}
class _ScreenLoginState extends State<ScreenLogin> {
final _usernameController = TextEditingController();
final _passwordController = TextEditingController();
bool _isDataMatched = false;
final _formkey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Form(
key: _formkey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: 'Username'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'value is empty';
} else {
return null;
}
},
),
const SizedBox(
height: 20,
),
TextFormField(
controller: _passwordController,
obscureText: true,
decoration: const InputDecoration(
border: OutlineInputBorder(), hintText: 'Password'),
validator: (value) {
if (value == null || value.isEmpty) {
return 'value is empty';
} else {
return null;
}
}),
SizedBox(
height: 20,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Visibility(
visible: _isDataMatched,
child: Text(
'Username and password does not match',
style: TextStyle(color: Colors.red),
),
),
ElevatedButton.icon(
onPressed: () {
if (_formkey.currentState!.validate()) {
checkLogin(context);
} else {
print('Data Empty');
}
},
icon: const Icon(Icons.check),
label: const Text('Login ')),
],
)
],
),
),
),
));
}
void checkLogin(BuildContext context) {
final _username = _usernameController;
final _password = _passwordController;
if (_password == _username) {
print('Username and password is matching');
} else {
print('Username and password does not match');
}
}
}
To get text, you need to use .text on controller.
_usernameController.text;
void checkLogin(BuildContext context) {
final _username = _usernameController.text;
final _password = _passwordController.text;
if (_password == _username) {
print('Username and password is matching');
} else {
print('Username and password does not match');
}
}
In login check you should do this:
void checkLogin(BuildContext context) {
final _username = _usernameController.text;
final _password = _passwordController.text;
if (_password == _username) {
print('Username and password is matching');
} else {
print('Username and password does not match');
}
}

Null Safety Issue in flutter

if (_formKey.currentState.validate()) {
setState(() {
buttonChanged = false;
});
}
according to my logic, the above statement would let me sign in with a login and password validation, but i keep getting an error
The method 'validate' can't be unconditionally invoked because the receiver can be 'null'.
Try making the call conditional (using '?.') or adding a null check to the target ('!').
when i do if (_formKey.currentState!.validate()) error goes away but my validation does not work, login happens even when it shouldnt.
Kindly help me with this issue, i am a beginner, learning flutter app developement via youtube.
this is my whole code
import 'package:flutter/material.dart';
import 'routes.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
#override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
bool buttonChanged = false;
String name = "";
final _formKey = GlobalKey<FormState>();
moveToHome(BuildContext context) async {
if (_formKey.currentState.validate()) {
setState(() {
buttonChanged = false;
});
}
await Future.delayed(const Duration(seconds: 1));
await Navigator.pushNamed(context, route.home);
setState(() {
buttonChanged = false;
});
}
#override
Widget build(BuildContext context) {
return Material(
color: Colors.grey[500],
child: Form(
key: _formKey,
child: Column(
children: [
const CircleAvatar(backgroundImage: AssetImage('images/login.jpg')),
const SizedBox(height: 15.0),
Text('Welcome $name',
style: const TextStyle(
fontSize: 24.0, fontWeight: FontWeight.bold)),
const SizedBox(height: 15.0),
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 15, vertical: 32),
child: Column(
children: [
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter the username',
labelText: 'UserName:'),
onChanged: (value) {
name = value;
setState(() {});
},
validator: (value) {
if (value != null && value.isEmpty) {
return 'Please enter the username';
}
return null;
}),
TextFormField(
obscureText: true,
decoration: const InputDecoration(
hintText: 'Enter the password',
labelText: 'Password:'),
validator: (value) {
if (value != null && value.isEmpty) {
return 'Please enter the password';
} else if (value != null && value.length < 6) {
return 'Password must be atleast 6 characters';
} else {
return null;
}
}),
const SizedBox(height: 15.0),
Material(
borderRadius:
BorderRadius.circular(buttonChanged ? 50.0 : 10.0),
color: Colors.blue,
child: InkWell(
splashColor: Colors.red,
onTap: () => moveToHome(context),
child: AnimatedContainer(
duration: const Duration(seconds: 1),
width: buttonChanged ? 50 : 130,
height: 50,
alignment: Alignment.center,
child: buttonChanged
? const Icon(Icons.done)
: const Text(
'Login',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16),
),
),
))
],
))
],
),
),
);
}
}
Your validation logic must be:
If the user’s input isn’t valid, the validator function returns a String containing an error message. If there are no errors, the validator must return null.
But you're using incorrect code in your validator property. The following code:
validator: (value) {
if (value != null && value.isEmpty) {
return 'Please enter the username';
}
return null;
}),
will always return null if you haven't insert the text to TextFormField. So,
_formKey.currentState!.validate() will always return true if both of your TextFormFields are without text.
To solve the problem, change the code like the following:
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter the username';
}
return null;
}),

Flutter pressing back button pops up previous snackBar from Login page again

I have a LoginPage in Flutter. After login, it shows a small snackbar with "success" or "failure.." if password is wrong, then it navigates to the todo list.
When I now press the "back" button on an Android device, it navigates back to the login screen. However, there is still the snackbar popping up and saying "Login successful, redirecting..", and also, my textfields are not emptied and still have the values from the first login, why? That should not happen, but I cannot figure out why that is... here is my code:
import 'package:flutter/material.dart';
import 'package:todoey_flutter/components/rounded_button.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todoey_flutter/util/file_handler.dart';
import 'package:provider/provider.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
String username;
String password;
String hashedPW;
// Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
var _nameController = TextEditingController();
var _pwController = TextEditingController();
#override
Widget build(BuildContext context) {
CryptOid cy = Provider.of<CryptOid>(context, listen: true);
FileHandler fh = Provider.of<FileHandler>(context, listen: true);
return Scaffold(
backgroundColor: Colors.white,
body: Builder(
builder: (BuildContext scaffoldBuildContext) {
return Container(
//inAsyncCall: isSpinning,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 34.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
/*
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),*/
SizedBox(
height: 48.0,
),
TextField(
controller: _nameController,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
username = value.toLowerCase();
},
decoration: InputDecoration(
hintText: 'Enter your username',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: _pwController,
obscureText: true,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
password = value;
},
decoration: InputDecoration(
hintText: 'Enter your password',
),
),
SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Login',
colour: Colors.lightBlueAccent,
onPressed: () async {
Scaffold.of(scaffoldBuildContext).removeCurrentSnackBar();
print("user: $username, pw: $password");
if ((username != '' && username != null) && (password != '' && password != null)) {
SharedPreferences prefs = await SharedPreferences.getInstance();
// cy.test();
if ((username != '' && username != null) && prefs.containsKey(username)) {
hashedPW = prefs.getString(username);
bool decryptPW = await cy.deHash(hashedPW, password);
if (decryptPW) {
cy.setUsername(username);
fh.setUser(username);
prefs.setString('activeUser', username);
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("Login successful! redirecting.."),
),
);
Navigator.pushNamed(context, 'taskScreen');
} else {
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("Wrong password for user $username!"),
),
);
}
} else {
String hashedPW = await cy.hashPW(password);
prefs.setString('activeUser', username);
prefs.setString(username, hashedPW);
cy.setUsername(username);
fh.setUser(username);
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("User created successful! redirecting.."),
),
);
Navigator.pushNamed(context, 'taskScreen');
//prefs.setString(username, hashedPW);
}
_nameController.clear();
_pwController.clear();
} else {
Scaffold.of(scaffoldBuildContext).showSnackBar(
SnackBar(
content: Text("User and password may not be empty.."),
),
);
_nameController.clear();
_pwController.clear();
return;
}
},
),
],
),
),
);
},
),
);
}
}
You should create a ScaffoldState GlobalKey then assign the to the scaffold.
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: Container());
}
The use the key to showSnackBar
void _showInSnackBar(String value) {
_scaffoldKey.currentState
.showSnackBar(new SnackBar(content: new Text(value)));
}
So your full code would look like this:
import 'package:flutter/material.dart';
import 'package:todoey_flutter/components/rounded_button.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:todoey_flutter/util/file_handler.dart';
import 'package:provider/provider.dart';
class LoginScreen extends StatefulWidget {
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String username;
String password;
String hashedPW;
// Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
var _nameController = TextEditingController();
var _pwController = TextEditingController();
#override
Widget build(BuildContext context) {
CryptOid cy = Provider.of<CryptOid>(context, listen: true);
FileHandler fh = Provider.of<FileHandler>(context, listen: true);
return Scaffold(
key: _scaffoldKey,
backgroundColor: Colors.white,
body: Builder(
builder: (BuildContext scaffoldBuildContext) {
return Container(
//inAsyncCall: isSpinning,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 34.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
/*
Flexible(
child: Hero(
tag: 'logo',
child: Container(
height: 200.0,
child: Image.asset('images/logo.png'),
),
),
),*/
SizedBox(
height: 48.0,
),
TextField(
controller: _nameController,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
username = value.toLowerCase();
},
decoration: InputDecoration(
hintText: 'Enter your username',
),
),
SizedBox(
height: 8.0,
),
TextField(
controller: _pwController,
obscureText: true,
style: TextStyle(color: Colors.black54),
onChanged: (value) {
//Do something with the user input.
password = value;
},
decoration: InputDecoration(
hintText: 'Enter your password',
),
),
SizedBox(
height: 24.0,
),
RoundedButton(
title: 'Login',
colour: Colors.lightBlueAccent,
onPressed: () async {
_scaffoldKey.currentState.removeCurrentSnackBar();
print("user: $username, pw: $password");
if ((username != '' && username != null) &&
(password != '' && password != null)) {
SharedPreferences prefs =
await SharedPreferences.getInstance();
// cy.test();
if ((username != '' && username != null) &&
prefs.containsKey(username)) {
hashedPW = prefs.getString(username);
bool decryptPW = await cy.deHash(hashedPW, password);
if (decryptPW) {
cy.setUsername(username);
fh.setUser(username);
prefs.setString('activeUser', username);
_showInSnackBar("Login successful! redirecting..");
Navigator.pushNamed(context, 'taskScreen');
} else {
_showInSnackBar(
"Wrong password for user $username!");
}
} else {
String hashedPW = await cy.hashPW(password);
prefs.setString('activeUser', username);
prefs.setString(username, hashedPW);
cy.setUsername(username);
fh.setUser(username);
_showInSnackBar(
"User created successful! redirecting..");
Navigator.pushNamed(context, 'taskScreen');
//prefs.setString(username, hashedPW);
}
_nameController.clear();
_pwController.clear();
} else {
_showInSnackBar("User and password may not be empty..");
_nameController.clear();
_pwController.clear();
return;
}
},
),
],
),
),
);
},
),
);
}
void _showInSnackBar(String value) {
_scaffoldKey.currentState
.showSnackBar(new SnackBar(content: new Text(value)));
}
}

Unable to identify source of exception error: Flutter

Image of code that occurs with error
I am going through a udemy Flutter course and I do not understand why the try catch cannot handle the error with the if statement inside inside of the try{}. I have had this problem for this a couple of times and I have just avoided it by running error-free trials.
The code is as follows:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import '../models/http_exception.dart';
class Auth with ChangeNotifier {
String _token;
//tokens only last about an hour
DateTime _expiryDate;
String _userId;
Future<void> _authenticate(
String email, String password, String urlSegment) async {
final url = 'UrlIsCorrectInMyCode'; //changed on purpose
try {
final response = await http.post(
url,
body: json.encode(
{
'email': email,
'password': password,
'returnSecureToken': true,
},
),
);
final responseData = json.decode(response.body);
if(responseData['error'] != null){
throw HttpException(responseData['error']['message']);
}
} catch (error) {
throw error;
}
}
Future<void> signUp(String email, String password) async {
return _authenticate(email, password, 'signUp');
//in order for the progress indicator to be shown
//it must be returned so that it takes the future of
//_authenticate and not just any future
}
Future<void> login(String email, String password) async {
return _authenticate(email, password, 'signInWithPassword');
}
}
And the class that registers UI and uses Auth:
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/auth.dart';
import '../models/http_exception.dart';
enum AuthMode { Signup, Login }
class AuthScreen extends StatelessWidget {
static const routeName = '/auth';
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
// final transformConfig = Matrix4.rotationZ(-8 * pi / 180);
// transformConfig.translate(-10.0);
return Scaffold(
// resizeToAvoidBottomInset: false,
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromRGBO(215, 117, 255, 1).withOpacity(0.5),
Color.fromRGBO(255, 188, 117, 1).withOpacity(0.9),
],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
stops: [0, 1],
),
),
),
SingleChildScrollView(
child: Container(
height: deviceSize.height,
width: deviceSize.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Flexible(
child: Container(
margin: EdgeInsets.only(bottom: 20.0),
padding:
EdgeInsets.symmetric(vertical: 8.0, horizontal: 94.0),
transform: Matrix4.rotationZ(-8 * pi / 180)
..translate(-10.0),
//transform allows to rotate or scale a box
//the '..' operator allows you to return the matrix4
//object that rotationZ provides instead of the void
//response that .translate provides
// ..translate(-10.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.deepOrange.shade900,
boxShadow: [
BoxShadow(
blurRadius: 8,
color: Colors.black26,
offset: Offset(0, 2),
)
],
),
child: Text(
'MyShop',
style: TextStyle(
color:
Theme.of(context).accentTextTheme.headline6.color,
fontSize: 50,
fontFamily: 'Anton',
fontWeight: FontWeight.normal,
),
),
),
),
Flexible(
flex: deviceSize.width > 600 ? 2 : 1,
child: AuthCard(),
),
],
),
),
),
],
),
);
}
}
class AuthCard extends StatefulWidget {
const AuthCard({
Key key,
}) : super(key: key);
#override
_AuthCardState createState() => _AuthCardState();
}
class _AuthCardState extends State<AuthCard> {
final GlobalKey<FormState> _formKey = GlobalKey();
AuthMode _authMode = AuthMode.Login;
Map<String, String> _authData = {
'email': '',
'password': '',
};
var _isLoading = false;
final _passwordController = TextEditingController();
void _showErrorDialog(String message) {
showDialog(
context: context,
builder: (ctx) => AlertDialog(
title: Text("An error occured"),
content: Text(message),
actions: [
FlatButton(
child: Text("Okay"),
onPressed: () {
Navigator.of(ctx).pop();
},
),
],
),
);
}
Future<void> _submit() async {
if (!_formKey.currentState.validate()) {
// Invalid!
return;
}
_formKey.currentState.save();
setState(() {
_isLoading = true;
});
try {
if (_authMode == AuthMode.Login) {
await Provider.of<Auth>(context, listen: false).login(
_authData['email'],
_authData['password'],
);
} else {
await Provider.of<Auth>(context, listen: false).signUp(
_authData['email'],
_authData['password'],
);
}
} on HttpException catch (error) {
//this means a special type of error is thrown
//this acts as a filter for the type of error
var errorMessage = 'Authentication failed.';
if (error.toString().contains("EMAIL_EXISTS")) {
errorMessage = 'This email address is already in use';
} else if (error.toString().contains('INVALID_EMAIL')) {
errorMessage = 'This is not a valid email address.';
} else if (error.toString().contains('WEAK_PASSWORD')) {
errorMessage = 'This password is too weak.';
} else if (error.toString().contains('EMAIL_NOT_FOUND')) {
errorMessage = 'Could not find a user with that email.';
} else if (error.toString().contains('INVALID_PASSWORD')) {
errorMessage = 'Invalid password.';
}
_showErrorDialog(errorMessage);
} catch (error) {
const errorMessage = 'Could not authenticate. Please try again.';
_showErrorDialog(errorMessage);
}
setState(() {
_isLoading = false;
});
}
void _switchAuthMode() {
if (_authMode == AuthMode.Login) {
setState(() {
_authMode = AuthMode.Signup;
});
} else {
setState(() {
_authMode = AuthMode.Login;
});
}
}
#override
Widget build(BuildContext context) {
final deviceSize = MediaQuery.of(context).size;
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
elevation: 8.0,
child: Container(
height: _authMode == AuthMode.Signup ? 320 : 260,
constraints:
BoxConstraints(minHeight: _authMode == AuthMode.Signup ? 320 : 260),
width: deviceSize.width * 0.75,
padding: EdgeInsets.all(16.0),
child: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(labelText: 'E-Mail'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Invalid email!';
} else {
return null;
}
},
onSaved: (value) {
_authData['email'] = value;
},
),
TextFormField(
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
controller: _passwordController,
validator: (value) {
if (value.isEmpty || value.length < 5) {
return 'Password is too short!';
} else {
return null;
}
},
onSaved: (value) {
_authData['password'] = value;
},
),
if (_authMode == AuthMode.Signup)
TextFormField(
enabled: _authMode == AuthMode.Signup,
decoration: InputDecoration(labelText: 'Confirm Password'),
obscureText: true,
//this allows stars to mask the input
validator: _authMode == AuthMode.Signup
? (value) {
if (value != _passwordController.text) {
return 'Passwords do not match!';
} else {
return null;
}
}
: null,
),
SizedBox(
height: 20,
),
if (_isLoading)
CircularProgressIndicator()
else
RaisedButton(
child:
Text(_authMode == AuthMode.Login ? 'LOGIN' : 'SIGN UP'),
onPressed: _submit,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30),
),
padding:
EdgeInsets.symmetric(horizontal: 30.0, vertical: 8.0),
color: Theme.of(context).primaryColor,
textColor: Theme.of(context).primaryTextTheme.button.color,
),
FlatButton(
child: Text(
'${_authMode == AuthMode.Login ? 'SIGNUP' : 'LOGIN'} INSTEAD'),
onPressed: _switchAuthMode,
padding: EdgeInsets.symmetric(horizontal: 30.0, vertical: 4),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
//reduces the amount of surface area that is tappable
textColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}

The getter 'length' was called on null. Receiver: null Tried calling: length

I am trying to fetch device contacts in flutter using the package contacts_service and I am getting an error like this. I tried declaring the list _contact to be an empty list but that didn't worked for me. By searching on internet, I got to know that some of the fields that are fetched are null that is why it causes this error. Please help me to Solve This.
Here is my Error
import 'dart:io';
import 'package:android_intent/android_intent.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:flutter/services.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:flutter/material.dart';
import 'package:udhar/widgets/bottom_sheet.dart';
import 'dart:math';
class ContactList extends StatefulWidget {
#override
_ContactListState createState() => _ContactListState();
}
class _ContactListState extends State<ContactList> {
List<Contact> _contacts;
refreshContactsWithQuery(String query) async {
PermissionStatus permissionStatus = await _getContactPermission();
if (permissionStatus == PermissionStatus.granted) {
// Load without thumbnails initially.
var contacts = (await ContactsService.getContacts(
withThumbnails: false, query: '$query'))
.toList();
// var contacts = (await ContactsService.getContactsForPhone("8554964652"))
// .toList();
setState(() {
_contacts = contacts;
});
} else {
_handleInvalidPermissions(permissionStatus);
}
}
List colors = [
Colors.redAccent,
Colors.greenAccent,
Colors.purpleAccent,
Colors.blueAccent,
Colors.orangeAccent
];
Random random = new Random();
bool isNumeric(String s) {
if (s == null) {
return false;
}
return double.tryParse(s) != null;
}
String firstLetterWord(String str) {
String result = "";
if (isNumeric(str)) {
return "#";
}
// Traverse the string.
bool v = true;
for (int i = 0; i < str.length; i++) {
// If it is space, set v as true.
if (str[i] == ' ')
v = true;
// Else check if v is true or not.
// If true, copy character in output
// string and set v as false.
else if (str[i] != ' ' && v == true) {
result += (str[i]);
v = false;
}
}
return result;
}
#override
initState() {
super.initState();
refreshContacts();
}
refreshContacts() async {
PermissionStatus permissionStatus = await _getContactPermission();
if (permissionStatus == PermissionStatus.granted) {
// Load without thumbnails initially.
var contacts =
(await ContactsService.getContacts(withThumbnails: false)).toList();
// var contacts = (await ContactsService.getContactsForPhone("8554964652"))
// .toList();
setState(() {
_contacts = contacts;
});
} else {
_handleInvalidPermissions(permissionStatus);
}
}
updateContact() async {
Contact ninja = _contacts
.toList()
.firstWhere((contact) => contact.familyName.startsWith("Ninja"));
ninja.avatar = null;
await ContactsService.updateContact(ninja);
refreshContacts();
}
Future<PermissionStatus> _getContactPermission() async {
PermissionStatus permission = await PermissionHandler()
.checkPermissionStatus(PermissionGroup.contacts);
if (permission != PermissionStatus.granted &&
permission != PermissionStatus.disabled) {
Map<PermissionGroup, PermissionStatus> permissionStatus =
await PermissionHandler()
.requestPermissions([PermissionGroup.contacts]);
return permissionStatus[PermissionGroup.contacts] ??
PermissionStatus.unknown;
} else {
return permission;
}
}
void _handleInvalidPermissions(PermissionStatus permissionStatus) {
if (permissionStatus == PermissionStatus.denied) {
throw new PlatformException(
code: "PERMISSION_DENIED",
message: "Access to location data denied",
details: null);
} else if (permissionStatus == PermissionStatus.disabled) {
throw new PlatformException(
code: "PERMISSION_DISABLED",
message: "Location data is not available on device",
details: null);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: Colors.grey,
),
onPressed: () {
Navigator.pop(context);
}),
title: Text(
'Customer Select Karein',
style: TextStyle(color: Colors.black),
),
// Positioned(
// top: 20, child: Text('Apne customer aur supplier select karein'))
backgroundColor: Colors.white,
elevation: 0,
),
body: Column(children: <Widget>[
Expanded(
flex: 0,
child: Padding(
padding: EdgeInsets.all(10.0),
child: TextField(
decoration: inputDecoration3,
textInputAction: TextInputAction.search,
onChanged: (String s) {
refreshContactsWithQuery(s);
},
))),
Expanded(
flex: 0,
child: Padding(
padding: EdgeInsets.all(0),
child: Card(
color: Colors.white,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 0.0),
child: GestureDetector(
onTap: () {
openAddContacts();
},
child: ListTile(
leading: Icon(
Icons.add,
color: Colors.green,
),
title: Text(
'Manually add karein',
style: TextStyle(fontSize: 15, color: Colors.green),
),
onTap: () {
NewCustomerSheet(context);
},
),
)),
)),
Expanded(
flex: 6,
child: _contacts != null
? ListView.builder(
// separatorBuilder: (context, index) => Divider(
// color: Colors.black,
// ),
itemCount: _contacts?.length ?? 0,
itemBuilder: (BuildContext context, int index) {
Contact c = _contacts?.elementAt(index);
return Card(
elevation: 1.0,
child: ListTile(
onTap: () {
debugPrint('Name:');
debugPrint(c.displayName ?? "");
print(c.phones.first.value);
},
leading: CircleAvatar(
child: Text(
firstLetterWord(c.displayName).toUpperCase(),
style: TextStyle(color: Colors.white),
),
backgroundColor:
colors[random.nextInt(colors.length)],
),
title: Container(
child: Row(
children: <Widget>[
Flexible(
child: Text(c.displayName ?? "",
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 15.0)),
),
],
)),
trailing: Text(
'₹ 500',
style: TextStyle(
fontSize: 20.0,
color: Colors.blue,
),
),
//Divider(height:50,);
),
);
},
)
: Center(
child: CircularProgressIndicator(),
),
)
]),
);
}
void openAddContacts() async {
if (Platform.isAndroid) {
final AndroidIntent intent = AndroidIntent(
action: 'ContactsContract.Intents.Insert.ACTION',
category: 'ContactsContract.RawContacts.CONTENT_TYPE',
);
await intent.launch();
}
}
InputDecoration inputDecoration3 = InputDecoration(
hintText: 'Search',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
),
fillColor: Colors.grey[200],
filled: true,
prefixIcon: Icon(
Icons.search,
color: Colors.grey,
),
);enter code here
}