Skip to content

Commit b82ce14

Browse files
authored
fix(core): ensure StreamChannel future completes after channel initialization (#2324)
1 parent 72d6e35 commit b82ce14

File tree

4 files changed

+24
-14
lines changed

4 files changed

+24
-14
lines changed

packages/stream_chat_flutter_core/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
- Fixed `MessageListCore.dispose()` crash when channel reload fails due to insufficient permissions.
1111
- Fixed incorrect parent message comparison in `MessageListCore.didUpdateWidget()`.
12+
- Ensure `StreamChannel` future builder completes after channel
13+
initialization. [[#2323]](https://github.com/GetStream/stream-chat-flutter/issues/2323)
1214

1315
## 9.14.0
1416

packages/stream_chat_flutter_core/lib/src/stream_channel.dart

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,24 @@ class StreamChannel extends StatefulWidget {
8181
StackTrace? stackTrace,
8282
) {
8383
final backgroundColor = _getDefaultBackgroundColor(context);
84+
85+
Object? unwrapParallelError(Object error) {
86+
if (error case ParallelWaitError(:final List<AsyncError?> errors)) {
87+
return errors.firstWhereOrNull((it) => it != null)?.error;
88+
}
89+
90+
return error;
91+
}
92+
93+
final exception = unwrapParallelError(error);
8494
return Material(
8595
color: backgroundColor,
8696
child: Center(
87-
child: switch (error) {
97+
child: switch (exception) {
8898
DioException(type: DioExceptionType.badResponse) =>
89-
Text(error.message ?? 'Bad response'),
99+
Text(exception.message ?? 'Bad response'),
90100
DioException() => const Text('Check your connection and retry'),
91-
_ => Text(error.toString()),
101+
_ => Text(exception.toString()),
92102
},
93103
),
94104
);
@@ -728,12 +738,12 @@ class StreamChannelState extends State<StreamChannel> {
728738
if (channel.state?.isUpToDate == false) return loadChannelAtMessage(null);
729739
}
730740

731-
late Future<void> _channelInitFuture;
741+
late Future<List<void>> _channelInitFuture;
732742

733743
@override
734744
void initState() {
735745
super.initState();
736-
_channelInitFuture = _maybeInitChannel();
746+
_channelInitFuture = [_maybeInitChannel(), channel.initialized].wait;
737747
}
738748

739749
@override
@@ -742,7 +752,7 @@ class StreamChannelState extends State<StreamChannel> {
742752
if (oldWidget.channel.cid != widget.channel.cid ||
743753
oldWidget.initialMessageId != widget.initialMessageId) {
744754
// Re-initialize channel if the channel CID or initial message ID changes.
745-
_channelInitFuture = _maybeInitChannel();
755+
_channelInitFuture = [_maybeInitChannel(), channel.initialized].wait;
746756
}
747757
}
748758

packages/stream_chat_flutter_core/test/message_list_core_test.dart

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ void main() {
9292
);
9393

9494
final mockChannel = MockChannel();
95-
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
9695
when(() => mockChannel.state.unreadCount).thenReturn(0);
9796
when(() => mockChannel.state.isUpToDate).thenReturn(true);
9897
when(() => mockChannel.state.messagesStream)
@@ -135,7 +134,6 @@ void main() {
135134
when(() => mockChannel.state.messagesStream)
136135
.thenAnswer((_) => Stream.value([]));
137136
when(() => mockChannel.state.messages).thenReturn([]);
138-
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
139137

140138
await tester.pumpWidget(
141139
StreamChannel(
@@ -178,7 +176,6 @@ void main() {
178176
when(() => mockChannel.state.messagesStream)
179177
.thenAnswer((_) => Stream.value(messages));
180178
when(() => mockChannel.state.messages).thenReturn(messages);
181-
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
182179

183180
await tester.pumpWidget(
184181
StreamChannel(
@@ -224,7 +221,6 @@ void main() {
224221
final mockChannel = MockChannel();
225222

226223
when(() => mockChannel.state.isUpToDate).thenReturn(true);
227-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
228224

229225
const error = 'Error! Error! Error!';
230226
when(() => mockChannel.state.messagesStream)
@@ -266,7 +262,6 @@ void main() {
266262
final mockChannel = MockChannel();
267263

268264
when(() => mockChannel.state.isUpToDate).thenReturn(true);
269-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
270265

271266
const messages = <Message>[];
272267
when(() => mockChannel.state.messagesStream)
@@ -307,7 +302,6 @@ void main() {
307302
final mockChannel = MockChannel();
308303

309304
when(() => mockChannel.state.isUpToDate).thenReturn(false);
310-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
311305
when(() => mockChannel.query(
312306
state: any(named: 'state'),
313307
watch: any(named: 'watch'),
@@ -362,7 +356,6 @@ void main() {
362356
final mockChannel = MockChannel();
363357

364358
when(() => mockChannel.state.isUpToDate).thenReturn(true);
365-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
366359

367360
final messages = _generateMessages();
368361
when(() => mockChannel.state.messagesStream)
@@ -411,7 +404,6 @@ void main() {
411404
final mockChannel = MockChannel();
412405

413406
when(() => mockChannel.state.isUpToDate).thenReturn(true);
414-
when(() => mockChannel.initialized).thenAnswer((_) async => true);
415407

416408
final threads = {parentMessage.id: messages};
417409

packages/stream_chat_flutter_core/test/mocks.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,19 @@ class NonInitializedMockChannel extends Mock implements Channel {
3737

3838
@override
3939
ChannelClientState? get state => null;
40+
41+
@override
42+
Future<bool> get initialized async => false;
4043
}
4144

4245
class MockChannel extends NonInitializedMockChannel {
4346
ChannelClientState? _state;
4447

4548
@override
4649
ChannelClientState get state => _state ??= MockChannelState();
50+
51+
@override
52+
Future<bool> get initialized async => true;
4753
}
4854

4955
class MockChannelState extends Mock implements ChannelClientState {}

0 commit comments

Comments
 (0)