NoSuchMethodError (NoSuchMethodError: The getter 'uid' was called on null - flutter

I am new to flutter and fairly new to Firebase. I have created or I should say, followed a tutorial on how to create a Login/Register Page using Firebase as the backend. Everything works fine, except the fact that when I restart my application and enter an account already created I get the error from the title. NoSuchMethodError (NoSuchMethodError: The getter 'uid' was called on null. Receiver: null Tried calling: uid)
Here is the link to the tutorial I have followed.
https://www.freecodespot.com/blog/flutter-login-and-registration-using-firebase/#Logindart_Source_Code
After that, the application freezes, so I restart it and it shows I am logged in.
P.S. Creating a new account, and trying to log in works. Trying to Log In into an existing account seems to be the problem, but after restarting the app, it works. Sorry for any spelling errors, english is not my first language.
Error on line 91.
import '/models/loginuser.dart';
import '/services/auth.dart';
import 'package:flutter/material.dart';
class Login extends StatefulWidget {
final Function? toggleView;
Login({this.toggleView});
#override
State<StatefulWidget> createState() {
return _Login();
}
}
class _Login extends State<Login> {
bool _obscureText = true;
final _email = TextEditingController();
final _password = TextEditingController();
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final AuthSerice _auth = AuthSerice();
#override
Widget build(BuildContext context) {
final emailField = TextFormField(
controller: _email,
autofocus: false,
validator: (value) {
if (value != null) {
if (value.contains('#') && value.endsWith('.com')) {
return null;
}
return 'Enter an email address!';
}
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "Email",
border:
OutlineInputBorder(borderRadius: BorderRadius.circular(32.0))));
final passwordField = TextFormField(
obscureText: _obscureText,
controller: _password,
autofocus: false,
validator: (value) {
if (value == null || value.trim().isEmpty) {
return 'This field is required!';
}
if (value.trim().length < 6) {
return 'Password must be at least 6 characters in length!';
}
// Return null if the entered password is valid
return null;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
hintText: "Password",
suffixIcon: IconButton(
icon:
Icon(_obscureText ? Icons.visibility : Icons.visibility_off),
onPressed: () {
setState(() {
_obscureText = !_obscureText;
});
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(32.0),
)));
final txtbutton = TextButton(
onPressed: () {
widget.toggleView!();
},
child: const Text('Register here!'));
final loginEmailPasswordButon = Material(
elevation: 5.0,
borderRadius: BorderRadius.circular(30.0),
color: Theme.of(context).primaryColor,
child: MaterialButton(
minWidth: MediaQuery.of(context).size.width,
padding: const EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
onPressed: () async {
if (_formKey.currentState!.validate()) {
dynamic result = await _auth.signInEmailPassword(LoginUser(email: _email.text,password: _password.text));
if (result.uid == null) { //null means unsuccessfull authentication
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text(result.code),
);
});
}
}
},
child: Text(
"Log in",
style: TextStyle(color: Theme.of(context).primaryColorLight),
textAlign: TextAlign.center,
),
),
);
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: AppBar(
title: const Text('LOGIN VXS FARMING'),
backgroundColor: Theme.of(context).primaryColor,
centerTitle: true,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
emailField,
const SizedBox(height: 25.0),
passwordField,
txtbutton,
const SizedBox(height: 35.0),
loginEmailPasswordButon,
const SizedBox(height: 15.0),
],
),
),
),
],
),
);
}
}
Commenting the if from line 91, there is no crash and the log in happens, but if I enter a wrong email, or password, there is no prompt saying that. It just clicks the button and nothing happens.

Related

Null value comes from singleton structure

I am developing an application with flutter. I set up a singleton structure to access the data in shared preferences. I made a password change area in the settings section of the application. And I wrote the service with node js, everything works fine, but the email value is null.
how can i fix the problem
data_store (singleton)
class DataStore {
static DataStore? _dataStore;
static DataStore? getInstance() {
if (_dataStore == null) {
// keep local instance till it is fully initialized.
var data = DataStore._();
_dataStore = data;
}
return _dataStore;
}
DataStore._();
UserModel user = UserModel();
bool? putUser(UserModel user) {
this.user = user;
return null;
}
UserModel? getUser() {
return user;
}
}
change password page
import 'package:flutter/material.dart';
import 'package:meetdy/Constants/Utils/app_shared_preferences.dart';
import 'package:meetdy/Constants/colors.dart';
import 'package:meetdy/Constants/utils/data_store.dart';
import 'package:meetdy/Models/auth_models/change_passsword_models/change_password_req_model.dart';
import 'package:meetdy/Models/auth_models/user_model.dart';
import 'package:meetdy/Services/auth_services/change_password_services/change_password_services.dart';
import 'package:provider/provider.dart';
import 'package:sizer/sizer.dart';
class ChangePasswordScreen extends StatefulWidget {
const ChangePasswordScreen({Key? key}) : super(key: key);
#override
State<ChangePasswordScreen> createState() => _ChangePasswordScreenState();
}
class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
late Size size = MediaQuery.of(context).size;
bool _isObscure = true;
bool isLoading = false;
final _formKey = GlobalKey<FormState>();
final _passwordController = TextEditingController();
final DataStore? _dataStore = DataStore.getInstance();
UserModel? user;
#override
void initState() {
user = _dataStore?.getUser();
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: GestureDetector(
onTap: () {
FocusManager.instance.primaryFocus?.unfocus();
},
child: Scaffold(
appBar: buildAppBar(context),
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 3.h, vertical: 1.h),
child: Column(
children: [
SizedBox(height: 2.h),
// Login TextFields
Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: [
Form(
key: _formKey,
child: TextFormField(
obscureText: _isObscure,
controller: _passwordController,
cursorColor: AppColors.lightBlack,
decoration: InputDecoration(
suffixIcon: IconButton(
icon: Icon(
_isObscure
? Icons.visibility
: Icons.visibility_off,
color: Colors.grey,
),
onPressed: () {
setState(() {
_isObscure = !_isObscure;
});
}),
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
disabledBorder: InputBorder.none,
labelText: 'Password',
labelStyle: TextStyle(
color: AppColors.lightBlack,
),
),
validator: (value) {
if (value!.isEmpty) {
return 'Required';
} else if (value.length < 6) {
return 'Password must be at least 6 characters';
}
return null;
},
onSaved: (value) {
_passwordController.text = value!;
},
),
),
SizedBox(height: 4.h),
Consumer<ChangePasswordService>(
builder: (context, provider, child) {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
"Update",
style: TextStyle(
fontSize: 22.sp,
color: AppColors.black,
fontWeight: FontWeight.w300),
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: 1.0.h)),
isLoading
? CircularProgressIndicator(
color: AppColors.orange)
: FloatingActionButton(
backgroundColor: AppColors.orange,
onPressed: () async {
final form = _formKey.currentState;
if (!form!.validate()) {
return;
}
setState(() {
isLoading = true;
});
String password =
_passwordController.text.trim();
String? email = user!.email;
ChangePasswordReqModel passwordData =
ChangePasswordReqModel(
email: email,
password: password);
var newPassword = await provider
.changePassword(passwordData);
setState(() {
isLoading = false;
});
if (newPassword?.error != null) {
var snackBar = SnackBar(
content: Text(
newPassword?.error?.message ??
""),
duration: Duration(seconds: 2),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20)),
clipBehavior: Clip.hardEdge,
);
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
} else {
var snackBar = SnackBar(
content: Text(
"Your password has been successfully changed"),
duration: Duration(seconds: 2),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(20)),
clipBehavior: Clip.hardEdge,
);
// ignore: use_build_context_synchronously
ScaffoldMessenger.of(context)
.showSnackBar(snackBar);
}
_passwordController.clear();
},
child: Icon(
Icons.keyboard_arrow_right_sharp))
]);
})
],
),
),
],
),
),
),
),
);
}
AppBar buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
title: Text(
"Change Password",
style: TextStyle(
color: AppColors.lightBlack,
),
),
leading: IconButton(
icon: Icon(Icons.arrow_back, color: AppColors.lightBlack),
onPressed: () => Navigator.of(context).pop(),
),
);
}
}

Flutter gives error message "Missing concrete implementation of 'State.build" in spite of declaring the override

Error message :
Missing concrete implementation of 'State.build'.
Try implementing the missing method, or make the class abstract.
I get the above error for class _ResetPasswordViewState which is located on Line 13 , in the code below. I get the error message in spite of writing the code for that override. I started getting the error on writing the code for Future passwordReset(), which starts on Line 22. Can someone tell me the mistake I did .
This is the code of my Password Reset file.
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:secure_pass/services/auth/auth_exceptions.dart';
import 'package:secure_pass/utilities/dialogs/error_dialog.dart';
class ResetPasswordView extends StatefulWidget {
const ResetPasswordView({Key? key}) : super(key: key);
#override
State<ResetPasswordView> createState() => _ResetPasswordViewState();
}
class _ResetPasswordViewState extends State<ResetPasswordView> {
final _email = TextEditingController();
#override
void dispose() {
_email.dispose();
super.dispose();
}
Future passwordReset() async{
try {
await FirebaseAuth.instance.sendPasswordResetEmail(email: _email.text);
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content : Text('Password reset link sent! Check your email'),
);
}
);
} on UserNotFoundAuthException {
await showErrorDialog(
context,
'User not found',
);
} on InvalidEmailAuthException {
await showErrorDialog(
context,
'This is an invalid email address',
);
} on GenericAuthException {
await showErrorDialog(
context,
'Please try again',
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurple[200],
elevation: 0,
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.symmetric(horizontal: 23.0),
child: Text(
"Enter your Email and we will send you a password reset link",
textAlign: TextAlign.center,
),
),
const SizedBox(height: 10),
//email textfield
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Container(
decoration: BoxDecoration(
color: Colors.grey[200],
border: Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(12),
),
child: Padding(
padding: const EdgeInsets.only(left: 20.0),
child: TextField(
controller: _email,
enableSuggestions: false,
autocorrect: false,
keyboardType: TextInputType.emailAddress,
decoration: const InputDecoration(
hintText: 'Enter your email here',
border: InputBorder.none
),
),
),
),
),
const SizedBox(height: 10),
MaterialButton(
onPressed: passwordReset,
child: Text('Reset Password'),
color: Colors.deepPurple[200],
),
],
),
);
}
}
}
Because you have put you build Widget method inside another method which is the reset password and the stateful widget is looking for the build method in the first stage to run it . i know you did it by mistake and you forgot a } at the end of the fucntion of the reset password, just add it and you will be good to go !

The following _CastError was thrown building NoteAdder(dirty, state: _NoteAdder#76214):Null check operator used on a null value

The error (given in the title) was thrown when I ran the app.
Here is my code
class NoteAdder extends StatefulWidget {
#override
_NoteAdder createState() => _NoteAdder();
}
class _NoteAdder extends State<NoteAdder> {
Note? note;
TextEditingController titleController = TextEditingController();
TextEditingController descriptionController = TextEditingController();
#override
Widget build(BuildContext context) {
titleController.text = note!.title!;
descriptionController.text = note!.description!;
return AlertDialog(
backgroundColor: Colors.lime,
content: Column(
children: [
const Text(
'ADD NOTE',
style: TextStyle(fontSize: 25),
),
const SizedBox(height: 30),
Container(
alignment: Alignment.topLeft,
child: const Text('Title:'),
),
TextField(
controller: titleController,
decoration: InputDecoration(
border: UnderlineInputBorder(),
),
),
const SizedBox(height: 30),
Container(
alignment: Alignment.topLeft,
child: const Text('Description:'),
),
TextField(
controller: descriptionController,
maxLines: 13,
decoration: InputDecoration(
border: UnderlineInputBorder(),
),
),
const SizedBox(height: 35),
Container(
alignment: Alignment.center,
child: ElevatedButton(
style: ElevatedButton.styleFrom(primary: Colors.red),
onPressed: () {
setState(() {
save();
});
},
child: const Text('Save')))
],
));
}
void save() async {
note?.date = DateFormat.yMMMd().format(DateTime.now()) as DateTime?;
if (note?.id != null) {
await NoteDatabaseHelper.update(note!)??0;
} else {
await NoteDatabaseHelper.insert(note!)??0;
}
}
}
I am a bit new to flutter. Please help me to solve this problem
Link to my complete project: https://github.com/SayanBanerjee09082002/Daily_Utility
Note: The add screen appears when I press a floating action button. The app runs ok until I hit that button.
Since you wrote Note? note;, note == null so trying to use it with null check like this note?.date = DateFormat.yMMMd().format(DateTime.now()) as DateTime?; will throw error. Now I don't know what the constructor of your class Note look like so my answer may not be accurate; but as answer, I will advice you to do either:
Note? note = Note(); //I don't know the structure of the constructor, so you have to deal with that part
or inside save()
if(note != null) {
note.date = DateFormat.yMMMd().format(DateTime.now()) as DateTime;
}

Firebase Infinite Loading after Login/Register

so i am working on an app which uses firebase.
But I am having an issue although this has been solved that doesnt seem to help me. My loading screen goes to infinite loading after login/register.
Login Code
import 'package:flutter/material.dart';
import 'package:studo/services/auth.dart';
import 'package:studo/shared/constants.dart';
import 'package:studo/shared/loading.dart';
class SignIn extends StatefulWidget {
final Function toggleView;
SignIn({this.toggleView});
#override
_SignInState createState() => _SignInState();
}
class _SignInState extends State<SignIn> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
String error = '';
bool loading = false;
// text field state
String email = '';
String password = '';
#override
Widget build(BuildContext context) {
return loading
? Loading()
: Scaffold(
body: SingleChildScrollView(
child: Center(
child: Container(
padding:
EdgeInsets.symmetric(vertical: 20.0, horizontal: 50.0),
child: Form(
key: _formKey,
child: Column(
children: <Widget>[
SizedBox(height: 30.0),
CircleAvatar(
backgroundImage: AssetImage('assets/login.png'),
backgroundColor: Colors.transparent,
radius: 150,
),
TextFormField(
decoration: textInputDecoration.copyWith(
hintText: 'Email',
hintStyle: TextStyle(color: Colors.purple)),
validator: (val) =>
val.isEmpty ? 'Enter an email' : null,
onChanged: (val) {
setState(() => email = val);
},
),
SizedBox(height: 20.0),
TextFormField(
obscureText: true,
decoration: textInputDecoration.copyWith(
hintText: 'Password',
hintStyle: TextStyle(color: Colors.purple)),
validator: (val) => val.length < 6
? 'Enter a password 6+ chars long'
: null,
onChanged: (val) {
setState(() => password = val);
},
),
SizedBox(height: 20.0),
RaisedButton(
color: Colors.purple,
child: Text(
'Login',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if (_formKey.currentState.validate()) {
setState(() => loading = true);
dynamic result =
await _auth.signInWithEmailAndPassword(
email, password);
if (result == null) {
setState(() {
loading = false;
error =
'Could not sign in with those credentials';
});
}
}
}),
SizedBox(height: 12.0),
Text(
error,
style: TextStyle(color: Colors.red, fontSize: 14.0),
),
GestureDetector(
onTap: () {
Navigator.pushReplacementNamed(
context, '/register');
},
child: Text(
'Dont have an acoount Sign Up',
style: TextStyle(color: Colors.purple),
),
),
],
),
),
),
),
),
);
}
}
Loading.dart code
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
class Loading extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: Center(
child: Column(
children: [
SizedBox(height: 50,),
SpinKitChasingDots(
color: Colors.purple,
size: 50.0,
),
SizedBox(height: 70,),
Text('Please Exit the App and then Open Again Due to an issue. The Home Page will Load again',
style: TextStyle(fontSize: 10),
)
],
),
),
);
}
}
A help would be greatly appreciated.
i think i am wrong with the on pressed part but i cant possibly figure that out. PLease help me
In your onPressed you are only handling the result == null. You should also handle when you have a result, such that you can go to a next page when returned result is logged in, or set loading = false.
This can be done with an else statement, because if result != null you want to handle the result.
The result should be of the class UserCredential, which contains the User class.
It could be that the email or password is incorrect, you want to handle these cases as well, good practice is to do this in a try-catch block. Example from firebase
try {
UserCredential userCredential = await
FirebaseAuth.instance.signInWithEmailAndPassword(
email: "barry.allen#example.com",
password: "SuperSecretPassword!"
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
print('No user found for that email.');
} else if (e.code == 'wrong-password') {
print('Wrong password provided for that user.');
}
}
You've returned the loading screen only, so it will of course be in infinite loop. Return your Home page instead.

Flutter Textform Validation not showing up

I have watched a couple of tutorials on how to make validators work but none of them seemed to work. Can anyone help me with this? This is the code of a simple sign in page. My validators don't show up on screen if there's any sort of error it should be detecting. I've watched tutorials where it shows up in red but in my app, it doesn't show up at all.
class UserLogin extends StatefulWidget {
UserLogin({this.auth,this.onSignedIn});
final BaseAuth auth;
final VoidCallback onSignedIn;
#override
State<StatefulWidget> createState()=> _UserLoginState();
}
class _UserLoginState extends State<UserLogin> {
final formkey = GlobalKey<FormState>();
bool _validateAndSave()
{
final form = formkey.currentState;
if(form.validate())
{
form.save();
return true;
}
else
return false;
}
static final incorrect_icon = Icon(
Icons.error,
color: Colors.pink,
);
void _validateAndSubmit() async
{
if(_validateAndSave()) {
try {
String userId = await widget.auth.signIn(emailid, password);
print('Signed in! $userId');
//widget.onSignedIn();
Navigator.push(context, MaterialPageRoute(builder: (context)=>Feed()));
}
catch (e) {
print('Error: $e');
}
}
}
static final TextEditingController emailContr = new TextEditingController();
static final TextEditingController passwordContr = new TextEditingController();
static String get emailid => emailContr.text;
static String get password => passwordContr.text;
final _email = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
controller: emailContr,
autofocus: false,
validator: (input) {
if(input.isEmpty)
{
return 'Email cannot be empty';
}
return null;
},
//onSaved: (input)=> emailid = input,
decoration: InputDecoration(
hintText: 'Enter Email Address',
suffixIcon: Icon(Icons.email),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
final _pass = Container(
padding: EdgeInsets.only(left: 10, right: 10),
child: TextFormField(
controller: passwordContr,
obscureText: true,
autofocus: false,
validator: (input) {
if(input.length <= 6)
{
return 'Password should be at least 6 characters';
}
return null;
},
decoration: InputDecoration(
hintText: 'Enter password',
suffixIcon: Icon(Icons.lock),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10)
),
),
),
);
/*final login_button =
},
);
*/
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.yellow,
body: Container(
child: Form(
key: formkey,
child: Column(
children: <Widget>[
SizedBox(height: 200,),
Text('Vibing',
style:TextStyle(
fontWeight: FontWeight.bold,
fontSize: 64,
),
),
SizedBox(height: 100,),
_email,
SizedBox(height: 20,),
_pass,
SizedBox(height:30),
RaisedButton(
color: Colors.yellow,
elevation: 5,
child: Text('Login'),
onPressed: (){
_validateAndSubmit();
formkey.currentState.reset();
}
),
SizedBox(height:10),
FlatButton(
child: Text('Forgot password'),
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder:(context)=>ForgotPassword()),)
),
SizedBox(height:10),
FlatButton(
child: Text('New? Register here!'),
onPressed: ()=> Navigator.push(context, MaterialPageRoute(builder:(context)=>UserReg()),)
),
],
),
),
) ,
);
}
}
The problem is that you're resetting the form after validation so any error shown will reset. Just remove this line from your login button callback:
formkey.currentState.reset();
And voila:
reset():
Resets every [FormField] that is a descendant of this [Form] back to its
[FormField.initialValue].
In your case, the initialValue is empty string "" and that's why when you called reset() method of Form, it's setting an empty string, that will not show any error, as nothing is there.