Tudor Mihail
Tudor Mihail

Reputation: 23

Disabling the back option in Flutter

I am trying to disable the back navigation when \_timerStarted is true or \_isBrushing is true. This is my current implementation:

return PopScope(
    canPop: false,
    onPopInvokedWithResult: (didPop, result) async {
      // Allow pop only if the timer has finished or the user taps finishBrushing
      if (_timerStarted || _isBrushing) {
        // Show snackBar with 'Finish brushing to exit the screen'
        return; // Prevent exiting the screen by not invoking the pop
      }

      final navigator = Navigator.of(context);
      navigator.pop(result);
    },
    child: Scaffold(
    ...
    )
);

This is perfectly working, but whenever the back option is working and I exit the screen, I get the error:

E/flutter ( 5204): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: 'package:flutter/src/widgets/navigator.dart': Failed assertion: line 5350 pos 12: '!_debugLocked': is not true. E/flutter ( 5204): #0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:50:61) E/flutter ( 5204): #1
_AssertionError._throwNew (dart:core-patch/errors_patch.dart:40:5) E/flutter ( 5204): #2 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:5350:12) E/flutter ( 5204): #3 TimerScreenState.build. (package:toothbrush/timer.dart:594:21) E/flutter ( 5204): #4
PopScope._callPopInvoked (package:flutter/src/widgets/pop_scope.dart:137:30) E/flutter ( 5204): #5 _PopScopeState.onPopInvokedWithResult (package:flutter/src/widgets/pop_scope.dart:172:12) E/flutter ( 5204): #6 ModalRoute.onPopInvokedWithResult (package:flutter/src/widgets/routes.dart:1780:16) E/flutter ( 5204): #7 _RouteEntry.handlePop (package:flutter/src/widgets/navigator.dart:3171:11) E/flutter ( 5204): #8 NavigatorState._flushHistoryUpdates (package:flutter/src/widgets/navigator.dart:4340:22) E/flutter ( 5204): #9 NavigatorState.pop (package:flutter/src/widgets/navigator.dart:5368:7) E/flutter ( 5204): #10 TimerScreenState.build. (package:toothbrush/timer.dart:594:21) E/flutter ( 5204): #11
PopScope._callPopInvoked (package:flutter/src/widgets/pop_scope.dart:137:30) E/flutter ( 5204): #12 _PopScopeState.onPopInvokedWithResult (package:flutter/src/widgets/pop_scope.dart:172:12) E/flutter ( 5204): #13 ModalRoute.onPopInvokedWithResult (package:flutter/src/widgets/routes.dart:1780:16) E/flutter ( 5204): #14 NavigatorState.maybePop (package:flutter/src/widgets/navigator.dart:5319:25) E/flutter ( 5204): E/flutter ( 5204): #15
WidgetsBinding.handlePopRoute (package:flutter/src/widgets/binding.dart:848:11) E/flutter ( 5204): E/flutter ( 5204): #16
MethodChannel._handleAsMethodCall (package:flutter/src/services/platform_channel.dart:571:42) E/flutter ( 5204): E/flutter ( 5204): #17
_DefaultBinaryMessenger.setMessageHandler. (package:flutter/src/services/binding.dart:618:22) E/flutter ( 5204): E/flutter ( 5204):

Again, everything works as expected, but I would like to understand and fix this error as well. What can I do?

Upvotes: 1

Views: 81

Answers (1)

gopelkujo
gopelkujo

Reputation: 832

As you can see in the onPopInvokedWithResult documentation:

This will still be called even when the pop is canceled. A pop is canceled when the relevant Route.popDisposition returns false, such as when canPop is set to false on a PopScope. The didPop parameter indicates whether or not the back navigation actually happened successfully.

You should check the didPop variable first before doing any other things in onPopInvokedWithResult. I added the didPop checking in your code:

return PopScope(
    canPop: false,
    onPopInvokedWithResult: (didPop, result) async {
      // Check if [didPop], then don't continue the process.
      if (didPop) return;

      // Allow pop only if the timer has finished or the user taps finishBrushing
      if (_timerStarted || _isBrushing) {
        // Show snackBar with 'Finish brushing to exit the screen'
        return; // Prevent exiting the screen by not invoking the pop
      }

      final navigator = Navigator.of(context);
      navigator.pop(result);
    },
    child: Scaffold(
    ...
    )
);

Upvotes: 2

Related Questions