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

PopScope seems to be incompatible with GoRouter #138737

Open
2 tasks done
btrautmann opened this issue Nov 20, 2023 · 39 comments
Open
2 tasks done

PopScope seems to be incompatible with GoRouter #138737

btrautmann opened this issue Nov 20, 2023 · 39 comments
Assignees
Labels
customer: crowd Affects or could affect many people, though not necessarily a specific customer. found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: go_router The go_router package P1 High-priority issues at the top of the work list package flutter/packages repository. See also p: labels. team-go_router Owned by Go Router team triaged-go_router Triaged by Go Router team

Comments

@btrautmann
Copy link

btrautmann commented Nov 20, 2023

Is there an existing issue for this?

Steps to reproduce

Original comment was made at #138525 (comment) but I'm pasting here:

[...] our team was investigating PopScope and found some interesting behavior that can be reproduced using this repo. I don't believe this component is behaving as described in the docs.

Using GoRouter APIs on iOS 17:

  1. When canPop is set to true, user can go back via app bar or back button but onPopInvoked is never invoked.
  2. When canPop is set to false, user cannot go back via app bar or back button but again onPopInvoked is only invoked with didPop set to false when pressing app bar back button. It is not invoked for the back gesture.

Using GoRouter APIs on Android 14:

  1. When canPop is set to true, user can go back via app bar or back button but onPopInvoked is never invoked.
  2. When canPop is set to false, user cannot go back via app bar or back button. onPopInvoked is invoked in both cases with didPop set to false.

Summary Table:

NOTE: For clarity, please note that for each column with onPopInvoked in the title, the true or false in the rows associated with that column indicate whether or not the onPopInvoked callback was invoked. This column is NOT intended to indicate anything about the didPop value, which is always (AFAIK) correct.

Platform Nav API canPop onPopInvoked(appBar) onPopInvoked (back swipe) onPopInvoked (Physical button) Expected behavior?
iOS GoRouter true false false --- false
iOS GoRouter false true false --- false
Android GoRouter true false false false false
Android GoRouter false true true true true

Expected results

The component should behave as described in the docs.

Actual results

See the table in the Steps to reproduce section.

Code sample

Code can be found in this repo.

Screenshots or Video

Screenshots / Video demonstration

[Upload media here]

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.16.0, on macOS 13.6.1 22G313 darwin-arm64, locale en-US)
    • Flutter version 3.16.0 on channel stable at /Users/brandontrautmann/fvm/versions/3.16.0
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision db7ef5bf9f (2 days ago), 2023-11-15 11:25:44 -0800
    • Engine revision 74d16627b9
    • Dart version 3.2.0
    • DevTools version 2.28.2

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.1)
    • Android SDK at /Users/brandontrautmann/Library/Android/sdk
    • Platform android-33, build-tools 33.0.1
    • ANDROID_SDK_ROOT = /Users/brandontrautmann/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.3.1)
    • Xcode at /Applications/Xcode_14.app/Contents/Developer
    • Build 14E300c
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b829.9-10027231)

[✓] IntelliJ IDEA Community Edition (version 2023.2.1)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.76.0

[✓] Connected device (4 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554                        • android-arm64  • Android 13 (API 33) (emulator)
    • iPhone 13 mini (mobile)     • 0492C672-A151-402C-AAA0-0B694038CF37 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-0 (simulator)
    • macOS (desktop)             • macos                                • darwin-arm64   • macOS 13.6.1 22G313 darwin-arm64
    • Chrome (web)                • chrome                               • web-javascript • Google Chrome 119.0.6045.159

[✓] Network resources
    • All expected network resources are available.

• No issues found!
@dam-ease
Copy link

Thanks for filing this and the detailed explanation.
I can reproduce this on the latest master and stable channels.

stable, master flutter doctor -v

[!] Flutter (Channel stable, 3.16.0, on macOS 14.0 23A344 darwin-arm64, locale
    en-NG)
    • Flutter version 3.16.0 on channel stable at
      /Users/damilolaalimi/sdks/flutter
    ! Warning: `dart` on your path resolves to
      /opt/homebrew/Cellar/dart/3.1.5/libexec/bin/dart, which is not inside your
      current Flutter SDK checkout at /Users/damilolaalimi/sdks/flutter.
      Consider adding /Users/damilolaalimi/sdks/flutter/bin to the front of your
      path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision db7ef5bf9f (5 days ago), 2023-11-15 11:25:44 -0800
    • Engine revision 74d16627b9
    • Dart version 3.2.0
    • DevTools version 2.28.2
    • If those were intentional, you can disregard the above warnings; however
      it is recommended to use "git" directly to perform update checks and
      upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/damilolaalimi/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/damilolaalimi/Library/Android/sdk
    • Java binary at: /Applications/Android
      Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build
      17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build
      17.0.6+0-17.0.6b802.4-9586694)

[!] Android Studio (version unknown)
    • Android Studio at /Users/damilolaalimi/Downloads/Android Studio
      Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to determine Android Studio version.
    • Java version OpenJDK Runtime Environment (build
      17.0.7+0-17.0.7b1000.6-10550314)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.50.0

[✓] VS Code (version 1.83.1)
    • VS Code at /Users/damilolaalimi/Downloads/Visual Studio Code.app/Contents
    • Flutter extension version 3.50.0

[✓] Connected device (5 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554                        •
      android-arm64  • Android 14 (API 34) (emulator)
    • Damilola’s iPhone (mobile)  • 00008110-001964480AE1801E            • ios
      • iOS 17.1.1 21B91
    • iPhone 15 (mobile)          • F17D2919-6D61-4295-8408-1719692FE958 • ios
      • com.apple.CoreSimulator.SimRuntime.iOS-17-0 (simulator)
    • macOS (desktop)             • macos                                •
      darwin-arm64   • macOS 14.0 23A344 darwin-arm64
    • Chrome (web)                • chrome                               •
      web-javascript • Google Chrome 119.0.6045.159

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.
[!] Flutter (Channel master, 3.17.0-12.0.pre.39, on macOS 14.0 23A344 darwin-arm64, locale en-NG)
    • Flutter version 3.17.0-12.0.pre.39 on channel master at /Users/damilolaalimi/fvm/versions/master
    ! Warning: `dart` on your path resolves to /opt/homebrew/Cellar/dart/3.1.5/libexec/bin/dart, which is not inside your current Flutter SDK checkout at /Users/damilolaalimi/fvm/versions/master. Consider adding /Users/damilolaalimi/fvm/versions/master/bin to the front of your path.
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision b6ef78e955 (2 hours ago), 2023-11-20 23:37:25 -0500
    • Engine revision 70b1c73412
    • Dart version 3.3.0 (build 3.3.0-152.0.dev)
    • DevTools version 2.30.0-dev.4
    • If those were intentional, you can disregard the above warnings; however it is recommended to use "git" directly to perform update checks and upgrades.

[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
    • Android SDK at /Users/damilolaalimi/Library/Android/sdk
    • Platform android-34, build-tools 34.0.0
    • ANDROID_HOME = /Users/damilolaalimi/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jbr/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 15.0.1)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 15A507
    • CocoaPods version 1.12.1

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2022.2)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)

[!] Android Studio (version unknown)
    • Android Studio at /Users/damilolaalimi/Downloads/Android Studio Preview.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    ✗ Unable to determine Android Studio version.
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] VS Code (version 1.84.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.50.0

[✓] VS Code (version 1.83.1)
    • VS Code at /Users/damilolaalimi/Downloads/Visual Studio Code.app/Contents
    • Flutter extension version 3.50.0

[✓] Connected device (5 available)
    • sdk gphone64 arm64 (mobile) • emulator-5554                        • android-arm64  • Android 14 (API 34) (emulator)
    • Damilola’s iPhone (mobile)  • 00008110-001964480AE1801E            • ios            • iOS 17.1.1 21B91
    • iPhone 15 (mobile)          • F17D2919-6D61-4295-8408-1719692FE958 • ios            • com.apple.CoreSimulator.SimRuntime.iOS-17-0 (simulator)
    • macOS (desktop)             • macos                                • darwin-arm64   • macOS 14.0 23A344 darwin-arm64
    • Chrome (web)                • chrome                               • web-javascript • Google Chrome 119.0.6045.159

[✓] Network resources
    • All expected network resources are available.

! Doctor found issues in 2 categories.

@dam-ease dam-ease added package flutter/packages repository. See also p: labels. has reproducible steps The issue has been confirmed reproducible and is ready to work on p: go_router The go_router package team-go_router Owned by Go Router team found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 and removed in triage Presently being triaged by the triage team labels Nov 21, 2023
@chunhtai
Copy link
Contributor

I am actively working on this. It will have to wait for #137792 before I can fix this issue

@chunhtai chunhtai self-assigned this Nov 30, 2023
@chunhtai chunhtai added P1 High-priority issues at the top of the work list triaged-go_router Triaged by Go Router team labels Nov 30, 2023
@RioChndr
Copy link

Hi @btrautmann. I look into your reproduce_repo. I see you use go instead push, I wonder why you use this method. It would be nice if popScope could trigger the onPopInvoked. I also create Reproduce Repo that use go and push to test it.

@btrautmann
Copy link
Author

btrautmann commented Dec 26, 2023

I look into your reproduce_repo. I see you use go instead push, I wonder why you use this method.

Our team uses go pretty much everywhere because it's idempotent (i.e you can invoke a go call 100x and you will have the same result as if you invoked it just once). This is not true of push and can lead to navigation issues. There are obviously use cases for push but IMO it shouldn't be the default.

Edit: Just to clarify, my usage of go in the repro was simply habit, I didn't intend it to influence the filed issue behavior at all.

@thanglq1
Copy link

I'm encountering an issue with local notifications. When I click on a notification to open the detail page and then press the physical back button, the onPopInvoked method is not being called, even though the canPop value is false. But its work when I clicked on back button in the appbar.

@l1qu1d
Copy link

l1qu1d commented Jan 23, 2024

I couldn't find anyone else mentioning this but PopScope with GoRouter doesn't work as it should on web either.

Note: Most of the code was copied from Flutter's official PopScope example but with Navigator which works as you'd expect. I modified it for GoRouter.

Dartpad PopScope Example

  1. Click on Next page.
    1. Goes to next page.
  2. Click the brower's back button.
    1. Goes back to Page One. This shouldn't happen.
  3. Click on Next page.
    1. Goes to next page.
  4. Now click the Go Back button.
    1. onPopInvoked is called as it should and a popup shows.

@dam-ease dam-ease added the customer: crowd Affects or could affect many people, though not necessarily a specific customer. label Jan 23, 2024
@VasuBhav
Copy link

VasuBhav commented Feb 1, 2024

I have the same issues in my cases i'm using only pushnamed in all routes

@Abhijit-Revamp
Copy link

@chunhtai
Can you please include WEB also to this. It's broken when using browser (Chrome) back button.

@vysotsky
Copy link

vysotsky commented Feb 27, 2024

Hello everyone. Are there any updates or workarounds? This issue is affecting our users and it's very painful. Is there any possible solution that will also work with the predictive back on Android? Or maybe someone has switched from GoRouter to something else and can highlight some of the benefits of that? Because this is also something we are considering...

@AriesCrimson
Copy link

My only workaround for this is to stay in 12.1.3 in the meantime

@KDCinfo
Copy link

KDCinfo commented Apr 2, 2024

That's a great workaround @limitless-brain !! 🎉 (Or fix even, depending on your use case.)

Tested successfully with go_router: 13.2.2.

import 'dart:developer';

import 'package:flutter/material.dart';

class PrePopWidget extends StatelessWidget {
  const PrePopWidget({
    super.key,
    required this.child,
  });

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return BackButtonListener(
      child: child,
      onBackButtonPressed: () async {
        log('[pre_pop_widget] [onBackButtonPressed]');

        if (shouldNotPop) {
          // Let the system know we've got this.
          return Future.value(true);
        }

        // Let the system handle the back button press, which typically pops the route.
        return Future.value(false);
      },
    );
  }
}

@sahinemin
Copy link

sahinemin commented Apr 6, 2024

That's a great workaround @limitless-brain !! 🎉 (Or fix even, depending on your use case.)

Tested successfully with go_router: 13.2.2.

import 'dart:developer';

import 'package:flutter/material.dart';

class PrePopWidget extends StatelessWidget {
  const PrePopWidget({
    super.key,
    required this.child,
  });

  final Widget child;

  @override
  Widget build(BuildContext context) {
    return BackButtonListener(
      child: child,
      onBackButtonPressed: () async {
        log('[pre_pop_widget] [onBackButtonPressed]');

        if (shouldNotPop) {
          // Let the system know we've got this.
          return Future.value(true);
        }

        // Let the system handle the back button press, which typically pops the route.
        return Future.value(false);
      },
    );
  }
}

Did you try this solution on browser ? In my case it is not working on browser's back button. I am also using go_router 13.2.2

@KDCinfo
Copy link

KDCinfo commented Apr 6, 2024

Did you try this solution on browser ? In my case it is not working on browser's back button. I am also using go_router 13.2.2

I did not. Good use-case catch!

@muhammadkamel
Copy link

Any updates?

Still reproducible in Go Router version [go_router: ^13.2.4]

@amin79
Copy link

amin79 commented Apr 30, 2024

You can use BackButtonListener

BackButtonListener(
  onBackButtonPressed: () async {
    print('test');
    return true;
  },
  child: SomeWidgets(),
);

God bless you!!

@amin79
Copy link

amin79 commented Apr 30, 2024

You can use BackButtonListener

BackButtonListener(
  onBackButtonPressed: () async {
    print('test');
    return true;
  },
  child: SomeWidgets(),
);

There is one problem here. If I push another page and then try to back, BackButtonListener would be called on the first page. How to solve this problem?

@kwarnkham
Copy link

You can use BackButtonListener

BackButtonListener(
  onBackButtonPressed: () async {
    print('test');
    return true;
  },
  child: SomeWidgets(),
);

There is one problem here. If I push another page and then try to back, BackButtonListener would be called on the first page. How to solve this problem?

Try this.

onBackButtonPressed: () { return Future.value(!context.canPop()); }

@cver22
Copy link

cver22 commented May 6, 2024

Been following this, I've implemented the BackButtonListener in place of all my WillPopScope and it handles fine on every page EXCEPT on my top level StatefulShellRoute. BackButtonListener isn't even being called there.

Side quest, if anyone know a better way of handling both swipe and taping of the top tab buttons as I kind of had to get creative to make sure it was working.

Edit: learning how to properly paste code, sorry, should be better now.

class HomeScreen extends StatefulWidget {
  const HomeScreen({
    super.key,
    required this.navigationShell,
    required this.children,
  });

  final StatefulNavigationShell navigationShell;

  final List<Widget> children;

  @override
  _HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> with SingleTickerProviderStateMixin {
  late final TabController _tabController = TabController(
      length: widget.children.length, vsync: this, initialIndex: widget.navigationShell.currentIndex);

  final GlobalKey<ScaffoldState> _key = GlobalKey<ScaffoldState>();
  static const double iconSize = 24.0;
  bool _isNavigatingProgrammatically = false;
  bool snackBarActive = false;

  @override
  void didUpdateWidget(covariant HomeScreen oldWidget) {
    super.didUpdateWidget(oldWidget);
    _tabController.index = widget.navigationShell.currentIndex;
  }

  @override
  void initState() {
    super.initState();
    _tabController.animation!.addListener(_handleTabChange);
  }

  @override
  void dispose() {
    // Remove the listener to prevent memory leaks.
    _tabController.animation!.removeListener(_handleTabChange);
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    List<Tab> tabs = [
      const Tab(icon: Icon(Icons.account_balance_wallet, size: iconSize)),
      const Tab(icon: Icon(Icons.assignment, size: iconSize)),
      const Tab(icon: Icon(Icons.assessment, size: iconSize)),
      _buildMailIcon(context: context),
    ];

    debugPrint('Rendering App Screen');
    var state = Env.store.state;
    bool logsPresent = state.booksState.books.isNotEmpty;

    if (state.authState.authLoadingState == LoadingState.deleting ||
        state.authState.authLoadingState == LoadingState.deleted) {
      return Container();
    }

    //TODO implement PopScope here when its fixed for the router
    return BackButtonListener(
      onBackButtonPressed: () {
        debugPrint('HomeScreen - onBackButtonPressed tabController: ${_tabController.index}');
        if (context.canPop()) {
          if (_tabController.index != 0) {
            //back to logs
            widget.navigationShell.goBranch(0);
            return Future.value(true);
          } else if (_key.currentState!.isDrawerOpen) {
            //back to logs
            context.pop();
            return Future.value(true);
          } else {
            // Let the system handle the back button press, which typically pops the route.
            return Future.value(false);
          }
        } else {
          return Future.value(true);
        }
      },
      child: DefaultTabController(
        length: 4,
        child: Builder(
          builder: (BuildContext context) {
            return ConnectState<SnackBarState>(
                where: notIdentical,
                map: (state) => state.snackBarState,
                builder: (snackState) {
                  return ConnectState<AuthState>(
                      where: notIdentical,
                      map: (state) => state.authState,
                      builder: (authState) {

                        return Scaffold(
                          drawer: const HomeDrawer(),
                          appBar: AppBar(
                              actions: _actions(logsPresent),
                              bottom: TabBar(
                                controller: _tabController,
                                tabs: tabs,
                                onTap: (int tappedIndex) => _onTabTap(context, tappedIndex),
                              )),
                          body: TabBarView(
                            controller: _tabController,
                            children: widget.children,
                          ),
                        );
                      });
                });
          },
        ),
      ),
    );
  }

  void _handleTabChange() {
    int newIndex = _tabController.animation!.value.round();
    if (_tabController.index != newIndex) {
      if (_isNavigatingProgrammatically) {
        // Skip handling if the change is triggered programmatically
        return;
      }
      setState(() {
        _tabController.index = newIndex;
      });
      _onTabTap(context, newIndex); // Perform your action on tab change.
    }
  }

  /// Top trailing actions are dependent on what tab screen the user is on
  List<Widget> _actions(bool logsPresent) {
    return <Widget>[
      Builder(builder: (BuildContext context) {
        if (_tabController.index == 0) {
          return Container();
        } else if (_tabController.index == 1 && logsPresent) {
          return const EntriesHomeScreenActions();
        } else if (_tabController.index == 2 && logsPresent) {
          return const ChartHomeScreenActions();
        } else if (_tabController.index == 3) {
          return const MessagesHomeScreenActions();
        } else {
          return Container();
        }
      })
    ];
  }

  void _onTabTap(BuildContext context, int index) {
    setState(() {
      _isNavigatingProgrammatically = true;
      // Indicate programmatic navigation
    });

    widget.navigationShell.goBranch(index);

    // Optionally, reset the flag after a short delay or after navigation completes
    Future.delayed(const Duration(milliseconds: 200), () {
      setState(() {
        _isNavigatingProgrammatically = false;
      });
    });
  }

  Tab _buildMailIcon({required BuildContext context}) {
    return Tab(
      child: ConnectState<FcmState>(
          where: notIdentical,
          map: (state) => state.fcmState,
          builder: (fcmState) {
            int unRead = List<Message>.from(fcmState.messages)
                .where((message) => !message.readList.contains(Env.store.state.authState.user.value.id))
                .length;

            if (unRead == 0) {
              return const Icon(Icons.mail_outline, size: iconSize);
            } else {
              String displayNumber = unRead > 99 ? '99+' : unRead.toString();
              double badgeRightPosition = 18;
              if (unRead >= 100) {
                badgeRightPosition = 8;
              } else if (unRead > 10) {
                badgeRightPosition = 14;
              }

              return Stack(children: [
                const Padding(
                  padding: EdgeInsets.fromLTRB(24.0, 10.0, 24.0, 10.0),
                  child: Icon(Icons.mail_outline, size: iconSize),
                ),
                Positioned(
                  right: badgeRightPosition,
                  top: 5,
                  child: Container(
                    padding: const EdgeInsets.all(2),
                    decoration: BoxDecoration(
                      color: Colors.red,
                      borderRadius: BorderRadius.circular(12), // Makes it circular
                    ),
                    constraints: const BoxConstraints(
                      minWidth: 12,
                      minHeight: 12,
                    ),
                    child: Text(
                      displayNumber,
                      style: const TextStyle(
                        color: Colors.white,
                        fontSize: 12,
                      ),
                      textAlign: TextAlign.center,
                    ),
                  ),
                ),
              ]);
            }
          }),
    );
  }
}

@dishank-tci
Copy link

Seems like need to go back to basics and use Navigation 1.0. Easy and effective.

@Carapacik
Copy link

@chunhtai Any updates?

I am actively working on this. It will have to wait for #137792 before I can fix this issue

@flutter-triage-bot
Copy link

This issue is assigned to @chunhtai but has had no recent status updates. Please consider unassigning this issue if it is not going to be addressed in the near future. This allows people to have a clearer picture of what work is actually planned. Thanks!

@berial
Copy link

berial commented May 31, 2024

How to listen for physical back button on A page as the initial page? Or A use go/replace/pushReplacement to B, listen back button on B page.

I use BackButtonListener return true and PopScope canPop = false, but they didn't work.

-- BackButtonListener PopScop
A not work not work
B (A push B) work work
B (A go/replace/pushReplacement B) not work not work
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() => runApp(const MyApp());

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      title: "flutter demo",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routerConfig: router,
    );
  }
}

final router = GoRouter(
  initialLocation: "/one",
  overridePlatformDefaultLocation: true,
  routes: [
    GoRoute(path: "/one", builder: (_, __) => const OnePage()),
    GoRoute(path: "/second", builder: (_, __) => const SecondPage()),
  ],
);

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

  @override
  Widget build(BuildContext context) {
    // return PopScope(
    //   canPop: false,
    //   onPopInvoked: (didPop) {
    //     print('OnePage onPopInvoked: $didPop'); // OnePge didn't print log.
    //   },
    return BackButtonListener(
      onBackButtonPressed: () async {
        print('OnePage onBackButtonPressed'); // OnePge didn't print log.
        return true;
      },
      child: Scaffold(
        body: Container(
          alignment: Alignment.center,
          child: TextButton(
            onPressed: () {
              context.push("/second");
              // context.go("/second"); // SecondPage didn't print log.
              // context.pushReplacement("/second"); // SecondPage didn't print log.
            },
            child: const Text("one page"),
          ),
        ),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    // return PopScope(
    //   canPop: false,
    //   onPopInvoked: (didPop) {
    //     print('SecondPage onPopInvoked: $didPop');
    //   },
    return BackButtonListener(
      onBackButtonPressed: () async {
        print('SecondPage onBackButtonPressed');
        return true;
      },
      child: Scaffold(
        body: Container(
          alignment: Alignment.center,
          child: const Text("second page"),
        ),
      ),
    );
  }
}

@vysotsky
Copy link

Any news?
I'm going to start considering switching to something other than go_router. Has anyone done this? Was it successful?

@YugeCse
Copy link

YugeCse commented Jun 25, 2024

There is no good solution to resolve this question. It is still exists. We hope that the issus will be fixed.

@vietstone-ng
Copy link

vietstone-ng commented Jun 26, 2024

Oh, it works with go_router 12.x and Android's predictive back disabled (android:enableOnBackInvokedCallback="false"). Ideally, it should work with go_router 14.x and Android's predictive back enabled android:enableOnBackInvokedCallback="true".

@l1qu1d
Copy link

l1qu1d commented Jun 26, 2024

Any news? I'm going to start considering switching to something other than go_router. Has anyone done this? Was it successful?

I've been looking into AutoRoute: https://pub.dev/packages/auto_route. It uses code generation (not a big deal) but seems less complex overall and is feature complete.

@EArminjon
Copy link
Contributor

EArminjon commented Jun 26, 2024

Oh, it works with go_router 12.x and Android's predictive back disabled (android:enableOnBackInvokedCallback="false"). Ideally, it should work with go_router 14.x and Android's predictive back enabled android:enableOnBackInvokedCallback="true".

With enableOnBackInvokedCallback=false, PopScope() and go router 14.2.0 work well on Android 14.
I can well handle swipe to back, back button, webview navigation etc.

@l1qu1d
Copy link

l1qu1d commented Jun 28, 2024

Any news? I'm going to start considering switching to something other than go_router. Has anyone done this? Was it successful?

I've been looking into AutoRoute: https://pub.dev/packages/auto_route. It uses code generation (not a big deal) but seems less complex overall and is feature complete.

We've fully transitioned to AutoRoute and it has been a LOT less complex and easier to integrate overall, in my experience. Not only that, a lot of the numerous backlogged bugs that plague go_router aren't issues in AutoRoute.

@BramMusters
Copy link

Any news? I'm going to start considering switching to something other than go_router. Has anyone done this? Was it successful?

I've been looking into AutoRoute: https://pub.dev/packages/auto_route. It uses code generation (not a big deal) but seems less complex overall and is feature complete.

We've fully transitioned to AutoRoute and it has been a LOT less complex and easier to integrate overall, in my experience. Not only that, a lot of the numerous backlogged bugs that plague go_router aren't issues in AutoRoute.

How hard was the migration? I am doubting to migrate as well, but am reluctant to do all the migration stuff..

@amrgetment
Copy link

@BramMusters works fine for now, go_router: 12.1.3 until someone get a time to deep investigate this issue

@l1qu1d
Copy link

l1qu1d commented Jul 1, 2024

Any news? I'm going to start considering switching to something other than go_router. Has anyone done this? Was it successful?

I've been looking into AutoRoute: https://pub.dev/packages/auto_route. It uses code generation (not a big deal) but seems less complex overall and is feature complete.

We've fully transitioned to AutoRoute and it has been a LOT less complex and easier to integrate overall, in my experience. Not only that, a lot of the numerous backlogged bugs that plague go_router aren't issues in AutoRoute.

How hard was the migration? I am doubting to migrate as well, but am reluctant to do all the migration stuff..

I did an initial test build where I took some of our most complicated routing and tried it with AutoRoute, including understanding the API took a day. It was straightforward and the API is well documented. After that, it took me a day(ish) to fully transition. In fact, I was able to remove a lot of code we had around GoRouter because of how much of the code gen takes care of a lot of common routing problems.

@chunhtai
Copy link
Contributor

chunhtai commented Jul 1, 2024

the framework change is landed, I have to wait for next stable release before I can fix the incompatibility in go_router

@flutter-triage-bot flutter-triage-bot bot removed the Bot is counting down the days until it unassigns the issue label Jul 1, 2024
@agustincards14
Copy link

I've read through this thread and haven't really seen a simple workaround for both platforms. Here is mine for now.

So BackButtonListener only works with Android.
But PopScope.onPopInvoked is called on both platforms IFF canPop==false.

My workaround on go_router: ^13.2.4 is:

PopScope(
      canPop: false,
      onPopInvoked: (didPop) async {
         // do work here . . .
         context.pop();
      }

I don't see when context.canPop()==false, so that call should be safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customer: crowd Affects or could affect many people, though not necessarily a specific customer. found in release: 3.16 Found to occur in 3.16 found in release: 3.17 Found to occur in 3.17 has reproducible steps The issue has been confirmed reproducible and is ready to work on p: go_router The go_router package P1 High-priority issues at the top of the work list package flutter/packages repository. See also p: labels. team-go_router Owned by Go Router team triaged-go_router Triaged by Go Router team
Projects
None yet
Development

No branches or pull requests