Skip to content

Custom/scoped popping and PopScope #50

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

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## [2.1.0] - 04/03/2025

- **BREAKING CHANGES!**: added dialog context to `confirmBtnTap` and `cancelBtnTap` functions. Signatures now are:
```dart
void Function(BuildContext context);
```
- Added `PopScope` widget with `canPop` to prevent unwanted navigation while dialog is showing.
- Updated README

## [2.0.1] - 06/03/2023

- Updated README
Expand Down
75 changes: 47 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,37 +22,56 @@ CoolAlert.show(
);
```


### CoolAlert Class

| Attribute | Data type | Description | Default Value |
|:---------------------|:-----------------------------|:---------------------------------------------------------------------------------|:-------------------------------------------------------------------------:|
| context | BuildContext | @required | Null |
| type | CoolAlertType | @required - Type of alert dialog, ex: CoolAlertType.success for success dialogs | Null |
| title | String | Set a custom title for dialog | Based on the CoolAlertType selected |
| text | String | Set the description text of the dialog. | Null |
| widget | Widget | Set any you expect widget of the dialog. | Null |
| confirmBtnText | String | Text of confirm button | 'Ok' |
| confirmBtnTap | void Function(BuildContext)? | Function that handle click of confirm button, provides dialog context parameter. | (c) => Navigator.pop(c) |
| confirmBtnColor | Color | Color of confirm Button | Theme.of(context).primaryColor |
| cancelBtnText | String | Text of cancel button | 'Cancel' |
| cancelBtnTap | void Function(BuildContext)? | Function that handle click of cancel button, provides dialog context parameter. | (c) => Navigator.pop(c) |
| barrierDismissible | bool | Dismiss dialog on touch overlay | true |
| animType | CoolAlertAnimType | Type of dialogue enter animation | CoolAlertAnimType.scale |
| backgroundColor | Color | Background color of the animation | Color(0xFF515C6F) |
| confirmBtnTextStyle | TextStyle | Confirm button text theme | TextStyle(color: Colors.white, fontWeight:FontWeight.w600,fontSize: 18.0) |
| cancelBtnTextStyle | TextStyle | Cancel button text theme | TextStyle(color: Colors.grey, fontWeight:FontWeight.w600,fontSize: 18.0) |
| flareAsset | String | Custom flare asset | "animation.flr" |
| flareAnimationName | String | The name of the flare animation to play | "play" |
| lottieAsset | String | Custom lottie asset | "animation.json" |
| autoCloseDuration | Duration | Determines how long the dialog stays open for before closing | Null |
| width | double | Dialog width | MediaQuery.of(context).size.width |
| loopAnimation | boolean | Determines if the animation should loop or not | false |
| closeOnConfirmBtnTap | boolean | Detemines if dialog closes when the confirm button is tapped | true |
| reverseBtnOrder | boolean | Reverse the order of the buttons | false |
| canPop | boolean | Prevents undesired navigation unless explicitly desired. | true |
| onPopInvoked | void Function(bool)? | Notifies of whether the context was popped with `didPop` parameter | Null |

### Popping the dialog

To pop the dialog from one of the buttons, you have the following options.

1. Using `closeOnConfirmBtnTap: true` will automatically pop the dialog when the confirm button is tapped.
2. Using `confirmBtnTap` or `cancelBtnTap` functions to pop the dialog manually. This should be done with the context provided (see notes below)
```dart
CoolAlert.show(
context: context,
type: CoolAlertType.success,
text: "Your transaction was successful!",
confirmBtnTap: (dialogContext) {
Navigator.pop(dialogContext);
}
);
```
**Notes:**

| Attribute | Data type | Description | Default Value |
|:----------------------|:-------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------|:-----------------------------------:|
| context| BuildContext | @required | Null |
| type | CoolAlertType | @required - Type of alert dialog, ex: CoolAlertType.success for success dialogs | Null
title| String | Set a custom title for dialog | Based on the CoolAlertType selected| |
| text| String | Set the description text of the dialog. | Null |
| widget| Widget | Set any you expect widget of the dialog. | Null |
| confirmBtnText | String | Text of confirm button | 'Ok' | |
| confirmBtnTap| Function | Function that handle click of confirm button | () => Navigator.pop(context)|
| confirmBtnColor| Color | Color of confirm Button | Theme.of(context).primaryColor | |
| cancelBtnText| String | Text of cancel button | 'Cancel' |
| cancelBtnTap| Function | Function that handle click of cancel button | () => Navigator.pop(context)
| barrierDismissible| bool | Dismiss dialog on touch overlay | true
| animType | CoolAlertAnimType| Type of dialogue enter animation | CoolAlertAnimType.scale|
| backgroundColor | Color| Background color of the animation | Color(0xFF515C6F)|
| confirmBtnTextStyle | TextStyle | Confirm button text theme | TextStyle(color: Colors.white, fontWeight:FontWeight.w600,fontSize: 18.0)|
| cancelBtnTextStyle | TextStyle | Cancel button text theme | TextStyle(color: Colors.grey, fontWeight:FontWeight.w600,fontSize: 18.0)|
| flareAsset | String | Custom flare asset | "animation.flr" |
| flareAnimationName | String | The name of the flare animation to play | "play" |
| lottieAsset | String | Custom lottie asset | "animation.json" |
|autoCloseDuration|Duration|Determines how long the dialog stays open for before closing|Null|
|width|double|Dialog width|MediaQuery.of(context).size.width|
|loopAnimation|boolean|Determines if the animation should loop or not|false|
|closeOnConfirmBtnTap|boolean|Detemines if dialog closes when the confirm button is tapped|true|
|reverseBtnOrder|boolean|Reverse the order of the buttons|false|


- if you have have `closeOnConfirmBtnTap: true` while calling `Navigator.pop(dialogContext)` in the above example, you'll pop twice and may run into some issues. Have either one or the other.
- If you have `autoCloseDuration` set, this is a wrapper for `Navigator.pop(coolAlertParentContext, rootNavigator: true)` after the duration is up. In the above example, if the user taps "confirm" and the dialog auto closes, it will pop twice and you may run into issues.



Expand Down
30 changes: 29 additions & 1 deletion example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ class _MyHomePageState extends State<MyHomePage> {
onChanged: (value) => message = value,
),
closeOnConfirmBtnTap: false,
onConfirmBtnTap: () async {
onConfirmBtnTap: (_) async {
if (message.length < 5) {
await CoolAlert.show(
context: context,
Expand All @@ -163,6 +163,33 @@ class _MyHomePageState extends State<MyHomePage> {
color: Colors.orange,
);

final unpoppableAlert = _buildButton(
onTap: () {
CoolAlert.show(
context: context,
type: CoolAlertType.custom,
text: 'You cannot pop this alert except with Navigator(root) pop',
// closeOnConfirmBtnTap: false,
canPop: false,
closeOnConfirmBtnTap: false,
onPopInvoked: (didPop) {
print('Pop invoked, has page been popped? $didPop');
},
confirmBtnText: "Pop with dialog context",
onConfirmBtnTap: (context) {
print("Confirm tapped");
},
showCancelBtn: true,
cancelBtnText: "Pop with root context",
onCancelBtnTap: (context) {
Navigator.of(context).pop();
},
);
},
text: 'Unpoppable',
color: Colors.blue,
);

return Scaffold(
appBar: AppBar(
title: Text(widget.title),
Expand All @@ -179,6 +206,7 @@ class _MyHomePageState extends State<MyHomePage> {
confirmAlert,
loadingAlert,
customAlert,
unpoppableAlert,
],
),
),
Expand Down
24 changes: 19 additions & 5 deletions lib/cool_alert.dart
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,11 @@ class CoolAlert {
/// Barrier Dissmisable
bool barrierDismissible = true,

// Triggered when confirm button is tapped
VoidCallback? onConfirmBtnTap,
/// Triggered when confirm button is tapped, [BuildContext] parameter is scoped to the dialog
void Function(BuildContext)? onConfirmBtnTap,

/// Triggered when cancel button is tapped
VoidCallback? onCancelBtnTap,
/// Triggered when cancel button is tapped, [BuildContext] parameter is scoped to the dialog
void Function(BuildContext)? onCancelBtnTap,

/// Confirmation button text
String confirmBtnText = 'Ok',
Expand Down Expand Up @@ -105,6 +105,14 @@ class CoolAlert {
/// When it is false, you will have to close it manually by using Navigator.of(context).pop();
bool closeOnConfirmBtnTap = true,

/// Determines if the dialog can be popped, a wrapper for [PopScope.canPop].
/// If false, the dialog will not be popped.
bool canPop = true,

/// Triggered when the dialog is popped, a wrapper for [PopScope.onPopInvoked].
/// [bool] parameter indicates if the dialog has been popped.
void Function(bool)? onPopInvoked,

/// Reverse the order of the buttons
bool reverseBtnOrder = false,
}) {
Expand Down Expand Up @@ -143,7 +151,7 @@ class CoolAlert {
reverseBtnOrder: reverseBtnOrder,
);

final child = AlertDialog(
final dialog = AlertDialog(
contentPadding: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(borderRadius),
Expand All @@ -153,6 +161,12 @@ class CoolAlert {
),
);

final child = PopScope(
canPop: canPop,
onPopInvoked: onPopInvoked,
child: dialog,
);

return showGeneralDialog(
barrierColor: Colors.black.withOpacity(0.5),
transitionBuilder: (context, anim1, __, widget) {
Expand Down
4 changes: 2 additions & 2 deletions lib/src/models/cool_alert_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ class CoolAlertOptions {
CoolAlertType type;
CoolAlertAnimType? animType;
bool? barrierDismissible = false;
VoidCallback? onConfirmBtnTap;
VoidCallback? onCancelBtnTap;
void Function(BuildContext)? onConfirmBtnTap;
void Function(BuildContext)? onCancelBtnTap;
String? confirmBtnText;
String? cancelBtnText;
Color? confirmBtnColor;
Expand Down
4 changes: 2 additions & 2 deletions lib/src/widgets/cool_alert_buttons.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class CoolAlertButtons extends StatelessWidget {
isOkayBtn: true,
text: options.confirmBtnText!,
onTap: () {
options.onConfirmBtnTap?.call();
options.onConfirmBtnTap?.call(context);

// If autoCloseDuration is NOT null, it means the dialg will be auto closed, so disable confirm button tap
if (options.autoCloseDuration != null) {
Expand Down Expand Up @@ -66,7 +66,7 @@ class CoolAlertButtons extends StatelessWidget {
isOkayBtn: false,
text: options.cancelBtnText!,
onTap: () {
options.onCancelBtnTap?.call();
options.onCancelBtnTap?.call(context);
Navigator.pop(context);
},
);
Expand Down