'Flutter - use WillPopScope with custom dialog to confirm app exit

I've implemented app exit confirmation this way:

 return WillPopScope(
      onWillPop: _promptExit,
      child: Container() /*Remaining window layout*/

_promptExit funcion shows dialog to confirm exit:

return showDialog(
      context: context,
      builder: (context) => new AlertDialog(
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20.0))),
        title: new Text(Strings.prompt_exit_title),
        content: new Text(Strings.prompt_exit_content),
        actions: <Widget>[
          FlatButton(
            child: new Text(Strings.no),
            onPressed: () => Navigator.of(context).pop(false),
          ),
          SizedBox(height: 16),
          FlatButton(
            child: new Text(Strings.yes),
            onPressed: () => Navigator.of(context).pop(true),
          ),
        ],
      ),
    ) ??
        false;

It works, but I want to use custom dialog instead of standard one: https://github.com/marcos930807/awesomeDialogs

It calls showDialog internally, so I tried this way:

 AwesomeDialog dlg = AwesomeDialog(
      context: context,
      dialogType: DialogType.QUESTION,
      animType: AnimType.BOTTOMSLIDE,
      title: Strings.prompt_exit_title,
      desc: Strings.prompt_exit_content,
      dismissOnBackKeyPress: false,
      useRootNavigator: true,
      btnCancelOnPress: () {  Navigator.of(context).pop(false);},
      btnOkOnPress: () {   Navigator.of(context).pop(true);},
      btnOkText: Strings.yes,
      btnCancelText: Strings.no
    );

    return dlg.show() ?? false;

But I can't pop this way, I am getting black screen. What should I do?



Solution 1:[1]

showDialog will not pop the dialog itself. So you need to use Navigator.of(context).pop() and get the return value.

awesomeDialogs wrap the pop() function itself and do nothing to the return value (awesome_dialog.dart)

   ...
    pressEvent: () {
      dissmiss();
      btnOkOnPress?.call();
    },
   ...
    pressEvent: () {
      dissmiss();
      btnCancelOnPress?.call();
    },
   ...

dissmiss() {
  if (!isDissmisedBySystem) Navigator.of(context, rootNavigator:useRootNavigator)?.pop();
}
...

So you need to handle the return value by yourself and don't use pop() again:

var result;

AwesomeDialog dlg = AwesomeDialog(
  context: context,
  dialogType: DialogType.QUESTION,
  animType: AnimType.BOTTOMSLIDE,
  title: Strings.prompt_exit_title,
  desc: Strings.prompt_exit_content,
  dismissOnBackKeyPress: false,
  useRootNavigator: true,
  btnCancelOnPress: () {result = false;},
  btnOkOnPress: () {result = true;},
  btnOkText: Strings.yes,
  btnCancelText: Strings.no
);

await dlg.show();

return result;

Solution 2:[2]

Yes, you are right. So that's how it should look:

Future<bool> _promptExit()  async {

    bool canExit;

    AwesomeDialog dlg = AwesomeDialog(
      context: context,
      dialogType: DialogType.QUESTION,
      animType: AnimType.BOTTOMSLIDE,
      title: Strings.prompt_exit_title,
      desc: Strings.prompt_exit_content,
      dismissOnTouchOutside: true,
      btnCancelOnPress: () => canExit = false,
      btnOkOnPress: () => canExit = true,
      btnOkText: Strings.yes,
      btnCancelText: Strings.no
    );

    await dlg.show();
    return Future.value(canExit);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 yellowgray
Solution 2