diff --git a/lib/widgets/action_sheet.dart b/lib/widgets/action_sheet.dart index 3784b65b01..91ea939419 100644 --- a/lib/widgets/action_sheet.dart +++ b/lib/widgets/action_sheet.dart @@ -120,7 +120,7 @@ class AddThumbsUpButton extends MessageActionSheetMenuItemButton { default: } - await showErrorDialog(context: context, + showErrorDialog(context: context, title: 'Adding reaction failed', message: errorMessage); } } @@ -165,7 +165,7 @@ class StarButton extends MessageActionSheetMenuItemButton { default: } - await showErrorDialog(context: messageListContext, + showErrorDialog(context: messageListContext, title: switch(op) { UpdateMessageFlagsOp.remove => zulipLocalizations.errorUnstarMessageFailedTitle, UpdateMessageFlagsOp.add => zulipLocalizations.errorStarMessageFailedTitle, @@ -215,7 +215,7 @@ Future fetchRawContentWithFeedback({ // TODO(?) give no feedback on error conditions we expect to // flag centrally in event polling, like invalid auth, // user/realm deactivated. (Support with reusable code.) - await showErrorDialog(context: context, + showErrorDialog(context: context, title: errorDialogTitle, message: errorMessage); } @@ -423,7 +423,7 @@ class ShareButton extends MessageActionSheetMenuItemButton { // Until we learn otherwise, assume something wrong happened. case ShareResultStatus.unavailable: if (!messageListContext.mounted) return; - await showErrorDialog(context: messageListContext, + showErrorDialog(context: messageListContext, title: zulipLocalizations.errorSharingFailed); case ShareResultStatus.success: case ShareResultStatus.dismissed: diff --git a/lib/widgets/actions.dart b/lib/widgets/actions.dart index d65801bc28..934e04934e 100644 --- a/lib/widgets/actions.dart +++ b/lib/widgets/actions.dart @@ -27,7 +27,7 @@ Future markNarrowAsRead(BuildContext context, Narrow narrow) async { return; } catch (e) { if (!context.mounted) return; - await showErrorDialog(context: context, + showErrorDialog(context: context, title: zulipLocalizations.errorMarkAsReadFailedTitle, message: e.toString()); // TODO(#741): extract user-facing message better return; diff --git a/lib/widgets/content.dart b/lib/widgets/content.dart index 5a58b929e2..f7918103fc 100644 --- a/lib/widgets/content.dart +++ b/lib/widgets/content.dart @@ -1195,7 +1195,7 @@ class GlobalTime extends StatelessWidget { } void _launchUrl(BuildContext context, String urlString) async { - Future showError(BuildContext context, String? message) { + DialogStatus showError(BuildContext context, String? message) { return showErrorDialog(context: context, title: 'Unable to open link', message: [ @@ -1207,7 +1207,7 @@ void _launchUrl(BuildContext context, String urlString) async { final store = PerAccountStoreWidget.of(context); final url = store.tryResolveUrl(urlString); if (url == null) { // TODO(log) - await showError(context, null); + showError(context, null); return; } @@ -1236,7 +1236,7 @@ void _launchUrl(BuildContext context, String urlString) async { } if (!launched) { // TODO(log) if (!context.mounted) return; - await showError(context, errorMessage); + showError(context, errorMessage); } } diff --git a/lib/widgets/dialog.dart b/lib/widgets/dialog.dart index d4d60128b8..c6bdc4ef65 100644 --- a/lib/widgets/dialog.dart +++ b/lib/widgets/dialog.dart @@ -15,16 +15,32 @@ Widget _dialogActionText(String text) { ); } +/// Tracks the status of a dialog, in being still open or already closed. +/// +/// See also: +/// * [showDialog], whose return value this class is intended to wrap. +class DialogStatus { + const DialogStatus(this.closed); + + /// Resolves when the dialog is closed. + final Future closed; +} + /// Displays an [AlertDialog] with a dismiss button. /// -/// Returns a [Future] that resolves when the dialog is closed. -Future showErrorDialog({ +/// The [DialogStatus.closed] field of the return value can be used +/// for waiting for the dialog to be closed. +// This API is inspired by [ScaffoldManager.showSnackBar]. We wrap +// [showDialog]'s return value, a [Future], inside [DialogStatus] +// whose documentation can be accessed. This helps avoid confusion when +// intepreting the meaning of the [Future]. +DialogStatus showErrorDialog({ required BuildContext context, required String title, String? message, }) { final zulipLocalizations = ZulipLocalizations.of(context); - return showDialog( + final future = showDialog( context: context, builder: (BuildContext context) => AlertDialog( title: Text(title), @@ -34,6 +50,7 @@ Future showErrorDialog({ onPressed: () => Navigator.pop(context), child: _dialogActionText(zulipLocalizations.errorDialogContinue)), ])); + return DialogStatus(future); } void showSuggestedActionDialog({ diff --git a/lib/widgets/lightbox.dart b/lib/widgets/lightbox.dart index 15751bbde1..5622ab9200 100644 --- a/lib/widgets/lightbox.dart +++ b/lib/widgets/lightbox.dart @@ -476,11 +476,11 @@ class _VideoLightboxPageState extends State with PerAccountSt assert(debugLog("VideoPlayerController.initialize failed: $error")); if (!mounted) return; final zulipLocalizations = ZulipLocalizations.of(context); - // Wait until the dialog is closed - await showErrorDialog( + final dialog = showErrorDialog( context: context, title: zulipLocalizations.errorDialogTitle, message: zulipLocalizations.errorVideoPlayerFailed); + await dialog.closed; if (!mounted) return; Navigator.pop(context); // Pops the lightbox } diff --git a/lib/widgets/login.dart b/lib/widgets/login.dart index 4027b93af0..0a05478be8 100644 --- a/lib/widgets/login.dart +++ b/lib/widgets/login.dart @@ -307,7 +307,7 @@ class _LoginPageState extends State { if (e is PlatformException && e.message != null) { message = e.message!; } - await showErrorDialog(context: context, + showErrorDialog(context: context, title: zulipLocalizations.errorWebAuthOperationalErrorTitle, message: message); } finally { @@ -351,7 +351,7 @@ class _LoginPageState extends State { if (e is PlatformException && e.message != null) { message = e.message!; } - await showErrorDialog(context: context, + showErrorDialog(context: context, title: zulipLocalizations.errorWebAuthOperationalErrorTitle, message: message); }