From bdb0f1c75537a4d644fbad7e5a5d3695f39ed28c Mon Sep 17 00:00:00 2001 From: Chris Bobbe Date: Wed, 17 Jul 2024 12:17:04 -0700 Subject: [PATCH] compose box: On failed message send, show error dialog Fixes: #815 --- lib/widgets/compose_box.dart | 22 ++++++++++++++++++++-- test/widgets/compose_box_test.dart | 19 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/lib/widgets/compose_box.dart b/lib/widgets/compose_box.dart index c80c5dd26a..f3a651b7a0 100644 --- a/lib/widgets/compose_box.dart +++ b/lib/widgets/compose_box.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/zulip_localizations.dart'; import 'package:image_picker/image_picker.dart'; +import '../api/exception.dart'; import '../api/model/model.dart'; import '../api/route/messages.dart'; import '../model/compose.dart'; @@ -716,7 +717,7 @@ class _SendButtonState extends State<_SendButton> { || widget.contentController.hasValidationErrors.value; } - void _send() { + void _send() async { if (_hasValidationErrors) { final zulipLocalizations = ZulipLocalizations.of(context); List validationErrorMessages = [ @@ -735,9 +736,26 @@ class _SendButtonState extends State<_SendButton> { final store = PerAccountStoreWidget.of(context); final content = widget.contentController.textNormalized; - store.sendMessage(destination: widget.getDestination(), content: content); widget.contentController.clear(); + + try { + // TODO(#720) await send request, putting input(s) and send button into a + // disabled "working on it" state (allowing input text to be selected + // for copying). + await store.sendMessage(destination: widget.getDestination(), content: content); + } on ApiRequestException catch (e) { + if (!mounted) return; + final zulipLocalizations = ZulipLocalizations.of(context); + final message = switch (e) { + ZulipApiException() => zulipLocalizations.errorServerMessage(e.message), + _ => e.message, + }; + showErrorDialog(context: context, + title: zulipLocalizations.errorMessageNotSent, + message: message); + return; + } } @override diff --git a/test/widgets/compose_box_test.dart b/test/widgets/compose_box_test.dart index b64061ec91..0bafa3051b 100644 --- a/test/widgets/compose_box_test.dart +++ b/test/widgets/compose_box_test.dart @@ -16,6 +16,7 @@ import '../example_data.dart' as eg; import '../flutter_checks.dart'; import '../model/binding.dart'; import '../stdlib_checks.dart'; +import 'dialog_checks.dart'; void main() { TestZulipBinding.ensureInitialized(); @@ -219,5 +220,23 @@ void main() { final errorDialogs = tester.widgetList(find.byType(AlertDialog)); check(errorDialogs).isEmpty(); }); + + testWidgets('ZulipApiException', (tester) async { + await setupAndTapSend(tester, prepareResponse: (message) { + connection.prepare( + httpStatus: 400, + json: { + 'result': 'error', + 'code': 'BAD_REQUEST', + 'msg': 'You do not have permission to initiate direct message conversations.', + }); + }); + final zulipLocalizations = GlobalLocalizations.zulipLocalizations; + await tester.tap(find.byWidget(checkErrorDialog(tester, + expectedTitle: zulipLocalizations.errorMessageNotSent, + expectedMessage: zulipLocalizations.errorServerMessage( + 'You do not have permission to initiate direct message conversations.'), + ))); + }); }); }