Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bug]: [web] Popscope is not working with RouterService #1080

Open
Abhijit-Revamp opened this issue Feb 13, 2024 · 5 comments
Open

[bug]: [web] Popscope is not working with RouterService #1080

Abhijit-Revamp opened this issue Feb 13, 2024 · 5 comments
Labels

Comments

@Abhijit-Revamp
Copy link

Describe the bug

Popscope and WillPopScope (Deprecated) is not working in browser. Browser back button ignores settings.

Create a new page (web template) and make the following change to the builder. Set the "canPop" to "false" to avoid back navigation from new page to previous page.

Original:

return ScreenTypeLayout.builder(
        mobile: (_) => const Page3ViewMobile(),
        tablet: (_) => const Page3ViewTablet(),
        desktop: (_) => const Page3ViewDesktop(),
    );

Modified:

return PopScope(
      canPop: false,
      child: ScreenTypeLayout.builder(
        mobile: (_) => const Page3ViewMobile(),
        tablet: (_) => const Page3ViewTablet(),
        desktop: (_) => const Page3ViewDesktop(),
      ),
    );

To reproduce

  1. create app with web template
  2. create new view as follows
    stacked create view page2 -t web
  3. On home_view add a button and call handler
  4. in the model add handler
  Future nextPage() async {
    await _routerService.replaceWith(const Page3ViewRoute());
  }
  1. On page2_view change the builder as above

Expected behavior

With "canPop" set to false, the browser BACK button should not go back.

Screenshots

No response

Additional Context

Even "WillPopScop" (Deprecated) won't work

image
@FilledStacks
Copy link
Contributor

Hey,

Can you check if that's the expected behaviour in a Flutter app without Stacked.

I don't think you're allowed to block the back button, Stacked doesn't do anything different with navigation, we use all the default Flutter navigation functionality just with a better API for the devs to work against.

@Abhijit-Revamp
Copy link
Author

This works in Flutter app without stacked. Here is the code which you can test (3 scenarios)

  1. Create a new flutter project
  2. replace the entire main.dart with following (I have created a very basic stuff that shows how it works)
  3. Run it on Chrome (or any supported browser) - you will see, clicking the browser back button, it prevents going back.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const MyApp());
}

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

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
          useMaterial3: true,
        ),
        home: MyHomePage(),
        routes: {
          'home': (context) => MyHomePage(),
          'page1': (context) => Page1(),
          'page2': (context) => Page2(),
          'page3': (context) => Page3(),
        });
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State {
  @override
  Widget build(BuildContext context) {
    return Container(
        child: Card(
            child: Center(
      child: Column(
        children: [
          IconButton(
            icon: Icon(Icons.run_circle),
            onPressed: () {
              Navigator.pushNamed(context, 'page1');
            },
          ),
          IconButton(
            icon: Icon(Icons.transfer_within_a_station),
            onPressed: () {
              Navigator.pushNamed(context, 'page2');
            },
          ),
          IconButton(
            icon: Icon(Icons.no_transfer),
            onPressed: () {
              Navigator.pushNamed(context, 'page3');
            },
          ),
        ],
      ),
    )));
  }
}

class Page1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Container(
          child: Card(
        child: ListTile(
          title: Text('WillPopScope [Deprecated]'),
          subtitle: Text('Click browser back button'),
          leading: IconButton(
              icon: Icon(Icons.home),
              onPressed: () {
                Navigator.pop(context);
              }),
        ),
      )),
    );
  }
}

class Page2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      child: Container(
          child: Card(
        child: ListTile(
          title: Text('PopScope : canPop = false'),
          subtitle: Text('Click browser back button'),
          leading: IconButton(
              icon: Icon(Icons.home),
              onPressed: () {
                Navigator.pop(context);
              }),
        ),
      )),
    );
  }
}

class Page3 extends StatefulWidget {
  const Page3();

  @override
  State<Page3> createState() => Page3State();
}

class Page3State extends State<Page3> {
  @override
  Widget build(BuildContext context) {
    return PopScope(
      canPop: false,
      onPopInvoked: (didPop) async {
        if (didPop) {
          return;
        }
        _showBackDialog();
      },
      child: Container(
          child: Card(
        child: ListTile(
          title: Text('PopScope : canPop = true'),
          subtitle: Text('Click browser back button'),
          leading: IconButton(
              icon: Icon(Icons.home),
              onPressed: () {
                Navigator.pop(context);
              }),
        ),
      )),
    );
  }

  void _showBackDialog() {
    showDialog<void>(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: const Text('Are you sure?'),
          content: const Text(
            'Are you sure you want to leave this page?',
          ),
          actions: <Widget>[
            TextButton(
              style: TextButton.styleFrom(
                textStyle: Theme.of(context).textTheme.labelLarge,
              ),
              child: const Text('Nevermind'),
              onPressed: () {
                Navigator.pop(context);
              },
            ),
            TextButton(
              style: TextButton.styleFrom(
                textStyle: Theme.of(context).textTheme.labelLarge,
              ),
              child: const Text('Leave'),
              onPressed: () {
                Navigator.pop(context);
                Navigator.pop(context);
              },
            ),
          ],
        );
      },
    );
  }
}

@FilledStacks
Copy link
Contributor

Thanks for filing the issue, much appreciated.

We will take a look at this.

@SandaruwanFdo
Copy link

Is this fixed? Thank you for amazing package

@jakusb
Copy link

jakusb commented Aug 21, 2024

I run into this issue too.
I have a horizontal scrolling table and when I try to swipe right to scroll table back to left, it pops the route.
PopScope's onPopInvokedWithResult method is triggered and it had didPop=true, even though canPop=false.
This is making it impossible to use a large table with horizontal scrolling using 2-finger swipe

@FilledStacks FilledStacks added the p3 label Oct 4, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants