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.
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()),
),
],
);
}
)
]
)
);
}
}
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.
I'm working on a doctor consulting app and I have to user logins(The doctor Login and the Client Login).
My problem is that after closing the app and restarting if the doctor is logged in it will go to the client's homepage instead of the doctor's homepage. In my startup file I have `
class HomeController extends StatelessWidget {
#override
Widget build(BuildContext context) {
final AuthService auth = Provider.of(context).auth;
return StreamBuilder<String>(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
return signedIn ? UsersHome() : OnboardingScreen();
}
return CircularProgressIndicator();
},
);
}`
I
I want to use shared preferences to save the user roles locally on the app. So if the Client's log in it will go to the ClientHome and if the doctor log in it will go to the DoctorHome.
Is there any alternatives. My backend is firebase
I need help
This my login page is similar to the doctor login
enum AuthMode { Signup, Login }
final primaryColor = Colors.blue;
enum AuthFormType { signIn, signUp, reset, anonymous, convert }
class Login extends StatefulWidget {
final AuthFormType authFormType;
Login({Key key, #required this.authFormType}) : super(key: key);
#override
_LoginState createState() =>
_LoginState(authFormType: this.authFormType);
}
class _LoginState extends State<Login> {
AuthFormType authFormType;
_LoginState({this.authFormType});
final formKey = GlobalKey<FormState>();
String _email, _password, _name, _warning;
void switchFormState(String state) {
formKey.currentState.reset();
if (state == "signUp") {
setState(() {
authFormType = AuthFormType.signUp;
});
} else if (state == 'home') {
Navigator.of(context).pop();
} else {
setState(() {
authFormType = AuthFormType.signIn;
});
}
}
bool validate() {
final form = formKey.currentState;
if (authFormType == AuthFormType.anonymous) {
return true;
}
form.save();
if (form.validate()) {
form.save();
return true;
} else {
return false;
}
}
void submit() async {
if (validate()) {
try {
final auth = Provider.of(context).auth;
switch (authFormType) {
case AuthFormType.signIn:
await auth.signInWithEmailAndPassword(_email, _password);
Navigator.of(context).pushReplacementNamed('/home');
break;
case AuthFormType.signUp:
await auth.createUserWithEmailAndPassword
(
_email, _password, _name);
Navigator.of(context).pushReplacementNamed('/home');
break;
case AuthFormType.reset:
await auth.sendPasswordResetEmail(_email);
_warning = "A password reset link has been sent to $_email";
setState(() {
authFormType = AuthFormType.signIn;
});
break;
case AuthFormType.anonymous:
await auth.singInAnonymously();
Navigator.of(context).pushReplacementNamed('/home');
break;
case AuthFormType.convert:
await auth.convertUserWithEmail(_email, _password, _name);
Navigator.of(context).pop();
break;
}
} catch (e) {
print(e);
setState(() {
_warning = e.message;
});
}
}
}
#override
Widget build(BuildContext context) {
final _auth = Provider.of(context).auth;
return Scaffold(
body: Container(
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF5bd75b)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 80,),
Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start, //m8Oq9ycK9VntE8mk8om5yoQbB10= first one
children: <Widget>[
Center(child: FadeAnimation(1, buildHeaderText(),), ),
SizedBox(height: 10,),
],
),
),
SizedBox(height: 20),
Expanded(
child: Container(
decoration: BoxDecoration(
color: Color(0xFF32cd32),
borderRadius: BorderRadius.only(topLeft: Radius.circular(60), topRight: Radius.circular(60))
),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(30),
child: Column(
children: <Widget>[
SizedBox(height: 0,),
FadeAnimation(1.4, Container(
child: Column(
children: <Widget>[
showAlert(),
Padding(
padding: const EdgeInsets.all(20.0),
child: Form(
key: formKey,
child: Column(
children: buildInputs(),
),
),
),
],
),
)),
SizedBox(height: 0,),
FadeAnimation(2,
Container(
child: Column(
children:buildButtons(),
),
)
),
SizedBox(height: 0,),
FadeAnimation(1.7, Text("Continue with social media", style: TextStyle(color: Colors.white),)),
SizedBox(height: 20,),
Row(
children: <Widget>[
Expanded(
child: FadeAnimation(1.8, Container(
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.blue
),
child: Center(
child: FlatButton(
child: Text("Facebook", style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),),
onPressed: (){
},
)
),
)),
),
SizedBox(width: 30,),
Expanded(
child: FadeAnimation(1.9, Container(
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(50),
color: Colors.white
),
child: Center(
child: FlatButton(
child: Text("Google", style: TextStyle(color: Colors.redAccent, fontWeight: FontWeight.bold),),
onPressed: () async {
try {
if(authFormType == AuthFormType.convert) {
await _auth.convertWithGoogle();
Navigator.of(context).pop();
} else {
await _auth.signInWithGoogle();
Navigator.of(context).pushReplacementNamed('/home');
}
} catch (e) {
setState(() {
print(e);
_warning = e.message;
});
}
},
)
),
)),
)
],
),
SizedBox(height: 0),
FadeAnimation(3, FlatButton(child:Text('By continueing, you agree to Terms & Conditions', style: TextStyle(color: Colors.white, fontSize: 12, ), ),
onPressed: (){
Navigator.of(context).pushReplacementNamed('/Terms');
},
)
)
],
),
),
),
),
)
],
),
),
);
}
Widget showAlert() {
if (_warning != null) {
return Container(
color: Colors.amberAccent,
width: double.infinity,
padding: EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(Icons.error_outline),
),
Expanded(
child: AutoSizeText(
_warning,
maxLines: 3,
),
),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: IconButton(
icon: Icon(Icons.close),
onPressed: () {
setState(() {
_warning = null;
});
},
),
)
],
),
);
}
return SizedBox(
height: 0,
);
}
AutoSizeText buildHeaderText() {
String _headerText;
if (authFormType == AuthFormType.signIn) {
_headerText = "Sign In";
} else if (authFormType == AuthFormType.reset) {
_headerText = "Reset Password";
} else {
_headerText = "Create New Account";
}
return AutoSizeText(
_headerText,
maxLines: 1,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 35,
color: Colors.white,
),
);
}
List<Widget> buildInputs() {
List<Widget> textFields = [];
if (authFormType == AuthFormType.reset) {
textFields.add(
TextFormField(
validator: EmailValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Email"),
onSaved: (value) => _email = value,
),
);
textFields.add(SizedBox(height: 20));
return textFields;
}
// if were in the sign up state add name
if ([AuthFormType.signUp, AuthFormType.convert].contains(authFormType)) {
textFields.add(
TextFormField(
validator: NameValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Full Name"),
onSaved: (value) => _name = value,
),
);
textFields.add(SizedBox(height: 20));
}
// add email & password
textFields.add(
TextFormField(
validator: EmailValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Email"),
onSaved: (value) => _email = value,
),
);
textFields.add(SizedBox(height: 20));
textFields.add(
TextFormField(
validator: PasswordValidator.validate,
style: TextStyle(fontSize: 22.0),
decoration: buildSignUpInputDecoration("Password"),
obscureText: true,
onSaved: (value) => _password = value,
),
);
textFields.add(SizedBox(height: 20));
return textFields;
}
InputDecoration buildSignUpInputDecoration(String hint) {
return InputDecoration(
hintText: hint,
filled: true,
fillColor: Colors.white,
focusColor: Colors.white,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.white, width: 0.0)),
contentPadding:
const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
);
}
List<Widget> buildButtons() {
String _switchButtonText, _newFormState, _submitButtonText;
bool _showForgotPassword = false;
if (authFormType == AuthFormType.signIn) {
_switchButtonText = "Create New Account";
_newFormState = "signUp";
_submitButtonText = "Sign In";
_showForgotPassword = true;
} else if (authFormType == AuthFormType.reset) {
_switchButtonText = "Return to Sign In";
_newFormState = "signIn";
_submitButtonText = "Submit";
} else if (authFormType == AuthFormType.convert) {
_switchButtonText = "Cancel";
_newFormState = "home";
_submitButtonText = "Sign Up";
} else {
_switchButtonText = "Have an Account? Sign In";
_newFormState = "signIn";
_submitButtonText = "Sign Up";
}
return [
Container(
width: MediaQuery.of(context).size.width * 0.7,
child: RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
color: Colors.white,
textColor: primaryColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
_submitButtonText,
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.w300),
),
),
onPressed: submit,
),
),
showForgotPassword(_showForgotPassword),
FlatButton(
child: Text(
_switchButtonText,
style: TextStyle(color: Colors.white),
),
onPressed: () {
switchFormState(_newFormState);
},
),
];
}
List<Widget> buildOre() {
String _switchButtonText;
bool _showForgotPassword = false;
if (authFormType == AuthFormType.signIn) {
_switchButtonText = "Create New Account";
_showForgotPassword = true;
} else if (authFormType == AuthFormType.reset) {
_switchButtonText = "Return to Sign In";
} else if (authFormType == AuthFormType.convert) {
_switchButtonText = "Cancel";
} else {
_switchButtonText = "Have an Account? Sign In";
}
return [
Container(
width: MediaQuery.of(context).size.width * 0.7,
child: RaisedButton(
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
color: Colors.white,
textColor: primaryColor,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
''
),
),
onPressed: submit,
),
),
showForgotPassword(_showForgotPassword),
FlatButton(
child: Text(
_switchButtonText,
style: TextStyle(color: Colors.white),
),
onPressed: () {
},
),
];
}
Widget showForgotPassword(bool visible) {
return Visibility(
child: FlatButton(
child: Text(
"Forgot Password?",
style: TextStyle(color: Colors.white),
),
onPressed: () {
setState(() {
authFormType = AuthFormType.reset;
});
},
),
visible: visible,
);
}
}
THIS IS THE FIREBASE-FIRESTORE
THIS IS THE CODE
I am assuming DoctorsHome is the name of your screen and that isDoctor is the field indicating if the role of the user is 'doctor'.
This way, if the user is signed you are going to show either DoctorHome or UsersHome based on isDoctor, and OnboardingScreen otherwise.
EDIT
if (snapshot.connectionState == ConnectionState.active) {
final bool signedIn = snapshot.hasData;
final String role = snapshot.data['role'];
final bool isDoctor;
if (role=='doctor') { isDoctor = true } else { isDoctor = false}
return signedIn ? (){ isDoctor ? DoctorsHome() : UsersHome() }() : OnboardingScreen();
}
i have developed an login page,if the email and password matches from the database it successfully login's and moves to the new page,but if its wrong i want to display an error message email or password doesn't match.
Here's my code:
class _AdminLoginState extends State<AdminLogin> {
String _username, _password;
TextEditingController _email = TextEditingController();
final GlobalKey<FormState> _formkey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('LOGIN'),
backgroundColor: Colors.indigo[900],
),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
padding: const EdgeInsets.only(top: 50),
child: SizedBox(
height: 150.0,
width: 300,
child: Image.asset("assets/admin.png",
fit: BoxFit.contain,),
),
),
Container(
child: Text("ADMIN",style: TextStyle(fontSize: 15,fontWeight: FontWeight.bold,color: Colors.indigo),),
),
Container(
padding: const EdgeInsets.only(bottom: 50),
child: Column(
children: <Widget>[
SingleChildScrollView(
child: Form(
key: _formkey,
child: Column(
children: <Widget>[
SizedBox(
height: 60,
),
SizedBox(
width: 380,
height: 70,
child: Container(
padding: EdgeInsets.all(4),
width: 500,
height: 60,
child: TextFormField(
autofocus: false,
obscureText: false,
keyboardType: TextInputType.emailAddress,
validator:(input){
if(input.isEmpty){
return 'please type username';
}
return null;
},
onSaved: (input) => _username =input ,
decoration: InputDecoration(
labelText: 'Email',
hintText: "Email",
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
),
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
),
),
),
),
SizedBox(
width: 380,
height: 70,
child: Container(
padding: EdgeInsets.all(4),
width: 400,
height: 60,
child: TextFormField(
autofocus: false,
obscureText: true,
validator:(input){
if(input.isEmpty){
return 'please type Password';
}
return null;
},
onSaved: (input) => _password =input ,
decoration: InputDecoration(
labelText: 'Password',
hintText: "Password",
labelStyle: TextStyle(
color: Colors.black,
fontSize: 16,
),
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(20.0),
),
),
),
),
),
),
Container(
padding: EdgeInsets.all(4),
width: 500,
height: 60,
child: RaisedButton(
onPressed: login,
textColor: Colors.white,
color: Colors.indigo[900],
child: Text('Login'),
),
)
],
),
),
),
],
),
),
],
),
),
);
}
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}catch(e){
print(e.message);
}
}
}
}
it will be really helpful if someone also helps me in validating the right email format and give give the proper validation for password
signInWithEmailAndPassword() returns an exception with a special code if the attempt is unsuccessful.
In order to print a message you need to add a catch block to your signInWithEmailAndPassword() method. Then you can use the error message.
Example:
firebase.auth().signInWithEmailAndPassword(email, password)
.catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
if (errorCode === 'auth/wrong-password') {
alert('Wrong password.');
} else {
alert(errorMessage);
}
console.log(error);
});
For security purposes I would suggest combining some of the messages together instead of giving a possible attacker a hint about if the email is already in the system or not.
I do not know how to use flutter so I can only give an idea;
In here you are directly trying to get the user from the method.
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Instead I would suggest using something like this (this is angular but I think you can easily apply to flutter with some modification)
final FirebaseUser user;
await firebase.auth().signInWithEmailAndPassword(email, password)
.then((data) => {
this.user = data.user;
})
.catch((error) => {
switch (error.code) {
case "auth/invalid-email":
case "auth/wrong-password":
case "auth/user-not-found":
{
this.accountErrorMessage = "Wrong email address or password.";
break;
}
case "auth/user-disabled":
case "user-disabled":
{
this.accountErrorMessage = "This account is disabled";
break;
}
}
You can find which kind of errors it may return from here:
https://firebase.google.com/docs/reference/js/firebase.auth.Auth.html#signinwithemailandpassword
Use errortext in InputDecoration
here is demo
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'email',
errorText: loginfail ? 'email not match' : null,
),
),
TextField(
controller: _text,
decoration: InputDecoration(
labelText: 'password',
errorText: loginfail ? 'password not match' : null,
),
),
RaisedButton(
onPressed: () {
login();
},
child: Text('Submit'),
textColor: Colors.white,
color: Colors.blueAccent,
)
],
),
),
);
}
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
if(!user.uid.isEmpty()){
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}else{
setState((){
loginfail = true; //loginfail is bool
});
}
}catch(e){
print(e.message);
}
}
hope it helps..
Following #Jaydeepchatrola answer's
I used a try catch block and checked if password was invalid or email, for better results!
try {
setState(() {
wrongEmail = false;
wrongPassword = false;
});
final newUser = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.pushNamed(context, Done.id);
}
} catch (e) {
print(e.code);
if (e.code == 'ERROR_WRONG_PASSWORD') {
setState(() {
wrongPassword = true;
});
} else {
setState(() {
emailText = 'User doesn\'t exist';
passwordText = 'Please check your email';
wrongPassword = true;
wrongEmail = true;
});
}
}
You need to catch the specific error. I had the problem by myself, with this code I solved the problem.
try {
final user = await _auth.signInWithEmailAndPassword(
email: email, password: password);
if (user != null) {
Navigator.pushNamed(context, HomeScreen.id);
}
} on auth.FirebaseAuthException catch (e) {
//Here you catch the specific error
if (e.code == 'wrong-password') {
//The thing that should happen if the password is incorrect
//In my case it will the change the hinttext
setState(() {
hintTextPassword = 'Password incorrect. Please try again';
passwordHintColor = Colors.red;
});
} else if (e.code == 'user-not-found') {
setState(() {
hintTextEmail = 'No user found for that email.';
emailHintColor = Colors.red;
});
}
} catch (e) {
print(e);
}
add rflutter_alert: ^2.0.4 in your project file pubspec.yaml under dependencies: and save it
add import 'package:rflutter_alert/rflutter_alert.dart'; in your file of your auth screen
add
Alert(
context: context,
title: "Failed Login",
desc: "Incorrect Email Or Password.")
.show();
in catch(e){}
like that:
Future<void> login() async{
final formState = _formkey.currentState;
if(formState.validate()){
formState.save();
try{
final FirebaseUser user = (await FirebaseAuth.instance.signInWithEmailAndPassword(email: _username, password: _password)).user;
Navigator.push(context, MaterialPageRoute(builder: (context) => Admin()));
}catch(e){
Alert(
context: context,
title: "Failed Login",
desc: "Incorrect Email Or Password.")
.show();
}
}