Firebase Infinite Loading after Login/Register - flutter

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.

Related

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

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.

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

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

Enable Button on flutter only if Checkbox is " checked"

Hello guys I have registration form with checkbox to be enabled in order to allow registration.
I need my user to do checkbox checked to have button enabled otherwise an tooltip will be shown.. like... " u need to accept terms and condition to register... "
This is the part of the CheckBox:
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Theme(
data: ThemeData(unselectedWidgetColor: Colors.white,),
child: Checkbox(
focusColor: Colors.lightBlue,
activeColor: Colors.orange,
value: rememberMe,
onChanged: (newValue) {
setState(() {
rememberMe = (newValue);
});
},
),
),
RichText(
text: TextSpan(children: [
TextSpan(
text: 'Accetto le condizioni e ',
style: TextStyle(fontSize: 10),
),
TextSpan(
text: 'il trattamento dei dati personali ',
style: TextStyle(fontSize: 10,decoration: TextDecoration.underline,),
),
]),
)
],
),
and this the "registration Button"
ButtonTheme(
minWidth: 100,
height: 50.0,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
elevation: 10,
onPressed: () async {
setState(() {
showSpinner = true;
});
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
setState(() {
showSpinner = false;
});
} catch (e) {
print(e);
}
},
color: Color(0xFF1f2032),
child: Text(
'SIGNUP',
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
),
There are certain things which I would like to give you an insight about. Which will help you surely, so follow along.
Pointers
Read upon Flutter Form and it's Validation, which answers your question on showing up the error message under your forms for the validations
One very useful widget to achieve what you want is Flutter Tooltip Unfortunately, you cannot bring up the tooltip which you wanted to do programmatically
Workaround: Do use any of these to show up you message
Snackbar Flutter
Flutter AlerDialog
Simply show up a text, like a validator for the form under the checkbox like I will demonstrate in the code for you
Now, I have demonstrated both of them in this code, but the code is not similar. It would be enough to you let you know the best practices you can do along with your tooltip message showcase
Please note: To make a tooltip like structure using Container(), you can follow this answer, will help you in a great extent
class _MyHomePageState extends State<MyHomePage> {
bool rememberMe = false;
// this bool will check rememberMe is checked
bool showErrorMessage = false;
//for form Validation
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: TextFormField(
validator: (value) {
// retiurning the validator message here
return value.isEmpty ? "Please enter the message" : null;
}
)
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('Accept Terms & Conditions'),
SizedBox(width: 20.0),
Checkbox(
focusColor: Colors.lightBlue,
activeColor: Colors.orange,
value: rememberMe,
onChanged: (newValue) {
setState(() => rememberMe = newValue);
}
)
]
),
// based up on this bool value
showErrorMessage ?
Container(
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(80.0)
),
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text('Please accept the terms and conditions to proceed...')
)
)
: Container(),
SizedBox(height: 20.0),
RaisedButton(
child: Text('Submit'),
onPressed: (){
// for your form validation
if(_formKey.currentState.validate()){
// do your success operation here!
// checking for the rememberValue
// and setting the message bool data
if(rememberMe != true)
setState(() => showErrorMessage = true);
else
setState(() => showErrorMessage = false);
}
}
)
]
)
)
);
}
}
How it works?
It will first check whether the form is empty, if it not, then checks whether the checkbox is empty or not
Fun Fact
You can use the above logic or bool showErrorMessage, to show anything, be it, SnackBar, AlertDialog or the message which I showed in the above code.
Result
You need to pass null to the onPressed of a Button to make it disabled. So you'll need to pass null to the onPressed of the RaisedButton when rememberMe is false.
ButtonTheme(
minWidth: 100,
height: 50.0,
child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
elevation: 10,
onPressed: rememberMe ? () async {
setState(() {
showSpinner = true;
});
try {
final newUser =
await _auth.createUserWithEmailAndPassword(
email: email, password: password);
if (newUser != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
}
setState(() {
showSpinner = false;
});
} catch (e) {
print(e);
}
} : null, // make it null if false
color: Color(0xFF1f2032),
child: Text(
'SIGNUP',
style: TextStyle(fontSize: 18, color: Colors.white),
),
),
),

How to start something automatically in flutter

I have the following code that initially displays a blank page, but I'd like an rAlert dialog to display automatically. Once the user clicks 'Request' or 'Cancel', some text will be displayed on the screen.
But I can't get the code to run that displays the Alert. I had it working by showing a button and clicking the button, but i need the Alert to display automatically when the page is displayed. I tried putting it in the initState. I didn't get any errors, but it didn't work either.
Anyone know what I need to do? Thanks?
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'dart:async';
import 'package:rostermeon/cwidgets/general_widgets.dart';
import 'package:rostermeon/rmo_constants.dart';
class ForgotPassword extends StatefulWidget {
static const String id = 'forgot_password_screen';
#override
_ForgotPasswordState createState() => _ForgotPasswordState();
}
class _ForgotPasswordState extends State<ForgotPassword> {
StreamController<bool> _events;
#override
initState() {
super.initState();
_events = new StreamController<bool>();
doRequest(context: context);
}
Future<bool> doSaveRequest({String pReason}) async {
await Future.delayed(const Duration(seconds: 3), () {});
return false;
}
Future<bool> doRequest({context}) {
String _reason = '';
GlobalKey<FormState> _formKey = GlobalKey<FormState>();
TextEditingController reasonController = TextEditingController();
TextStyle _style = TextStyle(fontFamily: 'Montserrat', fontSize: 18.0, fontWeight: FontWeight.normal);
InputDecoration _textFormFieldDecoration({String hintText, double padding}) => InputDecoration(
//contentPadding: EdgeInsets.fromLTRB(8.0, 8.0, 8.0, 8.0),
contentPadding: EdgeInsets.all(padding),
isDense: true,
hintText: hintText,
hintStyle: TextStyle(color: kHintText),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
);
return Alert(
context: context,
title: 'Request New Password',
content: StreamBuilder<bool>(
initialData: false,
stream: _events.stream,
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
print(" ${snapshot.data.toString()}");
return snapshot.data
? CircularProgressIndicator()
: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 20.0),
Text('Email', textAlign: TextAlign.left, style: _style),
SizedBox(height: 10.0),
TextFormField(
validator: (value) {
if (value.isEmpty) {
return "please enter email";
}
return null;
},
onSaved: (value) {
_reason = value;
},
decoration: _textFormFieldDecoration(
hintText: 'your email address',
padding: 8.0,
),
controller: reasonController,
),
SizedBox(height: 10.0),
],
),
);
}),
buttons: [
DialogButton(
child: Text('Request', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () async {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print(_reason);
_events.add(true);
var saved = await doSaveRequest(pReason: _reason);
if (saved) {
Navigator.pop(context, false);
} else {
_events.add(false);
}
Navigator.of(context).pop();
// Navigator.pop(context, false);
}
},
),
DialogButton(
child: Text('Cancel', style: TextStyle(color: Colors.white, fontSize: 20)),
color: kMainColor,
onPressed: () {
Navigator.pop(context, false);
},
),
],
).show();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: rmoAppBar(subText: 'Request New Password', hideBackButton: false),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[],
),
),
);
}
}
Dialogs/Alerts need the buildContext in order to work, You can't have the buildContext before build() method is called, that's why you can't just call it in initstate() before the build is called.
To make it work use addPostFrameCallback to make sure it delays until widget is built:
void initState() {
super.initState();
WidgetsBinding.instance
.addPostFrameCallback((_) => yourMethod(context));
}
https://www.didierboelens.com/2019/04/addpostframecallback/

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.