Chat Flutter v3
Chat Flutter
Chat
Flutter
Home
/
Chat
/
Flutter

Group Channel

A group channel is a chat that allows close interactions among a limited number of users.

Group channels can be private or public. A private group channel can let a user join the chat through an invitation by another user who is already a member of the chatroom. For 1-to-1 messaging, you can create a private group channel with two members. A public group chat can let a user join the chat without invitation from others. A group channel can consist of one to one hundred members by default setting. This default number of members can increase per request.

A user can receive all messages from the group channels that they are a member of, and sends a message to those channels. They can also receive push notifications, typing indicators, unread counts and read receipts from the joined channels when they go offline. For more information, see the Push notifications page.

Note: To learn about differences between open channels and group channels, see Channel types.


Choose a type of a channel

Sendbird Chat SDK for Flutter allows you to use a variety of behavior-related properties when creating different types of group channels.

Private vs. Public

A private group channel can be joined only by users that have accepted an invitation from an existing channel member by default. On the other hand, a public group channel can be joined by any user without an invitation, like an open channel.

A private channel can be used for 1-on-1 conversations, such as clinical consultations and Instagram-style Direct Messages, while a public channel for 1-to-N conversations, such as small group discussions among students.

1-to-1 vs. 1-to-N

The isDistinct property determines whether to resume an old channel or to create a new one when someone attempts to open a channel with the same members. For a 1-to-1 chat, it is highly recommended that you turn on the isDistinct property to continuously use the existing channel.

Let's say there is a distinct group channel with user A, B, and C. If you attempt to create a new channel with the same members, the existing channel will be used. This is similar to Twitter-style 1-to-1 direct messaging. If the distinct property of the channel is set to false, a new channel will be created.

Note: The default value of this property is false. When a new member is invited or an existing member leaves the channel, then the isDistinct property of the channel is automatically turned off as well.

Supergroup vs. Group

For occasions that demand engagement among a high volume of members, you can create a Supergroup channel, an expanded version of a group channel. It can be used for midsize conferences or large group discussion, such as company-wide stand-ups.

When the isSuper property is set to true, a Supergroup channel will be created and up to tens of thousands of members can gather in the channel. The maximum number of members for a Supergroup channel can be adjusted depending on your Chat subscription plan.

Note: When isSuper is set to true, isDistinct can't be supported.

Ephemeral vs. Persistent

Messages sent in an ephemeral group channel are not saved in Sendbird's database. As such, old messages that are pushed out of a user's chat view due to new messages can't be retrieved. On the other hand, messages sent in a persistent group channel are stored permanently in the database by default.


Create a channel

A user can create a group channel from inviting other users in their client app. At the implementation level, you need to create a GroupChannelParams object with a list of user IDs to invite. In the params, you can also specify a user ID to designate as an operator in the channel. Then, write a code what passes the user ID list as an argument to a parameter in the createChannel() method.

Before you write the code for creating a group channel for a typical 1-to-1 chat, you should make sure that you turn on the isDistinct property of the channel. Otherwise, if you turn off the isDistinct property, a new channel will be created with the same partner user even if there is already an existing channel between them. In this case, multiple 1-to-1 channels between the same two users can exist, each with its own chat history and data.

However, if you plan to create a Supergroup channel, the isDistinct property should be turned off.

try {
    final params = GroupChannelParams()
        ..userIds=userIds
        ..operatorUserIds=operatorUserIds;
    final channel = await GroupChannel.createChannel(params);
    // Now you can work with the channel object.
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

params

Type: GroupChannelParams
An object consisting of a set of parameters for group channel settings.

userIDs

Type: List<String>
A list of user IDs who be regular members of the channel.

operatorUserIds

Type: List<String>
A list of user IDs who be operators of the channel.


Invite users as members

Only members of a group channel can invite new users to the channel. You can also determine whether the newly invited user sees the past messages in the channel or not.

Note: You can set the Chat history option under Settings > Chat > Channels > Group channels in the Sendbird Dashboard. If the option is turned on, new members can view all messages that had been sent before they joined the channel. If turned off, new members only see messages sent after they came in. By default, this option is turned on.

final userIds = ['bob', 'young']
try {
    await groupChannel.inviteUsers(userIds);
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

userIds

Type: List<String>
A list of user IDs who will get invited to the channel.


Accept or decline an invitation from another user

A user who is invited to a group channel can accept or decline the invitation. If a user accepts an invitation, they join the channel as a new member and can start chatting with other members. Otherwise, the invitation will be canceled if a user declines it. Since a user is allowed to join up to 2,000 group channels, the invitation to a user who already belongs to a maximum number of group channels will be canceled automatically.

try {
    await groupChannel.acceptInvitation();
} catch (e) {
    // Handle error.
}

try {
    await groupChannel.declineInvitation();
} catch (e) {
    // Handle error.
}

By implementing the onUserReceivedInvitation() and onUserDeclinedInvitation() in the channel event handler, you can make the client apps of other members in the foreground to be notified of the results of two actions above.

Note: By using the setChannelInvitationPreference() you can determine for users within an application whether or not to automatically join a private group channel promptly from an invitation without having to accept it. By default, the value of channel invitation preference is true. If you want to give them the option to decide whether to accept or decline an invitation, you should set the value of the preference to false through the setChannelInvitationPreference() like the following sample code.

final autoAccept = false;

try {
    await sdk.setChannelInvitationPreference(autoAccept);
} catch (e) {
    // Handle error.
}

Join a channel as a member

This is only for public group channels. Any user can join a public group channel as a member without an invitation and chat with other members in the channel. Since a user is allowed to join up to 2,000 group channels, a user who already belongs to a maximum number of group channels can't join a new channel.

try {
    if (groupChannel.isPublic) {
        await groupChannel.join();
    }
} catch (e) {
    // Handle error.
}

Leave a channel

A user can leave group channels as shown below. After leaving, the user can't receive messages from the channel, and this method can't be called for deactivated users.

try {
    await groupChannel.leave();
} catch (e) {
    // Handle error.
}

Freeze and unfreeze a channel

You can temporarily freeze a group channel in order to stop members from chatting in the channel. Unfreezing the channel will enable the members to enjoy the chat again.

Note: In a frozen channel, regular members can't chat with each other, but the operators can send a message to the channel.

try {
    await groupChannel.freeze();
} catch (e) {
    // Handle error.
}
// When the channel successfully gets frozen, you can display a message telling that chatting in the channel is unavailable.
// Or set other actions in response to the successful operation.

try {
    await groupChannel.unfreeze();
} catch (e) {
    // Handle error.
}
// When the channel successfully gets unfrozen, you can display a message telling that chatting in the channel is now available.
// Or set other actions in response to the successful operation.

Delete a channel

Only the operators of a group channel can delete the channel. Otherwise, an error will be thrown, which should be handled through the try and catch blocks.

Note: The following code works properly in the operators' client apps only.

try {
    await groupChannel.deleteChannel();
    // The channel is successfully deleted.
} catch (e) {
    // Handle error.
}

Retrieve a list of channels

You can retrieve a list of the current user's private group channels using the loadNext() method of a GroupChannelListQuery instance, which returns a list of GroupChannel objects.

Note: Using the includeEmptyChannel option of a GroupChannelListQuery instance, you can determine whether to include empty channels in the result. Empty channels are group channels that have been created but don't contain any messages, and thus aren't included in the result by default. However, if you turn off the Chat history option in your dashboard, you may retrieve empty channels in the result.

try {
    final query = GroupChannelListQuery()
        ..includeEmptyChannel = true
        ..memberStateFilter = MemberStateFilter.joined
        ..order = GroupChannelListOrder.latestLastMessage
        ..limit = 15;
    final result = await query.loadNext();
    // A list of private group channels matching the list query criteria is successfully retrieved.
} catch (e) {
    // Handle error.
}

List of properties

Property nameDescription

includeEmptyChannel

Type: bool
Determines whether to include empty group channels in the results.

memberStateFilter

Type: MemberStateFilter
Restricts the search scope based on the state of the current user. Acceptable values include All, JOINED, and INVITED.

order

Type: GroupChannelListOrder
A list of user IDs who will get invited to the channel. Acceptable values are CHRONOLOGICAL, LATEST_LAST_MESSAGE, CHANNEL_NAME_ALPHABETICAL, and METADATA_VALUE_ALPHABETICAL.

limit

Type: int
Specifies the number of results to return per call. Acceptable values are 1 to 100, inclusive. The recommended value for this parameter is 30.

Note: Refer to this section in the Group channel > Advanced page for information on how to search for specific group channels with keywords and filters.


Retrieve a channel by URL

Since a channel URL is a unique identifier of a group channel, you can use a URL when retrieving a channel object.

try {
    final channel = await GroupChannel.getChannel(CHANNEL_URL);
    // Now you can work with the returned channel.
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

CHANNEL_URL

Type: String
Specifies the URL of the channel to retrieve.

Note: We recommend that you store a user's channel URLs to handle the lifecycle or state changes of your client app, or other unexpected situations. For example, when a user is disconnected from Sendbird server due to switching to another app temporarily, you can provide a smooth restoration of the user's state using a stored URL to fetch the appropriate channel instance.


Hide or archive a channel from a list of channels

The following code will allow you to hide or archive a specific group channel from a list of the channels.

try {
    await groupChannel.hideChannel(hidePreviousMessage: false, allowAutoUnhide: true);
} catch (e) {
    // Handle error.
}
// The channel successfully gets hidden from the list.
// The current user's channel view should be refreshed to reflect the change.

try {
    await groupChannel.unhideChannel();
} catch (e) {
    // Handle error.
}
// The channel successfully reappears in the list.
// The current user's channel view should be refreshed to reflect the change.

List of parameters

Parameter nameDescription

hidePreviousMessage

Type: bool
When the channel gets appeared back in the list, determines whether to conceal the messages sent and received before hiding or archiving the channel. If set to true, the previous messages aren't displayed in the channel. (Default: false)

allowAutoUnhide

Type: bool
Determines the state and operating behavior of the channel in the list. If set to true, the channel is hidden from the list and automatically reappears when receiving a new message from other members. If set to false, the channel is archived and disappears from the list, and never appears back unless the unhideChannel() method is called for unarchiving. (Default: true)


Filter channels by user IDs

Using the GroupChannelListQuery's userIdsExactFilter or userIdsIncludeFilter, you can filter group channels by user IDs. Let's assume the ID of the current user is “Harry” and the user is a member of three group channels:

  • Channel A: Harry and Jay.
  • Channel B: Harry, John, and Jin.
  • Channel C: Harry, John, Jin, and Jay.

A userIdsExactFilter returns a list of the current user's group channels containing exactly the queried user IDs. In case you specify only one user ID in the filter, the filter returns a list of the current user's one or more distinct 1-to-1 group channels with the specified user.

try {
    final query = GroupChannelListQuery()
        ..userIdsExactFilter = ['Jay'];
    final result = await query.loadNext();
} catch (e) {
    // Handle error.
}
// If successful, only Channel A is returned.

A userIdsIncludeFilter returns a list of the current user's group channels including the queried user IDs partially and exactly. Depending on the value of the GroupChannelListQueryType parameter, different results can be returned.

try {
    final query = GroupChannelListQuery()
    query.setUserIdsIncludeFilter(['John', 'Jay', 'Jin'], GroupChannelListQueryType.and);
    final result = await query.loadNext();
    // The result channels include only ['John', 'Jay', 'Jin'] as a subset. Thus, if successful, only Channel C is returned.
} catch (e) {
    // Handle error.
}

try {
    final query = GroupChannelListQuery()
    query.setUserIdsIncludeFilter(['John', 'Jay', 'Jin'], GroupChannelListQueryType.or);
    final result = await query.loadNext();
    // The result channels may include any of the elements in ['John', 'Jay', 'Jin']. Thus, if successful, all Channel A,B, and C are returned.
} catch (e) {
    // Handle error.
}

Send a message

In a group channel, users can send messages of the following types:

Message typeDescription

UserMessage

A text message sent by a user.

FileMessage

A binary file message sent by a user.

In addition to these message types, you can further subclassify a message by specifying its custom type. This custom type takes on the form of a String and can be used to search or filter messages. It allows you to append information to your message and customize message categorization.

The following code shows several types of parameters that you can configure to customize text messages by using a UserMessageParams. Under the UserMessageParams object, you can assign values to message, data and other properties. By assigning an arbitrary string to the data property, you can set custom font size, font type or JSON object. To send your messages, you need to pass the UserMessageParams object as an argument to the parameter in the sendUserMessage() method.

Note: Starting from Flutter Chat SDK 3.1.0, the UserMessageParams requires the message parameter.

Through the result of the sendUserMessage() method, Sendbird server always notifies whether your message has been successfully sent to the channel. When there is a delivery failure due to network issues, an exception will return.

try {
    final params = UserMessageParams(message: 'message')
        ..customType = 'custom'
        ..mentionType = MentionType.users
        ..mentionUserIds = ['Jeff', 'Julia']
        ..metaArrays = [
            MessageMetaArray(key: 'itemType', values: ['tablet']),
            MessageMetaArray(key: 'quality', values: ['best', 'good'])
        ]
        ..targetLanguages = ['fr', 'de']
        ..pushNotificationDeliveryOption = PushNotificationDeliveryOption.normal;

    final preMessage = groupChannel.sendUserMessage(params, onCompleted:(message, err) {
        // If error is null and message is sent successfully,
    });
    //use preMessage to display the message before it is sent to the server.
} catch (e) {
    // Handle error.
}

Send a binary message

A user can also send binary files through the Chat SDK. The two ways to send a binary file are: sending the file itself, or sending a file URL.

Sending a raw file means you're uploading it to Sendbird server where it can be downloaded in client apps. When you upload a file directly to the server, there is a size limit imposed on the file depending on your plan. You can see the limit in the Sendbird dashboard and adjust it with our sales team.

The other option is to send a file hosted on your server. You can pass the file's URL, which represents its location, as an argument to a parameter. In this case, your file is not hosted on Sendbird server and it can only be downloaded from your own server. When you send a file message with a URL, there is no limit on the file size since it's not directly uploaded to Sendbird server.

The following code shows several types of parameters that you can configure to customize your file messages by using a FileMessageParams. Under the FileMessageParams object, you can assign specific values to customType and other properties. To send your messages, you need to pass the FileMessageParams object as an argument to the parameter in the sendFileMessage() method.

Through the result of the sendFileMessage() method, Sendbird server always notifies whether your message has been successfully sent to the channel. When there is a delivery failure due to network issues, an exception will return.

try {
    final params = FileMessageParams.withFile(file, name: ‘file_name’)
        ..thumbnailSizes =  [Size(100, 100), Size(200, 200)]
        ..customType = 'custom'
        ..mentionType = MentionType.users
        ..mentonUserIds = ['Jeff', 'Julia']
        ..pushNotificationDeliveryOption = PushNotificationDeliveryOption.normal;

    final preMessage = groupChannel.sendFileMessage(params, onCompleted: (message, err) {
        // A file message with detailed configuration is successfully sent to the channel.
        // If error is null and message is sent successfully,
    });
    //use preMessage to display the message before it is sent to the server.
} catch (e) {
    // Handle error.
}

Reply to a message

You can reply to a specific message in a channel through the sendUserMessage() or sendFileMessage() method. To do so, you should create a UserMessageParams or a FileMessageParams object and then specify the parentMessageId property of the object. Sending reply messages works the same way as sending regular messages to a channel except replies have an additional parentMessageId property.

Reply with a text message

When replying to a message through the sendUserMessage() method, specify and pass a UserMessageParams object to the method as a parameter.

Note: Starting from Flutter Chat SDK 3.1.0, the UserMessageParams requires the message parameter.

try {
    final params = UserMessageParams(message: 'message')
        ..parentMessageId = PARENT_MESSAGE_ID;

    final result = await channel.sendUserMessage(params);
    // A reply to a specific message in the form of a text message is successfully sent.
} catch (e) {
    // Handle error.
}

List of parameters and properties

Parameter nameDescription

params

Type: UserMessageParams
An object consisting of a set of parameters for user message settings.

Property nameDescription

parentMessageId

Type: int?
Specifies the unique ID of a parent message. A parent message is a message that has a thread of replies. If the message sent through the sendUserMessage() method is a parent message, the value of this property is 0. If the message is a reply to a parent message, the value is the message ID of the parent message.

Reply with a file message

When replying with a file message through the sendFileMessage() method, specify and pass a FileMessageParams object as an argument to a parameter in the method.

try {
    final params = FileMessageParams().withFile(file, name: 'file_name')
        ..parentMessageId = PARENT_MESSAGE_ID;

    final result = await channel.sendFileMessage(params);
    // A reply to a specific message in the form of a text message is successfully sent
} catch (e) {
    // Handle error.
}

List of parameters and properties

Parameter nameDescription

params

Type: FileMessageParams
An object consisting of a set of parameters for file message settings.

PropertyDescription

parentMessageId

Type: int?
Specifies the unique ID of a parent message. A parent message is a message that has a thread of replies. If the message sent through the sendFileMessage() method is a parent message, the value of this property is 0. If the message is a reply to a parent message, the value is the message ID of the parent message.


Mention other members in a message

When a member wants to call the attention of other members in a group channel, they can mention those members in a message. Users have the option of calling specific members in the channel by their user IDs or calling all members in the channel.

Up to ten members mentioned in the message will be notified.

Mention by user IDs

To mention specific users, specify a list of the user IDs to mention in the userIDsToMention and add the list to either UserMessageParams or FileMessageParams which may contain options for further action. Then pass the params to either the sendUserMessages() or sendFileMessage() method, respectively.

Mentioned users must belong to the channel where the message is being sent. Users who are mentioned but don't belong to the channel won't be included in the mentioned user IDs array of the sent message.

Note: Starting from Flutter Chat SDK 3.1.0, UserMessageParams requires the message parameter.

try {
    final userIDsToMention = ['Harry', 'Jay', 'Jin'];

    final params = UserMessageParams(message: MESSAGE)
        ..mentionedUserIds = userIDsToMention;

    final preMessage = groupChannel.sendUserMessage(params, onCompleted: (msg, err) {
        // If error is null, message is sent successfully.
    });
} catch (e) {
    // Handle error.
}

Mention all channel members

When a user types "@channel" or other designated text in a message, you can set mentionType to MentionType.channel and let the user call the attention of everyone in the channel.

Note: Starting from Flutter Chat SDK 3.1.0, UserMessageParams requires the message parameter.

try {
    final params = UserMessageParams(message: MESSAGE)
        ..mentionType = MentionType.channel

    final preMessage = groupChannel.sendUserMessage(params, onCompleted: (msg, err) {
        // If error is null, message is sent successfully.
    });
} catch (e) {
    // Handle error.
}

Limitations

Using channel mention is subject to the following limitations.

Channel mentions per user

Channel sizeAllowed mentions per hour

Less than or equal to 100 users

10

Greater than 100 users

1

Channel mentions per channel

Channel sizeAllowed mentions per hour

Less than or equal to 100 users

100

Greater than 100 users

10


React to a message

Message reactions will help you build an engaging chat experience that goes beyond text messages. They are a quick and easy way for users to respond to a message. Users can express their acknowledgement of or feelings about a message without written text by simply adding reactions. They can also view and delete their reactions to the message.

Note: Currently, message reactions are only available in group channels.

final emojiKey = 'smile'

// The BASE_MESSAGE below indicates an BaseMessage object to add a reaction to.
try {
    final event = await groupChannel.addReaction(BASE_MESSAGE, key: emojiKey);
} catch (e) {
    // Handle error.
}

// The BASE_MESSAGE below indicates an BaseMessage object to remove a reaction from.
try {
    final event = await groupChannel.deleteReaction(BASE_MESSAGE, key: emojiKey);
} catch (e) {
    // Handle error.
}

// To add or remove an emoji that matches the `emojiKey` under a message in the current user's chat view, the apply() method should be called in the channel event handler's updatedReaction() method.

You can also decide how to display reactions that were added to messages in the current user’s chat view.

try {
    final currentUserId = sendbird.currentUser().userId;
    final params = MessageListParams()
        ..includeReactions = true
        ..previousResultSize = 20;
    final messages = await groupChannel.getMessagesByTimestamp(TIMESTAMP, params);
    messages.forEach((m) {
        m.reactions.forEach((reaction) {
            // Check if this emoji has been used when the current user reacted to the message.
            if (reaction.userIds.firstWhere((u) => currentUserId == u.userId) != null) {
                final key = reaction.key
                final updatedAt = reaction.updatedAt

                // Show the emoji however you want in the current user's chat view.
            }
        })
    });
} catch (e) {
    // Handle error.
}

If one of the group channel members reacts to a message, the onReactionUpdated() method in the channel event handler will be invoked on all channel members’ devices including the one that belongs to the current user. The apply() method will reflect the reaction change to the message in real time.

class MyClass with ChannelEventHandler {
    // Add this class through the sdk.addChannelEventHandler(UNIQUE_HANDLER_ID, this).
    // Or remove it through the sdk.removeChannelEventHandler(UNIQUE_HANDLER_ID) when it is no longer needed.

    @override
    void onReactionUpdated(BaseChannel channel, ReactionEvent event) {
    // If there is a message with the reactionEvent.messageId, you can apply the reaction change to the message by calling the message.apply(reactionEvent) method.

    // Add or remove an emoji that appears below the message on the current user's chat view.
    }
}

Load previous messages

Using the loadNext() method of a PreviousMessageListQuery instance which returns a list of BaseMessage objects, you can retrieve a set number of previous messages in an group channel. With a returned list, you can display the past messages in your UI once they have loaded.

Note: You can decide whether a user can see the messages sent prior to the user joining a group channel. In the Sendbird Dashboard, go to the Settings > Chat > Channels > Group channels, there is the Chat history option. If turned on, new users are allowed to view a message history in joined group channels. If turned off, new users aren't allowed to see the messages prior to joining a group channel.

Note: Starting from Flutter Chat SDK 3.1.0, the PreviousMessageListQuery requires the channelType and channelUrl parameters.

// There should be only one single instance per channel.
final listQuery = PreviousMessageListQuery(
        channelType: ChannelType.group,
        channelUrl: CHANNEL_URL,
    )
    ..limit = LIMIT
    ..reverse = REVERSE
    ..includeMetaArray = true   // Determines whether to retrieve a list of messages along with their metaarrays.
    ..includeReactions = true;  // Determines whether to retrieve a list of messages along with their reactions.

try {
    final messages = await listQuery.loadNext();
} catch (e) {
    // Handle error
}

List of arguments

ArgumentDescription

LIMIT

Type: int
Specifies the number of results to return per call. Acceptable values are 1 to 100, inclusive. The recommended value for this parameter is 30.

REVERSE

Type: bool
Determines whether to sort the retrieved messages in reverse order. If true, returns a list of messages which the latest comes at first and the earliest at last. the results are sorted in reverse order. If false, returns a list of messages which the earliest comes at first and the latest at last.

A limit parameter determines how many messages should be included in a returned list. A PreviousMessageListQuery instance itself does pagination of a result set based on the value of the limit parameter, and internally manages a token to retrieve the next page in the result set.

Each time the loadNext() method is called, the instance retrieves a set number of messages in the next page and then updates the value of the token to complete the current call and prepare a next call.

If you create a new query instance and call the loadNext() method, a set number of the most recent messages are retrieved because its token has nothing to do with the previously created instance. So we recommend that you create a single query instance and store it as a member variable for traversing through the entire message history.

Note: Before calling the loadNext() method again, the previous call should have been completed.

The following table shows all the supported filters for PreviousMessageListQuery to search for messages you want to retrieve. You can use any filters in a similar fashion with the sample code above.

List of filters

NameDescription

MessageTypeFilter

Messages with the specified message type. The messageTypeFilter property can be used to enable this filter. Acceptable values are MessageTypeFilter.all, MessageTypeFilter.user, MessageTypeFilter.file and MessageTypeFilter.admin. (Default: MessageTypeFilter.all)

CustomTypesFilter

Messages with the specified custom types. The customTypesFilter property can be used to enable this filter.

SenderIdsFilter

Messages that are sent by the specified users. The senderIdsFilter property can be used to enable this filter.


Load messages by timestamp or message ID

Using the getMessagesByTimestamp() method, you can retrieve a set number of previous and next messages on both sides of a specific timestamp in a group channel.

The following code shows several types of parameters that you can configure to customize a message query by using MessageListParams. Under the MessageListParams object, you can assign specific values to previousResultSize, customType, and other properties. To retrieve messages in a channel, you need to pass the MessageListParams object as an argument to the parameter in the getMessagesByTimestamp() method.

You can also retrieve a set number of previous and next messages on both sides of a specific message ID in a group channel, using the getMessagesById() and a MessageListParams object.

ByTimestampByID
try {
    final params = MessageListParams()
        ..isInclusive = false
        ..previousResultSize = 20
        ..reverse = true
        ..messageTypeFilter = MessageTypeFilter.all
        ..customType = 'custom';

    final messages = await groupChannel.getMessagesByTimestamp(
        DateTime.now().millisecondsSinceEpoch, params: params
    );
    // A list of previous messages of a specified timestamp is successfully retrieved.
} catch (e) {
    // Handle exception.
}

List messages along with their replies

The getMessagesByTimestamp(), getMessagesById(), or the loadNext() method of the PreviousMessageListQuery instance can be used to retrieve messages and their replies in a specific thread.

Load channel messages

The loadNext() method of the PreviousMessageListQuery instance returns a list of BaseMessage objects. With this method, you can retrieve previous messages in a specific channel.

To include the replies of the target messages in the results, change the value of the includeReplies property set to true.

Note: Starting from Flutter Chat SDK 3.1.0, the PreviousMessageListQuery requires the channelType and channelUrl parameters.

final listQuery = PreviousMessageListQuery(
        channelType: ChannelType.group,
        channelUrl: CHANNEL_URL,
    )
    ..limit = LIMIT
    ..reverse = REVERSE
    ..includeReplies = INCLUDE_REPLIES
    ..includeThreadInfo = INCLUDE_THREAD_INFO
    ..includeParentMessageText = INCLUDE_PARENT_MESSAGE_TEXT;

try {
    final messages = await listQuery.loadNext();
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

LIMIT

Type: int
Specifies the number of results to return per call. Acceptable values are 1 to 100, inclusive. The recommended value for this parameter is 30.

REVERSE

Type: bool
Determines whether to sort the retrieved messages in reverse order. If false, the results are in ascending order.

INCLUDE_REPLIES

Type: bool
Determines whether to include replies in the results.

INCLUDE_THREAD_INFO

Type: bool
Determines whether to include the thread information of the messages in the results when the results contain parent messages.

INCLUDE_PARENT_MESSAGE_TEXT

Type: bool
Determines whether to include the parent message text in the results when the retrieved messages are replies in a thread. If the type of the parent message is UserMessage, the value is a message property. If it is a FileMessage, the value is the name of the uploaded file.

Load messages by timestamp or message ID

The getMessagesByTimestamp() and getMessagesById() methods of a BaseChannel instance return a list of BaseMessage objects.

When using either of the methods above, you can also pass a MessageListParams object as an argument to the parameter in those methods.

final params = MessageListParams()
    ..previousResultSize = PREV_RESULT_SIZE
    ..nextResultSize = NEXT_RESULT_SIZE
    ..isInclusive = INCLUSIVE
    ..reverse = REVERSE
    ..includeReplies = INCLUDE_REPLIES
    ..includeThreadInfo = INCLUDE_THREAD_INFO
    ..includeParentMessageText = INCLUDE_PARENT_MESSAGE_TEXT;

List of arguments

ArgumentDescription

PREV_RESULT_SIZE

Type: int
Specifies the number of messages to retrieve that were sent before the specified timestamp or message ID.

NEXT_RESULT_SIZE

Type: int
Specifies the number of messages to retrieve that were sent after the specified timestamp or message ID.

INCLUSIVE

Type: bool
Determines whether to include the messages with the matching timestamp or message ID in the results.

REVERSE

Type: bool
Determines whether to sort the retrieved messages in reverse order. If false, the results are in ascending order.

INCLUDE_REPLIES

Type: bool
Determines whether to include replies in the results.

INCLUDE_THREAD_INFO

Type: bool
Determines whether to include the thread information of the messages in the results when the results contain parent messages.

INCLUDE_PARENT_MESSAGE_TEXT

Type: bool
Determines whether to include the parent message text in the results when the messages are replies in a thread. If the type of the parent message is UserMessage, the value is a message property. If it is a FileMessage, the value is the name of the uploaded file.

By timestamp

The getMessagesByTimestamp() method returns a set number of messages of previous and next messages on both sides of a specific timestamp in a channel.

try {
    final messages = await groupChannel.getMessagesByTimestamp(TIMESTAMP, params);
    // A list of previous and next messages on both sides of the specified timestamp is successfully retrieved.
    // You can access and display the data of each message.
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

TIMESTAMP

Type: int
Specifies the timestamp to be the reference point for messages to retrieve, in Unix milliseconds format. Messages sent before or after the timestamp can be retrieved.

By message ID

The getMessagesById() method returns a set number of previous and next messages on both sides of a specific message ID in a channel.

try {
    final messages = await groupChannel.getMessagesById(MESSAGE_ID, params);
    // A list of previous and next messages on both sides of a specified timestamp is successfully retrieved.
    // you can access and display the data of each message
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

MESSAGE_ID

Type: int
Specifies the message ID to be the reference point for messages to retrieve. Messages sent before or after the message with the matching message ID can be retrieved.


Retrieve a message

You can retrieve a specific message by creating and passing the MessageRetrievalParams object as a parameter to the getMessage() method.

Note: Starting from Chat SDK for Flutter 3.1.0, the MessageRetrievalParams requires the channelType, channelUrl, and messageId parameters.

try {
    final params = MessageRetrievalParams(
        messageId: MESSAGE_ID,
        channelType: ChannelType.group,
        channelUrl: CHANNEL_URL,
    );

    final message = await BaseMessage.getMessage(params);
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

MESSAGE_ID

Type: int
Specifies the unique ID of the message to retrieve.

CHANNEL_URL

Type: String
Specifies the URL of the channel to retrieve the message.


Update a message

A user can update any of their own text and file messages sent through the updateUserMessage() or updateFileMessage methods. An error is returned if a user attempts to update another user's messages. In addition, channel operators can update any messages sent in a channel.

Note: Starting from Chat SDK for Flutter 3.1.0, the UserMessageParams requires the message parameter.

UserMessageFileMessage
try {
    final params = UserMessageParams(message: MESSAGE)
        ..customType = 'new custom type'
        ..data = 'new data';

    groupChannel.updateUserMessage(message.messageId, params, onCompleted: (message, err) {
        //Use the message from the onCompleted block.
    });
    // The message is updated.
} catch (e) {
    // Handle exception.
}

If a message is updated, the onMessageUpdated() method in the channel event handler will be invoked on all channel participants' devices except the one that updated the message.

class MyClass with ChannelEventHandler {
    // Add this class through the sendbird.addChannelEventHandler(UNIQUE_HANDLER_ID, this).
    // Or remove it through the sendbird.removeChannelEventHandler(UNIQUE_HANDLER_ID) when it is no longer needed.

    @override
    void onMessageUpdated(BaseChannel channel, BaseMessage message) {

    }
}

Delete a message

A user can delete any messages which were sent by themselves. An error is returned if a user attempts to delete the messages of other members. Channel operators can delete any messages in a channel as well.

try {
    await groupChannel.deleteMessage(messageId);
} catch (e) {
    // Handle exception.
}

If a message is deleted, the onMessageDeleted() method in the channel event handler will be invoked on all channel participants' devices including the one that deleted the message.

class MyClass with ChannelEventHandler {
    // Add this class through sdk.addChannelEventHandler(UNIQUE_HANDLER_ID, this).
    // Or remove it through sdk.removeChannelEventHandler(UNIQUE_HANDLER_ID) when it is no longer needed.

    @override
    void onMessageDeleted(BaseChannel channel, int messageId) {

    }
}

Copy a message

A user can copy and send their own message in the same channel or to another channel. Both user messages and file messages can be copied.

try {
    final preMessage = groupChannel.copyMessage(MESSAGE_TO_COPY, TARGET_CHANNEL, onCompleted:(msg, err) {
        // The message is successfully copied to the target channel.
    });
    // Use preMessage to populate before the message is sent to the server.
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

MESSAGE_TO_COPY

Type: BaseMessage
Specifies a message to copy.

TARGET_CHANNEL

Type: BaseChannel
Specifies a target channel to send a copied message to.

onCompleted

Type: Function(BaseMessage, SBError)
Specifies the callback handler to receive the response from Sendbird server for a message copy request.


Clear the chat history

With the resetMyHistory() method, you can help the current user clear the chat history in a group channel and start a fresh conversation with other members in the same channel.

The method clears the chat history only from the current user’s channel view and other members can still see all the messages in their channel view. Also, those messages aren’t deleted from the database of the Sendbird server.

The resetMyHistory() method simply clears the messages for the current user by updating the properties of a groupChannel object, including the lastMessage, readReceipts and other internally managed data such as the number of unread messages.

Note: This feature is effective only when the Chat history option is turned on in the Sendbird Dashboard under Settings > Chat > Channels > Group channels.

try {
    await groupChannel.resetMyHistory();
} catch (e) {
    // Handle error.
}

When a user is online, all data associated with the group channels they are a member of are automatically updated by the SendbirdSdk instance. However, when a user is disconnected from Sendbird server and reconnected later, you should call the refresh() method to update the channels with the latest information.

try {
    final channel = await groupChannel.refresh();
} catch (e) {
    // Handle error.
}

Note: If you want your users to see the most recently updated channels when their client app comes to the foreground, we recommend you call the refresh() in the onReconnectionSucceeded() method which receives a callback from Sendbird server when successfully reconnected.


Retrieve a list of all members

You can retrieve a list of members in a group channel using the members property of a groupChannel object.

final members = groupChannel.members;

Retrieve the online status of members

To stay updated on the online status of each member in a group channel, call the refresh() method before using the members property of a groupChannel object to retrieve the members of the channel.

By checking the connectionStatus property of each Member object in the members property, you can then retrieve the user's current connection status.

Note: If your client app needs to keep track of the connection status of users in real time, we recommend that you periodically call the loadNext() method of a ApplicationUserListQuery instance after specifying its userIds filter, perhaps in intervals of one minute or more.


Retrieve a list of members and operators in a specific order

Members and operators of a group channel can be retrieved by using the loadNext() method of a GroupChannelMemberListQuery instance. For a specific order, set either of the values in the following table to the order property of a GroupChannelMemberListQuery.

Note: Starting from Flutter Chat SDK 3.1.0, the GroupChannelMemberListQuery requires the channelUrl parameter.

Member list order

The following table lists the values you can set to sort the list of members and operators.

ValueDescription

nicknameAlphabetical

Arranges members and operators in the alphabetical order of their nickname (default).

operatorThenMemberNicknameAlphabetical

Lists operators before members, both in the alphabetical order of their nickname.

try {
    final query = GroupChannelMemberListQuery(channelUrl: groupChannel.channelUrl)
        ..limit = 10
        ..order = operatorThenMemberNicknameAlphabetical;

    final result = await query.loadNext();
    // A list of matching members and operators is successfully retrieved.
} catch (e) {
    // Handle error
}

Operator filter

Operators are those who monitor and control the activities in a group channel. The following table lists the values you can set to filter operators in a group channel. Set one of these values to the operatorFilter of a GroupChannelMemberListQuery.

ValueDescription

all

Not applies any filter to the group channel member list (default).

operator

Retrieves only the operators of a group channel.

nonOperator

Retrieves only the regular members of a group channel, excluding operators.

try {
    final query = GroupChannelMemberListQuery(channelUrl: groupChannel.channelUrl)
        ..limit = 10
        ..operatorFilter = OperatorFilter.operator;

    final result = await query.loadNext();
    // A list of matching members and operators is successfully retrieved.
} catch (e) {
    // Handle error.
}

Retrieve a list of operators

Operators are those who monitor and control the activities in a group channel. You can create an OperatorListQuery instance and use the loadNext() method to retrieve only a list of operators of a specific group channel.

try {
    final query = OperatorListQuery(
            channelUrl: groupChannel.channelUrl,
            channelType: groupChannel.channelType,
        )
        ..limit = 10;

    final result = await query.loadNext();
    // A list of operators is successfully retrieved.
} catch (e) {
    // Handle error.
}

Register operators

You can register members as an operator of a group channel by passing their user ID into the addOperators() method.

try {
    await groupChannel.addOperators([USER_ID_1, USER_ID_2]);
    // The participants are successfully registered as operators of the channel.
} catch (e) {
    // Handle error.
}

Remove operators

You can remove operators from a group channel by passing the user ID of operators into the removeOperators() method. However, the demoted operators will still be kept as channel members.

try {
    await groupChannel.removeOperators([USER_ID_1, USER_ID_2]);
    // The cancel operation is succeeded,
    // and you could display a message regarding the role change to those who are not operators anymore.
} catch (e) {
    // Handle error.
}

If you want to remove all operators in a group channel at once, use the removeAllOperators() method as follows.

try {
    await groupChannel.removeAllOperators();
    // The cancel operation is succeeded,
    // and you could display a message regarding the role change to those who are not operators anymore.
} catch (e) {
    // Handle error.
}

Retrieve a list of banned or muted users

You can create a query instance to get a list of users who are banned or muted from a group channel.

Note: Only operators of a group channel can use this functionality.

Banned usersMuted users
try {
    final query = UserListQuery()
        ..queryType = UserListQueryType.banned;
    final result = await query.loadNext();
} catch (e) {
    // Handle error.
}

Ban and unban a user

The Ban feature allows operators of a group channel to remove any users that display inappropriate behaviors in the channel. Banned users are immediately expelled from a channel and allowed to join the channel again only after the time period set by the operators. The operators can ban and unban users from group channels using a user ID as follows.

try {
    await groupChannel.banUser(
        userId: USER_ID,
        seconds: SECONDS,
        description: DESCRIPTION
    );
    // The user is successfully banned from the channel.
    // You could notify the user of being banned by displaying a prompt.

    await groupChannel.unbanUser(userId: USER_ID);
    // The user is successfully unbanned.
    // You could notify the user of being unbanned by displaying a prompt.
} catch (e) {
    // Handle error.
}

Mute and unmute a user

The Mute feature allows operators of a group channel to prohibit a group of selected users from sending messages. Muted users can remain in the channel and are allowed to view the messages, but can't send any new messages until the operators unmute them. Operators can mute and unmute users in the channel using a user ID as follows.

try {
    await groupChannel.muteUser(
        userId: USER_ID,
        seconds: SECONDS,
        description: DESCRIPTION
    );
    // The user is successfully muted.
    // You could notify the user of being muted by displaying a prompt.

    await groupChannel.unmuteUser(userId: USER_ID);
    // The user is successfully unmuted.
    // You could notify the user of being unmuted by displaying a prompt.
} catch (e) {
    // Handle error.
}

Report a message, a user, or a channel

In a group channel, a user can report suspicious or inappropriate messages as well as the other users who use abusive language. The user can also report channels if there is any inappropriate content or activity within the channel. Based on this feature and our report API, you can build a clean in-app chat environment without objectionable content and subject.

Report a messageReport a userReport a channel
try {
    await groupChannel.reportMessage(
        message: MESSAGE_TO_REPORT,
        category: REPORT_CATEGORY,
        description: DESCRIPTION
    );
} catch (e) {
    // Handle error.
}

List of arguments

ArgumentDescription

MESSAGE_TO_REPORT

Type: BaseMessage
Specifies the message to report for its suspicious, harassing, or inappropriate content.

OFFENDING_USER_ID

Type: String
Specifies the user ID who uses offensive or abusive language, such as sending explicit messages.

REPORT_CATEGORY

Type: enum
Specifies a report category which indicates the reason for reporting. Acceptable values are ReportCategory.suspicious, ReportCategory.harassing, ReportCategory.inappropriate, and ReportCategory.spam.

DESCRIPTION

Type: String?
Specifies additional information or note to include in the report.

To report a message, user, or channel, you should specify the report category in the code. The following table lists the categories you can use.

List of report categories

CategoryDescription

suspicious

Messages, users, and channels that attempt to conspire, plot, or organize dangerous and illegal activities that could harm other people, including crime and terrorism.

harassing

Messages, users, and channels that are intended to intimidate, harass, bully, or insult other people.

inappropriate

Messages, users, and channels that are disrespectful, offensive, and hurtful toward other people.

spam

A cascade of repetitive messages that contain identical, and irrelevant content to the interaction and context of the channel. They can also entice people to install malicious software in their devices.