fix: removed stream_chat docs
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"label": "Stream Chat (LLC)",
|
||||
"position": 2
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
---
|
||||
id: channel_members
|
||||
sidebar_position: 10
|
||||
title: Channel Members
|
||||
---
|
||||
|
||||
Manipulating Members In A Channel
|
||||
|
||||
### Adding & Removing Channel Members
|
||||
|
||||
Using the addMembers() method adds the given users as members, while removeMembers() removes them.
|
||||
|
||||
```dart
|
||||
await channel.addMembers(["thierry", "josh"]);
|
||||
await channel.removeMembers(["tommaso"]);
|
||||
```
|
||||
|
||||
You can optionally include a message object that client-side SDKs will use to populate a system message.
|
||||
This works for both add and remove members:
|
||||
|
||||
```dart
|
||||
// using client-side client
|
||||
await channel.addMembers(['tommaso'], Message(text: 'Tommaso joined'));
|
||||
```
|
||||
|
||||
### Leaving a channel
|
||||
|
||||
It is possible for user to leave the channel without moderator-level permissions.
|
||||
Make sure channel members have `RemoveOwnChannelMembership` permission.
|
||||
|
||||
```dart
|
||||
// remove own channel membership
|
||||
await channel.removeMembers(['my_user_id']);
|
||||
```
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
---
|
||||
id: creating_channels
|
||||
sidebar_position: 6
|
||||
title: Creating Channels
|
||||
---
|
||||
|
||||
Create Channels In Your App
|
||||
|
||||
Both channel <b>channel.query</b> and <b>channel.watch</b> methods ensure that a channel exists and create one otherwise.
|
||||
If all you need is to ensure that a channel exists, you can use <b>channel.create</b>.
|
||||
Typically you use <b>channel.watch</b> client side and <b>channel.create</b> for a server side integration.
|
||||
Channels are unique either by the specified channel id or by the list of members.
|
||||
|
||||
### Creating a Channel Using a Channel ID
|
||||
|
||||
This is typically the best approach if you already have some sort of object in your database that the channel is associated with.
|
||||
As an example if you're building a live-streaming service like Twitch you have a channel for every streamer in your database.
|
||||
|
||||
```dart
|
||||
final channel = client.channel(
|
||||
"messaging",
|
||||
id: "travel",
|
||||
extraData: {
|
||||
"name": "Founder Chat",
|
||||
"image": "http://bit.ly/2O35mws",
|
||||
"members": ["thierry", "tommaso"],
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
Note: Note that for client side integrations you'll typically prefer to use channel.watch() instead of channel.create.
|
||||
Channel.watch both creates the channel and watches it at the same time.
|
||||
|
||||
### Creating a Channel for a List of Members
|
||||
|
||||
Channels can be used to create conversations between users.
|
||||
In most cases, you want conversations to be unique and make sure that a group of users have only one channel.
|
||||
|
||||
You can achieve this by leaving the channel ID empty and provide channel type and members.
|
||||
When you do so, the API will ensure that only one channel for the members you specified exists (the order of the members does not matter).
|
||||
|
||||
Note: You cannot add/remove members for channels created this way.
|
||||
|
||||
```dart
|
||||
client.channel("messaging", extraData: {"members": ["thierry", "tommaso"]});
|
||||
```
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
id: deleting_and_hiding_channel
|
||||
sidebar_position: 13
|
||||
title: Deleting And Hiding A Channel
|
||||
---
|
||||
|
||||
Remove Channels By Deleting Or Hiding
|
||||
|
||||
### Deleting a Channel
|
||||
|
||||
You can delete a Channel using the delete method. This marks the channel as deleted and hides all the content.
|
||||
|
||||
```dart
|
||||
await channel.delete();
|
||||
```
|
||||
|
||||
Note: If you recreate this channel, it will show up empty. Recovering old messages is not currently supported via the Stream Chat API.
|
||||
|
||||
### Hiding a Channel
|
||||
|
||||
Hiding a channel will remove it from query channel requests for that user until a new message is added.
|
||||
Please keep in mind that hiding a channel is only available to members of that channel.
|
||||
|
||||
Optionally you can also clear the entire message history of that channel for the user.
|
||||
This way, when a new message is received, it will be the only one present in the channel.
|
||||
|
||||
```dart
|
||||
// hides the channel until a new message is added there
|
||||
await channel.hide();
|
||||
|
||||
// shows a previously hidden channel
|
||||
await channel.show();
|
||||
|
||||
// hide the channel and clear the message history
|
||||
await channel.hide(clearHistory: true);
|
||||
```
|
||||
|
||||
Note: You can still retrieve the list of hidden channels using the { "hidden" : true } query parameter.
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
---
|
||||
id: events
|
||||
sidebar_position: 25
|
||||
title: Events
|
||||
---
|
||||
|
||||
Understand Low Level Messaging Events
|
||||
|
||||
Events allow the client to stay up to date with changes to the chat. Examples are a new message, a user's image that updated, a reaction, or a member joining the channel. There are a 4 different type of events. These first 2 types of events you receive if you're connected to Stream, no further action is needed to receive these events:
|
||||
|
||||
Client events: You always receive these events.
|
||||
Examples are `connection.recovered`, `health.check` and `connection.changed`
|
||||
Notification events: Notification events notify you when something changed on a channel you are a member of even if you're not explicitly watching that channel.
|
||||
One example is someone starting a new channel to message you while you are currently in the app.
|
||||
|
||||
User presence events: `queryUsers`, `queryChannels` and `channel.watch()` allow you to specify `presence=True`,
|
||||
if you specify this option you'll opt in to receiving updates about the users on these channels.
|
||||
You'll receive events when they go online/offline or their data is updated
|
||||
Channel events: if you call `queryChannels` with `watch=true`, or you call `channel.watch()` you'll opt-in to receiving events for the given channels.
|
||||
Examples are new messages, people joining the chat etc.
|
||||
|
||||
### Listening To Events
|
||||
|
||||
As soon as you call watch on a Channel or queryChannels you’ll start to listen to these events. You can hook into specific events:
|
||||
|
||||
```dart
|
||||
channel.on("message.deleted").listen((Event event) {
|
||||
print("message ${event.message.id} was deleted");
|
||||
});
|
||||
```
|
||||
|
||||
You can also listen to all events at once:
|
||||
|
||||
```dart
|
||||
channel.on().listen((Event event) {
|
||||
print("received a new event of type ${event.type}");
|
||||
});
|
||||
```
|
||||
|
||||
### Connection Events
|
||||
|
||||
The official SDKs make sure that a connection to Stream is kept alive at all times and that chat state
|
||||
is recovered when the user's internet connection comes back online.
|
||||
Your application can subscribe to changes to the connection using client events.
|
||||
|
||||
```dart
|
||||
client.on('connection.changed', (e) => {
|
||||
if (e.online) {
|
||||
print('the connection is up!');
|
||||
} else {
|
||||
print('the connection is down!');
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
### Stop Listening for Events
|
||||
|
||||
It is a good practice to unregister event handlers once they are not in use anymore. Doing so will save you from performance degradations coming from memory leaks or even from errors and exceptions (i.e. null pointer exceptions)
|
||||
|
||||
```dart
|
||||
final subscription = channel.on().listen((Event event) {
|
||||
print("received a new event of type ${event.type}");
|
||||
});
|
||||
|
||||
subscription.cancel();
|
||||
```
|
||||
|
||||
### Custom Events
|
||||
|
||||
Custom events allow you to build more complex interactions within a channel or with a user.
|
||||
|
||||
#### To a channel
|
||||
|
||||
Users connected to a channel, either as a watcher or member, can send custom events and have them delivered to all users watching the channel.
|
||||
|
||||
```dart
|
||||
// sends an event for the current user to all connect clients on the channel
|
||||
await channel.sendEvent(
|
||||
Event(
|
||||
type: 'friendship_request',
|
||||
extraData: {
|
||||
'text': 'Hey there, long time no see!',
|
||||
},
|
||||
),
|
||||
);
|
||||
```
|
||||
@@ -1,23 +0,0 @@
|
||||
---
|
||||
id: introduction
|
||||
sidebar_position: 1
|
||||
title: Introduction
|
||||
---
|
||||
Exploring the Basics of the stream_chat package (LLC)
|
||||
|
||||
<h2> Official Dart Client for Stream Chat </h2>
|
||||
|
||||
The official Dart client for Stream Chat, a service for building chat applications.
|
||||
This library can be used on any Dart project and on both mobile and web apps with Flutter.
|
||||
|
||||
The Low Level Client ([stream_chat]('https://pub.dev/packages/stream_chat')) provides the basic
|
||||
bindings for integrating Stream Chat into your Flutter app with the ability to connect users,
|
||||
listening to events, send and receive messages, channel CRUD operations, etc.
|
||||
This allows you to control and customise your interface completely while using the
|
||||
Stream Chat backend.
|
||||
|
||||
Check out our Core package ([stream_chat_flutter_core]('https://pub.dev/packages/stream_chat_flutter_core'))
|
||||
for easier implementations of common uses such as retrieving channels,
|
||||
retrieving channel message lists, seraching for messages, etc.
|
||||
|
||||
This section goes into detail on using the LLC and various things you can achieve using it.
|
||||
@@ -1,63 +0,0 @@
|
||||
---
|
||||
id: invites
|
||||
sidebar_position: 11
|
||||
title: Invites
|
||||
---
|
||||
|
||||
Invite A User To Join A Channel
|
||||
|
||||
### Inviting Users
|
||||
|
||||
Stream Chat provides the ability to invite users to a channel via the `channel` method with the `invites` array.
|
||||
Upon invitation, the end-user will receive a notification that they were invited to the specified channel.
|
||||
|
||||
See the following for an example on how to invite a user by adding an invites array containing the user ID:
|
||||
|
||||
```dart
|
||||
final invite = client.channel("messaging", id: "awesome-chat",
|
||||
extraData: {
|
||||
"name": "Founder Chat",
|
||||
"members": ["thierry", "tommaso", "nick"],
|
||||
"invites": ["nick"],
|
||||
});
|
||||
|
||||
await invite.create();
|
||||
```
|
||||
|
||||
### Accepting an Invite
|
||||
|
||||
In order to accept an invite, you must use call the `acceptInvite` method.
|
||||
The `acceptInvite` method accepts and object with an optional `message` property.
|
||||
Please see below for an example of how to call `acceptInvite`:
|
||||
|
||||
```dart
|
||||
final channel = client.channel("messaging", id: "awesome-chat");
|
||||
await channel.acceptInvite();
|
||||
```
|
||||
|
||||
### Rejecting an Invite
|
||||
|
||||
To reject an invite, call the `rejectInvite` method.
|
||||
This method does not require a user ID as it pulls the user ID from the current session in store from the `connectUser` call.
|
||||
|
||||
```dart
|
||||
await channel.rejectInvite();
|
||||
```
|
||||
|
||||
### Query for Accepted Invites
|
||||
|
||||
Querying for accepted invites is done via the `queryChannels` method.
|
||||
This allows you to return a list of accepted invites with a single call. See below for an example:
|
||||
|
||||
```dart
|
||||
final invites = await client.queryChannels(filter: {"invite": "accepted"});
|
||||
```
|
||||
|
||||
### Query for Rejected Invites
|
||||
|
||||
Similar to querying for accepted invites, you can query for rejected invites with `queryChannels`.
|
||||
See below for an example:
|
||||
|
||||
```dart
|
||||
final rejected = await client.queryChannels(filter: {"invite": "rejected"});
|
||||
```
|
||||
@@ -1,127 +0,0 @@
|
||||
---
|
||||
id: messages
|
||||
sidebar_position: 16
|
||||
title: Messages
|
||||
---
|
||||
|
||||
Send, Update And Delete Messages
|
||||
|
||||
Let's dive right into it, the example below shows how to send a simple message using Stream:
|
||||
|
||||
```dart
|
||||
final message = Message(
|
||||
text: '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.'
|
||||
);
|
||||
|
||||
await channel.sendMessage(message);
|
||||
```
|
||||
|
||||
Note how server side SDKs require that you specify `user_id` to indicate who is sending the message.
|
||||
You can add custom fields to both the message and the attachments.
|
||||
There's a 5KB limit for the custom fields.
|
||||
File uploads are uploaded to the CDN so don't count towards this 5KB limit.
|
||||
|
||||
A more complex example for creating a message is shown below:
|
||||
|
||||
```dart
|
||||
final message = Message(
|
||||
text: '@Josh I told them I was pesca-pescatarian. Which is one who eats solely fish who eat other fish.',
|
||||
attachments: [
|
||||
Attachment(
|
||||
type: "image",
|
||||
assetUrl: "https://bit.ly/2K74TaG",
|
||||
thumbUrl: "https://bit.ly/2Uumxti",
|
||||
extraData: {
|
||||
"myCustomField": 123,
|
||||
}
|
||||
),
|
||||
],
|
||||
mentionedUsers: [
|
||||
User(id: "josh")
|
||||
],
|
||||
extraData: {
|
||||
"anotherCustomField": 234,
|
||||
},
|
||||
);
|
||||
|
||||
await channel.sendMessage(message);
|
||||
```
|
||||
|
||||
By default Stream’s UI components support the following attachment types:
|
||||
|
||||
* Audio
|
||||
* Video
|
||||
* Image
|
||||
* Text
|
||||
|
||||
You can specify different types as long as you implement the frontend rendering logic to handle them. Common use cases include:
|
||||
|
||||
* Embedding products (photos, descriptions, outbound links, etc.)
|
||||
* Sharing of a users location
|
||||
* The React tutorial for Stream Chat explains how to customize the Attachment component.
|
||||
|
||||
### Get a Message
|
||||
|
||||
You can get a single message by its ID using the `getMessage` call:
|
||||
|
||||
```dart
|
||||
final message = await client.getMessage("message-id");
|
||||
```
|
||||
|
||||
### Update a Message
|
||||
|
||||
You can edit a message by calling updateMessage and including a message with an ID – the ID field is required when editing a message:
|
||||
|
||||
```dart
|
||||
await client.updateMessage(Message(id: "123", text: "the edited version of my text"));
|
||||
```
|
||||
|
||||
### Partial Update
|
||||
|
||||
A partial update can be used to set and unset specific fields when it is necessary to retain additional data fields on the object.
|
||||
AKA a patch style update.
|
||||
|
||||
```dart
|
||||
// partial update message text
|
||||
const text = 'the text was partial updated';
|
||||
const updated = await client.partiallyUpdateMessage(originalMessage.id, {
|
||||
set: {
|
||||
text
|
||||
}
|
||||
});
|
||||
|
||||
// unset color property
|
||||
await client.partiallyUpdateMessage(originalMessage.id, {
|
||||
'unset': ['color'],
|
||||
});
|
||||
|
||||
// set nested property
|
||||
await client.partiallyUpdateMessage(originalMessage.id, {
|
||||
'set': {
|
||||
'details.status': 'complete'
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Delete A Message
|
||||
|
||||
You can delete a message by calling deleteMessage and including a message with an ID. Messages can be soft deleted or hard deleted. Unless specified via the hard parameter, messages are soft deleted.
|
||||
|
||||
```dart
|
||||
await client.deleteMessage("123");
|
||||
```
|
||||
|
||||
### Soft delete
|
||||
|
||||
1. Can be done client-side by users
|
||||
2. Message is still returned in the message list and all its data is kept as it is
|
||||
3. Message type is set to "deleted"
|
||||
4. Reactions and replies are kept in place
|
||||
|
||||
### Hard delete
|
||||
|
||||
1. Can be done client-side by users but be cautious this action is not recoverable
|
||||
2. The message is removed from the channel and its data is wiped
|
||||
3. All reactions are deleted
|
||||
4. All replies and their reactions are deleted
|
||||
5. By default messages are soft deleted, this is a great way to keep the channel history consistent.
|
||||
@@ -1,120 +0,0 @@
|
||||
---
|
||||
id: moderation_tools
|
||||
sidebar_position: 23
|
||||
title: Moderation Tools
|
||||
---
|
||||
|
||||
Moderation Tools For A Better Chat Experience
|
||||
|
||||
### Flag
|
||||
|
||||
Any user is allowed to flag a message.
|
||||
Flagging does not perform any particular action on the chat.
|
||||
The API will only trigger the related webhook event and make the message appear on your Stream Dashboard Chat Moderation view.
|
||||
|
||||
```dart
|
||||
await client.flagMessage("messageID");
|
||||
```
|
||||
|
||||
### Mutes
|
||||
|
||||
Any user is allowed to mute another user.
|
||||
Mutes are stored at user level and returned with the rest of the user information when connectUser is called.
|
||||
A user will be be muted until the user is unmuted or the mute is expired.
|
||||
|
||||
```dart
|
||||
await client.muteUser("eviluser");
|
||||
|
||||
await client.unmuteUser("eviluser");
|
||||
```
|
||||
|
||||
After muting a user messages will still be delivered via web-socket.
|
||||
Implementing business logic such as hiding messages from muted users or display them differently is left to the developer to implement.
|
||||
|
||||
Messages from muted users are not delivered via push (APN/Firebase)
|
||||
|
||||
### Ban
|
||||
|
||||
Users can be banned from an app entirely or from a channel. When a user is banned, they will not be allowed to post messages until the ban is removed or expired but will be able to connect to Chat and to channels as before.
|
||||
|
||||
Users must be a member of a channel to be banned from that channel. Channel watchers cannot be banned.
|
||||
|
||||
It is also possible to ban the user's last known IP address to prevent creation of new "throw-away" accounts. This type of ban is only applicable on the app level. We do not recommend applying IP ban without reasonable timeout, however this is not restricted. The IP address will be unbanned either after reaching a timeout or with explicit user unban.
|
||||
|
||||
In most cases only admins or moderators are allowed to ban other users from a channel.
|
||||
|
||||
```dart
|
||||
// ban a user for 60 minutes from all channel
|
||||
await client.banUser('eviluser', {
|
||||
'banned_by_id': userID, // ID of the user who is performing the ban (Server-side auth)
|
||||
'timeout': 60,
|
||||
'reason': 'Banned for one hour',
|
||||
});
|
||||
|
||||
// ban a user and their IP address for 24 hours
|
||||
await client.banUser('eviluser', {
|
||||
'banned_by_id': userID,
|
||||
'timeout': 24*60,
|
||||
'ip_ban': true,
|
||||
'reason': 'Please come back tomorrow',
|
||||
});
|
||||
|
||||
// ban a user from the livestream:fortnite channel
|
||||
await channel.banUser('eviluser', {
|
||||
'banned_by_id': userID,
|
||||
'reason': 'Profanity is not allowed here',
|
||||
});
|
||||
|
||||
// remove ban from channel
|
||||
await channel.unbanUser('eviluser');
|
||||
|
||||
// remove global ban
|
||||
await authClient.unbanUser('eviluser');
|
||||
```
|
||||
|
||||
### Query Banned Users
|
||||
|
||||
Banned users can be retrieved in different ways:
|
||||
|
||||
Using the dedicated query bans endpoint
|
||||
User Search: you can add the banned:true condition to your search. Please note that this will only return users that were banned at the app-level and not the ones that were banned only on channels.
|
||||
|
||||
```dart
|
||||
// retrieve the list of banned users
|
||||
await client.queryUsers(filter: Filter.equal('banned', true), pagination: PaginationParams(limit:10, offset:0));
|
||||
```
|
||||
|
||||
### Shadow Ban
|
||||
|
||||
Users can be shadow banned from a channel, set of channels, or an entire app. When a user is shadow banned, they will still be allowed to post messages, but any message sent during the ban, will have the shadowed: true field set; this will be invisible from the author of the message.
|
||||
|
||||
You will need to implement UI logic for how your application will handle shadowed messages. Having the client hide these messages for everybody other than the user sending them is a common approach.
|
||||
|
||||
```dart
|
||||
// shadow ban a user from all channels
|
||||
await client.shadowBan('eviluser');
|
||||
|
||||
// shadow ban a user from a channel
|
||||
await channel.shadowBan('eviluser');
|
||||
|
||||
// remove shadow ban from channel
|
||||
await channel.removeShadowBan('eviluser');
|
||||
|
||||
// remove global shadow ban
|
||||
await client.removeShadowBan('eviluser');
|
||||
Administrators can view shadow banned user status in queryChannels(), queryMembers() and queryUsers().
|
||||
```
|
||||
|
||||
### Block Lists
|
||||
|
||||
A list of words you can define to moderate chat messages.
|
||||
A block list can be assigned to each channel type to either block or flag messages that contain these words.
|
||||
More information can be found [here](https://getstream.io/chat/docs/react/block_lists/?language=dart).
|
||||
|
||||
### Advanced Chat Moderation
|
||||
|
||||
Advanced Chat Moderation is currently in beta and accepting trial candidates. Please contact support to discuss your options.
|
||||
Advanced Chat Moderation uses an AI-based classification system to detect various types of bad content.
|
||||
The tool is powered by a machine learning model that provides a confidence interval (0-1) for a message,
|
||||
in each of three categories: Spam, Explicit and Toxic.
|
||||
The model is highly configurable for each channel type and removes the manual work of a human moderator. You can learn more [here](https://getstream.io/chat/docs/react/advanced_moderation_beta/?language=dart).
|
||||
@@ -1,64 +0,0 @@
|
||||
---
|
||||
id: muting_channels
|
||||
sidebar_position: 12
|
||||
title: Muting Channels
|
||||
---
|
||||
|
||||
Muting Channels For Users
|
||||
|
||||
Messages added to a channel will not trigger push notifications, nor change the unread count for the users that muted it.
|
||||
|
||||
By default, mutes stay in place indefinitely until the user removes it; however, you can optionally set an expiration time.
|
||||
|
||||
The list of muted channels and their expiration time is returned when the user connects.
|
||||
|
||||
### Channel Mute
|
||||
|
||||
```dart
|
||||
// mute channel for current user
|
||||
await channel.mute();
|
||||
|
||||
// mute a channel for 2 weeks
|
||||
await channel.mute(expiration: Duration(days: 15));
|
||||
|
||||
// mute a channel for 10 seconds
|
||||
await channel.mute(expiration: Duration(seconds: 10));
|
||||
|
||||
// check if channel is muted
|
||||
channel.isMuted;
|
||||
```
|
||||
|
||||
### Query Muted Channels
|
||||
|
||||
Muted channels can be filtered or excluded by using the `muted` in your query channels filter.
|
||||
|
||||
```dart
|
||||
// retrieve all channels excluding muted ones
|
||||
await client.queryChannels(
|
||||
filter: {
|
||||
'members': {
|
||||
r'$in': [userId],
|
||||
},
|
||||
'muted': false,
|
||||
}
|
||||
);
|
||||
|
||||
// retrieve all muted channels
|
||||
await client.queryChannels(
|
||||
filter: {
|
||||
'muted': true,
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
### Remove a Channel Mute
|
||||
|
||||
Whenever you need to unmute, you are able to.
|
||||
|
||||
```dart
|
||||
// unmute channel for current user
|
||||
await channel.unmute();
|
||||
|
||||
// unmute channel for a user (server-side)
|
||||
await channel.unmute({ user_id: userId });
|
||||
```
|
||||
@@ -1,37 +0,0 @@
|
||||
---
|
||||
id: paginating_channels
|
||||
sidebar_position: 15
|
||||
title: Channel Pagination
|
||||
---
|
||||
|
||||
Understanding Pagination For The Channel List
|
||||
|
||||
The channel query endpoint allows you to paginate the list of messages, watchers, and members for one channel.
|
||||
To make sure that you are able to retrieve a consistent list of messages, pagination does not work with simple offset/limit parameters but instead,
|
||||
it relies on passing the ID of the messages from the previous page.
|
||||
|
||||
For example: say that you fetched the first 100 messages from a channel and want to lead the next 100.
|
||||
To do this you need to make a channel query request and pass the ID of the oldest message if you are paginating in descending order or the ID of the newest message if paginating in ascending order.
|
||||
|
||||
Use the `id_lt` parameter to retrieve messages older than the provided ID and `id_gt` to retrieve messages newer than the provided ID.
|
||||
|
||||
The terms `id_lt` and `id_gt` stand for ID less than and ID greater than.
|
||||
|
||||
ID-based pagination improves performance and prevents issues related to the list of messages changing while you’re paginating. If needed, you can also use the inclusive versions of those two parameters: id_lte and id_gte.
|
||||
|
||||
```dart
|
||||
final response = await channel.query(
|
||||
messagesPagination: PaginationParams(limit: 2, lessThanOrEqual: "123"),
|
||||
membersPagination: PaginationParams(limit: 2, offset: 0),
|
||||
watchersPagination: PaginationParams(limit: 2, offset: 0),
|
||||
);
|
||||
```
|
||||
|
||||
For members and watchers, we use limit and offset parameters.
|
||||
|
||||
<b>Notes:</b>
|
||||
|
||||
1. Soon we will create friendlier aliases for `id_lt` and `id_gt`. Our best candidates are before_id and after_id,
|
||||
let us know if you have any feedback or suggestion!
|
||||
|
||||
2. The maximum number of messages that can be retrieved at once from the API is 300.
|
||||
@@ -1,66 +0,0 @@
|
||||
---
|
||||
id: pinned_messages
|
||||
sidebar_position: 22
|
||||
title: Pinned Messages
|
||||
---
|
||||
|
||||
Pinning A Message In A Channel
|
||||
|
||||
Pinned messages allow users to highlight important messages, make announcements, or temporarily promote content.
|
||||
Pinning a message is, by default, restricted to certain user roles, but this is flexible.
|
||||
Each channel can have multiple pinned messages and these can be created or updated with or without an expiration.
|
||||
|
||||
### Pin and unpin a message
|
||||
|
||||
An existing message can be updated to be pinned or unpinned by using the `channel.pinMessage` and `channel.unpinMessage` methods.
|
||||
Or a new message can be pinned when it is sent by setting the `pinned` and `pin_expires` fields when using `channel.sendMessage`.
|
||||
|
||||
```dart
|
||||
// create pinned message
|
||||
final message = await channel
|
||||
.sendMessage(Message(
|
||||
text: 'my message',
|
||||
pinned: true,
|
||||
pinExpires: DateTime.now().add(Duration(days: 3)),
|
||||
))
|
||||
.then((resp) => resp.message);
|
||||
|
||||
// unpin message
|
||||
await channel.unpinMessage(message);
|
||||
|
||||
// pin message for 120 seconds
|
||||
await channel.pinMessage(message, 120);
|
||||
|
||||
// change message expiration to 2077
|
||||
await channel.pinMessage(message, DateTime(2077));
|
||||
|
||||
// remove expiration date from pinned message
|
||||
await channel.pinMessage(message, null);
|
||||
```
|
||||
|
||||
To pin the message user has to have PinMessage permission.
|
||||
You can find the list of permissions and defaults in Permission Resources and Default Permissions sections
|
||||
|
||||
### Retrieve pinned messages
|
||||
|
||||
You can easily retrieve the last 10 pinned messages from the `channel.pinned_messages` field:
|
||||
|
||||
```dart
|
||||
// get channel state
|
||||
final channelState = await channel.query();
|
||||
|
||||
// get pinned messages from it
|
||||
final pinnedMessages = channelState.pinnedMessages;
|
||||
```
|
||||
|
||||
To learn more about channels you can visit Querying Channels page
|
||||
Search for all pinned messages
|
||||
|
||||
Stream Chat also provides search filter in case if you need to display more than 10 pinned messages in specific channel.
|
||||
|
||||
```dart
|
||||
// list all pinned messages of the channel
|
||||
final response = await channel.search(
|
||||
messageFilters: Filter.equal('pinned', true),
|
||||
);
|
||||
```
|
||||
@@ -1,41 +0,0 @@
|
||||
---
|
||||
id: querying_channels
|
||||
sidebar_position: 7
|
||||
title: Querying Channels
|
||||
---
|
||||
|
||||
More About Fetching A List Of Channels
|
||||
|
||||
If you’re building a similar application to Facebook Messenger or Intercom, you’ll want to show a list of Channels.
|
||||
The Chat API supports MongoDB style queries to make this easy to implement.
|
||||
|
||||
You can query channels based on built-in fields as well as any custom field you add to channels.
|
||||
Multiple filters can be combined using AND, OR logical operators, each filter can use its comparison (equality, inequality, greater than, greater or equal, etc.). You can find the complete list of supported operators in the query syntax section of the docs.
|
||||
|
||||
As an example, let's say that you want to query the last conversations I participated in sorted by `last_message_at`.
|
||||
|
||||
Here’s an example of how you can query the list of channels:
|
||||
|
||||
```dart
|
||||
final filter = Filter.in_('members', ['thierry']);
|
||||
|
||||
final sort = [SortOption("last_message_at", direction: SortOption.DESC)];
|
||||
|
||||
final channels = await client.queryChannels(
|
||||
filter: filter,
|
||||
sort: sort,
|
||||
options: {
|
||||
"watch": true,
|
||||
"state": true,
|
||||
},
|
||||
);
|
||||
|
||||
channels.forEach((Channel c) {
|
||||
print("${c.extraData['name']} ${c.cid}");
|
||||
});
|
||||
```
|
||||
|
||||
The query channels endpoint will only return channels that the user can read,
|
||||
you should make sure that the query uses a filter that includes such logic.
|
||||
For example: messaging channels are readable only to their members,
|
||||
such requirement can be included in the query filter (see below).
|
||||
@@ -1,71 +0,0 @@
|
||||
---
|
||||
id: querying_users
|
||||
sidebar_position: 4
|
||||
title: Querying Users
|
||||
---
|
||||
Querying Users Across Channels
|
||||
|
||||
The Query Users method allows you to search for users and see if they are online/offline.
|
||||
The example below shows how you can retrieve the details for 3 users in one API call:
|
||||
|
||||
```dart
|
||||
final _result = client.queryUsers(
|
||||
filter: Filter.in_('id', ['john', 'jack', 'jessie']),
|
||||
);
|
||||
```
|
||||
|
||||
You can also add sort options and pagination to the query:
|
||||
|
||||
```dart
|
||||
final _result = client.queryUsers(
|
||||
filter: Filter.in_('id', ['john', 'jack', 'jessie']),
|
||||
sort: [SortOption('last_active')],
|
||||
pagination: PaginationParams(
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
You can filter and sort on the custom fields you've set for your user, the user id, and when the user was last active.
|
||||
|
||||
The options for the queryUser method are presence, limit, and offset.
|
||||
If presence is true this makes sure you receive the user.presence.changed event when a user goes online or offline.
|
||||
|
||||
### Querying using the autocomplete operator
|
||||
|
||||
You can autocomplete the results of your user query by username and/or ID.
|
||||
|
||||
### By Custom Field
|
||||
|
||||
```dart
|
||||
final _result = client.queryUsers(
|
||||
filter: Filter.autoComplete('name', 'ro'),
|
||||
);
|
||||
```
|
||||
This would return an array of any matching users, such as:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": "userID",
|
||||
"name": "Curiosity Rover"
|
||||
},
|
||||
{
|
||||
"id": "userID2",
|
||||
"name": "Roxy"
|
||||
},
|
||||
{
|
||||
"id": "userID3",
|
||||
"name": "Roxanne"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### By ID
|
||||
|
||||
```dart
|
||||
final _result = client.queryUsers(
|
||||
filter: Filter.autoComplete('id', 'USER_ID'),
|
||||
);
|
||||
```
|
||||
@@ -1,52 +0,0 @@
|
||||
---
|
||||
id: reactions
|
||||
sidebar_position: 18
|
||||
title: Reactions
|
||||
---
|
||||
|
||||
Adding And Removing User Reactions
|
||||
|
||||
Stream Chat has built-in support for user Reactions. Common examples are likes, comments, loves, etc. Reactions can be customized so that you are able to use any type of reaction your application requires.
|
||||
|
||||
|
||||
Similar to other objects in Stream Chat, reactions allow you to add custom data to the reaction of your choice. This is helpful if you want to customize the reaction logic.
|
||||
|
||||
<b>Note:</b> Custom data for reactions is limited to 1KB.
|
||||
|
||||
```dart
|
||||
await channel.sendReaction("messageID", "like", extraData: {"customField": 1});
|
||||
```
|
||||
|
||||
### Removing a Reaction
|
||||
|
||||
```dart
|
||||
await channel.deleteReaction("messageID", "like");
|
||||
```
|
||||
|
||||
### Paginating Reactions
|
||||
|
||||
Messages returned by the APIs automatically include the 10 most recent reactions.
|
||||
You can also retrieve more reactions and paginate using the following logic:
|
||||
|
||||
```dart
|
||||
// get the first 10 reactions
|
||||
await channel.getReactions("messageID", PaginationParams(limit: 10));
|
||||
|
||||
// get 3 reactions past the first 10
|
||||
await channel.getReactions("messageID", PaginationParams(limit: 3, offset:10));
|
||||
```
|
||||
|
||||
### Cumulative (Clap) Reactions
|
||||
|
||||
You can use the Reactions API to build something similar to Medium's clap reactions.
|
||||
If you are not familiar with this, Medium allows you to clap articles more than once and shows the sum of all claps from all users.
|
||||
|
||||
To do this, you only need to include a score for the reaction (ie. user X clapped 25 times) and the API will return the sum of all reaction scores as well as each user individual scores (ie. clapped 475 times, user Y clapped 14 times).
|
||||
|
||||
```dart
|
||||
// user claps 5 times on a message
|
||||
await channel.sendReaction("messageID", "like", score: 5);
|
||||
|
||||
// same user claps 20 times more
|
||||
await channel.sendReaction("messageID", "like", score: 25);
|
||||
```
|
||||
@@ -1,33 +0,0 @@
|
||||
---
|
||||
id: searching_messages
|
||||
sidebar_position: 20
|
||||
title: Searching Messages
|
||||
---
|
||||
|
||||
Searching For Messages Across Channels
|
||||
|
||||
Message search is built-in to the chat API. You can enable and/or disable the search indexing on a per channel type.
|
||||
The command shown below selects the channels in which John is a member.
|
||||
Next, it searches the messages in those channels for the keyword “'supercalifragilisticexpialidocious'”:
|
||||
|
||||
```dart
|
||||
final search = await client.search(
|
||||
Filter.in_('members', ['john']),
|
||||
query: 'supercalifragilisticexpialidocious',
|
||||
paginationParams: PaginationParams(
|
||||
limit: 2,
|
||||
offset: 0
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
Pagination works via the standard limit and offset parameters. The first argument, filter, uses a MongoDB style query expression.
|
||||
|
||||
We do not run MongoDB on the backend, so only a subset of the standard MongoDB filters are supported.
|
||||
Additionally, this endpoint can be used to search for messages that have attachments.
|
||||
|
||||
```dart
|
||||
// Search file of type videos
|
||||
final response = await channel.search(messageFilter: Filter.in_('attachments.type', ['video']));
|
||||
return response;
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
id: setup
|
||||
sidebar_position: 2
|
||||
title: Setup
|
||||
---
|
||||
|
||||
Understanding Setup
|
||||
@@ -1,39 +0,0 @@
|
||||
---
|
||||
id: silent_messages
|
||||
sidebar_position: 21
|
||||
title: Silent Messages
|
||||
---
|
||||
|
||||
Pushing Silent Messages
|
||||
|
||||
Sometimes you want to add system or transactional messages to channels such as: "your ride is waiting for you",
|
||||
"James updated the information for the trip", "You and Jane are now matched" and so on.
|
||||
|
||||
You may not want these messages to mark a channel as unread or increase the unread messages for users.
|
||||
|
||||
Silent messages are special messages that don't increase the unread messages count nor mark a channel as unread.
|
||||
Creating a silent message is very simple, you only need to include the silent field boolean field and set it to true.
|
||||
|
||||
```dart
|
||||
final text = 'You completed your trip';
|
||||
|
||||
const message = {
|
||||
|
||||
text: text,
|
||||
|
||||
user: systemUser,
|
||||
|
||||
silent: true,
|
||||
|
||||
attachments: tripAttachments,
|
||||
|
||||
};
|
||||
await channel.sendMessage(message);
|
||||
```
|
||||
|
||||
<b>Notes: </b>
|
||||
|
||||
1. Existing messages cannot be turned into a silent message or vice versa.
|
||||
|
||||
2. Silent messages do send push notifications by default. To skip our push notification service,
|
||||
mark the message with `skip_push: true`.
|
||||
@@ -1,17 +0,0 @@
|
||||
---
|
||||
id: slow_mode
|
||||
sidebar_position: 14
|
||||
title: Slow Mode
|
||||
---
|
||||
|
||||
Using Slow Mode For Reduced Message Traffic
|
||||
|
||||
Slow mode helps reduce noise on a channel by limiting users to a maximum of 1 message per cooldown interval.
|
||||
|
||||
The cooldown interval is configurable and can be anything between 1 and 120 seconds. For instance, if you enable slow mode and set the cooldown interval to 30 seconds a user will be able to post at most 1 message every 30 seconds.
|
||||
|
||||
Moderators, admins and server-side API calls are not restricted by the cooldown period and can post messages as usual.
|
||||
Slow mode is disabled by default and can be enabled/disabled by admins and moderators.
|
||||
|
||||
<b>Note:</b> SLOW MODE is in the works for the Flutter SDK
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
---
|
||||
id: threads_and_replies
|
||||
sidebar_position: 19
|
||||
title: Threads And Replies
|
||||
---
|
||||
|
||||
Creating And Paginating Threads
|
||||
|
||||
Threads and replies provide your users with a way to go into more detail about a specific topic.
|
||||
|
||||
This can be very helpful to keep the conversation organized and reduce noise.
|
||||
To create a thread you simply send a message with a `parent_id`. Have a look at the example below:
|
||||
|
||||
```dart
|
||||
final reply = await channel.sendMessage(
|
||||
Message(text: 'Hey, I am replying to a message!',
|
||||
parentId: parentID,
|
||||
showInChannel: false,
|
||||
));
|
||||
```
|
||||
|
||||
If you specify `show_in_channel`, the message will be visible both in a thread of replies as well as the main channel.
|
||||
Messages inside a thread can also have reactions, attachments and mention as any other message.
|
||||
|
||||
### Thread Pagination
|
||||
|
||||
When you read a channel you do not receive messages inside threads.
|
||||
The parent message includes the count of replies which it is usually what apps show as the link to the thread screen.
|
||||
Reading a thread and paginating its messages works in a very similar way as paginating a channel.
|
||||
|
||||
```dart
|
||||
// retrieve the first 20 messages inside the thread
|
||||
await channel.getReplies(parentMessageId, PaginationParams(limit: 20));
|
||||
|
||||
// retrieve the 20 more messages before the message with id "42"
|
||||
await channel.getReplies(parentMessageId, PaginationParams(limit: 20, lessThanOrEqual: '42'));
|
||||
```
|
||||
|
||||
### Quote Message
|
||||
|
||||
Instead of replying in a thread, it's also possible to quote a message. Quoting a message doesn't result in the creation of a thread;
|
||||
the message is quoted inline.
|
||||
|
||||
To quote a message, simply provide the `quoted_message_id` field when sending a message:
|
||||
|
||||
```dart
|
||||
// Create the initial message
|
||||
await channel.sendMessage(Message(id: 'first_message_id', text: 'The initial message' ));
|
||||
|
||||
// Quote the initial message
|
||||
final res = await channel.sendMessage(Message(
|
||||
id: 'message_with_quoted_message',
|
||||
text: 'This is the first message that quotes another message',
|
||||
quotedMessageId: 'first_message_id',
|
||||
));
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
---
|
||||
id: typing_indicators
|
||||
sidebar_position: 24
|
||||
title: Typing Indicators
|
||||
---
|
||||
|
||||
Adding Typing Indicators To Your App
|
||||
|
||||
All official SDKs support typing events out of the box and are handled on all channels with the typing_events featured enabled.
|
||||
Typing indicators allow you to show to users who is currently typing in the channel.
|
||||
This feature can be switched on/off on a channel-type basis using the CLI or directly from the Dashboard.
|
||||
If you are using one of the official SDK libraries, you will only need to ensure that typing indicators are enabled to get this working.
|
||||
|
||||
If you are building your UI on top of one of our Chat Clients instead, you will need to take care of four things:
|
||||
|
||||
Send an event `typing.start` when the user starts typing
|
||||
Send an event `typing.stop` after the user stopped typing
|
||||
Handle the two events and use them to toggle the typing indicator UI
|
||||
Use `parent_id` field of the event to indicate that typing is happening in a thread
|
||||
|
||||
### Sending start and stop typing events
|
||||
|
||||
```dart
|
||||
// The Dart client keeps track of the typing state for you.
|
||||
// Just call `channel.keystroke()` when the user types and
|
||||
// `channel.stopTyping()` when the user sends the message (or aborts)
|
||||
|
||||
// sends a typing.start event at most once every two seconds
|
||||
await channel.keystroke();
|
||||
|
||||
// sends a typing.start event for a particular thread
|
||||
await channel.keystroke(thread_id);
|
||||
|
||||
// sends the typing.stop event
|
||||
await channel.stopTyping();
|
||||
```
|
||||
|
||||
When sending events on user input, you should make sure to follow some best-practices to avoid bugs.
|
||||
|
||||
Only send typing.start when the user starts typing
|
||||
Send typing.stop after a few seconds since the last keystroke
|
||||
|
||||
### Receiving typing indicator events
|
||||
|
||||
```dart
|
||||
// channels keep track of the users that are currently typing
|
||||
// the `channel.state.typingEvents` is an immutable object which gets regenerated
|
||||
// every time a new user is added or removed to this list
|
||||
print(channel.state.typingEvents);
|
||||
|
||||
// add typing start event handling
|
||||
channel.on('typing.start', (event) => {
|
||||
print('${event.user.name} started typing');
|
||||
});
|
||||
|
||||
// add typing stop event handling
|
||||
channel.on('typing.stop', event => {
|
||||
print('${event.user.name} stopped typing');
|
||||
});
|
||||
```
|
||||
|
||||
Because clients might fail at sending `typing.stop` event all Chat clients periodically prune the list of typing users.
|
||||
@@ -1,48 +0,0 @@
|
||||
---
|
||||
id: updating_channels
|
||||
sidebar_position: 9
|
||||
title: Updating Channels
|
||||
---
|
||||
|
||||
Exploring Multiple Ways To Update A Channel
|
||||
|
||||
There are two ways to update a channel using the Stream API - a partial or full update.
|
||||
A partial update will retain any custom key-value data, whereas a complete update is going to remove any that are unspecified in the API request.
|
||||
|
||||
### Partial Update
|
||||
|
||||
A partial update can be used to set and unset specific fields when it is necessary to retain additional custom data fields on the object.
|
||||
AKA a patch style update.
|
||||
|
||||
```dart
|
||||
// Here's a channel with some custom field data that might be useful
|
||||
var channel = client.channel(type, id: id, extraData: {
|
||||
"source": "user",
|
||||
"source_detail" :{ "user_id": 123 },
|
||||
"channel_detail" :{ "topic": "Plants and Animals", "rating": "pg" }
|
||||
});
|
||||
|
||||
// let's change the source of this channel
|
||||
await channel.updatePartial({ "set" :{ "source": "system" } });
|
||||
|
||||
// since it's system generated we no longer need source_detail
|
||||
await channel.updatePartial({ "unset": ["source_detail"] });
|
||||
|
||||
// and finally update one of the nested fields in the channel_detail
|
||||
await channel.updatePartial({ "set": { "channel_detail.topic": "Nature" } });
|
||||
|
||||
// and maybe we decide we no longer need a rating
|
||||
await channel.updatePartial({ "unset": ["channel_detail.rating"] });
|
||||
```
|
||||
|
||||
### Full Update (overwrite)
|
||||
|
||||
The update function updates all of the channel data.
|
||||
<b>Any data that is present on the channel and not included in a full update will be deleted.</b>
|
||||
|
||||
```dart
|
||||
await channel.update({
|
||||
"name": "myspecialchannel",
|
||||
"color": "green",
|
||||
}, Message(text: "Thierry changed the channel color to green"));
|
||||
```
|
||||
@@ -1,103 +0,0 @@
|
||||
---
|
||||
id: uploading_files
|
||||
sidebar_position: 17
|
||||
title: Uploading Files
|
||||
---
|
||||
|
||||
Uploading Files And Using A Custom CDN
|
||||
|
||||
The `channel.sendImage` and `channel.sendFile` methods make it easy to upload files.
|
||||
|
||||
This functionality defaults to using the Stream CDN. If you would like, you can easily change the logic to upload to your own CDN of choice.
|
||||
The maximum file size is 20mb for the Stream Chat CDN.
|
||||
|
||||
```dart
|
||||
final client = StreamChatClient('api-key');
|
||||
var attachment = Attachment();
|
||||
|
||||
// Upload an image without monitoring send progress
|
||||
client.sendImage(image, channelId, channelType).then((response) {
|
||||
// Successful upload, you can now attach this image
|
||||
// to an message that you then send to a channel
|
||||
final imageUrl = response.file;
|
||||
attachment = attachment.copyWith(
|
||||
type: 'image',
|
||||
imageUrl: imageUrl,
|
||||
);
|
||||
final message = Message(attachments: [attachment]);
|
||||
client.sendMessage(message, channelId, channelType);
|
||||
}).catchError((error, stk) {
|
||||
// Handle error
|
||||
});
|
||||
|
||||
// Upload an file, monitoring the progress with a onSendProgress callback
|
||||
await client.sendFile(
|
||||
file,
|
||||
channelId,
|
||||
channelType,
|
||||
onSendProgress: (sent, total) {
|
||||
// Handle the send progress
|
||||
attachment = attachment.copyWith(
|
||||
uploadState: UploadState.inProgress(
|
||||
uploaded: sent,
|
||||
total: total,
|
||||
),
|
||||
);
|
||||
},
|
||||
).then((response) {
|
||||
// Successful upload, you can now attach this file
|
||||
// to an message that you then send to a channel
|
||||
final fileUrl = response.file;
|
||||
attachment = attachment.copyWith(
|
||||
type: 'file',
|
||||
assetUrl: fileUrl,
|
||||
uploadState: UploadState.success(),
|
||||
);
|
||||
final message = Message(attachments: [attachment]);
|
||||
client.sendMessage(message, channelId, channelType);
|
||||
}).catchError((error, stk) {
|
||||
// Handle error
|
||||
attachment = attachment.copyWith(
|
||||
uploadState: UploadState.failed(error: error),
|
||||
);
|
||||
});
|
||||
|
||||
// Alternatively you can call the sendMessage directly on the channel
|
||||
// which will automatically handle all the upload process of the provided
|
||||
// attachments.
|
||||
final channel = client.channel(channelType, id: channelId);
|
||||
|
||||
// Creating a message object with multiple local attachments
|
||||
final message = Message(text: 'Hello', attachments: [
|
||||
Attachment(
|
||||
type: 'image',
|
||||
file: AttachmentFile(path: 'imagePath/imageName.png'),
|
||||
),
|
||||
Attachment(
|
||||
type: 'file',
|
||||
file: AttachmentFile(path: 'filePath/fileName.pdf'),
|
||||
),
|
||||
]);
|
||||
|
||||
// Sending the message to the channel
|
||||
await channel.sendMessage(message);
|
||||
```
|
||||
|
||||
In the code example above, note how the message attachments are created after the files are uploaded. The React components support regular uploads, clipboard pasting, drag and drop, as well as URL enrichment via built-in open-graph scraping. As a bonus, the Stream CDN will automatically handle image resizing for you.
|
||||
|
||||
### Using Your Own CDN
|
||||
|
||||
All 5 SDKs make it easy to use your own CDN for uploads. The code examples below show how to change where files are uploaded:
|
||||
|
||||
```dart
|
||||
// Set a custom FileUploader implementation when building your client
|
||||
final client = StreamChatClient(
|
||||
'api-key',
|
||||
attachmentFileUploader: MyFileUploader(),
|
||||
);
|
||||
```
|
||||
|
||||
You'll have to create your own implementation of the `AttachmentFileUploader` interface,
|
||||
and any upload calls will be sent to that implementation.
|
||||
Take a look [at the interface](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat/lib/src/attachment_file_uploader.dart#L7)
|
||||
and [our own default implementation of it](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat/lib/src/attachment_file_uploader.dart#L58) for more info.
|
||||
@@ -1,94 +0,0 @@
|
||||
---
|
||||
id: user_presence
|
||||
sidebar_position: 5
|
||||
title: User Presence
|
||||
---
|
||||
|
||||
Check If A User Is Online / Check Last Active
|
||||
|
||||
User presence allows you to show when a user was last active and if they are online right now.
|
||||
Whenever you read a user the data will look like this:
|
||||
|
||||
```json
|
||||
{
|
||||
id: 'unique_user_id',
|
||||
online: true,
|
||||
status: 'Eating a veggie burger...',
|
||||
last_active: '2019-01-07T13:17:42.375Z'
|
||||
}
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
1. The online field indicates if the user is online. The status field stores text indicating the current user status.
|
||||
2. The last_active field is updated when a user connects and then refreshed every 15 minutes.
|
||||
|
||||
### Invisible
|
||||
|
||||
To mark a user invisible simply set the invisible property to true. You can also set a custom status message at the same time:
|
||||
|
||||
```dart
|
||||
await client.connectUser(
|
||||
User(
|
||||
id: 'super-band-9',
|
||||
extraData: {
|
||||
'invisible': true,
|
||||
},
|
||||
),
|
||||
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
|
||||
);
|
||||
```
|
||||
|
||||
Notes:
|
||||
|
||||
1. When invisible is set to true, the current user will appear as offline to other users.
|
||||
|
||||
### Listening to Presence Changes
|
||||
|
||||
Of course, you want to listen to the user presence changes. This allows you to show a user as offline when they leave and update their status in real time.
|
||||
These 3 endpoints allow you to watch user presence:
|
||||
|
||||
```dart
|
||||
// If you pass presence: true to channel.watch it will watch the list of user presence changes.
|
||||
// Note that you can listen to at most 10 users using this API call
|
||||
final channel = client.channel(
|
||||
'messaging',
|
||||
id: 'flutterdevs',
|
||||
extraData: {
|
||||
'name': 'Flutter devs',
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
await channel.watch({
|
||||
'presence': true,
|
||||
});
|
||||
|
||||
// queryChannels allows you to listen to the members of the channels that are returned
|
||||
// so this does the same thing as above and listens to online status changes for john and jack
|
||||
|
||||
final filter = Filter.in_('members', ['john']);
|
||||
|
||||
final sort = [SortOption("last_message_at", direction: SortOption.DESC)];
|
||||
|
||||
final channels = await client.queryChannels(
|
||||
filter: filter,
|
||||
sort: sort,
|
||||
options: {
|
||||
'presence': true,
|
||||
},
|
||||
);
|
||||
|
||||
// queryUsers allows you to listen to user presence changes for john and jack
|
||||
final result = await client.queryUsers(
|
||||
filter: Filter.in_('id', ['john', 'jack', 'jessie']),
|
||||
sort: [SortOption('last_active')],
|
||||
pagination: PaginationParams(
|
||||
offset: 0,
|
||||
limit: 20,
|
||||
),
|
||||
options: {
|
||||
'presence': true,
|
||||
},
|
||||
);
|
||||
```
|
||||
@@ -1,7 +0,0 @@
|
||||
---
|
||||
id: user_types
|
||||
sidebar_position: 3
|
||||
title: User Types
|
||||
---
|
||||
|
||||
Diving Into User Types
|
||||
@@ -1,116 +0,0 @@
|
||||
---
|
||||
id: watching_channels
|
||||
sidebar_position: 8
|
||||
title: Watching Channels
|
||||
---
|
||||
|
||||
More About Watching A Channel
|
||||
|
||||
The call to channel.watch does a few different things in one API call:
|
||||
|
||||
* It creates the channel if it doesn't exist yet (if this user has the right permissions to create a channel)
|
||||
* It queries the channel state and returns members, watchers and messages
|
||||
* It watches the channel state and tells the server that you want to receive events when anything in this channel changes
|
||||
* To start watching a channel
|
||||
|
||||
The examples below show how to watch a channel. Note that you need to be connected as a user before you can watch a channel.
|
||||
|
||||
```dart
|
||||
final state = await channel.watch();
|
||||
```
|
||||
|
||||
### Watchers vs Members
|
||||
|
||||
The concepts of watchers vs members can require a bit of clarification:
|
||||
|
||||
* <b>Members</b>: a permanent association between a user and a channel. If the user is online and not watching the channel they will receive a notification event, if they are offline they will receive a push notification.
|
||||
* <b>Watchers</b>: the list of watchers is temporary. It's anyone who is currently watching the channel.
|
||||
|
||||
Being able to send messages, and otherwise engage with a channel as a non-member requires certain permissions.
|
||||
For example, we have pre-configured permissions on our livestream channel type to allow non-members to interact,
|
||||
but in the messaging channel type, only members of the channel can interact.
|
||||
|
||||
### Watching Multiple Channels
|
||||
|
||||
The default queryChannels API returns channels and starts watching them.
|
||||
There is no need to also use channel.watch on the channels returned from queryChannels
|
||||
|
||||
```dart
|
||||
// first let’s create a filter to make messaging channels that include a specific user
|
||||
final filter = Filter.in_('members', [user_id]);
|
||||
|
||||
// we can also define a sort order of most recent messages first
|
||||
final sort = [SortOption("last_message_at", direction: SortOption.DESC)];
|
||||
|
||||
// finally, we can query for those channels, automatically watching them for the
|
||||
// currently connected user
|
||||
final channels = await client.queryChannels(
|
||||
filter: filter,
|
||||
sort: sort,
|
||||
options: {
|
||||
"watch": true,
|
||||
"state": true,
|
||||
},
|
||||
);
|
||||
```
|
||||
|
||||
### Stop Watching a Channel
|
||||
|
||||
To stop receiving channel events:
|
||||
|
||||
```dart
|
||||
// we can also stop watching a channel
|
||||
final stopWatching = await channel.stopWatching();
|
||||
```
|
||||
|
||||
### Watcher Count
|
||||
|
||||
To get the watcher count of a channel:
|
||||
|
||||
```dart
|
||||
// create a new channel of type “livestream” with name “watch-this-channel”
|
||||
final channel = client.channel("livestream", id: "watch-this-channel");
|
||||
|
||||
// retrieve our channels
|
||||
channel.query();
|
||||
|
||||
// each channel object has a state collection with a watcher_count property
|
||||
return channel.state.watcherCount;
|
||||
```
|
||||
|
||||
### Paginating Channel Watchers with channel.query
|
||||
|
||||
```dart
|
||||
// create a new channel of type “livestream” with name “watch-this-channel”
|
||||
final channel = client.channel("livestream", id: "watch-this-channel");
|
||||
|
||||
// now query the newly created channel for watchers, retrieving the first 5
|
||||
final result = await channel.query(
|
||||
watchersPagination: PaginationParams(
|
||||
limit: 5,
|
||||
offset: 0,
|
||||
),
|
||||
);
|
||||
|
||||
return result.watchers;
|
||||
```
|
||||
|
||||
### Listening to Changes in Watchers
|
||||
|
||||
A user already watching the channel can listen to users starting and stopping watching the channel with the realtime events:
|
||||
|
||||
```dart
|
||||
final channel = client.channel("livestream", id: "watch-this-channel");
|
||||
|
||||
await channel.watch();
|
||||
|
||||
// handle watch started event
|
||||
channel
|
||||
.on("user.watching.start")
|
||||
.listen((event) => print('${event.user.id} started watching'));
|
||||
|
||||
// handle watch stopped event
|
||||
channel
|
||||
.on("user.watching.stop")
|
||||
.listen((event) => print('${event.user.id} stopped watching'));
|
||||
```
|
||||
Reference in New Issue
Block a user