diff --git a/packages/stream_chat_flutter_core/CHANGELOG.md b/packages/stream_chat_flutter_core/CHANGELOG.md index 4ebfaa2bc..ea013ee6e 100644 --- a/packages/stream_chat_flutter_core/CHANGELOG.md +++ b/packages/stream_chat_flutter_core/CHANGELOG.md @@ -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 diff --git a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart index a26774106..08aae045d 100644 --- a/packages/stream_chat_flutter_core/lib/src/stream_channel.dart +++ b/packages/stream_chat_flutter_core/lib/src/stream_channel.dart @@ -81,14 +81,24 @@ class StreamChannel extends StatefulWidget { StackTrace? stackTrace, ) { final backgroundColor = _getDefaultBackgroundColor(context); + + Object? unwrapParallelError(Object error) { + if (error case ParallelWaitError(:final List 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()), }, ), ); @@ -728,12 +738,12 @@ class StreamChannelState extends State { if (channel.state?.isUpToDate == false) return loadChannelAtMessage(null); } - late Future _channelInitFuture; + late Future> _channelInitFuture; @override void initState() { super.initState(); - _channelInitFuture = _maybeInitChannel(); + _channelInitFuture = [_maybeInitChannel(), channel.initialized].wait; } @override @@ -742,7 +752,7 @@ class StreamChannelState extends State { 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; } } diff --git a/packages/stream_chat_flutter_core/test/message_list_core_test.dart b/packages/stream_chat_flutter_core/test/message_list_core_test.dart index afc0ce22a..b978f2e61 100644 --- a/packages/stream_chat_flutter_core/test/message_list_core_test.dart +++ b/packages/stream_chat_flutter_core/test/message_list_core_test.dart @@ -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) @@ -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( @@ -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( @@ -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) @@ -266,7 +262,6 @@ void main() { final mockChannel = MockChannel(); when(() => mockChannel.state.isUpToDate).thenReturn(true); - when(() => mockChannel.initialized).thenAnswer((_) async => true); const messages = []; when(() => mockChannel.state.messagesStream) @@ -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'), @@ -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) @@ -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}; diff --git a/packages/stream_chat_flutter_core/test/mocks.dart b/packages/stream_chat_flutter_core/test/mocks.dart index 2725fe098..723520225 100644 --- a/packages/stream_chat_flutter_core/test/mocks.dart +++ b/packages/stream_chat_flutter_core/test/mocks.dart @@ -37,6 +37,9 @@ class NonInitializedMockChannel extends Mock implements Channel { @override ChannelClientState? get state => null; + + @override + Future get initialized async => false; } class MockChannel extends NonInitializedMockChannel { @@ -44,6 +47,9 @@ class MockChannel extends NonInitializedMockChannel { @override ChannelClientState get state => _state ??= MockChannelState(); + + @override + Future get initialized async => true; } class MockChannelState extends Mock implements ChannelClientState {}