my flutter firebase app always have same error - firebase

I have made a online store app with flutter and backend on firebase , in sign up page whenever click on create account button it says same error, no matter if I put data on Text Fields or not, I am really confused about this!
the error is
given String is empty or null
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../widgets/custom_button.dart';
import '../widgets/custom_input.dart';
import 'const.dart';
import 'login.dart';
class SingUP extends StatefulWidget {
SingUP({Key? key}) : super(key: key);
#override
State<SingUP> createState() => _SingUPState();
}
class _SingUPState extends State<SingUP> {
Future<void> advanceAlertDialog(String message) {
return Get.defaultDialog(
title: 'Invalid Input',
content: Text(message),
actions: [
ElevatedButton(
onPressed: () => Get.back(),
child: Text('OK !'),
)
],
contentPadding: EdgeInsets.all(15.0),
);
}
Future<String?> signInMethod() async {
try {
await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: takeEmail, password: takePassword);
return 'ok';
} on FirebaseAuthException catch (error) {
if (error.code == 'weak-password') {
return 'the password is too week';
} else if (error.code == 'email-already-in-use') {
return 'The account with this email is already exist !';
}
return error.message;
} catch (error) {
return error.toString();
}
}
void signIn() async {
setState(() {
isLoading = true;
});
String? result = await signInMethod();
if (result != 'ok') {
advanceAlertDialog(result!);
setState(() {
isLoading = false;
});
} else {
setState(() {
isLoading = false;
});
Get.to(LoginPage());
Get.snackbar('Successful', 'Account Created !',
backgroundColor: Colors.greenAccent, icon: Icon(Icons.check_circle));
}
}
bool isLoading = false;
String takeEmail = '';
String takePassword = '';
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: EdgeInsets.only(top: 50),
child: Text(
'Create a New Account !',
style: Constans.headingTextStyle,
textAlign: TextAlign.center,
),
),
Column(
children: [
CustomInput(
hintText: 'Enter Your Email ...',
onChanged: (value) {
takeEmail = value;
},
checkPassword: false,
),
CustomInput(
hintText: 'Enter Your Password ...',
onChanged: (value) {
takeEmail = value;
},
checkPassword: true,
),
CustomButton(
text: 'Create Account',
loading: isLoading,
onTap: () {
signIn();
},
mode: false,
)
],
),
CustomButton(
text: 'Back to Login',
onTap: () => Get.back(),
mode: true,
loading: isLoading,
)
],
),
),
);
}
}

Emain and password widgets are the same takeEmail = value;, change the password onChange value to takePassword = value;, also where is exactly the error thrown?. I advice to add breakpoints to signInMethod() to see the input values of email: takeEmail, password: takePassword (both of this strings) and after the on FirebaseAuthException catch (error) { to see if the error is thrown from firebase or is in your code.

Related

The non-nullable local variable 'result' must be assigned before it can be used

I cannot find the solution to this problem. I am creating a sign up screen connected to firebase but it is giving me this error, "The non-nullable local variable 'result' must be assigned before it can be used. Try giving it an initializer expression, or ensure that it's assigned on every execution path."
The error is here. On the first and third line under result.
FirebaseFirestore.instance.collection("User").doc(result.user!.uid).set({
"UserName": userName.text,
"UserId": result.user!.uid,
"UserEmail": email.text,
"UserAddress": address.text,
"UserGender": isMale == true ? "Male" : "Female",
"UserNumber": phoneNumber.text,
});
This is the whole code
`import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:e_commerce_application/screens/homepage.dart';
import 'package:e_commerce_application/screens/login.dart';
import 'package:e_commerce_application/widgets/changescreen.dart';
import 'package:e_commerce_application/widgets/mybutton.dart';
import 'package:e_commerce_application/widgets/mytextformField.dart';
import 'package:e_commerce_application/widgets/passwordtextformfield.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class SignUp extends StatefulWidget {
#override
_SignUpState createState() => _SignUpState();
}
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
String p =
r'^(([^<>()[\]\\.,;:\s#\"]+(\.[^<>()[\]\\.,;:\s#\"]+)*)|(\".+\"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$';
RegExp regExp = new RegExp(p);
bool obserText = true;
final TextEditingController email = TextEditingController();
final TextEditingController userName = TextEditingController();
final TextEditingController phoneNumber = TextEditingController();
final TextEditingController password = TextEditingController();
final TextEditingController address = TextEditingController();
bool isMale = true;
bool isLoading = false;
class _SignUpState extends State<SignUp> {
void submit() async {
UserCredential result;
try {
setState(() {
isLoading = true;
});
result = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.text, password: password.text);
print(result);
} on PlatformException catch (error) {
var message = "Please Check Your Internet Connection ";
if (error.message != null) {
message = error.message!;
}
_scaffoldKey.currentState!.showSnackBar(SnackBar(
content: Text(message.toString()),
duration: Duration(milliseconds: 600),
backgroundColor: Theme.of(context).primaryColor,
));
setState(() {
isLoading = false;
});
} catch (error) {
setState(() {
isLoading = false;
});
_scaffoldKey.currentState!.showSnackBar(SnackBar(
content: Text(error.toString()),
duration: Duration(milliseconds: 600),
backgroundColor: Theme.of(context).primaryColor,
));
print(error);
}
FirebaseFirestore.instance.collection("User").doc(result.user!.uid).set({
"UserName": userName.text,
"UserId": result.user!.uid,
"UserEmail": email.text,
"UserAddress": address.text,
"UserGender": isMale == true ? "Male" : "Female",
"UserNumber": phoneNumber.text,
});
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (ctx) => HomePage()));
setState(() {
isLoading = false;
});
}
void vaildation() async {
if (userName.text.isEmpty &&
email.text.isEmpty &&
password.text.isEmpty &&
phoneNumber.text.isEmpty &&
address.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("All Flied Are Empty"),
),
);
} else if (userName.text.length < 6) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Name Must Be 6 "),
),
);
} else if (email.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Email Is Empty"),
),
);
} else if (!regExp.hasMatch(email.text)) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Please Try Vaild Email"),
),
);
} else if (password.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Password Is Empty"),
),
);
} else if (password.text.length < 8) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Password Is Too Short"),
),
);
} else if (phoneNumber.text.length < 11 || phoneNumber.text.length > 11) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Phone Number Must Be 11 "),
),
);
} else if (address.text.isEmpty) {
_scaffoldKey.currentState!.showSnackBar(
SnackBar(
content: Text("Address Is Empty "),
),
);
} else {
submit();
}
}
Widget _buildAllTextFormField() {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
MyTextFormField(
name: "UserName",
controller: userName,
),
SizedBox(
height: 10,
),
MyTextFormField(
name: "Email",
controller: email,
),
SizedBox(
height: 10,
),
PasswordTextFormField(
obserText: obserText,
controller: password,
name: "Password",
onTap: () {
FocusScope.of(context).unfocus();
setState(() {
obserText = !obserText;
});
},
),
SizedBox(
height: 10,
),
GestureDetector(
onTap: () {
setState(() {
isMale = !isMale;
});
},
child: Container(
height: 60,
padding: EdgeInsets.only(left: 10),
width: double.infinity,
decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
child: Center(
child: Row(
children: [
Text(
isMale == true ? "Male" : "Female",
style: TextStyle(color: Colors.black87, fontSize: 18),
),
],
),
),
),
),
SizedBox(
height: 10,
),
MyTextFormField(
name: "Phone Number",
controller: phoneNumber,
),
SizedBox(
height: 10,
),
MyTextFormField(
name: "Address",
controller: address,
),
],
),
);
}
Widget _buildBottomPart() {
return Container(
margin: EdgeInsets.symmetric(horizontal: 10),
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
_buildAllTextFormField(),
SizedBox(
height: 10,
),
isLoading == false
? MyButton(
name: "SignUp",
onPressed: () {
vaildation();
},
)
: Center(
child: CircularProgressIndicator(),
),
ChangeScreen(
name: "Login",
whichAccount: "I Have Already An Account!",
onTap: () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (ctx) => Login(),
),
);
},
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _scaffoldKey,
body: ListView(
children: [
Container(
height: 200,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Register",
style: TextStyle(
fontSize: 40,
fontWeight: FontWeight.bold,
),
),
],
),
),
Container(
height: 500,
child: _buildBottomPart(),
),
],
),
);
}
}
`
You are assigning result in your try catch, and accessing it after your try catch.
So if anything happens in your try block, result will never be assigned, and you cannot access whatever you want on it.
Solution would be to put your Firestore Call in your try catch block.
try {
setState(() {
isLoading = true;
});
result = await FirebaseAuth.instance.createUserWithEmailAndPassword(
email: email.text, password: password.text);
print(result);
FirebaseFirestore.instance.collection("User").doc(result.user!.uid).set({
"UserName": userName.text,
"UserId": result.user!.uid,
"UserEmail": email.text,
"UserAddress": address.text,
"UserGender": isMale == true ? "Male" : "Female",
"UserNumber": phoneNumber.text,
});
Null safety in dart also cause this error in my code. The only solution is to assign a pre-define value to variable.
String imagePath = "path";
String imageName = '/image.jpeg';
I was getting this error in last line, in var imagePath.
class _newpostState extends State<newpost> {
//class newpost extends StatefulWidget {
//const newpost({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
String imagePath = "path";
String imageName = '/image.jpeg';
void pickImage() async {
final ImagePicker _picker = ImagePicker();
final XFile? image = await _picker.pickImage(source: ImageSource.gallery);
print(image!.name);
setState(() {
imagePath = image.path;
imageName = image.name;
});
}
final TextEditingController titlecontroller = TextEditingController();
final TextEditingController DcripController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
void submit() async {
//for post database
FirebaseAuth auth = FirebaseAuth.instance;
FirebaseFirestore firestore = FirebaseFirestore.instance;
//for storage
firebase_storage.FirebaseStorage storage =
firebase_storage.FirebaseStorage.instance;
try {
File file = File(imagePath);
await storage.ref(imageName).putFile(file);
It's so, frustrating to read "variable must be assigned before it can be used" because you already assigned the variable.
to solve this issue, provide a default value when you create the variable.
suppose the variable is a string.
String result; // instead of this
String result= ""; // use this

issue with flutter firebase login

I recently made things work with the login/register module on my app but there are 2 things that are not working:
first when I register it's ok, I can see in my Firebase Console that the app is creating a new user so that's fine. However, when I try to log in with a user that doesn't exist it still makes me go to the homepage.
no idea how to make a persistent login, like someone who log in and someone who register when they close the app and then restart the app they should be able to keep the login and then logout if they want.
CAN ANYBODY HELP??
I leave here the code:
MAIN
import 'package:flutter/material.dart';
import 'package:sport_app/auth_screen.dart';
import 'package:sport_app/home_screen.dart';
import 'package:sport_app/intro_screen.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: Color(0xfff2f9fe),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[200]),
borderRadius: BorderRadius.circular(25),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[200]),
borderRadius: BorderRadius.circular(25),
),
disabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.grey[200]),
borderRadius: BorderRadius.circular(25),
),
),
),
home: IntroScreen(),
routes: {
'intro': (context) => IntroScreen(),
'home': (context) => HomeScreen(),
'login': (context) => AuthScreen(authType: AuthType.login),
'register': (context) => AuthScreen(authType: AuthType.register),
},
);
}
}
AUTH_PAGE
import 'package:flutter/material.dart';
import 'package:sport_app/auth_screen.dart';
import 'package:sport_app/auth.dart';
import 'package:sport_app/original_button.dart';
class AuthForm extends StatefulWidget {
final AuthType authType;
const AuthForm({Key key, #required this.authType}) : super(key: key);
#override
_AuthFormState createState() => _AuthFormState();
}
class _AuthFormState extends State<AuthForm> {
final _formKey = GlobalKey<FormState>();
String _email = '', _password = '';
AuthBase authBase = AuthBase();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50, vertical: 20),
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Enter your email',
hintText: 'ex: test#gmail.com',
),
onChanged: (value) {
_email = value;
},
validator: (value) =>
value.isEmpty ? 'You must enter a valid email' : null,
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
labelText: 'Enter your password',
),
obscureText: true,
onChanged: (value) {
_password = value;
},
validator: (value) => value.length <= 6
? 'Your password must be larger than 6 characters'
: null,
),
SizedBox(height: 20),
OriginalButton(
text: widget.authType == AuthType.login ? 'Login' : 'Register',
color: Colors.lightBlue,
textColor: Colors.white,
onPressed: () async {
if (_formKey.currentState.validate()) {
if (widget.authType == AuthType.login) {
await authBase.loginWithEmailAndPassword(_email, _password);
Navigator.of(context).pushReplacementNamed('home');
} else {
await authBase.registerWithEmailAndPassword(_email, _password);
Navigator.of(context).pushReplacementNamed('home');
}
// print(_email);
// print(_password);
}
},
),
SizedBox(height: 6),
FlatButton(
onPressed: () {
if (widget.authType == AuthType.login) {
Navigator.of(context).pushReplacementNamed('register');
print(widget.authType);
} else {
Navigator.of(context).pushReplacementNamed('login');
}
},
child: Text(
widget.authType == AuthType.login
? 'Don\'t have an account?'
: 'Already have an account?',
style: TextStyle(fontSize: 18, color: Colors.black54),
),
),
],
),
),
);
}
}
AUTHBASE
import 'package:flutter/material.dart';
import 'package:firebase_auth/firebase_auth.dart';
class User {
final String uid;
User({#required this.uid});
}
class AuthBase {
User _userFromFirebase(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
Future<void> registerWithEmailAndPassword(
String email, String password) async {
try {
final authResult = await FirebaseAuth.instance
.createUserWithEmailAndPassword(email: email, password: password);
return _userFromFirebase(authResult.user);
} catch (e) {
print(e.toString());
return null;
}
}
Future<void> loginWithEmailAndPassword(String email, String password) async {
try {
final authResult = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password);
return _userFromFirebase(authResult.user);
} catch (e) {
print(e.toString());
return null;
}
}
Future<void> logout() async {
await FirebaseAuth.instance.signOut();
}
}
UPDATE
You simply navigate to the homepage, even when the login has not completed successfully, becaus there is no condition logic. Do the navigation only in your authBase class, then you should be fine.
You need to import the FirebaseAuthException before you can use it. Then, you
Future<bool> loginWithEmailAndPassword(String email, String password) async {
try {
final authResult = await FirebaseAuth.instance
.signInWithEmailAndPassword(email: email, password: password);
if(authResult.user != null) { Navigator.of(context).pushReplacementNamed('home'); }
} on FirebaseAuthException catch (e) {
print(e.toString());
if(e.code == 'wrong-password') { Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Wrong Password"),
)); }
else if (e.code == 'user-not-found') { Scaffold.of(context).showSnackBar(SnackBar(
content: Text("User not found"),
)); }
else if (e.code == 'invalid-email') { Scaffold.of(context).showSnackBar(SnackBar(
content: Text("Invalid E-Mail"),
)); }
return false;
}
}
and remove change your widget code to:
if (_formKey.currentState.validate()) {
if (widget.authType == AuthType.login) {
await authBase.loginWithEmailAndPassword(_email, _password);
} else {
await authBase.registerWithEmailAndPassword(_email, _password);
}
}
Second Problem:
You could try storing the login credentials in the storage (user flutter_secure_storage package for encryption) after the first login and then retrieve it on App startup to perform login like above
Here is a link for the package you should use to store the credentials
flutter_secure_storage

How do i catch error of authentication while logging in and signup using firebase and flutter?

I am pretty new to flutter and this is my first project in which i am using backend like firebase.
So i pre build an ui and started to integrate firebase in it it was successfully done and it is working as accepted but when i am trying to print out the errors while logging in signup i am failing to do that, i am able to catch the errors in my console but i wait to update my users with that error text.
when ever i am trying to log in though i am providing a wrong password it is taking me to the home page which i dont want
This is my Log In page with a pre build ui and with working setup of log in
import 'package:flutter/material.dart';
import 'package:notepad/Authentigation%20Screens/signUp.dart';
import 'package:notepad/animation/bouncypagetrans.dart';
import 'package:notepad/animation/fadeanimation.dart';
import 'package:notepad/auth/authMethod.dart';
import 'package:notepad/screens/homepage.dart';
import 'package:notepad/widgets/VxTextsHeaders.dart';
import 'package:notepad/widgets/customRaisedButton.dart';
import 'package:notepad/widgets/loading.dart';
import 'package:notepad/widgets/textformField.dart';
import 'ForgotPassword.dart';
class LogIn extends StatefulWidget {
#override
_LogInState createState() => _LogInState();
}
class _LogInState extends State<LogIn> {
String error;
AuthMethods authMethods = new AuthMethods();
bool isLoading = false;
final formKey = GlobalKey<FormState>();
TextEditingController emailTextEditingController =
new TextEditingController();
TextEditingController passwordTextEditingController =
new TextEditingController();
logMein() {
if (formKey.currentState.validate()) {
try {
setState(() {
isLoading = true;
});
authMethods
.signInWithEmailAndPassword(emailTextEditingController.text,
passwordTextEditingController.text)
.then((val) {
// print("${val.uId}");
Navigator.pushReplacement(
context,
BouncyPageRout(
widget: HomePage(),
),
);
});
} catch (e) {
setState(() {
error = e.message;
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomPadding: true,
body: isLoading
? Loading()
: SafeArea(
child: Container(
width: double.infinity,
padding: EdgeInsets.fromLTRB(30.0, 100.0, 30.0, 20.0),
height: MediaQuery.of(context).size.height,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FadeAnimation(
1.0,
headerTitle("Hello,"),
),
FadeAnimation(
2.0,
headerSubTitle("Log in to continue"),
),
],
),
SizedBox(height: 65),
Column(
children: [
Form(
key: formKey,
child: Column(children: [
SizedBox(height: 20),
FadeAnimation(
3.0,
buildTextField(
validator: (val) {
return val.isEmpty ||
RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(val)
? null
: "Please provide a valid Email";
},
labelText: "Email",
controller: emailTextEditingController),
),
SizedBox(height: 20),
FadeAnimation(
3.5,
buildTextField(
validator: (val) {
return val.isEmpty || val.length < 6
? "Please Provide a Strong Password,/n Provide somthing greater than 6 "
: null;
},
labelText: "Password",
obscureText: true,
controller:
passwordTextEditingController),
),
])),
SizedBox(height: 10.0),
Container(
alignment: Alignment.centerRight,
child: FadeAnimation(
4.0,
InkWell(
onTap: () {
Navigator.push(
context,
BouncyPageRout(
widget: ForgotPassword(),
),
);
},
child: Text(
'Forgot Password?',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.deepOrange,
fontSize: 14),
),
),
),
),
SizedBox(height: 40),
FadeAnimation(
4.5,
raisedButton(
context: context,
onPressed: () {
logMein();
},
color: Colors.deepOrange,
title: "Log In",
textColor: Colors.white,
),
),
SizedBox(
height: 20.0,
),
FadeAnimation(
5.0,
raisedButton(
context: context,
onPressed: () {
Navigator.push(
context,
BouncyPageRout(
widget: SignUp(),
),
);
},
color: Colors.white,
title: "SignUp"),
),
],
)
],
),
),
),
),
);
}
}
AuthMethods page with contains all the codes of firebase
import 'package:notepad/auth/user.dart';
class AuthMethods {
String error;
final FirebaseAuth _auth = FirebaseAuth.instance;
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(userId: user.uid) : null;
}
Future signInWithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.signInWithEmailAndPassword(
email: email, password: password);
FirebaseUser firebaseUser = result.user;
return _userFromFirebaseUser(firebaseUser);
} catch (e) {
print(e.toString());
}
}
Future signUpwithEmailAndPassword(String email, String password) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser firebaseUser = result.user;
return _userFromFirebaseUser(firebaseUser);
} catch (e) {
print(e.toString());
}
}
Future resetPass(String email) async {
try {
return await _auth.sendPasswordResetEmail(email: email);
} catch (e) {
print(e.toString());
}
}
Future signOut() async {
try {
return await _auth.signOut();
} catch (e) {
print(e.toString());
}
}
}
so basically i want to notify my users a valid error message and untill they solve that they should not navigate to a perticular screen
You can use a snackbar widget and call them in your throw function! Follow this link to learn more about snackbars
https://flutter.dev/docs/cookbook/design/snackbars

Cannot convert Future<String> to String and use in Dart (Flutter)

I try to implement Firebase authentication in my mobile app. (I am very new to this..)
I have the following code which attempts to create the user for the first time:
class WpAuthService {
FirebaseAuth _auth = FirebaseAuth.instance;
Stream<WpUser> get wpUser {
return _auth.authStateChanges().map((User firebaseUser) =>
(firebaseUser != null) ? WpUser(uid: firebaseUser.uid) : null);
}
Future<String> createUserWithEmail(email, password) async {
UserCredential userCredential;
try {
userCredential = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
} on FirebaseAuthException catch (e) {
print(e.code + " - " + e.message);
return e.message;
}
return 'SUCCESS';
}
}
And in another file, I am trying to call the createUserWithEmail function as following:
class SignupForm extends StatefulWidget {
#override
_SignupFormState createState() => _SignupFormState();
}
class _SignupFormState extends State<SignupForm> {
final _formKey = GlobalKey<FormState>();
var _userEmail = "";
var _userPassword = "";
String _opResult;
void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState.save();
WpAuthService()
.createUserWithEmail(_userEmail, _userPassword)
.then((value) {
setState(() {
_opResult = value;
});
});
print('MESSAGE:');
print(_opResult);
if (_opResult != 'SUCCESS') {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(_opResult),
backgroundColor: Theme.of(context).errorColor,
),
);
}
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Card(
margin: EdgeInsets.all(20),
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
key: ValueKey('email'),
validator: (value) {
if (value.isEmpty || !value.contains('#')) {
return 'Please enter a valid email address.';
}
return null;
},
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(labelText: 'Email address'),
onSaved: (value) {
_userEmail = value;
},
),
TextFormField(
key: ValueKey('password'),
validator: (value) {
if (value.isEmpty || value.length < 7) {
return 'Password must be at least 7 characters long.';
}
return null;
},
decoration: InputDecoration(labelText: 'Password'),
obscureText: true,
onSaved: (value) {
_userPassword = value;
},
),
SizedBox(height: 12),
RaisedButton(
child: Text('Sign up',
style: Theme.of(context).textTheme.headline6),
onPressed: _trySubmit,
),
],
),
),
),
),
),
);
}
}
When I run the above piece of code, it prints out the following:
I/flutter ( 4032): MESSAGE:
I/flutter ( 4032): null
════════ Exception caught by gesture ═══════════════════════════════════════════
The following assertion was thrown while handling a gesture:
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 370 pos 10: 'data != null'
Looking at some other examples, I expect my implementation to work but something is seemingly wrong. How can I use the return value as String from the createUserWithEmail function?
by default your _opResult variable is null and your passing it to the Text widget of the Snackbar which throws that assertion.
You need either to first wait for the response to return or change your code to be inside the then method.
void _trySubmit() {
final isValid = _formKey.currentState.validate();
FocusScope.of(context).unfocus();
if (isValid) {
_formKey.currentState.save();
WpAuthService()
.createUserWithEmail(_userEmail, _userPassword)
.then((value) {
setState(() {
_opResult = value;
});
print('MESSAGE:');
print(_opResult);
if (_opResult != 'SUCCESS') {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(_opResult),
backgroundColor: Theme.of(context).errorColor,
),
);
}
});
}
}
Your _opResult is null. And it is not equal to 'SUCCESS'. And you are trying to set it into Text() widget. Text widget requires a string parameter, not null.
You can set a default string when initializing the _opResult. Like this:
String _opResult = "";
print('MESSAGE:');
print(_opResult);
if (_opResult != 'SUCCESS') {
Scaffold.of(context).showSnackBar(
SnackBar(
content: Text(_opResult),
backgroundColor: Theme.of(context).errorColor,
),
);
}
Solved.
In the createUserWithEmail function, I was returning String values as the following:
return e.message;
return 'SUCCESS';
I updated it so that the function now returns as stated below:
return Future.value(e.message);
return Future.value('SUCCESS');
Everything else is the same and it worked.
But I saw some other examples where people were just returning String values from their functions. My problem is solved but is this behavior really expected? You are more than welcome to educate me.

Error: Missing or insufficient permissions firestore

I'm having troubles with creating users in my app, I get an error that says I don't have sufficient permissions even though I should have permission. My security rules are allowing users to be created so I don't really understand why I am getting this error. What's even more strange is that it works on my mates computer, he can create users (with the exact same userdetails). He is on a pc and I on a mac not sure if that matters?
The error I get is the following:
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: PlatformException(Error 7, FIRFirestoreErrorDomain, Missing or insufficient permissions.)
Our security rules are:
service cloud.firestore {
//match /databases/{database}/documents {
match /databases/{database}/documents {
match /{document=**} {
allow read: if request.auth != null;
}
match /Users/{userId} {
allow update: if request.auth.uid == userId;
}
match /Users/{document=**} {
allow create;
}
match /Recipes/{document=**} {
allow create: if request.auth != null;
allow update, delete: if request.resource.data.userId == request.auth.uid;
}
match /Recipes/{document=**}/newRatings {
allow create, update: if request.auth != null;
}
}
} ```
Our code for registering users is:
´´´ import 'package:cibus/pages/loginScreens/username_screen.dart';
import 'package:cibus/pages/loginScreens/verify_screen.dart';
import 'package:cibus/services/colors.dart';
import 'package:flutter/material.dart';
import 'package:cibus/services/login/auth.dart';
import 'package:cibus/services/constants.dart';
import 'package:cibus/pages/loginScreens/e-sign_in_screen.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_user_stream/firebase_user_stream.dart';
import 'package:cibus/services/my_page_view.dart';
import 'package:provider/provider.dart';
import 'package:cibus/services/login/user.dart';
import 'package:cibus/services/database.dart';
import 'package:cibus/pages/loading_screen.dart';
const registerButtonColor = kTurquoise;
const formSizedBox = SizedBox(height: 20.0);
const EdgeInsets formPadding =
EdgeInsets.symmetric(vertical: 10.0, horizontal: 50.0);
const TextStyle textStyleErrorMessage =
TextStyle(color: Colors.red, fontSize: 14.0);
const TextStyle textStyleRegisterButton = TextStyle(color: Colors.white);
OutlineInputBorder textInputBorder = OutlineInputBorder(
borderRadius: BorderRadius.circular(25.0),
);
class RegisterScreen extends StatefulWidget {
final Function toggleView;
RegisterScreen({this.toggleView});
#override
_RegisterScreenState createState() => _RegisterScreenState();
}
class _RegisterScreenState extends State<RegisterScreen> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
bool loading = false;
bool isVerified = false;
//final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
//text field state
String email = '';
String password = '';
String error = '';
String name = '';
String description = '';
String _currentUsername;
int age = 0;
int dropdownValue = null;
final TextEditingController _pass = TextEditingController();
final TextEditingController _confirmPass = TextEditingController();
#override
Widget build(BuildContext context) {
return loading
? LoadingScreen()
: Scaffold(
backgroundColor: Theme.of(context).backgroundColor,
appBar: AppBar(
backgroundColor: Theme.of(context).backgroundColor,
elevation: 0.0,
title: Text('Sign up to Cibus', style: TextStyle(color: kCoral)),
actions: <Widget>[
FlatButton.icon(
icon: Icon(Icons.person, color: kCoral),
label: Text('Sign in', style: TextStyle(color: kCoral)),
onPressed: () {
//widget.toggleView();
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return EmailSignIn();
},
),
);
},
),
],
),
body: Padding(
padding: formPadding,
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(children: <Widget>[
formSizedBox,
TextFormField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Email',
),
validator: (val) =>
val.isEmpty ? 'Enter an email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Password',
),
obscureText: true,
controller: _pass,
validator: (String val) {
Pattern pattern =
r'^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[!##\$&*~]).{8,}$';
RegExp regex = new RegExp(pattern);
print(val);
if (val.isEmpty) {
return 'Please enter password';
} else if (val.length < 8) {
return 'Minimum 8 characters required';
} else if (!val.contains(RegExp(r'[A-Z]'))) {
return 'One upper case letter required.';
} else if (!val.contains(RegExp(r'[a-z]'))) {
return 'One lower case letter required.';
} else if (!val.contains(RegExp(r'[0-9]'))) {
return 'One digit required.';
} else if (!val
.contains(RegExp(r'[!##$%^&*(),.?":{}|<>]'))) {
return 'One special character required.';
} /*
else {
if (!regex.hasMatch(val))
return 'Enter valid password: \n'
'Password must contain at least one upper case letter. \n'
'Password must contain at least one lower case letter. \n'
'Password must contain at least one digit. \n'
'Password must contain at least one special character.'; */
else
return null;
//}
},
onChanged: (val) {
setState(() => password = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: ' Re-enter Password',
),
obscureText: true,
controller: _confirmPass,
validator: (String val) {
if (val.isEmpty)
return 'Re-enter password field is empty';
if (val != _pass.text)
return 'passwords do not match';
return null;
},
onChanged: (val) {
setState(() => password = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Name',
),
validator: (val) =>
val.isEmpty ? 'Enter your name' : null,
onChanged: (val) {
setState(() => name = val);
},
),
formSizedBox,
TextFormField(
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Description',
),
minLines: 5,
maxLines: 10,
validator: (val) =>
val.isEmpty ? 'Enter your description' : null,
onChanged: (val) {
setState(() => description = val);
},
),
formSizedBox,
TextFormField(
maxLength: 20,
decoration: InputDecoration(
enabledBorder: textInputBorder,
border: textInputBorder,
labelText: 'Username',
),
validator: (val) {
if (val.length < 3)
return 'Username must be more than 2 characters';
/*else if (checkUsername == false)
return 'Username is allready taken';*/
return null;
},
onChanged: (val) {
setState(() {
_currentUsername = val;
print(_currentUsername);
});
}),
formSizedBox,
RaisedButton(
color: kCoral,
child: Text('Register', style: textStyleRegisterButton),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
bool isUsernameFree = await DatabaseService()
.isUsernameTaken(username: _currentUsername);
print(' checkUsername: $isUsernameFree');
if (!isUsernameFree) {
dynamic result =
await _auth.registerWithEmailAndPassword(
email, password, name, description, age);
if (result == null) {
setState(() {
error = 'Email is already registered';
_verificationEmailDialog();
});
} else {
Navigator.of(context).pushReplacement(
MaterialPageRoute(
builder: (context) {
return VerifyScreen();
},
),
);
}
} else {
setState(() {
error = 'Username is already taken';
});
_usernameDialog();
}
}
},
),
Text(
error,
style: textStyleErrorMessage,
),
])),
),
));
}
Future<void> _usernameDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Username is already taken'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
'Unfortunately it seems like your username is allready taken. Please try another one'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Aight bruh'),
onPressed: () {
setState(() {
loading = false;
});
Navigator.of(context)
.pop(); //TODO: When popping try to keep text in forms
},
),
],
);
},
);
}
Future<void> _verificationEmailDialog() async {
return showDialog<void>(
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return AlertDialog(
title: Text('Email is already in use'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Text(
'Unfortunately it seems like the email is already in use. Please try another one'),
],
),
),
actions: <Widget>[
FlatButton(
child: Text('Aight bruh'),
onPressed: () {
setState(() {
loading = false;
});
Navigator.of(context)
.pop(); //TODO: When popping try to keep text in forms
},
),
],
);
},
);
}
}
and here is the registerWithEmailAndPassword function:
Future registerWithEmailAndPassword(String email, String password,
String name, String description, int age) async {
try {
AuthResult result = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
FirebaseUser user = result.user;
user.sendEmailVerification();
user.isEmailVerified;
print('Email verification sent?');
//create a new document for the user with the uid
await DatabaseService(uid: user.uid)
.updateUserData(name: name, description: description, age: age);
await DatabaseService(uid: user.uid).updateUserPicture(
pictureURL:
'https://firebasestorage.googleapis.com/v0/b/independent-project-7edde.appspot.com/o/blank_profile_picture.png?alt=media&token=49efb712-d543-40ca-8e33-8c0fdb029ea5');
return _userFromFirebaseUser(user);
} catch (e) {
print(e.toString());
return null;
}
}
It was a mistake on my part with the Security rules. I had that users could create users but they could only read if they were authenticated, so when I checked if username was taken the error occurred since I did not have the read permissions. I just added the read part on users and it works
match /Users/{document=**} {
allow create: if true;
allow read: if true;
}
´´´

Resources