flutterdart

My Flutter PopScope is not working anymore


I put in a PopScope for one of the pages in my flutter app so that users cannot navigate back to the previous screen when they are on this screen. It worked before, I made some other changes but nothing related to PopScope, so I'm a bit lost as to how this could have happened. The page will still allow a user to navigate back to the previous screen if they tap "Back" on the device.

class LoginScreenColor extends StatelessWidget {
  const LoginScreenColor({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primaryColor: const Color(0xfff51957),
        textSelectionTheme: const TextSelectionThemeData(
          cursorColor: Color(0xfff51957),
        ),
        inputDecorationTheme: const InputDecorationTheme(
          labelStyle: TextStyle(
            color: Color(
                0xfff51957),
          ),
          focusedBorder: UnderlineInputBorder(
            borderSide: BorderSide(color: Color(0xfff51957)),
          ),
        ),
      ),
      home: LoginScreen(),
    );
  }
}

class LoginScreen extends StatelessWidget {
  LoginScreen({Key? key}) : super(key: key);

  final FirebaseAuth _auth = FirebaseAuth.instance;
  final GoogleSignIn googleSignIn = GoogleSignIn();

  // Email and Pass focusNodes
  final FocusNode emailFocusNode = FocusNode();
  final FocusNode passwordFocusNode = FocusNode();

  // Controllers for Email and Pass
  final TextEditingController emailController = TextEditingController();
  final TextEditingController passwordController = TextEditingController();

  // Continue with Google
  Future<UserCredential> signInWithGoogle() async {
    final GoogleSignInAccount? googleSignInAccount =
        await googleSignIn.signIn();
    final GoogleSignInAuthentication googleSignInAuthentication =
        await googleSignInAccount!.authentication;

    final AuthCredential credential = GoogleAuthProvider.credential(
      accessToken: googleSignInAuthentication.accessToken,
      idToken: googleSignInAuthentication.idToken,
    );

    final UserCredential userCredential =
        await _auth.signInWithCredential(credential);

    // Set a flag to indicate the user has just signed in
    SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool('justSignedIn', true);

    return userCredential;
  }

  // Sign in with Email and Password
  Future<UserCredential> signInWithEmail() async {
    final String email = emailController.text;
    final String password = passwordController.text;

    final UserCredential userCredential =
        await _auth.signInWithEmailAndPassword(
      email: email,
      password: password,
    );

    return userCredential;
  }

  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvoked: (bool didPop) => showDialog<void>(
        context: context,
        builder: (BuildContext context) {
          return AlertDialog(
            backgroundColor: Colors.white,
            title: const Text(
              'Please Complete Setup',
              style: TextStyle(
                fontWeight: FontWeight.bold,
                fontFamily: 'Montserrat',
              ),
            ),
            content: const Text(
              'Please complete the setup process first, any and all settings can be changed after initial setup.',
              style: TextStyle(
                fontSize: 20,
                fontFamily: 'Montserrat',
              ),
            ),
            actions: <Widget>[
              TextButton(
                onPressed: () => Navigator.pop(context),
                child: const Text(
                  'Ok',
                  style: TextStyle(
                    color: Color(0xfff51957),
                    fontFamily: 'Montserrat',
                    fontSize: 20,
                  ),
                ),
              ),
            ],
          );
        },
      ),
      child: Scaffold(
        body: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(16.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Column(
                  children: <Widget>[
                    const SizedBox(
                      height: 30,
                    ),
                    SizedBox(
                      height: 200,
                      width: 200,
                      child: Lottie.asset('assets/sign.json'),
                    ),
                    const SizedBox(height: 40.0),
                    RichText(
                      text: TextSpan(
                        children: <TextSpan>[
                          TextSpan(
                            text: 'Discover your next ',
                            style: GoogleFonts.montserrat(
                              fontSize: 24.0,
                              fontWeight: FontWeight.bold,
                              color: Colors.black,
                            ),
                          ),
                          TextSpan(
                            text: 'adventure',
                            style: GoogleFonts.montserrat(
                              fontSize: 24.0,
                              fontWeight: FontWeight.bold,
                              color: const Color(0xfff51957),
                            ),
                          ),
                        ],
                      ),
                    ),
                    const SizedBox(height: 40.0),
                    TextField(
                      controller: emailController,
                      focusNode: emailFocusNode,
                      decoration: InputDecoration(
                        labelText: 'Email',
                        prefixIcon: const Icon(Icons.email),
                        labelStyle: TextStyle(
                          color: emailFocusNode.hasFocus
                              ? const Color(0xfff51957)
                              : null,
                        ),
                      ),
                    ),
                    const SizedBox(height: 20.0),
                    TextField(
                      controller: passwordController,
                      focusNode: passwordFocusNode,
                      obscureText: true,
                      decoration: InputDecoration(
                        labelText: 'Password',
                        prefixIcon: const Icon(Icons.lock),
                        labelStyle: TextStyle(
                          color: passwordFocusNode.hasFocus
                              ? const Color(0xfff51957)
                              : null,
                        ),
                      ),
                    ),
                    const SizedBox(height: 20.0),
                    SizedBox(
                      height: 50,
                      width: MediaQuery.of(context).size.width - 40.0,
                      child: ElevatedButton(
                        onPressed: () async {
                          try {
                            await signInWithEmail();
                            Navigator.push(
                              context,
                              PageRouteBuilder(
                                pageBuilder:
                                    (context, animation, secondaryAnimation) =>
                                        const PreferencesScreen(),
                                transitionsBuilder: (context, animation,
                                    secondaryAnimation, child) {
                                  var begin = const Offset(1.0, 0.0);
                                  var end = Offset.zero;
                                  var curve = Curves.ease;

                                  var tween = Tween(begin: begin, end: end)
                                      .chain(CurveTween(curve: curve));

                                  return SlideTransition(
                                    position: animation.drive(tween),
                                    child: child,
                                  );
                                },
                              ),
                            );
                          } on FirebaseAuthException catch (e) {
                            // Handle error
                            print(e.message);
                          }
                        },
                        style: ElevatedButton.styleFrom(
                          backgroundColor: const Color(0xfff51957),
                          shape: RoundedRectangleBorder(
                            borderRadius: BorderRadius.circular(15),
                          ),
                        ),
                        child: Text(
                          'Sign in',
                          style: GoogleFonts.montserrat(
                            fontWeight: FontWeight.bold,
                            color: Colors.white,
                          ),
                        ),
                      ),
                    ),
                    const SizedBox(height: 20.0),
                    Container(
                      margin: const EdgeInsets.only(top: 16.0),
                      child: OutlinedButton.icon(
                        onPressed: () async {
                          // Handle Google sign-in
                          final GoogleSignInAccount? googleUser =
                              await GoogleSignIn().signIn();
                          if (googleUser != null) {
                            final GoogleSignInAuthentication googleAuth =
                                await googleUser.authentication;
                            final OAuthCredential credential =
                                GoogleAuthProvider.credential(
                              accessToken: googleAuth.accessToken,
                              idToken: googleAuth.idToken,
                            );
                            try {
                              final UserCredential userCredential =
                                  await _auth.signInWithCredential(credential);
                              // Check if sign-in was successful
                              if (userCredential.user != null) {
                                // Navigate to PreferencesScreen
                                Navigator.push(
                                  context,
                                  MaterialPageRoute(
                                      builder: (context) =>
                                          const PreferencesScreen()),
                                );
                              }
                            } on FirebaseAuthException catch (e) {
                              // Handle error
                              print(e.message);
                            }
                          }
                        },
                        icon: Image.asset('images/google_logo.png',
                            width: 24.0, height: 24.0),
                        label: const Text('Continue with Google'),
                        style: OutlinedButton.styleFrom(
                            foregroundColor: Colors.black,
                            side: const BorderSide(color: Colors.grey)),
                      ),
                    ),
                    const SizedBox(height: 5.0),
                    Container(
                      margin: const EdgeInsets.only(top: 16.0),
                      child: OutlinedButton.icon(
                        onPressed: () {
                          // Handle Apple sign-in
                        },
                        icon: Image.asset('images/apple.png',
                            width: 40.0, height: 40.0),
                        label: const Text('Continue with Apple'),
                        style: OutlinedButton.styleFrom(
                            foregroundColor: Colors.black,
                            side: const BorderSide(color: Colors.grey)),
                      ),
                    ),
                  ],
                ),
                const SizedBox(height: 20.0), // Add this line
                Column(
                  children: <Widget>[
                    const Divider(color: Colors.black),
                    const SizedBox(height: 20.0),
                    Row(
                      mainAxisAlignment: MainAxisAlignment.center,
                      children: <Widget>[
                        Text(
                          'Don\'t have an account? ',
                          style: GoogleFonts.montserrat(
                            fontSize: 16.0,
                            color: Colors.black.withOpacity(0.6),
                          ),
                        ),
                        GestureDetector(
                          onTap: () {
                            Navigator.push(
                              context,
                              MaterialPageRoute(
                                builder: (context) => const RegisterScreenColor(),
                              ),
                            );
                          },
                          child: Text(
                            'Register',
                            style: GoogleFonts.montserrat(
                              fontSize: 16.0,
                              fontWeight: FontWeight.bold,
                            ),
                          ),
                        ),
                      ],
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

I tried changing the code like below by adding async, but nothing changed

return PopScope(
  canPop: false, // Prevent user from navigating back
  onPopInvoked: (bool didPop) async {
    return showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          backgroundColor: Colors.white,
          title: const Text(
            'Please Complete Setup',
            style: TextStyle(
              fontWeight: FontWeight.bold,
              fontFamily: 'Montserrat',
            ),
          ),
          content: const Text(
            'Please complete the setup process first, any and all settings can be changed after initial setup.',
            style: TextStyle(
              fontSize: 20,
              fontFamily: 'Montserrat',
            ),
          ),
          actions: <Widget>[
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text(
                'Ok',
                style: TextStyle(
                  color: Color(0xfff51957),
                  fontFamily: 'Montserrat',
                  fontSize: 20,
                ),
              ),
            ),
          ],
        );
      },
    );
  },
  child: Scaffold(
    // ...

Solution

  • Short-Answer:

    PopScope does not work if you replace the class it is in with a MaterialApp class and then set the class that the PopScope is in as the home: attribute.

    Example of where PopScope would NOT work:

    class LoginScreenColor extends StatelessWidget {
      const LoginScreenColor({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          // ...
          home: LoginScreen(),
        );
      }
    }
    
    class LoginScreen extends StatelessWidget {
      LoginScreen({Key? key}) : super(key: key);
    @override
      Widget build(BuildContext context) {
        return PopScope(
          canPop: false,
          onPopInvoked: (bool didPop) => showDialog<void>(
            // ...
          child: Scaffold(
    

    Solution/Reason:

    I found the issue and fixed it. Excuse any wrong terminology used, I'm still very new to Flutter and Dart. My LoginScreen class did not have a MaterialApp in its main widget tree, it stemmed from my previous WelcomeScreen's MaterialApp. But I tried making a MaterialApp for my LoginScreen so that I could set a specific theme for its fields. Meaning I called LoginScreenColor class which then as I understood called the LoginScreen class, and somehow that caused the PopScope widget not to work anymore, I left all PopScope code unchanged, removed the LoginScreenColor class, and added my Theme I wanted to add to my previous WelcomeScreen's MaterialApp.