Announcing v4 of the Flutter SDK for Stream Chat

...

We’re excited to announce v4.0.0 of our Flutter Chat SDK. Learn about all the updates, changes, and how you can upgrade here.

v4 Flutter Chat SDK feature image

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:

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:

class ChannelListPage extends StatelessWidget {
  const ChannelListPage({
    Key? key,
  }) : super(key: key);

  @override
  // 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:

class ChannelListPage extends StatefulWidget {
  const ChannelListPage({
    Key? key,
    required this.client,
  }) : super(key: key);

  final StreamChatClient client;

  @override
  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')],
  );

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  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!