I am using the method createUserWithEmailAndPassword but would like to collect more data when a user signs up. In addition to email and password I would also like to collect:
First Name
Last Name
Date of Birth
Here is my auth services code:
//Email & Password Sign Up
Future<String> createUserWithEmailAndPassword(
String email, String password,
) async {
final authResult = await _firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
// Update the username
await updateUserName(email, authResult.user);
return authResult.user.uid;
}
and my sign up page:
import 'package:easy_tiger/constants/appbar.dart';
import 'package:easy_tiger/screens/account.dart';
import 'package:easy_tiger/style.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:easy_tiger/services/auth_service.dart';
enum AuthFormType { signIn, signUp }
class SignUpPage extends StatefulWidget {
final AuthFormType authFormType;
SignUpPage({Key key, this.authFormType}) : super(key: key);
#override
_SignUpPageState createState() => _SignUpPageState(authFormType: this.authFormType);
}
class _SignUpPageState extends State<SignUpPage> {
AuthFormType authFormType;
_SignUpPageState({this.authFormType});
final formKey = GlobalKey<FormState>();
String _firstName,
_lastName,
_email,
_confirmEmail,
_password,
_confirmPassword,
_dateOfBirth;
bool validate(){
final form = formKey.currentState;
form.save();
if(form.validate()){
form.save();
return true;
} else {
return false;
}
}
void switchFormState(String state) {
formKey.currentState.reset();
formKey.currentState.validate();
if(state == 'signUp') {
setState(() {
authFormType = AuthFormType.signUp;
});
} else {
setState(() {
authFormType = AuthFormType.signIn;
});
}
}
void submit() async {
if (validate()) {
try {
final auth = Provider
.of(context)
.auth;
if (authFormType == AuthFormType.signIn) {
String uid = await auth.signInWithEmailAndPassword(_email, _password);
print("Signed In with ID $uid");
Navigator.of(context).pushReplacementNamed('/home');
} else {
String uid = await auth.createUserWithEmailAndPassword(
_email,
_password,);
print("Signed up with New ID $uid");
Navigator.of(context).pushReplacementNamed('/home');
}
} catch (e) {
print(e);
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: MainAppBar(
text: buildAppBarText(),
)),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Center(
child: Container(
child: Column(
children: <Widget>[
Align(
child: Text(buildTitleText(), style: AppBarTextStyle),
),
Container(
padding: EdgeInsets.only(top: 10),
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: formKey,
child: Column(
children: buildInputs() + buildSwitchText(),
)),
),
],
),
),
),
),
));
}
buildHeaderText() {
String _headerText;
if (authFormType == AuthFormType.signUp) {
_headerText = "Don't have an account?";
} else {
_headerText = "Already have an account?";
} return _headerText;
}
List<Widget> buildInputs() {
List<Widget> textFields = [];
if (authFormType == AuthFormType.signIn) {
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Email'),
validator: EmailValidator.validate,
onSaved: (value) => _email = value
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Password'),
obscureText: true,
validator: PasswordValidator.validate,
onSaved: (value) => _password = value,
),);
}
else {
textFields.clear();
//if we're in the sign up state, add name
// add email & password
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('First Name'),
onSaved: (value) => _firstName,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Last Name'),
onSaved: (value) => _lastName,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Email Address'),
onSaved: (value) => _email,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Confirm Email Address'),
onSaved: (value) => _confirmEmail,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Password'),
obscureText: true,
onSaved: (value) => _password,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Confirm Password'),
onSaved: (value) => _confirmPassword,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Date of Birth'),
onSaved: (value) => _dateOfBirth,
));
textFields.add(SizedBox(
height: 15,
));
}
return textFields;
}
List<Widget> buildSwitchText() {
String _switchButtonTextPart1, _switchButtonTextPart2,_newFormState;
if(authFormType == AuthFormType.signIn) {
_switchButtonTextPart1 = "Haven't got an account? ";
_switchButtonTextPart2 = 'Sign Up';
_newFormState = 'signUp';
} else {
_switchButtonTextPart1 = 'Already have an account? ';
_switchButtonTextPart2 = 'Sign In';
_newFormState = 'signIn';
} return [
SizedBox(height: 5.0),
Container(
width: MediaQuery.of(context).size.height * 0.7,
child: RaisedButton(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0),),
color: kPrimaryColor,
textColor: Colors.black,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(buildTitleText(),
style: TextStyle(fontFamily: FontNameDefault,
fontSize: 15.0),),
),
onPressed: submit),
),
SizedBox(height: 5.0,),
RichText(
text: TextSpan(
style: TextStyle(
fontFamily: FontNameDefault,
color: Colors.black,
fontSize: 12.0,
),
children: <TextSpan>[
TextSpan(
text: _switchButtonTextPart1
),
TextSpan(
text: _switchButtonTextPart2,
style: TextStyle(
decoration: TextDecoration.underline,
color: Colors.black,
fontSize: 12.0),
recognizer: TapGestureRecognizer()
..onTap = () {
switchFormState(_newFormState);
})
]),
),
];
}
String buildAppBarText() {
String _switchAppBarHeader;
if(authFormType == AuthFormType.signIn) {
_switchAppBarHeader = "Already have an account?";
} else {
_switchAppBarHeader = "Don't have an account?";
} return
_switchAppBarHeader;
}
String buildTitleText() {
String _switchTextHeader;
if(authFormType == AuthFormType.signIn) {
_switchTextHeader = "Sign In";
} else {
_switchTextHeader = "Sign Up";
} return
_switchTextHeader;
}
}
class AccountController extends StatelessWidget {
#override
Widget build(BuildContext context) {
final AuthService auth = Provider.of(context).auth;
return StreamBuilder(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
return signedIn ? SignInPage() : SignUpPage();
}
return CircularProgressIndicator();
});
}
}
InputDecoration buildSignUpInputDecoration(String hint) {
return InputDecoration(
isDense: true,
fillColor: Colors.white,
hintText: hint,
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 0.0),
),
contentPadding: const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
);
}
class Provider extends InheritedWidget {
final AuthService auth;
Provider({Key key, Widget child, this.auth}) : super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
static Provider of(BuildContext context) =>
context.dependOnInheritedWidgetOfExactType<Provider>();
}
Can someone advise the best way to go about achieving this thanks.
Managed to work out a solution...
In my signup screen I imported cloud_firestore:
import 'package:cloud_firestore/cloud_firestore.dart';
I then altered the following to use the uid we create to create a document and set the fields equal to the values passed:
if (validate()) {
try {
final auth = Provider
.of(context)
.auth;
if (authFormType == AuthFormType.signIn) {
String uid = await auth.signInWithEmailAndPassword(_email, _password);
print("Signed In with ID $uid");
Navigator.of(context).pushReplacementNamed('/home');
} else {
String uid = await auth.createUserWithEmailAndPassword(
_email,
_password,);
userCollection.document(uid).setData({
'First Name' : _firstName,
'Last Name' : _lastName,
'Date of Birth' : _dateOfBirth
});
print("Signed up with New ID $uid");
Navigator.of(context).pushReplacementNamed('/home');
}
} catch (e) {
print(e);
}
I had to remove my validation method as it was causing issues. Ran the new code and a new user appeared in my database.
you will save the addition data inside your firestore e.g(firstname, lastname, date of birth) and add extra field for user id which will identify/mapped/linked the user with the firebaseAuth data
you will get the data(uid) from the AuthResult.user object.
Related
I am using Firebase and keep getting this annoying message when I click on the Login button :
flutter: 'package:firebase_auth/src/firebase_auth.dart': Failed assertion: line 487 pos 12: 'email != null': is not true.
The code works fine. The app is built and run successfully. This happens when I enter my email and password and click on the login button. Referred to these threads: https://github.com/flutter/flutter/issues/22028 , _AssertionError ('package:firebase_auth/src/firebase_auth.dart': Failed assertion: line 95 pos 12: 'email != null': is not true.) but none helped. Any help would be greatly appreciated:)
My code is:
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Auth extends StatefulWidget {
#override
_AuthState createState() => _AuthState();
}
class _AuthState extends State<Auth> {
final _formKey = GlobalKey<FormState>();
final _password = TextEditingController(),
_email = TextEditingController(),
_phone = TextEditingController();
final _auth = FirebaseAuth.instance;
String email;
String password;
bool willLogin = true;
bool showPassword = false;
void _login() async {
_formKey.currentState.validate();
try {
final existingUser = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (existingUser != null) {
Navigator.pushNamed(context, '/home');
}
} catch (e) {
print(e);
}
}
void _signup() async {
_formKey.currentState.validate();
try {
final newUser = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, '/home');
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Dog SOS"),
leading: Icon(Icons.pets),
),
body: Form(
key: _formKey,
child: ListView(
padding: const EdgeInsets.all(24),
children: [
const SizedBox(
height: 10,
),
Center(
child: CircleAvatar(
backgroundColor: Theme.of(context).primaryColor,
child: Icon(
Icons.shield,
color: Colors.white,
size: 50,
),
radius: 60,
),
),
const SizedBox(
height: 20,
),
if (!willLogin) ...[
TextFormField(
decoration: InputDecoration(
labelText: "Phone",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
keyboardType: TextInputType.phone,
textInputAction: TextInputAction.next,
controller: _phone,
validator: (value) =>
value.isEmpty ? "Please Enter Phone Number" : null,
),
const SizedBox(
height: 10,
),
],
TextFormField(
decoration: InputDecoration(
labelText: "Email",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
keyboardType: TextInputType.emailAddress,
textInputAction: TextInputAction.next,
controller: _email,
validator: (value) => value.isEmpty ? "Please Enter Email" : null,
),
const SizedBox(
height: 10,
),
TextFormField(
decoration: InputDecoration(
labelText: "Password",
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
suffixIcon: IconButton(
icon: Icon(
showPassword
? Icons.visibility_off_outlined
: Icons.visibility_outlined,
),
onPressed: () {
setState(() {
showPassword = !showPassword;
});
},
),
),
obscureText: !showPassword,
textInputAction: TextInputAction.done,
controller: _password,
validator: (value) =>
value.isEmpty ? "Please Enter Password" : null,
),
const SizedBox(
height: 10,
),
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
child: Text(
willLogin ? "\nLOGIN\n" : "\nSIGN UP\n",
style: Theme.of(context)
.textTheme
.button
.copyWith(color: Colors.white),
),
color: Theme.of(context).primaryColor,
onPressed: () {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
_login();
}
},
),
Row(
children: [
Text(willLogin
? "Don't have an account?"
: "Already have an account?"),
FlatButton(
child: Text(
willLogin ? "Create One." : "Login.",
style: Theme.of(context).textTheme.button.copyWith(
color: Theme.of(context).primaryColor,
),
),
onPressed: () {
setState(() {
willLogin = !willLogin;
_signup();
});
},
),
],
),
],
),
),
);
}
}
String email;
String password;
Both of those are null, they are not referencing anything. You have to do the following, first bind the controller to the field which you are already doing then:
void _login() async {
_formKey.currentState.validate();
try {
final existingUser = await _auth.signInWithEmailAndPassword(
email: _email.text, password: _password.text);
if (existingUser != null) {
Navigator.pushNamed(context, '/home');
}
} catch (e) {
print(e);
}
}
Use the property text of the class TextEditingController to get the value of _email and _password.
I have my userData model as below:
class UserData {
String id;
String firstName;
String lastName;
String phoneNumber;
String streetAddress;
String city;
String state;
String postcode;
String country;
Timestamp createdAt;
Timestamp updatedAt;
UserData();
UserData.fromMap(Map<String, dynamic> data) {
id = data['id'];
firstName = data['first_name'];
lastName = data['last_name'];
phoneNumber = data['phone_number'];
streetAddress = data['street_address'];
city = data['city'];
postcode = data['postcode'];
state = data['state'];
country = data['country'];
createdAt = data['created_at'];
updatedAt = data['updated_at'];
}
Map<String, dynamic> toMap() {
return {
'id': id,
'first_name': firstName,
'last_name': lastName,
'phone_number': phoneNumber,
'street_address': streetAddress,
'city': city,
'postcode': postcode,
'state': state,
'country': country,
'created_at': createdAt,
'updated_at': updatedAt,
};
}
}
I have my Notifier class which I use to read and write userData to Firestore. Since this is userData, there will only be an instance per logged in user as they can only have one document holding their profile information.
class UserDataNotifier with ChangeNotifier {
UserData _currentLoggedInUserData;
Query userDataCollection = Firestore.instance.collection('userData');
UserData get currentLoggedInUserData => _currentLoggedInUserData;
set currentLoggedInUserData(UserData userData) {
_currentLoggedInUserData = userData;
notifyListeners();
}
getUserData(UserDataNotifier userDataNotifier) async {
String userId = (await FirebaseAuth.instance.currentUser()).uid;
await Firestore.instance.collection('userData').document(userId).get().then(
(value) => _currentLoggedInUserData = UserData.fromMap(value.data));
notifyListeners();
}
Future createOrUpdateUserData(UserData userData, bool isUpdating) async {
String userId = (await FirebaseAuth.instance.currentUser()).uid;
CollectionReference userDataRef = Firestore.instance.collection('userData');
if (isUpdating) {
userData.updatedAt = Timestamp.now();
await userDataRef.document(userId).updateData(userData.toMap());
print('updated userdata with id: ${userData.id}');
} else {
userData.createdAt = Timestamp.now();
DocumentReference documentReference = userDataRef.document(userId);
userData.id = documentReference.documentID;
await documentReference.setData(userData.toMap(), merge: true);
print('created userdata successfully with id: ${userData.id}');
}
notifyListeners();
}
}
How do I go about reading and displaying my userData in my profile screen?
Here's my Profile form screen:
class ProfileFormScreen extends StatefulWidget {
static const String id = 'profile_form';
#override
_ProfileFormScreenState createState() => _ProfileFormScreenState();
}
class _ProfileFormScreenState extends State<ProfileFormScreen> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
UserData _currentLoggedInUserData;
//global declarations
String selectedBusinessTypeDropDownValue = 'Fashion';
String selectedCountryDropDownValue = 'India';
String email;
bool showSpinner = false;
_saveUserData(BuildContext context) {
UserDataNotifier userNotifier =
Provider.of<UserDataNotifier>(context, listen: false);
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
userNotifier.createOrUpdateUserData(_currentLoggedInUserData, false);
Navigator.pop(context);
}
#override
void initState() {
super.initState();
UserDataNotifier userDataNotifier =
Provider.of<UserDataNotifier>(context, listen: false);
if (userDataNotifier.currentLoggedInUserData != null) {
_currentLoggedInUserData = userDataNotifier.currentLoggedInUserData;
print(_currentLoggedInUserData.id);
} else {
_currentLoggedInUserData = UserData();
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Edit Profile'),
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: SingleChildScrollView(
padding: EdgeInsets.only(top: 20.0),
child: Form(
autovalidate: true,
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
LabelTextPadding(text: 'Business Information'),
//location
RegularTextPadding(regText: 'Location'),
//address 1
_buildAddress(),
//city
_buildCityField(),
//postcode
_buildPostcode(),
//state
_buildStateField(),
//country
_buildCountry(),
SizedBox(
height: 20.0,
),
DividerClass(),
SizedBox(
height: 20.0,
),
//Personal information
LabelTextPadding(
text: 'Personal Information',
),
_buildFirstNameField(),
_buildLastNameField(),
_buildPhoneNumberField(),
_buildButtons(),
],
),
),
),
),
);
}
//business information
_buildAddress() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.streetAddress,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.streetAddress = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'house and street address'),
),
);
}
_buildCityField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.city,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.city = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter city'),
),
);
}
_buildPostcode() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.postcode,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.postcode = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter postcode'),
),
);
}
_buildStateField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.state,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.state = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter state'),
),
);
}
_buildCountry() {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(0.5)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
),
),
padding: const EdgeInsets.fromLTRB(10.0, 10.0, 20.0, 0.0),
margin: EdgeInsets.all(20.0),
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.country == null
? selectedCountryDropDownValue
: _currentLoggedInUserData.country,
icon: Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
elevation: 15,
underline: Container(
height: 0,
color: kThemeStyleButtonFillColour,
),
items: country
.map(
(country) =>
DropdownMenuItem(value: country, child: Text(country)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedCountryDropDownValue = newValue;
_currentLoggedInUserData.country = newValue;
});
},
),
),
);
}
//user personal info build
_buildFirstNameField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.firstName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.firstName = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'your first Name'),
),
);
}
_buildLastNameField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.lastName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.lastName = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'your last name'),
),
);
}
_buildPhoneNumberField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.phoneNumber,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.phoneNumber = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'your phone number'),
),
);
}
_buildButtons() {
return Padding(
padding: const EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Buttons(
onPressedButton: () {
Navigator.pop(context);
},
buttonLabel: 'Cancel',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton),
SizedBox(
width: 15.0,
),
Buttons(
onPressedButton: () => _saveUserData(context),
buttonLabel: 'Save',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton),
],
),
);
}
}
class TextInputFieldValidator {
static String validate(String value) {
if (value.isEmpty) {
return 'This field can\'t be empty, you must enter a text';
}
if (value.length < 3) {
return 'You must enter at least a word';
}
}
}
Here's what I've tried:
getUserData(UserDataNotifier userDataNotifier) async {
String userId = (await FirebaseAuth.instance.currentUser()).uid;
await Firestore.instance.collection('userData').document(userId).get();
notifyListeners();
}
I think you would start by assigning a variable, like this:
var myVar = await Firestore.instance.collection('userData').document(userId).get();
var yourVariable = myVar.data()["YourFieldNameInFireStore"];
You might want to look into Provider or otherwise using ChangeNotifier.
An example for that from pieces of code, not tailored to your question and typed up here so possibly containing typos / missing information:
class Muser extends ChangeNotifier {
FirebaseUser firebaseUser;
// this example uses FirebaseAuth, not anything from FireStore,
// but you could easily add variables to your User class here such as
// userAge for example, which you could update in your getUserData method or something
fauth.User fAuthUser = fauth.FirebaseAuth.instance.currentUser;
Muser({
this.firebaseUser, this.userAge,
});
getUserData() {
}
int userAge;
Map<dynamic, int> _specialCalculatedUserInfo;
Map<dynamic, int> get specialCalculatedUserInfo{
if (_specialCalculatedUserInfo== null) {
_specialCalculatedUserInfo= _calculateUserInfo();
}
notifyListeners();
return _specialCalculatedUserInfo;
}
}
class ProfileViewState extends State<ProfileView> {
#override
void dispose() {
// TODO: implement dispose for controllers
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(
children: <Widget>[
Column(
children: <Widget>[
Text("Your Profile"),
Consumer<Muser>(
builder: (context, user, child) {
return
Column(
children: [
Text("Age: ${user.userAge}"),
CircleAvatar(
radius: 50,
backgroundColor: Colors.brown.shade600,
backgroundImage: user.firebaseUser.photoUri.isEmpty
? AssetImage("assets/images/icon.png")
: NetworkImage(user.getPhotoURL()),
),
],
);
}
)
]
)
);
}
}
Running my App on Android and iOS I get the Error shown below. What I want to do, give every Data that get's added a Author, the Author should be the Mail Adress the User Registers with, so by Inviting other Users get Access to this Data.
Another Problem is that in Line 302 the String "user" is unused.
Do i really need to use this String?
Error
════════ Exception caught by widgets library ═══════════════════════════════════
The following NoSuchMethodError was thrown building FutureBuilder<FirebaseUser>(dirty, state: _FutureBuilderState<FirebaseUser>#7f7ed):
The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
The relevant error-causing widget was
FutureBuilder<FirebaseUser>
lib/…/MealPlan/mealTile.dart:92
When the exception was thrown, this was the stack
Code
import 'package:flutter/material.dart';
import 'package:mealapp/models/Widgets/whenAndWhatToEat.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
import 'package:mealapp/models/global.dart';
import 'package:status_alert/status_alert.dart';
import 'package:firebase_auth/firebase_auth.dart';
class MealTile extends StatefulWidget {
final MealsAndWhen mealsAndWhen;
MealTile({this.mealsAndWhen});
#override
MealTileState createState() {
return MealTileState();
}
}
class MealTileState extends State<MealTile> {
String id;
final db = Firestore.instance;
String mail;
List<String> authors = [];
DateTime selectedDate = DateTime.now();
Future pickDate() async {
DateTime datepick = await showDatePicker(
context: context,
initialDate: new DateTime.now(),
firstDate: new DateTime.now().add(Duration(days: 0)),
lastDate: new DateTime.now().add(Duration(days: 365)));
if (datepick != null)
setState(() {
selectedDate = datepick;
});
}
Future<String> inputData() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.uid : null;
}
Future<String> inputDataMail() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
return user != null ? user.email : null;
}
String userId;
void _getUserId() {
inputData().then((value) => setState(() {
userId = value;
}));
}
String currentMail;
void _getMail(doc) {
inputDataMail().then((value) => setState(() {
currentMail = value;
}));
}
/*void _getAuthors(DocumentSnapshot doc) async {
authors = [];
//if (await FirebaseAuth.instance.currentUser() != null) {
authors = List.from(doc.data['Authors']);
print(doc.data['authors']);
//authors.insert(0, currentMail);
//}
}*/
Widget buildItem(DocumentSnapshot doc) {
DateTime now = doc.data['Date'].toDate();
DateFormat formatter = DateFormat('dd-MM-yyyy');
String formatted = formatter.format(now);
_getUserId();
_getMail(doc);
if (doc.data['Authors'] != null) {
//_getAuthors(doc);
//print('Current mail: ' + currentMail + authors.toString() + doc.data['Author'] + doc.data['Meal']);
}
if (now.day == DateTime.now().day) { // If the Date of the meal is today
deleteData(doc, false); // Delete it!
}
// You could also change ".day" to ".hour".
// Example: if (now.day == DateTime.now().day && now.hour == DateTime.hour())
// So, if a meal is set for 2PM, it will delete at 2PM
return FutureBuilder<FirebaseUser>(
future: FirebaseAuth.instance.currentUser(),
builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
if (snapshot.hasData && snapshot != null) {
return Container(
margin: const EdgeInsets.all(8.0),
child: currentMail == doc.data['Author'] || // If the current mail is the author
List.from(doc.data['Authors']).contains(currentMail) // Or if the current mail is part of the authors
? Column( // then if true, show a Column
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
'Meal:',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Text(
'${doc.data['Meal']}',
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
SizedBox(height: 20),
Text(
'When:',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
onPressed: () => updateData(doc),
color: lightBlueColor,
icon: Icon(Icons.calendar_today,
color: Colors.white),
tooltip: 'Update Date',
),
Text(
formatted,
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.white),
textAlign: TextAlign.center,
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(width: 8),
FlatButton(
color: Colors.red,
onPressed: () => deleteData(doc, true),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Delete',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.delete_forever, color: Colors.white),
]),
),
SizedBox(width: 8),
FlatButton(
color: Colors.blue,
onPressed: () => [
showDialog(
context: context,
builder: (BuildContext context) {
return Dialog(
child: invite(doc),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12)),
),
);
})
],
shape: RoundedRectangleBorder(
borderRadius:
BorderRadiusDirectional.circular(12)),
child: Row(children: <Widget>[
Text('Invite',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.white)),
Icon(Icons.share, color: Colors.white),
]),
),
],
),
],
)
: Text(''), // if false, show an empty text widget
decoration: BoxDecoration(
color: lightBlueColor,
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
else {
return CircularProgressIndicator();
}
/*Navigator.pop(context);
return HomePage();*/
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: darkGreyColor,
body: ListView(
padding: EdgeInsets.only(top: 220),
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: db
.collection('mealList')
.orderBy('Date', descending: false) // Order by Date, not descending
.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Column(
children: snapshot.data.documents
.map((doc) => buildItem(doc))
.toList());
} else {
return Container();
}
},
),
],
),
);
}
/*share(BuildContext context, DocumentSnapshot doc) {
final RenderBox box = context.findRenderObject();
final dynamic date = timeago.format(doc['Date'].toDate());
Share.share(
"${doc['Meal']} - $date",
subject: doc['Meal'],
sharePositionOrigin: box.localToGlobal(Offset.zero) & box.size,
);
}*/
Widget invite(DocumentSnapshot doc) {
final _formKey = GlobalKey<FormState>();
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(24.0),
child: Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Center(
child: Text(
"Invite someone by mail",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
)),
SizedBox(
height: 24,
),
TextFormField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
labelText: 'Enter the email address'),
validator: (value) {
if (value.isEmpty) {
return 'Please enter an email address';
}
return null;
},
onSaved: (value) => mail = value,
),
FlatButton(
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
saveInviteToFirestore(doc, mail);
}
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12))),
child: Text("Save"),
color: redColor,
textColor: Colors.white,
),
]),
),
);
}
Future<String> getCurrentUser() async {
return await FirebaseAuth.instance.currentUser().then((value) => value.uid);
}
void saveInviteToFirestore(DocumentSnapshot doc, String email) async {
final String user = await getCurrentUser();
var list = List<String>();
list.add(email);
Firestore.instance
.collection('mealList')
.document(doc.documentID)
.updateData({"Authors": FieldValue.arrayUnion(list)});
//setState(() => id = doc.documentID);
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Added',
subtitle: 'You have Added your and the Date to your List',
configuration: IconConfiguration(icon: Icons.done),
);
//Navigator.pop(context);
}
void deleteData(DocumentSnapshot doc, bool showMessage) async {
await db.collection('mealList').document(doc.documentID).delete();
setState(() => id = null);
if (showMessage) {
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Deleted',
subtitle: 'You have Deleted your Meal',
configuration: IconConfiguration(icon: Icons.delete),
);
}
}
void updateData(DocumentSnapshot doc) async {
await pickDate();
await db
.collection('mealList')
.document(doc.documentID)
.updateData({'Date': selectedDate});
StatusAlert.show(
context,
duration: Duration(seconds: 2),
title: 'Updated',
subtitle: 'You have updated your Meal Date',
configuration: IconConfiguration(icon: Icons.done),
);
}
}
When user registration, authentication occurred but not added data to the firebase that asking while signup such as registration number, Name, and TP no, etc. in flutter. So, what's wrong with my code?
Below one is the code for signup_view.dart file
import 'package:auto_size_text/auto_size_text.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:uocportal/provider_widget.dart';
import 'package:uocportal/auth_service.dart';
import 'package:shared_preferences/shared_preferences.dart';
//import 'package:auto_size_text/auto_size_text.dart';
enum AuthFormType { signIn, signUp, reset }
class SignUpView extends StatefulWidget {
final AuthFormType authFormType;
SignUpView({Key key, #required this.authFormType}) : super(key: key);
#override
_SignUpViewState createState() =>
_SignUpViewState(authFormType: this.authFormType);
}
class _SignUpViewState extends State<SignUpView> {
AuthFormType authFormType;
_SignUpViewState({this.authFormType});
var reNumFieldController = new TextEditingController();
final formKey = GlobalKey<FormState>();
String
_email,
_password,
_name,
_regnumber,
_faculty,
_contact,
_warning;
final _userCollectionReference = Firestore.instance;
// prefs.setString('stringRegnumValue', _regnumber);
Future createUser() async {
try {
final prefs = await SharedPreferences.getInstance();
prefs.setString('my_regno_key', _regnumber.toString());
await _userCollectionReference
.collection('Users')
.document()
.setData({
'username': _name,
'email': _email,
'contact': _contact,
'faculty': _faculty,
'regnumber': _regnumber
});
} catch (e) {
return e.message;
}
}
void switchFormState(String state) {
formKey.currentState.reset();
if (state == "signUp") {
setState(() {
authFormType = AuthFormType.signUp;
});
} else {
setState(() {
authFormType = AuthFormType.signIn;
});
}
}
bool validate() {
final form = formKey.currentState;
form.save();
if (form.validate()) {
form.save();
return true;
} else {
return false;
}
}
void submit() async {
if (validate()) {
try {
final auth = Provider.of(context).auth;
if (authFormType == AuthFormType.signIn) {
String uid = await auth.signinWithEmailAndPassword(_email, _password);
print("$uid");
Navigator.of(context).pushReplacementNamed('/home');
} else if (authFormType == AuthFormType.reset) {
await auth.sendPasswordResetEmail(_email);
print("password reset mail sent");
_warning = "A Password reset link has been sent to $_email";
setState(() {
authFormType = AuthFormType.signIn;
});
} else {
String uid = await auth.createUserWithEmailAndPassword(
_email, _password, _name, _regnumber, _faculty, _contact);
print("$uid");
Navigator.of(context).pushReplacementNamed('/home');
createUser();
}
} catch (e) {
print(e);
// setState(() {
_warning = e.message;
// });
}
}
}
#override
Widget build(BuildContext context) {
final _height = MediaQuery.of(context).size.height;
final _width = MediaQuery.of(context).size.width;
return Scaffold(
appBar: AppBar(
title: Text('UOC Portal'),
backgroundColor: Color(0xFF4A184C),
),
body: new GestureDetector(
onTap: () {
// call this method here to hide soft keyboard
FocusScope.of(context).requestFocus(new FocusNode());
},
child: Container(
color: Colors.white,
height: _height,
width: _width,
child: SingleChildScrollView(
child: Container(
child: Column(
children: <Widget>[
showAlert(),
SizedBox(
height: _height * 0.05,
),
buildHeaderText(),
buildSubHeadText(),
SizedBox(
height: _height * 0.02,
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Form(
key: formKey,
child: Column(
children: buildInputs() + buildButtons())),
)
],
),
),
),
)));
}
Widget showAlert() {
if (_warning != null) {
return Container(
color: Colors.amber,
width: double.infinity,
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.error_outline),
),
Expanded(
child: AutoSizeText(
_warning,
maxLines: 3,
)),
IconButton(
icon: Icon(Icons.close),
onPressed: () {
setState(() {
_warning = null;
});
})
],
),
);
}
return SizedBox(
height: 0,
);
}
AutoSizeText buildHeaderText() {
String _headerText;
if (authFormType == AuthFormType.signIn) {
_headerText = "Welcome !!";
} else if (authFormType == AuthFormType.reset) {
_headerText = "Reset Password";
} else {
_headerText = "Sign Up";
}
return AutoSizeText(
_headerText,
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 35, color: Color(0xFF4A184C), fontWeight: FontWeight.bold),
);
}
AutoSizeText buildSubHeadText() {
String _headerText;
if (authFormType == AuthFormType.signIn) {
_headerText = "Sign in to Continue";
} else if (authFormType == AuthFormType.reset) {
_headerText = "";
} else {
_headerText = "Create a new Account";
}
return AutoSizeText(
_headerText,
maxLines: 2,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15, color: Color(0xFF4A184C)),
);
}
List<Widget> buildInputs() {
List<Widget> textFields = [];
if (authFormType == AuthFormType.reset) {
textFields.add(
TextFormField(
keyboardType: TextInputType.text,
validator: EmailValidator.validate,
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Email"),
onSaved: (value) => _email = value,
),
);
textFields.add(SizedBox(
height: 8,
));
return textFields;
}
//if were in the signup state add name
if (authFormType == AuthFormType.signUp) {
textFields.add(
TextFormField(
keyboardType: TextInputType.text,
validator: NameValidator.validate,
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Name"),
onSaved: (value) => _name = value,
),
);
textFields.add(SizedBox(
height: 8,
));
textFields.add(
DropdownButtonFormField<String>(
validator:(value) {
if (value == null) {
return "Faculty can't be empty";
}
},
value: _faculty,
items: ["Science",
"Management",
"Law",
"Art",
"UCSC",
"Medicine",
"Technology",
"Nursing",
"IIM"
].map((label) => DropdownMenuItem(
child: Text(label),
value: label,
))
.toList(),
onChanged: (value) {
setState(() => _faculty = value);
},
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Faculty"),
),
);
textFields.add(SizedBox(
height: 8,
));
textFields.add(
TextFormField(
validator: RegNoValidator.validate,
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Registration No."),
controller: reNumFieldController,
onSaved: (value) => _regnumber = value,
),
);
textFields.add(SizedBox(
height: 8,
));
textFields.add(
TextFormField(
keyboardType: TextInputType.phone,
validator: ContactValidator.validate,
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Contact Number"),
onSaved: (value) => _contact = value,
),
);
textFields.add(SizedBox(
height: 8,
));
}
//add email and Password
textFields.add(
TextFormField(
keyboardType: TextInputType.emailAddress,
validator: EmailValidator.validate,
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Email"),
onSaved: (value) => _email = value,
),
);
textFields.add(SizedBox(
height: 8,
));
textFields.add(
TextFormField(
validator: PasswordValidator.validate,
style: TextStyle(fontSize: 18.0, color: Color(0xFF4A184C)),
decoration: buildSignUpInputDecoration("Password"),
obscureText: true,
onSaved: (value) => _password = value,
),
);
return textFields;
}
InputDecoration buildSignUpInputDecoration(String hint) {
return InputDecoration(
//hintText: hint,
fillColor: Colors.white,
filled: true,
focusColor: Colors.amber,
labelText: hint,
errorMaxLines: 1,
hintStyle:
TextStyle(color: Color(0xFF4A184C), fontWeight: FontWeight.bold),
labelStyle:
TextStyle(color: Color(0xFF4A184C), fontWeight: FontWeight.bold),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: Colors.amber),
borderRadius: new BorderRadius.circular(25.0)),
contentPadding:
const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
);
}
List<Widget> buildButtons() {
String _switchButton, _newFormState, _submitButtonText;
bool _showForgotPasowrd = false;
if (authFormType == AuthFormType.signIn) {
_switchButton = "Don't have an account? | Sign Up";
_newFormState = "signUp";
_submitButtonText = "Sign In";
_showForgotPasowrd = true;
} else if (authFormType == AuthFormType.reset) {
_switchButton = "Return to Sign In";
_newFormState = "signIn";
_submitButtonText = "Submit";
_showForgotPasowrd = false;
} else {
_switchButton = "Have an Account? Sign In";
_newFormState = "signIn";
_submitButtonText = "Sign Up";
}
return [
SizedBox(
height: 10,
),
Container(
width: MediaQuery.of(context).size.width * 0.7,
child: RaisedButton(
onPressed: () {
submit();
},
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0)),
color: Color(0xFF4A184C),
textColor: Colors.amber,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
_submitButtonText,
style: TextStyle(fontSize: 20),
),
)),
),
showForgotPassowrd(_showForgotPasowrd),
FlatButton(
onPressed: () {
switchFormState(_newFormState);
},
child: Text(
_switchButton,
style: TextStyle(color: Colors.amber),
)),
];
}
Widget showForgotPassowrd(bool visibale) {
return Visibility(
child: FlatButton(
onPressed: () {
setState(() {
authFormType = AuthFormType.reset;
});
},
child: Text(
"Forgot Password?",
style: TextStyle(color: Colors.amber),
)),
visible: visibale,
);
}
}
Below one is the code for auth_service.dart file
import 'package:firebase_auth/firebase_auth.dart';
class AuthService {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
Stream<String> get onAuthStateChanged => _firebaseAuth.onAuthStateChanged.map(
(FirebaseUser user )=> user?.uid,
);
//Email & Password Sign Up
Future <String> createUserWithEmailAndPassword(String email, String password,
String name, String regnumber, String faculty, String contact) async {
final currentUser = await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password,);
//update the username
var userUpdateInfo = UserUpdateInfo();
userUpdateInfo.displayName = name;
await currentUser.updateProfile(userUpdateInfo);
await currentUser.reload();
return currentUser.uid;
}
//Email & Password Sign In
Future <String> signinWithEmailAndPassword(String email, String password) async{
return (await _firebaseAuth.signInWithEmailAndPassword(email: email, password: password)).uid;
}
//Sign Out
signOut(){
return _firebaseAuth.signOut();
}
//reset password
Future sendPasswordResetEmail(String email) async {
return _firebaseAuth.sendPasswordResetEmail(email: email);
}
}
These are the codes that I've used for creating user registration, sign-in, and reset the password. Here sign-in, sign-up and password reset appear within one page according to its state.
Please give me a better soution for this. :)
You'd need to execute createUser() before navigating to a different screen. It's best to add debugPrint() on the requests to be executed to verify that they're being called as expected.
Then update user data.
CollectionReference _userCollectionReference = FirebaseFirestore.instance
.collection('Users');
var userDocData = new Map<String, dynamic>();
userDocData['username'] = _name;
userDocData['email'] = _email;
userDocData['contact'] = _contact;
userDocData['faculty'] = _faculty;
userDocData['regnumber'] = _regnumber;
await _userCollectionReference.add(userDocData);
Also, make sure that the rules ables users to write to Firestore.
I get ERROR_INVALID_EMAIL when I try to login to firebase but if I replaced _email and _password with the real email and pass from firebase I get Log In FirebaseUser(Instance of 'PlatformUser')
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class Login extends StatefulWidget {
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return LoginState();
}
}
class LoginState extends State<Login> {
final GlobalKey<FormState> formState = GlobalKey<FormState>();
String _email;
String _password;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Login Page'),
centerTitle: true,
backgroundColor: Colors.deepOrange,
),
body: ListView(
children: <Widget>[
Container(
padding: EdgeInsets.all(10),
child: Column(
children: <Widget>[
Form(
key: formState,
child: Container(
child: Column(
children: <Widget>[
TextFormField(
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: InputDecoration(
icon: Icon(Icons.email),
hintText: 'Enter Your E-mail',
),
validator: (val) {
if (val.isEmpty) {
return 'Please Enter Your E-mail Address';
}
;
},
onSaved: (val) {
_email = val;
},
),
TextFormField(
autofocus: false,
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.vpn_key),
hintText: 'Enter Your Password',
),
validator: (val) {
if (val.isEmpty) {
return 'Enter Your Password';
} else if (val.length < 6) {
return 'Your Password need to be at least 6 characters';
}
;
},
onSaved: (val) {
_password = val;
},
),
RaisedButton(
child: Text('Login'),
onPressed: () async {
final formdata = formState.currentState;
if (formdata.validate()) {
final FirebaseAuth _auth = FirebaseAuth.instance;
formdata.save();
AuthResult result = await _auth.signInWithEmailAndPassword(
email: _email, password: _password)
.catchError((error) => print(error.code));
if (result != null) {
FirebaseUser user = result.user;
if (user != null) {
print('Log In: $user');
}
;
}
;
}
;
},
color: Colors.deepOrange,
textColor: Colors.white,
),
],
),
),
),
],
),
),
],
),
);
}
}
i have updated My question i have provided full code why i'm getting message of invalid email should i remove strings at first or remove _email _password from string