Skip to content

Commit 6697b4b

Browse files
committed
compose: Show a progress bar when sending message
This progress bar shifts the message list because it increases the height of the compose box. This is undesirable, but a fix can be implemented in the future. Signed-off-by: Zixuan James Li <[email protected]>
1 parent 6e59307 commit 6697b4b

File tree

3 files changed

+38
-1
lines changed

3 files changed

+38
-1
lines changed

lib/widgets/compose_box.dart

+28
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,21 @@ class ComposeContentController extends ComposeController<ContentValidationError>
272272
}
273273
}
274274

275+
class _TopBar extends StatelessWidget {
276+
const _TopBar({required this.showProgressIndicator});
277+
278+
final bool showProgressIndicator;
279+
280+
@override
281+
Widget build(BuildContext context) {
282+
// TODO: Figure out a way so that this does not shift the message list
283+
// when it gains more height.
284+
return Column(children: [
285+
if (showProgressIndicator) _progressIndicator(context),
286+
]);
287+
}
288+
}
289+
275290
class _ContentInput extends StatefulWidget {
276291
const _ContentInput({
277292
required this.enabled,
@@ -1072,6 +1087,14 @@ class _SendButtonState extends State<_SendButton> {
10721087
}
10731088
}
10741089

1090+
Widget _progressIndicator(BuildContext context) {
1091+
final designVariables = DesignVariables.of(context);
1092+
return LinearProgressIndicator(
1093+
minHeight: 2.0,
1094+
backgroundColor: designVariables.foreground.withFadedAlpha(0.2),
1095+
color: designVariables.foreground.withFadedAlpha(0.5));
1096+
}
1097+
10751098
class _ComposeBoxContainer extends StatelessWidget {
10761099
const _ComposeBoxContainer({required this.children});
10771100

@@ -1094,12 +1117,14 @@ class _ComposeBoxContainer extends StatelessWidget {
10941117

10951118
class _ComposeBoxLayout extends StatelessWidget {
10961119
const _ComposeBoxLayout({
1120+
required this.topBar,
10971121
required this.topicInput,
10981122
required this.contentInput,
10991123
required this.composeButtonBar,
11001124
required this.sendButton,
11011125
});
11021126

1127+
final Widget topBar;
11031128
final Widget? topicInput;
11041129
final Widget contentInput;
11051130
final Widget composeButtonBar;
@@ -1133,6 +1158,7 @@ class _ComposeBoxLayout extends StatelessWidget {
11331158
data: iconButtonThemeData,
11341159
child: _ComposeBoxContainer(
11351160
children: [
1161+
topBar,
11361162
SafeArea(
11371163
minimum: const EdgeInsets.symmetric(horizontal: 8),
11381164
child: Column(children: [
@@ -1208,6 +1234,7 @@ class _StreamComposeBoxState extends State<_StreamComposeBox> implements Compose
12081234
valueListenable: _enabled,
12091235
builder: (context, enabled, child) {
12101236
return _ComposeBoxLayout(
1237+
topBar: _TopBar(showProgressIndicator: !enabled),
12111238
topicInput: _TopicInput(
12121239
enabled: enabled,
12131240
streamId: widget.narrow.streamId,
@@ -1293,6 +1320,7 @@ class _FixedDestinationComposeBoxState extends State<_FixedDestinationComposeBox
12931320
valueListenable: _enabled,
12941321
builder: (context, enabled, child) {
12951322
return _ComposeBoxLayout(
1323+
topBar: _TopBar(showProgressIndicator: !enabled),
12961324
topicInput: null,
12971325
contentInput: _FixedDestinationContentInput(
12981326
enabled: enabled,

test/widgets/compose_box_test.dart

+2
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ void main() {
443443
final composeBoxController = controllerKey.currentState!;
444444
check(composeBoxController.enabled).isFalse();
445445
check(composeBoxController.contentController.text).isNotEmpty();
446+
check(find.byType(LinearProgressIndicator)).findsOne();
446447

447448
await tester.tap(find.byIcon(ZulipIcons.send));
448449
await tester.pump(Duration.zero);
@@ -455,6 +456,7 @@ void main() {
455456
await tester.pump(const Duration(seconds: 2));
456457
check(composeBoxController.enabled).isTrue();
457458
check(composeBoxController.contentController.text).isEmpty();
459+
check(find.byType(LinearProgressIndicator)).findsNothing();
458460
});
459461

460462
testWidgets('re-enable compose box even on failure; do not clear text', (tester) async {

test/widgets/message_list_test.dart

+8-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import '../api/fake_api.dart';
2828
import '../example_data.dart' as eg;
2929
import '../model/binding.dart';
3030
import '../model/content_test.dart';
31+
import '../model/message_list_test.dart';
3132
import '../model/test_store.dart';
3233
import '../flutter_checks.dart';
3334
import '../stdlib_checks.dart';
@@ -652,10 +653,16 @@ void main() {
652653
..decoration.isNotNull().hintText.equals('Message #${otherChannel.name} > new topic')
653654
..controller.isNotNull().text.equals('Some text');
654655

656+
connection.takeRequests();
655657
connection.prepare(json: SendMessageResult(id: 1).toJson());
658+
// Prepare for the progress indicator that shifts the message list
659+
// and triggers a message fetch as soon as we send the message.
660+
connection.prepare(json: olderResult(
661+
anchor: message.id, foundOldest: true, messages: []).toJson());
656662
await tester.tap(find.byIcon(ZulipIcons.send));
657663
await tester.pump();
658-
check(connection.lastRequest).isA<http.Request>()
664+
final requests = connection.takeRequests();
665+
check(requests.first).isA<http.Request>()
659666
..method.equals('POST')
660667
..url.path.equals('/api/v1/messages')
661668
..bodyFields.deepEquals({

0 commit comments

Comments
 (0)