import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:smooth_app/generic_lib/buttons/smooth_action_button.dart'; import 'package:smooth_app/generic_lib/dialogs/smooth_alert_dialog.dart'; /// Dialog with a stop button, while a future is running. /// /// Typical use-case: wait during download. class LoadingDialog { LoadingDialog._(); /// Is the dialog already pop'ed? bool _popEd = false; /// Runs a future while displaying a stoppable dialog. static Future run({ required final BuildContext context, required final Future future, final String? title, }) { final AppLocalizations? appLocalizations = AppLocalizations.of(context); return LoadingDialog._()._run( context: context, future: future, title: title ?? appLocalizations!.loading_dialog_default_title, ); } /// Shows an loading error dialog. /// /// Typical use-case: when the [run] call failed. static Future error({ required final BuildContext context, final String? title, }) async => showDialog( context: context, builder: (BuildContext context) { final AppLocalizations? appLocalizations = AppLocalizations.of(context); return SmoothAlertDialog( body: ListTile( leading: const Icon(Icons.error), title: Text( title ?? appLocalizations!.loading_dialog_default_error_message, ), ), actions: [ SmoothActionButton( text: appLocalizations!.close, onPressed: () => Navigator.pop(context), ), ], ); }, ); /// Displays "downloading" dialog while actually downloading Future _run({ required final BuildContext context, required final Future future, required final String title, }) async => showDialog( context: context, builder: (BuildContext context) { future.then( (final T value) => _popDialog(context, value), ); // TODO(monsieurtanuki): is that safe? If the future finishes before the "return" call? return _getDialog(context, title); }, ); /// Closes the dialog if relevant, pop'ing the [value] void _popDialog(final BuildContext context, final T? value) { if (_popEd) { return; } _popEd = true; // Here we use the root navigator so that we can pop dialog while using multiple navigators. Navigator.of(context, rootNavigator: true).pop(value); } /// Displayed dialog during future. Widget _getDialog( final BuildContext context, final String title, ) { final AppLocalizations? appLocalizations = AppLocalizations.of(context); return SmoothAlertDialog( body: ListTile( leading: const CircularProgressIndicator(), title: Text(title), ), actions: [ SmoothActionButton( text: appLocalizations!.stop, onPressed: () => _popDialog(context, null), ), ], ); } }