belovance / QuickAlert

An instantly ready, full-featured alerts for development on any platform with flutter. Enabling you to complete projects and deploy quickly. With QuickAlert, you can display animated alert dialogs such as success, error, warning, confirm, loading or even a custom dialog.
https://pub.dev/packages/quickalert
MIT License
46 stars 42 forks source link

Now onConfirmBtnTap, onCancelBtnTap callback functions will return current context #30

Closed abhay-s-rawat closed 5 months ago

abhay-s-rawat commented 5 months ago

Solved problem where when writing custom onConfirmBtnTap , popping the alert causes the screen to pop as we are popping top level context.

QuickAlert.show(
              context: context,
              type: QuickAlertType.error,
              title: "Deny rewards ?",
              cancelBtnText: 'Back',
              showCancelBtn: true,
              showConfirmBtn: true,
              //autoCloseDuration: const Duration(seconds: 10),
              onConfirmBtnTap: () {
// Some custom code
                Navigator.pop(context);
              },
            )
//Solution
// With below code we can catch the result too, thus detecting wheather the closure of alert is done by cancel/ok button or barrier dissmissable.
var result = await QuickAlert.show(
              context: context,
              type: QuickAlertType.error,
              title: "Deny rewards ?",
              cancelBtnText: 'Back',
              showCancelBtn: true,
              showConfirmBtn: true,
              //autoCloseDuration: const Duration(seconds: 10),
              onConfirmBtnTap: (ctx) {
// Some custom code
                Navigator.pop(ctx, true);
              },
            )
abhay-s-rawat commented 5 months ago

if you pass parent context and pop from the onConfirmBtnTap, it will pop current screen rather than popping dialogbox.I tested same in macos.

If you want to replicate then do as below: 1: Create a page that has a button ,on button press use navigator.push to push a new page. 2: In pushed page use another button that opens quickalert and make sure onConfirmBtnTap is not null. 3: Pass a function to onConfirmBtnTap and on end just pop the alert.

since the context of pushed page is passed on confirm button press the pushed page gets popped not the alert.

It will be well appriciated to discuss issue rather than just closing the pull request.

abhay-s-rawat commented 5 months ago

See in below file the context of alert is used to pop the alert not the parent. If you declare onConfirmBtnTap you cannot pop it

// quickalert_buttons.dart
@override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.only(top: 10.0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          cancelBtn(context),
          okayBtn(context), // the alert context not the parent which was passed
        ],
      ),
    );
  }

  Widget okayBtn(context) { // the alert context not the parent which was passed
    if (!options!.showConfirmBtn!) {
      return const SizedBox();
    }
    final showCancelBtn = options!.type == QuickAlertType.confirm
        ? true
        : options!.showCancelBtn!;

    final okayBtn = buildButton(
        context: context,
        isOkayBtn: true,
        text: options!.confirmBtnText!,
        onTap: () {
          options!.timer?.cancel();
// the alert context not the parent which was passed
// if options!.onConfirmBtnTap != null then user will use the parent context to pop which will pop current screen not alert
          options!.onConfirmBtnTap != null
              ? options!.onConfirmBtnTap!()
              : Navigator.pop(context);
        });

    if (showCancelBtn) {
      return Expanded(child: okayBtn);
    } else {
      return okayBtn;
    }
  }
abhay-s-rawat commented 5 months ago
//Solution 1
// replace below with
//options!.onConfirmBtnTap != null
//              ? options!.onConfirmBtnTap!()
//              : Navigator.pop(context);

if (options!.onConfirmBtnTap != null) {
     options!.onConfirmBtnTap!.call();
}
Navigator.pop(context);
// This will pop the alert always , if the onConfirmBtnTap is not null it will pop it after the function finished running.

//Problem:
// if async function is passed to onConfirmBtnTap it won't await and it will pop the alert regardless of function finish duration.
// So letting user decide when to pop will be best option.
//Solution 2: (recommened)
final okayBtn = buildButton(
        context: context,
        isOkayBtn: true,
        text: options!.confirmBtnText!,
        onTap: () {
          options!.timer?.cancel();
          options!.onConfirmBtnTap != null
              ? options!.onConfirmBtnTap!.call(context) // passed the alert context to the function
              : Navigator.pop(context);
        });

//Now user can decide when to pop even if the async function is passed to onConfirmBtnTap

onConfirmBtnTap: (ctx) async {
            // some async task
            Navigator.pop(ctx);
            }
          },