import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; extension Dialogs on BuildContext { Future _pushLoaderDialog() { final ctxWaiter = Completer(); showDialog( barrierDismissible: false, context: this, builder: (loaderContext) { if (!ctxWaiter.isCompleted) ctxWaiter.complete(loaderContext); return Dialog( child: LinearProgressIndicator(), ); }, ); return ctxWaiter.future; } /// For an async or other function, shows a /// loading dialog as the computation processes. /// /// If successful, the loading dialog is dismissed /// and the value is returned. /// /// If there is an error, an error dialog replaces /// the loading dialog. Upon dismissal of this /// error dialog, the error is rethrown. /// /// A generic error dialog is shown if /// [errorDialogBuilder] is null, or if the method /// returns null. /// /// If [errorDialogBuilder] is not given and [showLogBtn] /// is, the errorDialog will have a 'Show logs' button /// that shows logs in a new dialog when pressed. /// /// If [errorDialogBuilder] is provided, an /// [showLogBtn] is also true exception is thrown; Future loaderWithErrorDialog( FutureOr Function() computation, { Future Function( Object error, [ StackTrace stackTrace, ])? errorDialogBuilder, }) async { final loaderContext = await _pushLoaderDialog(); late final T value; try { value = await computation(); } catch (error, stackTrace) { Future attemptParameterErrorBuilder() async { if (errorDialogBuilder == null) return false; await errorDialogBuilder(error, stackTrace); return true; } Future showGenericOrUserDefinedErrorDialog() async { final didPEBSucceed = await attemptParameterErrorBuilder(); if (didPEBSucceed) return; if (kDebugMode) { return simpleDialog( error: error, stackTrace: stackTrace, ); } return simpleDialog(); } if (!loaderContext.mounted) rethrow; Navigator.of( loaderContext, rootNavigator: true, ).pop(); await showGenericOrUserDefinedErrorDialog(); rethrow; } if (loaderContext.mounted) { Navigator.of( loaderContext, rootNavigator: true, ).pop(); } return value; } Future simpleDialog({ String title = 'An error occurred', String content = 'Please try again later', Widget? extraAction, dynamic error, StackTrace? stackTrace, }) => showDialog( context: this, barrierDismissible: false, builder: (context) { final contentText = Text(content); return AlertDialog( title: Text(title, style: TextStyle( color: Color(0xFF898C81), fontWeight: FontWeight.w700)), content: content.length > 300 ? SingleChildScrollView( child: Text(content, style: TextStyle(color: Color(0xFF898C81))), ) : Text( content, style: TextStyle( color: Color(0xFF898C81)), // Set content text color ), actions: [ TextButton( onPressed: Navigator.of( this, rootNavigator: true, ).pop, style: TextButton.styleFrom( // backgroundColor: Color(0xFFAA8E83), // Background color backgroundColor: Color(0xFFB68A34), // Background color foregroundColor: Colors.white, // Font (text) color side: BorderSide( // color: Color(0xFF92722A)), // Border outline color color: Color(0xFFB68A34)), // Border outline color shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), // Optional: Rounded corners ), padding: EdgeInsets.symmetric( horizontal: 16, vertical: 12), // Optional: Padding ), child: const Text('Return'), ), if (extraAction != null) extraAction, if (error != null) ElevatedButton( onPressed: () { Navigator.of(context, rootNavigator: true).pop(); simpleDialog( title: 'Logs', content: '$error\n\nStackTrace: $stackTrace', ); }, child: const Text('Show Logs'), ), ], ); }, ); Future confirmationDialog( String titleText, String contentText, { String cancelText = 'Cancel', String confirmText = 'Confirm', }) => showDialog( context: this, barrierDismissible: false, builder: (context) => AlertDialog( title: Text(titleText), content: Text(contentText), actions: [ TextButton( onPressed: () => Navigator.of( this, rootNavigator: true, ).pop(false), child: Text(cancelText), ), ElevatedButton( onPressed: () => Navigator.of( this, rootNavigator: true, ).pop(true), child: Text( confirmText, ), ), ], ), ); }