Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/stream_chat_flutter_core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

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

## 9.14.0

Expand Down
22 changes: 16 additions & 6 deletions packages/stream_chat_flutter_core/lib/src/stream_channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,24 @@ class StreamChannel extends StatefulWidget {
StackTrace? stackTrace,
) {
final backgroundColor = _getDefaultBackgroundColor(context);

Object? unwrapParallelError(Object error) {
if (error case ParallelWaitError(:final List<AsyncError?> errors)) {
return errors.firstWhereOrNull((it) => it != null)?.error;
}

return error;
}

final exception = unwrapParallelError(error);
return Material(
color: backgroundColor,
child: Center(
child: switch (error) {
child: switch (exception) {
DioException(type: DioExceptionType.badResponse) =>
Text(error.message ?? 'Bad response'),
Text(exception.message ?? 'Bad response'),
DioException() => const Text('Check your connection and retry'),
_ => Text(error.toString()),
_ => Text(exception.toString()),
},
),
);
Expand Down Expand Up @@ -728,12 +738,12 @@ class StreamChannelState extends State<StreamChannel> {
if (channel.state?.isUpToDate == false) return loadChannelAtMessage(null);
}

late Future<void> _channelInitFuture;
late Future<List<void>> _channelInitFuture;

@override
void initState() {
super.initState();
_channelInitFuture = _maybeInitChannel();
_channelInitFuture = [_maybeInitChannel(), channel.initialized].wait;
}

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ void main() {
);

final mockChannel = MockChannel();
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));
when(() => mockChannel.state.unreadCount).thenReturn(0);
when(() => mockChannel.state.isUpToDate).thenReturn(true);
when(() => mockChannel.state.messagesStream)
Expand Down Expand Up @@ -135,7 +134,6 @@ void main() {
when(() => mockChannel.state.messagesStream)
.thenAnswer((_) => Stream.value([]));
when(() => mockChannel.state.messages).thenReturn([]);
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));

await tester.pumpWidget(
StreamChannel(
Expand Down Expand Up @@ -178,7 +176,6 @@ void main() {
when(() => mockChannel.state.messagesStream)
.thenAnswer((_) => Stream.value(messages));
when(() => mockChannel.state.messages).thenReturn(messages);
when(() => mockChannel.initialized).thenAnswer((_) => Future.value(true));

await tester.pumpWidget(
StreamChannel(
Expand Down Expand Up @@ -224,7 +221,6 @@ void main() {
final mockChannel = MockChannel();

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

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

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

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

when(() => mockChannel.state.isUpToDate).thenReturn(false);
when(() => mockChannel.initialized).thenAnswer((_) async => true);
when(() => mockChannel.query(
state: any(named: 'state'),
watch: any(named: 'watch'),
Expand Down Expand Up @@ -362,7 +356,6 @@ void main() {
final mockChannel = MockChannel();

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

final messages = _generateMessages();
when(() => mockChannel.state.messagesStream)
Expand Down Expand Up @@ -411,7 +404,6 @@ void main() {
final mockChannel = MockChannel();

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

final threads = {parentMessage.id: messages};

Expand Down
6 changes: 6 additions & 0 deletions packages/stream_chat_flutter_core/test/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@ class NonInitializedMockChannel extends Mock implements Channel {

@override
ChannelClientState? get state => null;

@override
Future<bool> get initialized async => false;
}

class MockChannel extends NonInitializedMockChannel {
ChannelClientState? _state;

@override
ChannelClientState get state => _state ??= MockChannelState();

@override
Future<bool> get initialized async => true;
}

class MockChannelState extends Mock implements ChannelClientState {}