Over the last few months, our Futter team has been hard at work making significant improvements to the Stream Chat Flutter SDK.
This version is focused on improving the developer experience by giving you more control and flexibility in how you use our core components and UI widgets.
For a detailed list of changes, including code examples, see our v4.0 migration guide.
Other examples:
- See our Stream Chat Flutter tutorial for an up-to-date guide using the latest Stream Chat version.
- See the Stream Flutter Samples repository with our fully-fledged messaging sample application using the latest version.
In addition to the functional changes outlined in this document, v4.0.0 comes with various bug fixes and performance improvements, and we recommend upgrading as soon as possible.
Name Changes
The majority of the Stream Chat widgets and classes have now been renamed to have a “Stream” prefix associated with them. This increases Stream widgets' discoverability and avoids name conflicts when importing.
For example, MessageListView
is now called StreamMessageListView
, and UserAvatar
is renamed to StreamUserAvatar
.
The old class names are deprecated and will be removed in the next major release (v5.0.0).
Business Logic - Controllers
This release sees the introduction of controllers to replace our current business logic implementations (Bloc). Please note that this is not related to the well-known Flutter Bloc package, but instead refers to the naming we used for our business logic components.
In this version we’re introducing controllers in place of their bloc counterparts:
- StreamChannelListController in favor of ChannelsBloc
- StreamMessageSearchListController in favor of MessageSearchBloc
- StreamUserListController in favor of UsersBloc
The Bloc components are deprecated in v4.0.0 but can still be used. They will be removed in the next major release (v5.0.0).
Example Code - StreamChannelListController
Let’s look at a code example to retrieve the list of channels. Pre-version 4.0.0, displaying a list of channels was achieved with the following code:
1234567891011121314151617181920212223class ChannelListPage extends StatelessWidget { const ChannelListPage({ Key? key, }) : super(key: key); // ignore: prefer_expression_function_bodies Widget build(BuildContext context) { return Scaffold( body: ChannelsBloc( child: ChannelListView( filter: Filter.in_( 'members', [StreamChat.of(context).currentUser!.id], ), sort: const [SortOption('last_message_at')], limit: 20, channelWidget: const ChannelPage(), ), ), ); } }
Take note of the ChannelsBloc widget in the tree. This required widget was accessed within the ChannelListView widget using InherittedWidgets, which allowed you to access and manipulate the state of the ChannelsBloc by calling ChannelsBloc.of(context)
.
While there is nothing significantly wrong with this approach, there are some limitations, and it makes accessing the state of your ChannelsBloc reliant on BuildContext and your position in the widget tree.
With v4.0.0, the equivalent of the above code is:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647class ChannelListPage extends StatefulWidget { const ChannelListPage({ Key? key, required this.client, }) : super(key: key); final StreamChatClient client; State<ChannelListPage> createState() => _ChannelListPageState(); } class _ChannelListPageState extends State<ChannelListPage> { late final _controller = StreamChannelListController( client: widget.client, filter: Filter.in_( 'members', [StreamChat.of(context).currentUser!.id], ), sort: const [SortOption('last_message_at')], ); void dispose() { _controller.dispose(); super.dispose(); } Widget build(BuildContext context) => Scaffold( body: RefreshIndicator( onRefresh: _controller.refresh, child: StreamChannelListView( controller: _controller, onChannelTap: (channel) => Navigator.push( context, MaterialPageRoute( builder: (_) => StreamChannel( channel: channel, child: const ChannelPage(), ), ), ), ), ), ); }
Although this code is longer and may seem more complex, it gives you more control over your channel list view state by introducing the StreamChannelListController.
In this example, you initialize the controller within a StatefullWidget. However, you have full control to initialize and expose it in whatever way makes sense for your application and architecture. You’re not reliant on BuildContext or your position in the widget tree to access and manipulate the controller and its state.
A benefit of this approach is that it also simplifies testing and mocking.
Similar to the above, the following controllers have also been introduced to replace their bloc counterparts:
- StreamMessageSearchListController
- StreamUserListController
Please see the migration guide for more examples and details.
An Improved Message Input Widget
The MessageInput
widget has undergone significant changes, now called StreamMessageInput
.
Similar to the controllers described above, we’ve added another called MessageInputController. This controller maintains the state of the message input and exposes various methods to allow you to customize and manipulate the underlying Message value.
A separate controller allows easier control over the message input content by moving logic out of the deprecated MessageInput and into the controller. This controller can then be created, managed, and exposed in whatever way you like.
Note that this controller is exposed within our stream_chat_flutter_core package, meaning you can use this controller without relying on our UI components. This distinction is true for all the newly introduced controllers.
The new StreamMessageInput
widget is also separated into smaller widgets: StreamCountDownButton, StreamAttachmentPicker, etc.
For additional information, please see the relevant section in our migration guide showing you various examples of using the new message input.
Removed Slidable Channel List Item
The default slidable channel preview behavior has been removed. We have created a guide showing you how you can easily add this functionality yourself.
Removed Video Compression
The automatic video compression when uploading a video has been removed. You can integrate this yourself by manipulating attachments using a custom attachment uploader.
Pin Permission Changes
pinPermissions
is no longer needed in the MessageListView widget. The permissions are automatically fetched for each Stream project. To enable users to pin the message, make sure the pin permissions are granted for different types of users on your Stream application dashboard.
Conclusion
We’re very excited about the v4 release and hope you enjoy using it. If you have any feedback or feature requests, please submit an issue on GitHub — it will help us improve our Chat SDK and build the APIs you need.
New to Stream? Try our 30-day free trial to access the latest version of our Flutter SDK, and check out our Maker Account that allows small teams and hobbyists to use Stream Chat for free.
Follow us on Twitter @getstream_io for all of our future updates.
As always, happy coding!