showTaskLoader<T> method
Shows a task loader dialog and executes a task asynchronously.
The showTaskLoader function displays a dialog with a circular progress indicator and an optional loading text. It also provides an option to cancel the task by showing a cancel button.
The task
parameter is a function that represents the task to be executed. It should return a future that resolves to a value of type T
.
The cancelTaskButton
parameter is the text to be displayed on the cancel button. It can be of any type and will be converted to a string.
The loadingText
parameter is the text to be displayed below the progress indicator. It can be of any type and will be converted to a string.
The yesButton
parameter is the text to be displayed on the OK button. It can be of any type and will be converted to a string.
The noButton
parameter is the text to be displayed on the NO button. It can be of any type and will be converted to a string.
The cancelConfirmationText
parameter is an optional message to be displayed before canceling the task. If provided, the user will be prompted to confirm the cancellation.
The onError
parameter is a callback function that is invoked when an error occurs during the task execution.
The function returns a future that resolves to the result of the task execution, or null
if the task was canceled.
Implementation
Future<T?> showTaskLoader<T>({
required Future<T?> Function() task,
Duration? timeout,
dynamic cancelTaskButton,
dynamic loadingText,
dynamic yesButton,
dynamic noButton,
dynamic cancelConfirmationText,
void Function(Object?)? onError,
void Function()? onCancel,
Widget? Function(Duration)? remainTimeWidget,
}) async {
late CancelableOperation<T?> operation;
Duration? remainTime = timeout;
Timer? timer;
var alertKey = GlobalKey();
showGeneralDialog(
context: this,
barrierDismissible: false,
pageBuilder: (BuildContext context, animation, secondaryAnimation) => PopScope(
canPop: onCancel != null,
onPopInvokedWithResult: (didPop, _) async {
if (didPop) await operation.cancel();
},
child: StatefulBuilder(builder: (BuildContext context, setState) {
if (cancelTaskButton == null && onCancel != null) {
cancelTaskButton = context.translations.cancel;
}
if (timeout != null && timeout.inSeconds > 0) {
timer ??= Timer.periodic(1.seconds, (timer) {
if (remainTime != null) {
remainTime = remainTime! - 1.seconds;
if (remainTime!.inSeconds <= 0) {
timer.cancel();
operation.cancel();
} else {
if (context.mounted) setState(() {});
}
}
});
}
return AlertDialog.adaptive(
key: alertKey,
actions: [
if (cancelTaskButton != null) ...[
ElevatedButton(
onPressed: () async {
if (cancelConfirmationText == null || await context.confirm(cancelConfirmationText, textCancel: noButton, textOK: yesButton)) {
await operation.cancel();
}
},
child: forceWidget(cancelTaskButton),
),
],
],
content: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
remainTime != null && remainTime!.inSeconds > 0
? CircularProgressIndicator(
value: 1 - (remainTime!.inSeconds / timeout!.inSeconds),
backgroundColor: Colors.grey.withValues(alpha: .1),
)
: const CircularProgressIndicator(),
if (loadingText != null) forceWidget(loadingText)!,
if (remainTimeWidget != null && remainTime != null && remainTime!.inSeconds > 0) forceWidget(remainTimeWidget(remainTime!))!,
].nonNulls.toList()
..insertBetween(const Gap(20)),
),
),
);
}),
),
);
operation = CancelableOperation.fromFuture(() async {
try {
var result = await task();
if (alertKey.currentContext != null) {
pop(result);
}
return result;
} catch (e) {
if (onError != null) {
if (alertKey.currentContext != null) {
pop(null);
}
onError(e); // Call onError function if provided
}
}
return null;
}(), onCancel: onCancel);
return await operation.valueOrCancellation();
}