Unhandled Exception: Looking up a deactivated widget's ancestor is unsafe - flutter

The code below worked well previously but unsure how this error is coming up.
class LoginScreen extends StatelessWidget {
// const LoginScreen({Key key}) : super(key: key);
static const String idScreen = "login";
final TextEditingController nameTextEditingController =
TextEditingController();
final TextEditingController phoneTextEditingController =
TextEditingController();
final TextEditingController passwordTextEditingController =
TextEditingController();
final TextEditingController emailTextEditingController =
TextEditingController();
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
SizedBox(
height: 35.0,
),
Image(
image: AssetImage("images/images/logo.png"),
width: 390.0,
height: 350.0,
alignment: Alignment.center,
),
SizedBox(
height: 1.0,
),
Text(
"Login as Driver",
style: TextStyle(fontSize: 24, fontFamily: "Brand Bold"),
textAlign: TextAlign.center,
),
Padding(
padding: EdgeInsets.all(20.0),
child: Column(
children: [
SizedBox(
height: 1.0,
),
TextField(
controller: emailTextEditingController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "Email",
labelStyle: TextStyle(
fontSize: 18.0,
),
),
style: TextStyle(fontSize: 18.0),
),
SizedBox(
height: 1.0,
),
TextField(
controller: passwordTextEditingController,
obscureText: true,
decoration: InputDecoration(
labelText: "Password",
labelStyle: TextStyle(
fontSize: 18.0,
),
),
style: TextStyle(fontSize: 14.0),
),
SizedBox(height: 10.0),
ElevatedButton(
//color: Colors.pink[200],
//textColor: Colors.white,
child: Container(
height: 50.0,
child: Center(
child: Center(
child: Text(
"Login",
style: TextStyle(
fontSize: 18.0, fontFamily: "Brand-Bold"),
),
),
),
),
//shape: new RoundedRectangleBorder(
// borderRadius: new BorderRadius.circular(24.0)),
onPressed: () {
if (!emailTextEditingController.text.contains("#")) {
displayToastMessage(
"Email address is not valid", context);
} else if (passwordTextEditingController.text.isEmpty) {
displayToastMessage("password is not valid", context);
} else {
loginUser(context);
}
},
),
],
),
),
TextButton(
onPressed: () {
Navigator.pushNamedAndRemoveUntil(
context, RegistrationScreen.idScreen, (route) => false);
},
child: Text(
"Account not found, Please register",
style: TextStyle(color: Colors.black),
),
),
],
),
),
),
);
}
void loginUser(BuildContext context) async {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return ProgressDialog(
message: "Authenticating, Please wait...",
);
});
final User? firebaseUser = (await _firebaseAuth
.signInWithEmailAndPassword(
email: emailTextEditingController.text,
password: passwordTextEditingController.text)
.catchError((errMsg) {
Navigator.pop(context);
displayToastMessage("Error: " + errMsg.toString(), context);
}))
.user;
if (firebaseUser != null) {
driversRef.child(firebaseUser.uid).once().then((DatabaseEvent event) {
if (event.snapshot.value != null) {
Navigator.pushNamedAndRemoveUntil(
context, MainScreen.idScreen, (route) => false);
displayToastMessage("You are logged in", context);
} else {
Navigator.pop(context);
_firebaseAuth.signOut();
displayToastMessage(
"No record exists for this user, please create a new account",
context);
}
});
} else {
Navigator.pop(context);
displayToastMessage("An error occured, cannot sign in", context);
}
}
}
I read other similar question but using the Navigator.pushNamedAndRemoveUntil in the dispose method. unsure how to do it.
The error points out at
Navigator.pushNamedAndRemoveUntil( //here
context, MainScreen.idScreen, (route) => false);
displayToastMessage("You are logged in", context);
} else {

You are calling the displayToastMessage with the context of a widget that has been removed from the tree and its context is no longer valid. For example here
Navigator.pushNamedAndRemoveUntil(context, MainScreen.idScreen, (route) => false);
displayToastMessage("You are logged in", context);
You are navigating to other screen and removing the current widget from the tree. In the next line you are calling displayToastMessage using the context of current widget which is already deactivated. The same problem occurs when using the Navigator.pop before displayToastMessage.
A solution is to call the displayToastMessage before navigating.
displayToastMessage("You are logged in", context);
Navigator.pushNamedAndRemoveUntil(context, MainScreen.idScreen, (route) => false);
Alternatively, you can call the displayToastMessage from the widget that you are navigating to.

Related

Duplicate global key detected in widget tree

I am facing a problem duplicate global key detected in widget tree when I use static keyword with global key.
If I don't use this static keyword then keyboard hides automatically after few seconds. What should I do?
This is the code that I have tried
`import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:email_validator/email_validator.dart';
import 'package:semesterproject/forgetpassword.dart';
import 'package:semesterproject/home.dart';
import 'package:semesterproject/signup.dart';
import 'package:semesterproject/textfielddec.dart';
class login extends StatelessWidget {
const login({super.key});
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
Colors.purpleAccent,
Colors.lightBlue,
Colors.indigoAccent
]),
),
child: Scaffold(
backgroundColor: Colors.transparent,
body: Center(
child: Container(
height: MediaQuery.of(context).size.height * 0.7,
width: MediaQuery.of(context).size.width * 0.8,
child: CustomForm(),
))),
);
}
}
class CustomForm extends StatefulWidget {
const CustomForm({super.key});
#override
State<CustomForm> createState() => _CustomFormState();
}
class _CustomFormState extends State<CustomForm> {
static final _formkey = GlobalKey<FormState>();
final TextEditingController passcontroller = TextEditingController();
final TextEditingController emailcontroller = TextEditingController();
bool passvisibility = true;
FirebaseAuth _auth = FirebaseAuth.instance;
var errormessage1 = null, errormessage2 = null;
void setpassvisibility() {
setState(() {
passvisibility = !passvisibility;
});
}
Future<void> login() async {
if (_formkey.currentState!.validate()) {
_formkey.currentState!.save();
try {
await _auth
.signInWithEmailAndPassword(
email: emailcontroller.text, password: passcontroller.text)
.then((value) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Homepage(),
)));
} on FirebaseAuthException catch (error) {
if (error.code == 'wrong-password') {
setState(() {
errormessage1 = "Incorrect Password!";
});
} else {
setState(() {
errormessage1 = null;
});
}
if (error.code == 'user-not-found') {
setState(() {
errormessage2 = "User email not found";
});
} else {
setState(() {
errormessage2 = null;
});
}
}
}
}
#override
Widget build(BuildContext context) {
return Form(
key: _formkey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
"Login to your Account",
style: TextStyle(
fontSize: 31,
fontWeight: FontWeight.bold,
color: Colors.cyanAccent),
),
SizedBox(
width: MediaQuery.of(context).size.width,
child: TextFormField(
controller: emailcontroller,
style: TextStyle(fontSize: 22),
decoration: InputDecoration(
errorText: errormessage2,
focusedBorder: getfocusedborder(),
enabledBorder: getenabledborder(),
errorBorder: geterrorborder(),
focusedErrorBorder: geterrorfocusedborder(),
hintText: "Email",
hintStyle: TextStyle(fontSize: 22),
errorStyle: TextStyle(fontSize: 18),
),
validator: (value) {
if (value!.isEmpty) return "this field is required";
if (EmailValidator.validate(value) == false)
return "Please enter a valid email";
return null;
},
),
),
SizedBox(
width: MediaQuery.of(context).size.width,
child: TextFormField(
style: TextStyle(fontSize: 22),
controller: passcontroller,
obscureText: passvisibility,
decoration: InputDecoration(
errorText: errormessage1,
focusedBorder: getfocusedborder(),
enabledBorder: getenabledborder(),
errorBorder: geterrorborder(),
focusedErrorBorder: geterrorfocusedborder(),
hintText: "Password",
hintStyle: TextStyle(fontSize: 22),
errorStyle: TextStyle(fontSize: 18),
suffixIcon: IconButton(
onPressed: setpassvisibility,
icon: passvisibility
? Icon(
Icons.visibility_off,
color: Colors.black,
)
: Icon(Icons.visibility),
color: Colors.black,
)),
validator: (value) {
if (value!.isEmpty) return "this field is required";
return null;
},
),
),
InkWell(
child: Text("Forgot password?",
style: TextStyle(color: Colors.amberAccent, fontSize: 22)),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => forgetpass(),
)),
),
SizedBox(
width: 280,
height: 50,
child: ElevatedButton(
onPressed: () => login(),
child: Text(
"Login",
style: TextStyle(fontSize: 22),
),
style: ElevatedButton.styleFrom(backgroundColor: Colors.indigo),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Don't have an account?",
style: TextStyle(fontSize: 22, color: Colors.amberAccent),
textAlign: TextAlign.center,
),
InkWell(
child: Text("Signup",
style: TextStyle(color: Colors.amber, fontSize: 20)),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Signup(),
)),
)
],
),
],
),
);
}
}`
I have go through with different posts of this error but I can't get the solution

I am trying to handle exceptions in my login page but its not working

I am trying to handle exceptions in my LoginView but its not working (It does not print it out to the user in the dialogue box. I don't know if I am missing something).
This is where I am trying to implement the exceptions in my LoginView.
Future loginCatch() async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _email.text.trim(),
password: _password.text.trim(),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content: Text('User not found'),
);
},
);
} else if (e.code == 'wrong-password') {
print('wrong password');
}
;
}
}
This is my LoginView:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:thehunt/constants/routes.dart';
import 'package:thehunt/views/forgot_password_view.dart';
class LoginView extends StatefulWidget {
final VoidCallback showRegisterView;
const LoginView({super.key, required this.showRegisterView});
#override
State<LoginView> createState() => _LoginViewState();
}
class _LoginViewState extends State<LoginView> {
//text controllers
late final TextEditingController _email;
late final TextEditingController _password;
Future logIn() async {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _email.text.trim(),
password: _password.text.trim(),
);
}
#override
void initState() {
_email = TextEditingController();
_password = TextEditingController();
super.initState();
}
#override
void dispose() {
_email.dispose();
_password.dispose();
super.dispose();
}
Future loginCatch() async {
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _email.text.trim(),
password: _password.text.trim(),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'user-not-found') {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content: Text('User not found'),
);
},
);
} else if (e.code == 'wrong-password') {
print('wrong password');
}
;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[300],
body: SafeArea(
child: Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'Welcome to The Hunt',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 30,
),
),
SizedBox(height: 36),
//email field
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(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Enter your email here',
),
controller: _email,
enableSuggestions: false,
autocorrect: false,
keyboardType: TextInputType.emailAddress,
),
),
),
),
const SizedBox(height: 10),
//password field
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(
decoration: const InputDecoration(
border: InputBorder.none,
hintText: 'Enter your password ',
),
controller: _password,
obscureText: true,
enableSuggestions: false,
autocorrect: false,
),
),
),
),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 25.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return ForgotPasswordView();
},
),
);
},
child: Text(
'Forgot your password?',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
],
),
),
//login button
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: 25.0,
),
child: GestureDetector(
onTap: logIn,
child: Container(
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.deepPurple,
borderRadius: BorderRadius.circular(12),
),
child: const Center(
child: Text(
'Login',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
)),
),
),
),
const SizedBox(height: 36),
// register now
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
GestureDetector(
//onTap: widget.showRegisterPage,
child: Text(
'Not registered yet?',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
GestureDetector(
onTap: widget.showRegisterView,
child: Text(
' Register now',
style: TextStyle(
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
],
)
// TextButton(
// onPressed: () {
// Navigator.of(context).pushNamedAndRemoveUntil(
// registerRoute,
// (route) => false,
// );
// },
// child: const Text('Not registered yet? Register here'),
// )
],
),
),
),
),
);
}
}
Please could someone show me how to do it?
Try the following code:
try {
await FirebaseAuth.instance.signInWithEmailAndPassword(
email: _email.text.trim(),
password: _password.text.trim(),
);
} on FirebaseAuthException catch (e) {
showDialog(
context: context,
builder: (context) {
return const AlertDialog(
content: Text(e.toString().split("] ")[1]),
);
},
);
}

StreamProvider is not responding to changed value of stream

I am making a flutter application where i need to register into firebase.
First I have SignInPage() which uses Navigator to redirect to ResidentRegister().Here is the form for registering into the application. The problem is the ResidentRegister() page is not getting redirected to HomeScreen() upon successful Authentication of the user. The user is properly registered into the firebase and HomeScreen() appears after hotrestart of the application. I have used StreamProvider for the purpose which should listen to a stream of type 'Resident' which is my User data model based on whether it is null or not in the Wrapper() class. In the 'Wrapper' class, the stream is getting 'instance of resident'(when I print the value of resident variable), but the else block is not getting executed. This is probably happening due to usage of Navigator as when I remove the first screen that is SignInPage(), the ResidentRegister() screen is successfully getting redirected to HomeScreen(). I don't know why this happens as I have wrapped the MaterialApp to StreamProvider widget.
Any help would be appreciated
Thanks!
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamProvider<Resident>(
create: (_)=> AuthService().resident,
child: Consumer<Resident>(
builder: (context, resident, _)
{
return MaterialApp(
home: (user != null) ? HomeScreen() : SignInPage(),
);
},
),
);
}
}
class SignInPage extends StatelessWidget {
SignInPage({this.title});
final String title;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('JNMCH eLogBook'),
centerTitle: true,
),
body: SizedBox.expand(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('Sign In',
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.w300,
fontSize: 65,
),),
SizedBox(height: 35,),
CustomButton(text: 'Sign In as a Resident', onPressed: ()=> Navigator.pushNamed(context, '/residentRegister')),
SizedBox(height:8.0),
CustomButton(text: 'Sign In as a Mentor', onPressed: () => Navigator.pushNamed(context,'/mentorSignIn')),
],
),
),
);
}
}
class ResidentRegister extends StatefulWidget {
#override
_ResidentRegisterState createState() => _ResidentRegisterState();
}
class _ResidentRegisterState extends State<ResidentRegister> {
final AuthService _auth = AuthService();
final _formKey = GlobalKey<FormState>();
String _email;
String _password;
String _confirmPassword;
String _error = '';
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: Text('Register as a Resident'),
),
body: SingleChildScrollView(
child: Stack(
children: <Widget>[
Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 80.0, horizontal: 40.0),
child: Card(
color: Colors.white,
elevation: 8.0,
child: Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
SizedBox(height: 20,),
Text('Register',
style: TextStyle(
color: Colors.teal,
fontWeight: FontWeight.w300,
fontSize: 65,
),
),
SizedBox(height: 35,),
TextFormField(
validator: (val) => val.isEmpty ? 'Enter an email' : null,
decoration: InputDecoration(
hintText: 'Email'
),
onChanged: (value) {
setState(() {
_email = value;
});
},
),
SizedBox(height: 20,),
TextFormField(
validator: (val) => val.length < 6 ? 'Enter a password 6+ char long' : null,
decoration: InputDecoration(
hintText: 'Password'
),
obscureText: true,
onChanged: (value) {
setState(() {
_password = value;
});
},
),
SizedBox(height: 20,),
TextFormField(
validator: (val) => val!=_password ? 'Confirm Password must be same as password' : null,
decoration: InputDecoration(
hintText: 'Confirm Password'
),
obscureText: true,
onChanged: (value) {
setState(() {
_confirmPassword = value;
});
},
),
SizedBox(height: 20,),
Padding(
padding: const EdgeInsets.all(0),
child: ButtonTheme(
minWidth: 150,
height: 50,
child: RaisedButton(onPressed: () async {
if(_formKey.currentState.validate()){
dynamic result = await _auth.register( _email,_password);
if(result == null){
setState(() {
_error = 'Please supply a valid email';
});
}
}
},
color: Colors.teal,
child:
Text(
'Submit',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20,),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(28.0),
side: BorderSide(color: Colors.teal[100]),
),
),
),
),
SizedBox(height: 20,),
Text(_error, style: TextStyle(
fontSize: 14.0,
color: Colors.red,
),),
SizedBox(height: 20,),
FlatButton(
color: Colors.white,
textColor: Colors.grey[600],
disabledColor: Colors.black,
disabledTextColor: Colors.black,
padding: EdgeInsets.all(8.0),
splashColor: Colors.teal,
onPressed: () {
Navigator.pop(context);
},
child: Text(
"Already have an account? Sign In!",
style: TextStyle(fontSize: 16.0),
),
)
],
),
),
),
),
),
],
),
),
);
}
}
class HomeScreen extends StatefulWidget {
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final AuthService _auth = AuthService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
actions: <Widget> [
FlatButton.icon(
onPressed: ()async {
await _auth.signOut();
},
icon: Icon(Icons.person,color: Colors.white,),
label: Text('Sign Out', style: TextStyle(color: Colors.white),)),
],
),
);
}
}
class AuthService{
final FirebaseAuth _auth = FirebaseAuth.instance;
// create resident user object based on Firebase User
Resident _residentFromFirebaseUser(FirebaseUser user){
return user!=null ? Resident(uid: user.uid) : null;
}
//auth change user stream
Stream<Resident> get resident {
return _auth.onAuthStateChanged
.map(_residentFromFirebaseUser);
}
//register with email and password
Future register(String email, String password) async{
try{
AuthResult result = await _auth.createUserWithEmailAndPassword(email: email, password: password);
FirebaseUser user = result.user;
print(user);
return _residentFromFirebaseUser(user);
}catch(e){
print(e.toString());
return null;
}
}
//sign out
Future signOut() async{
try{
return await _auth.signOut();
}catch(e){
print(e.toString());
return null;
}
}
}
class Resident{
final String uid;
Resident({ this.uid });
}
I believe you're using StreamProvider incorrectly. It shouldn't be:
StreamProvider<Resident>.value(value: ...)
Instead, try using:
StreamProvider<Resident>(
create: (_) => AuthService().resident,
child: Consumer<Resident>(
builder: (context, resident, _) {
// TODO: return home page or sign in page based on data
},
),
);
That should subscribe to the stream and rebuild on new events.

Bottom Navigation bar disappears on sign in, but returns when I go to another page and back?

I am trying to create an app that will show the user a generic homepage with products and give them the option to navigate to an account page where, if they are not signed in they will be shown a sign in/sign up page or if they have signed in, they will be shown their profile.
I have managed to get the sign in/sign out part working, but when I sign in and navigate to the profile page, my bottom navigation bar disappears. However, when I navigate to another page and back, it reappears.
Here is my home.dart file which controls navigation for my app:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
PageController _pageController = PageController();
List<Widget> _screens = [HomePage(), InboxPage(), AccountController()];
int _selectedIndex = 0;
void _onPageChanged(int index) {
setState(() {
_selectedIndex = index;
});
}
void _onItemTapped(int selectedIndex) {
_pageController.jumpToPage(selectedIndex);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView(
controller: _pageController,
children: _screens,
onPageChanged: _onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
bottomNavigationBar: BottomNavigationBar(onTap: _onItemTapped, items: [
BottomNavigationBarItem(
icon: Icon(
Icons.home,
color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
),
title: Text(
'Home',
style: TextStyle(
color: _selectedIndex == 0 ? Colors.blueAccent : Colors.grey,
),
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.email,
color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
),
title: Text(
'Inbox',
style: TextStyle(
color: _selectedIndex == 1 ? Colors.blueAccent : Colors.grey,
),
),
),
BottomNavigationBarItem(
icon: Icon(
Icons.account_circle,
color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
),
title: Text(
'Account',
style: TextStyle(
color: _selectedIndex == 2 ? Colors.blueAccent : Colors.grey,
),
),
),
]),
);
}
}
My accountcontroller.dart code which helps determine whether a user is logged in or not:
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 ? ProfileView() : SignUpPage();
}
return CircularProgressIndicator();
});
}
}
My profileview.dart:
class ProfileView extends StatefulWidget {
#override
_ProfileViewState createState() => _ProfileViewState();
}
class _ProfileViewState extends State<ProfileView> {
#override
Widget build(BuildContext context) {
return
Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(80),
child: MainAppBar(
text: 'Account',
)),
body: SingleChildScrollView(
child: Column(
children: <Widget>[
Text('Account Page'),
showSignOut(context),
goToHomepage(context),
],
),
),
);
}
}
Widget showSignOut(context) {
return RaisedButton(
child: Text('Sign Out'),
onPressed: () async {
try {
await Provider.of(context).auth.signOut();
Navigator.pushNamed(context, '/homepage');
print('Signed Out');
} catch (e) {
print(e);
}
});
}
Widget goToHomepage(context) {
return RaisedButton(
child: Text('Go to homepage'),
onPressed: () async {
try {
Navigator.pushNamed(context, '/homepage');
} catch (e) {
print(e);
}
});
}
And finally my signup.dart file which contains my sign up/sign in code:
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();
print('true');
return true;
} else {
print('false');
return false;
}
}
void switchFormState(String state) {
formKey.currentState.reset();
if (state == 'signIn') {
setState(() {
authFormType = AuthFormType.signIn;
});
} else {
setState(() {
authFormType = AuthFormType.signUp;
});
}
}
void submit() async {
final CollectionReference userCollection =
Firestore.instance.collection('UserData');
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);
}
}
}
DateTime selectedDate = DateTime.now();
TextEditingController _date = new TextEditingController();
Future<Null> _selectDate(BuildContext context) async {
DateFormat formatter =
DateFormat('dd/MM/yyyy'); //specifies day/month/year format
final DateTime picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(1901, 1),
builder: (BuildContext context, Widget child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: kPrimaryColor,
onPrimary: Colors.black,),
buttonTheme: ButtonThemeData(
colorScheme: Theme.of(context)
.colorScheme
.copyWith(primary: Colors.black),
),
),
child: child,
);
},
lastDate: DateTime(2100));
if (picked != null && picked != selectedDate)
setState(() {
selectedDate = picked;
_date.value = TextEditingValue(
text: formatter.format(
picked)); //Use formatter to format selected date and assign to text field
});
}
#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 = [];
DateFormat dateFormat = DateFormat("yyyy-MM-dd HH:mm:ss");
if (authFormType == AuthFormType.signIn) {
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Email'),
validator: SignInEmailValidator.validate,
onSaved: (value) => _email = value.trim()));
textFields.add(SizedBox(
height: 15,
));
textFields.add(
TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Password'),
obscureText: true,
validator: SignInPasswordValidator.validate,
onSaved: (value) => _password = value.trim(),
),
);
} 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'),
validator: NameValidator.validate,
onSaved: (value) => _firstName = value,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Last Name'),
onSaved: (value) => _lastName = value,
validator: NameValidator.validate,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Email Address'),
onSaved: (value) => _email = value.trim(),
validator: SignInEmailValidator.validate,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Confirm Email Address'),
onSaved: (value) => _confirmEmail = value,
validator: (confirmation) {
return confirmation == _email
? null
: "Confirm Email Address should match email address";
},
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Password'),
obscureText: true,
onSaved: (value) => _password = value,
));
textFields.add(SizedBox(
height: 15,
));
textFields.add(TextFormField(
style: TextStyle(
fontSize: 12.0,
),
decoration: buildSignUpInputDecoration('Confirm Password'),
onSaved: (value) => _confirmPassword = value,
validator: (confirmation) {
return confirmation == _password
? null
: "Confirm Password should match password";
}));
textFields.add(SizedBox(
height: 15,
));
textFields.add(GestureDetector(
onTap: () => _selectDate(context),
child: AbsorbPointer(
child: TextFormField(
style: TextStyle(fontSize: 12.0),
controller: _date,
keyboardType: TextInputType.datetime,
decoration: InputDecoration(
isDense: true,
fillColor: Colors.white,
hintText: 'Date of Birth',
filled: true,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(width: 0.0),
),
contentPadding:
const EdgeInsets.only(left: 14.0, bottom: 10.0, top: 10.0),
),
onSaved: (value) => _dateOfBirth = value,
),
),
));
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;
}
}
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),
);
}
Any ideas?
The HomePage(), InboxPage() and AccountController() are in your home-widget, which contains the bottomNavigationBar.
Your profile and signup pages are different pages with its own scaffold.
You have to create one central "index" widget wich holds every sub-page and the navigationbar.

Flutter: I got this error > Failed assertion: line 447 pos 12: 'context != null': is not true

I have a widget which is return an alertDialog, and according to the result of the http request, I show another alertDialog. Nut I got the below error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(157)] Unhandled Exception: 'package:flutter/src/widgets/localizations.dart': Failed assertion: line 447 pos 12: 'context != null': is not true.
import 'dart:io';
import 'package:Zabatnee/common_app/provider/user_details_provider.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ForgetPasswordDialog extends StatefulWidget {
static const routeName = '/customeDialog';
final String title,description;
ForgetPasswordDialog({
this.title,
this.description,
});
#override
_ForgetPasswordDialogState createState() => _ForgetPasswordDialogState();
}
class _ForgetPasswordDialogState extends State<ForgetPasswordDialog> {
final emailController = TextEditingController();
var _isLoading = false;
_showDialog(String title, String message) {
showDialog(
barrierDismissible: false,
context: context,
builder: (ctx) => WillPopScope(
onWillPop: () async => false,
child: new AlertDialog(
elevation: 15,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8))),
title: Text(
title,
style: TextStyle(color: Colors.white),
),
content: Text(
message,
style: TextStyle(color: Colors.white),
),
backgroundColor: Theme.of(context).primaryColor,
actions: <Widget>[
FlatButton(
child: Text(
'OK',
style: TextStyle(color: Theme.of(context).accentColor),
),
onPressed: () {
Navigator.of(context).pop();
setState(
() {
_isLoading = false;
},
);
},
)
],
),
),
);
}
Future<void> _forgetPassword (String email) async {
try{
if(mounted)
setState(() {
_isLoading = true;
});
await Provider.of<UserDetailsProvider>(context, listen: false).forgetPassword(email);
print('code are sent via email');
_showDialog('Conguratulations', 'code send successfully');
} on HttpException catch (error) {
_showDialog('Authentication Failed', error.message);
} on SocketException catch (_) {
_showDialog('An error occured',
'please check your internet connection and try again later');
} catch (error) {
_showDialog('Authentication Failed',
'Something went wrong, please try again later');
}
if(mounted)
setState(() {
_isLoading = false;
});
}
#override
void dispose() {
emailController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Dialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16)
),
elevation: 8,
backgroundColor: Theme.of(context).accentColor,
child: dialogContent(context),
);
}
dialogContent(BuildContext context){
return Container(
padding: EdgeInsets.only(
top: 50,
right: 16,
left: 16,
bottom: 16,
),
margin: EdgeInsets.all(8),
width: double.infinity,
decoration: BoxDecoration(
color: Theme.of(context).accentColor,
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(17),
boxShadow: [
BoxShadow(
color: Colors.black87,
blurRadius: 10.0,
offset: Offset(0.0,10.0),
)
]
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
widget.title,
style: TextStyle(
fontSize: 24,
),
),
SizedBox(
height: 20,
),
Text(widget.description, style: TextStyle(fontSize: 16),
),
SizedBox(
height: 20,
),
TextField(
controller: emailController,
style: TextStyle(color: Colors.white),
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
border: OutlineInputBorder(
borderSide: BorderSide(color:Theme.of(context).primaryColor)
),
fillColor: Colors.black87,
hintStyle: TextStyle(color:Colors.grey),
hintText: 'please enter your email',
labelText: 'Email',
labelStyle: TextStyle(color:Colors.white)
),
),
SizedBox(
height: 20,
),
Container(
width: double.infinity,
child: RaisedButton(
child: Text('Send'),
onPressed: (){
_isLoading
? CircularProgressIndicator()
: print(emailController.text);
_forgetPassword(emailController.text);
Navigator.of(context).pop();
}
),
),
Container(
width: double.infinity,
child: RaisedButton(
child: Text('Cancel'),
onPressed: (){
Navigator.of(context).pop();
}
),
),
],
),
);
}
}
In your showDialog, you haven't passed the context(in the parameters).
Do it like this,
_showDialog(String title, String message, BuildContext context) {
showDialog(
barrierDismissible: false,
context: context,
builder: (ctx) => WillPopScope(
onWillPop: () async => false,
child: new AlertDialog(
elevation: 15,
)
Then, when calling the function, pass the context too,
_showDialog('Conguratulations', 'code send successfully', context);
In your _showDialog() method, add one more parameter:
BuildContext context
Future<void> _showDialog(String title, String message, BuildContext context) async{
await showDialog(
barrierDismissible: false,
context: context,
builder: (ctx) => WillPopScope(
onWillPop: () async => false,
child: new AlertDialog(
elevation: 15,
.
.
)
Then, when calling the function, pass the context too,
_showDialog('Congratulations', 'code send successfully', context);
Also, make your method asynchronous by adding the async keyword before the curly braces, return type Future<void> and await keyword before showDialog() as showDialog is a future.