Skip to content

Commit 02a3980

Browse files
committed
compose: Add timeout to send message requests
Signed-off-by: Zixuan James Li <[email protected]>
1 parent 69cb6e7 commit 02a3980

File tree

7 files changed

+52
-6
lines changed

7 files changed

+52
-6
lines changed

assets/l10n/app_en.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,10 @@
169169
"@errorQuotationFailed": {
170170
"description": "Error message when quoting a message failed."
171171
},
172+
"errorSendMessageTimeout": "Message isn’t sent. Check your connection.",
173+
"@errorSendMessageTimeout": {
174+
"description": "Error message when failed to send a message due to timeout."
175+
},
172176
"errorServerMessage": "The server said:\n\n{message}",
173177
"@errorServerMessage": {
174178
"description": "Error message that quotes an error from the server.",

lib/generated/l10n/zulip_localizations.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,12 @@ abstract class ZulipLocalizations {
325325
/// **'Quotation failed'**
326326
String get errorQuotationFailed;
327327

328+
/// Error message when failed to send a message due to timeout.
329+
///
330+
/// In en, this message translates to:
331+
/// **'Message isn’t sent. Check your connection.'**
332+
String get errorSendMessageTimeout;
333+
328334
/// Error message that quotes an error from the server.
329335
///
330336
/// In en, this message translates to:

lib/generated/l10n/zulip_localizations_ar.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class ZulipLocalizationsAr extends ZulipLocalizations {
144144
@override
145145
String get errorQuotationFailed => 'Quotation failed';
146146

147+
@override
148+
String get errorSendMessageTimeout => 'Message isn’t sent. Check your connection.';
149+
147150
@override
148151
String errorServerMessage(String message) {
149152
return 'The server said:\n\n$message';

lib/generated/l10n/zulip_localizations_en.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class ZulipLocalizationsEn extends ZulipLocalizations {
144144
@override
145145
String get errorQuotationFailed => 'Quotation failed';
146146

147+
@override
148+
String get errorSendMessageTimeout => 'Message isn’t sent. Check your connection.';
149+
147150
@override
148151
String errorServerMessage(String message) {
149152
return 'The server said:\n\n$message';

lib/generated/l10n/zulip_localizations_ja.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,9 @@ class ZulipLocalizationsJa extends ZulipLocalizations {
144144
@override
145145
String get errorQuotationFailed => 'Quotation failed';
146146

147+
@override
148+
String get errorSendMessageTimeout => 'Message isn’t sent. Check your connection.';
149+
147150
@override
148151
String errorServerMessage(String message) {
149152
return 'The server said:\n\n$message';

lib/widgets/compose_box.dart

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import 'dart:async';
12
import 'dart:math';
23

34
import 'package:app_settings/app_settings.dart';
@@ -22,6 +23,8 @@ import 'store.dart';
2223
import 'text.dart';
2324
import 'theme.dart';
2425

26+
const Duration kSendMessageTimeout = Duration(seconds: 5);
27+
2528
const double _composeButtonSize = 44;
2629

2730
/// A [TextEditingController] for use in the compose box.
@@ -997,15 +1000,20 @@ class _SendButtonState extends State<_SendButton> {
9971000
widget.controller._enabled.value = false;
9981001

9991002
try {
1000-
await store.sendMessage(destination: widget.getDestination(), content: content);
1003+
await store
1004+
.sendMessage(destination: widget.getDestination(), content: content)
1005+
.timeout(kSendMessageTimeout);
10011006
widget.controller.content.clear();
1002-
} on ApiRequestException catch (e) {
1007+
} catch (e) {
10031008
if (!mounted) return;
10041009
final zulipLocalizations = ZulipLocalizations.of(context);
1005-
final message = switch (e) {
1006-
ZulipApiException() => zulipLocalizations.errorServerMessage(e.message),
1007-
_ => e.message,
1008-
};
1010+
String message;
1011+
switch (e) {
1012+
case ZulipApiException(): message = zulipLocalizations.errorServerMessage(e.message);
1013+
case ApiRequestException(): message = e.message;
1014+
case TimeoutException(): message = zulipLocalizations.errorSendMessageTimeout;
1015+
default: rethrow;
1016+
}
10091017
showErrorDialog(context: context,
10101018
title: zulipLocalizations.errorMessageNotSent,
10111019
message: message);

test/widgets/compose_box_test.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,25 @@ void main() {
480480
check(find.byType(LinearProgressIndicator)).findsNothing();
481481
});
482482

483+
testWidgets('fail after timeout', (tester) async {
484+
const longDelay = Duration(hours: 1);
485+
assert(longDelay > kSendMessageTimeout);
486+
await setupAndTapSend(tester, prepareResponse: (_) {
487+
connection.prepare(
488+
httpStatus: 400,
489+
json: {'result': 'error', 'code': 'BAD_REQUEST'},
490+
delay: longDelay);
491+
});
492+
493+
await tester.pump(kSendMessageTimeout);
494+
final zulipLocalizations = GlobalLocalizations.zulipLocalizations;
495+
await tester.tap(find.byWidget(checkErrorDialog(tester,
496+
expectedTitle: zulipLocalizations.errorMessageNotSent,
497+
expectedMessage: zulipLocalizations.errorSendMessageTimeout)));
498+
499+
await tester.pump(longDelay);
500+
});
501+
483502
testWidgets('ZulipApiException', (tester) async {
484503
await setupAndTapSend(tester, prepareResponse: (message) {
485504
connection.prepare(

0 commit comments

Comments
 (0)