0

Currently I have the problem, that the screens are not being properly disposed by the TopNavigationBar.

How can I properly dispose them?

I tried to add navigatorKey.currentState.pop; before I navigate to a specific screen, which get selected at the TopNavigationBar. So the current screen will get disposed and after that I navigate to the selected screen from the TopNavigationBar.

But unfortunatly I still get a Duplicate GlobalKey detected in widget tree. error. I think I am getting this error in the login screen, because the screens are not properly disposed (when I click 2 times on the TopNavigationBarItem "Login", then the error occurs). So I try to figure out, how I can properly dispose them.

What I am doing wrong? How can I properly dispose them?

I think, when I dispose the screens correctly, then my final GlobalKey<FormState> _formKeys will work as expected and the error will disappear.

Edit:

"Properly disposing screens" solved with the comment of Anees, but the problem is still not fixed.

I have 2 options:

-using the answer from Duplicate GlobalKey detected in widget tree and change my GlobalKey to final GlobalKey<FormState> _formKeys = GlobalKey<FormState>(); But then my keyboard on the smartphone is not working anymore (instantly disappearing after clicking on a Textfield).

or

-trying to find another solution for this problem without getting another problem.

navigation_service.dart code:

   import 'package:flutter/material.dart';

class NavigationService {
  final GlobalKey<NavigatorState> navigatorKey =
  GlobalKey<NavigatorState>();

  Future<dynamic> navigateTo(String routeName) {
    // dispose of the current screen, then navigate to the new screen
    navigatorKey.currentState.pop;
    return navigatorKey.currentState.pushNamed(routeName);
  }

  void goBack() {
    return navigatorKey.currentState.pop();
  }
}

top_nav_item.dart code: (onTap function is doing the navigation in the TopNavigationbar)

import 'package:bestfitnesstrackereu/widgets/top_navbar_item/top_navbar_item_desktop.dart';
import 'package:bestfitnesstrackereu/widgets/top_navbar_item/top_navbar_item_mobile.dart';
import 'package:bestfitnesstrackereu/widgets/top_navbar_item/top_navbar_item_tablet.dart';
import 'package:flutter/material.dart';
import 'package:responsive_builder/responsive_builder.dart';
import '../../datamodels/navbar_item_model.dart';
import '../../locator.dart';
import '../../services/navigation_service.dart';


class TopNavBarItem extends StatelessWidget {
  final String title;
  final String navigationPath;
  final IconData icon;
  const TopNavBarItem(this.title, this.navigationPath, {this.icon});

  @override
  Widget build(BuildContext context) {

    // every NavBarItem need to have this model
    var model = NavBarItemModel(
      title: title,
      navigationPath: navigationPath,
      iconData: icon,
    );

    return GestureDetector(
      onTap: () {
        locator<NavigationService>().navigateTo(navigationPath);
      },

      child: ScreenTypeLayout(
        desktop: TopNavBarItemTabletDesktop(
          model: model,
        ),
        tablet: TopNavBarItemTablet(
          model: model,
        ),
        mobile: TopNavBarItemMobile(
          model: model,
        ),
      ),
    );
  }
}

top_navigation_bar_user.dart code: (it's the TopNavigationBar)

class TopNavigationBarUserDesktop extends StatelessWidget {
  const TopNavigationBarUserDesktop({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 100,
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: <Widget>[
          SizedBox(width: 30,),
          TopNavBarLogo(),
          SizedBox(width: 30,),
          Visibility(child: Text( "TheBestFitnessTracker", style: TextStyle(color: Colors.black, fontSize: 14, fontWeight: FontWeight.normal,))),

          Spacer(),      //Space between logo+text and widgets in the center of the row
          TopNavBarItem('Informationen', InformationRoute, ),
          SizedBox(width: 30,),
          TopNavBarItem('Neuigkeiten', NeuigkeitenRoute),
          SizedBox(width: 30,),

          Spacer(), //Space between widgets in the center of the row and end of row
          SizedBox(width: 30,),
          TopNavBarItem('Login', AuthenticationPageRoute),
          SizedBox(width: 30,),
          TopNavBarItem('Teilehmer \n werden', RegristrationUserRoute),
          SizedBox(width: 30,),
        ],
      ),
    );
  }
}

authentification.dart (login) code: (problems with the GlobalKey _formKeys, so form widget and TextFormFields)

import 'package:bestfitnesstrackereu/routing/route_names.dart';
import 'package:email_validator/email_validator.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../../provider/auth.dart';
import '../../widgets/loading_circle/loading_circle.dart';

//AuthenticationPage (Login page)


class AuthenticationPage extends StatefulWidget {



  @override
  State<AuthenticationPage> createState() => _AuthenticationPageState();
}

class _AuthenticationPageState extends State<AuthenticationPage> {
  
  static final GlobalKey<FormState> _formKeys = GlobalKey<FormState>();
  var userData;

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    final authProvider = Provider.of<AuthProvider>(context);

    return Scaffold(
      body: SingleChildScrollView(
        child: Center(
          // checks the authentication status, when it is Authenticating, then return loading, else show the page
          child: authProvider.status == Status.Authenticating ? Loading() : Container(
            constraints: BoxConstraints(maxWidth: 440),
            padding: EdgeInsets.all(24),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Row(
                  children: [
                    Padding(
                      padding: EdgeInsets.only(right: 12),
                      child: Image.asset("assets/logo.png", width: 300,),
                    ),
                    Expanded(child: Container()),
                  ],
                ),

                SizedBox(
                  height: 30,
                ),

                Row(
                  children: [
                    Text("Login",
                      style: TextStyle(
                      fontSize: 30, fontWeight: FontWeight.bold
                    )),
                  ],
                ),

                SizedBox(height: 10,),

                Row(
                  children: const [
                    Text(
                      "Wilkommen zurück zum Login",
                      style: TextStyle(
                      color: Colors.grey,))
                  ],
                ),

                SizedBox(height: 15,),

                Form(
                  key: _formKeys,
                  //autovalidateMode: AutovalidateMode.always,
                  child: SingleChildScrollView(
                    child: Column(
                      mainAxisAlignment: MainAxisAlignment.center,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [

                        TextFormField(
                          //validator: (email) => EmailValidator.validate(email) ? null : "Bitte gib eine gültige E-Mail an.",
                          controller: authProvider.emailController,
                          decoration: InputDecoration(
                              labelText: "E-Mail",
                              hintText: "abc@domain.com",
                              suffixIcon: Icon(Icons.mail_outline,),
                              //isDense: true,
                              border: OutlineInputBorder(
                                  borderRadius: BorderRadius.circular(20)
                              )
                          ),
                        ),

                        SizedBox(height: 15,),

                        TextFormField(
                          validator: (password) {
                            print(authProvider.validatePassword(password));
                            return authProvider.validatePassword(password);
                          },
                          controller: authProvider.passwordController,
                          obscureText: true,
                          decoration: InputDecoration(
                              labelText: "Passwort",
                              hintText: "******",
                              suffixIcon: Icon(Icons.lock_outline, color: Colors.grey,),
                              border: OutlineInputBorder(
                                  borderRadius: BorderRadius.circular(20)
                              )
                          ),
                        ),
                      ],
                    ),
                  ),
                ),


                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 25.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      GestureDetector(
                        onTap: () {
                          authProvider.clearController();
                          Navigator.of(context).pushNamed(ForgotPasswordRoute);       // navigate to the forgot password page
                          },
                        child: Text(
                          'Passwort vergessen',
                          style: TextStyle(
                            color: Colors.blue[700],
                            fontWeight: FontWeight.bold,
                          ),
                        ),
                      )
                    ],
                  ),
                ),

                SizedBox(height: 15,),

                InkWell(
                  onTap: () async {

                    //check if email and password field is not empty
                    if(authProvider.emailController.text.trim().isEmpty || authProvider.passwordController.text.trim().isEmpty){
                      showDialog(context: context, builder: (BuildContext context){
                        return AlertDialog(
                          title: Text("Error: Bitte fülle das E-Mail- und Passwort-Feld aus."),
                          actions: [
                            TextButton(
                              child: Text("Ok"),
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                            )
                          ],
                        );
                      });
                    } else {

                    //checking if the email and password is valid
                    if(_formKeys.currentState.validate()){
                      print('validate email okok');

                    // input is the authProvider.emailController, which provides the written email from the user
                    // output are all the user informations in a Map<String, dynamic>
                    // used to check the status and role of the user
                    Map<String, dynamic> mapUserinformations = {};
                    mapUserinformations = await authProvider.getUserByEmail();

                    // checking if the admin/scientist exist
                    if (mapUserinformations != null){

                    //status from user = locked
                    if(mapUserinformations['status'] == 'gesperrt'){
                      showDialog(context: context, builder: (BuildContext context){
                        return AlertDialog(
                          title: Text("Error: Dein Account ist gesperrt"),
                          actions: [
                            TextButton(
                              child: Text("Ok"),
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                            )
                          ],
                        );
                      });
                    }

                    //status from user = deleted
                    if(mapUserinformations['status'] == 'gelöscht'){
                      showDialog(context: context, builder: (BuildContext context){
                        return AlertDialog(
                          title: Text("Error: Dein Account wurde gelöscht. Er existiert nicht mehr."),
                          actions: [
                            TextButton(
                              child: Text("Ok"),
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                            )
                          ],
                        );
                      });
                    }

                    //status from user = active
                    if(mapUserinformations['status'] == 'aktiv') {

                      //role from user = admin
                      if (mapUserinformations['role'] == 'Admin') {
                        print('admin - am einloggen');
                        if(!await authProvider.signIn()){      //signIn failed, then return "Login failed"
                          showDialog(context: context, builder: (BuildContext context){
                            return AlertDialog(
                              title: Text("Error: Login fehlgeschlagen. Falsche Kombination aus E-Mail und Passwort."),
                              actions: [
                                TextButton(
                                  child: Text("Ok"),
                                  onPressed: () {
                                    authProvider.clearController();
                                    Navigator.of(context).pop();
                                  },
                                )
                              ],
                            );
                          });
                        }
                        else {
                          authProvider.clearController();
                          Navigator.of(context).pushNamed(UsersAdministrationRoute);
                        }
                      }

                      //role from user = scientist
                      if (mapUserinformations['role'] == 'Wissenschaftler') {
                        print('scientist - am einloggen');
                        if(!await authProvider.signIn()){      //signIn failed, then return "Login failed"
                          showDialog(context: context, builder: (BuildContext context){
                            return AlertDialog(
                              title: Text("Error: Error: Login fehlgeschlagen. Falsche Kombination aus E-Mail und Passwort."),
                              actions: [
                                TextButton(
                                  child: Text("Ok"),
                                  onPressed: () {
                                    authProvider.clearController();
                                    Navigator.of(context).pop();
                                  },
                                )
                              ],
                            );
                          });
                        }
                        else {             //if signIn is success, then clear controller and navigate to User Scientist page
                          authProvider.clearController();
                          Navigator.of(context).pushNamed(UsersAdministrationRoute);
                        }
                      }

                      //role from user = user
                      if (mapUserinformations['role'] == 'User') {
                        print('user - kein zugriff');
                        showDialog(context: context, builder: (BuildContext context){
                          return AlertDialog(
                            title: Text("Error: Du hast keine Zugriffsberichtigung auf diesen Login."),
                            actions: [
                              TextButton(
                                child: Text("Ok"),
                                onPressed: () {
                                  authProvider.clearController();
                                  Navigator.of(context).pop();
                                },
                              )
                            ],
                          );
                        });
                      }
                    }
                  }else {
                      showDialog(context: context, builder: (BuildContext context){
                        return AlertDialog(
                          title: Text("Error: Ein Benutzer mit dieser E-Mail existiert nicht."),
                          actions: [
                            TextButton(
                              child: Text("Ok"),
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                            )
                          ],
                        );
                      });
                    }

                    }else{
                      print('validate email notgoodatall');
                      showDialog(context: context, builder: (BuildContext context){
                        return AlertDialog(
                          title: Text("Error: Bitte gebe eine gültige E-Mail an."),
                          actions: [
                            TextButton(
                              child: Text("Ok"),
                              onPressed: () {
                                Navigator.of(context).pop();
                              },
                            )
                          ],
                        );
                      });
                    }}},

                  child: Container(
                    decoration: BoxDecoration(color: Colors.deepPurple,
                    borderRadius: BorderRadius.circular(20)),
                    alignment: Alignment.center,
                    width: double.maxFinite,
                    padding: EdgeInsets.symmetric(vertical: 16),
                    child: Text(
                      "Login",
                      style: TextStyle(
                      color: Colors.white,
                    ),)
                )
                ),

                SizedBox(height: 15,),

                Row(
                  children: [
                    Expanded(
                        child: Divider(
                          height: 50,
                           color: Colors.grey[500],
                        )
                    ),
                    Padding(
                        padding: EdgeInsets.symmetric(horizontal: 20),
                      child: Text('Du bist noch nicht registriert?'),
                    ),
                    Expanded(
                        child: Divider(
                          height: 50,
                          color: Colors.grey[500],
                        )
                    ),
                  ],
                ),

                SizedBox(height: 15,),

                InkWell(
                    onTap: (){
                      authProvider.clearController();
                      Navigator.of(context).pushNamed(RegristrationUserRoute);   // navigation to the Registration page
                    },
                    child: Container(
                        decoration: BoxDecoration(color: Colors.deepPurple,
                            borderRadius: BorderRadius.circular(20)),
                        alignment: Alignment.center,
                        width: double.maxFinite,
                        padding: EdgeInsets.symmetric(vertical: 16),
                        child: Text(
                          "Teilnehmer werden",
                          style: TextStyle(
                            color: Colors.white,
                          ),)
                    )
                ),
              ],
            ),
          )
        ),
      ),
    );
  }
}
Hans Sama
  • 123
  • 7

1 Answers1

1

You should try like this

pushNamedAndRemoveUntil('/login', (Route route) => false);

Anees
  • 99
  • 7
  • Thanks, it works. But my problem is still not fixed. I guess properly disposing the screen wasn't the problem. – Hans Sama Jul 07 '22 at 15:12