Merge branch 'develop' into localization-ko-and-jp
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
---
|
||||
id: adding_chat_to_video_livestreams
|
||||
sidebar_position: 7
|
||||
title: Adding Chat To Video Livestreams
|
||||
---
|
||||
|
||||
Adding Chat To Video Livestreams
|
||||
|
||||
### Introduction
|
||||
|
||||
Video livestreams are usually complemented with a chat section to make the livestream more interactive
|
||||
and encourage retention. There are several ways to show the chat interface on the screen and requires
|
||||
some design choices.
|
||||
|
||||
This guide details multiple ways of adding chat functionality to your video livestream.
|
||||
|
||||
### Implementing Chat
|
||||
|
||||
There are two common scenarios in live-streaming applications depending how well integrated the two
|
||||
components (video + chat) are allowed to be on the screen. Two common types are split-screen and a
|
||||
chat overlay that fades in.
|
||||
|
||||
Let's explore creating both types:
|
||||
|
||||
### Split-screen
|
||||
|
||||
In the split-screen implementation, we have a visual split between the video and the message list.
|
||||
This allows the content to be unobstructed by chat and have a clear separation of boundaries.
|
||||
|
||||

|
||||
|
||||
```dart
|
||||
Scaffold(
|
||||
body: Column(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: // Your video implementation here,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: MessageListView(),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
### Overlapping chat with a transparency gradient
|
||||
|
||||
Another way to add chat is to overlay the video content with messages which progressively fade out
|
||||
as we go to the top of the screen. This gives the content a more rich feel as it takes the whole
|
||||
screen and allows the chat to be more homogeneously integrated with the content.
|
||||
|
||||
The second type looks like this:
|
||||
|
||||

|
||||
|
||||
We can use a `Stack` for achieving this:
|
||||
|
||||
```dart
|
||||
Scaffold(
|
||||
body: Stack(
|
||||
children: <Widget>[
|
||||
// Add your video implementation here
|
||||
ShaderMask(
|
||||
shaderCallback: (rect) {
|
||||
return LinearGradient(
|
||||
begin: Alignment.bottomCenter,
|
||||
end: Alignment.topCenter,
|
||||
colors: [Colors.black, Colors.transparent],
|
||||
stops: [0.4, 0.65]
|
||||
).createShader(Rect.fromLTRB(0, 0, rect.width, rect.height));
|
||||
},
|
||||
blendMode: BlendMode.dstIn,
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: MessageListView(),
|
||||
),
|
||||
MessageInput(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
id: adding_local_data_persistence
|
||||
sidebar_position: 9
|
||||
title: Adding Local Data Persistence
|
||||
---
|
||||
|
||||
Adding Local Data Persistence
|
||||
|
||||
### Introduction
|
||||
|
||||
Most messaging apps need to work regardless of whether the app is currently connected to the internet.
|
||||
Local data persistence stores the fetched data from the backend on a local SQLite database using the
|
||||
moor package in Flutter. All packages in the SDK can use local data persistence to store messages
|
||||
across multiple platforms.
|
||||
|
||||
### Implementation
|
||||
|
||||
To add data persistence you can extend the class ChatPersistenceClient and pass an instance to the StreamChatClient.
|
||||
|
||||
```dart
|
||||
class CustomChatPersistentClient extends ChatPersistenceClient {
|
||||
...
|
||||
}
|
||||
|
||||
final client = StreamChatClient(
|
||||
apiKey ?? kDefaultStreamApiKey,
|
||||
logLevel: Level.INFO,
|
||||
)..chatPersistenceClient = CustomChatPersistentClient();
|
||||
```
|
||||
|
||||
We provide an official persistent client in the [stream_chat_persistence](https://pub.dev/packages/stream_chat_persistence)
|
||||
package that works using the library [moor](https://moor.simonbinder.eu), an SQLite ORM.
|
||||
|
||||
Add this to your package's `pubspec.yaml` file, using the latest version.
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
stream_chat_persistence: ^latest_version
|
||||
```
|
||||
|
||||
You should then run `flutter packages get`
|
||||
|
||||
The usage is pretty simple.
|
||||
|
||||
1. Create a new instance of `StreamChatPersistenceClient` providing `logLevel` and `connectionMode`
|
||||
|
||||
```dart
|
||||
final chatPersistentClient = StreamChatPersistenceClient(
|
||||
logLevel: Level.INFO,
|
||||
connectionMode: ConnectionMode.background,
|
||||
);
|
||||
```
|
||||
|
||||
2. Pass the instance to the official `StreamChatClient`
|
||||
|
||||
```dart
|
||||
final client = StreamChatClient(
|
||||
apiKey ?? kDefaultStreamApiKey,
|
||||
logLevel: Level.INFO,
|
||||
)..chatPersistenceClient = chatPersistentClient;
|
||||
```
|
||||
|
||||
And you are ready to go...
|
||||
|
||||
Note that passing `ConnectionMode.background` the database uses a background isolate to unblock the main thread.
|
||||
The `StreamChatClient` uses the `chatPersistentClient` to synchronize the database with the newest
|
||||
information every time it receives new data about channels/messages/users.
|
||||
|
||||
### Multi-user
|
||||
|
||||
The DB file is named after the `userId`, so if you instantiate a client using a different `userId` you will use a different database.
|
||||
Calling `client.disconnectUser(flushChatPersistence: true)` flushes all current database data.
|
||||
|
||||
### Updating/deleting/sending a message while offline
|
||||
|
||||
The information about the action is saved in offline storage. When the client returns online, everything is retried.
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
id: adding_localization
|
||||
sidebar_position: 2
|
||||
title: Adding Localization
|
||||
title: Adding Localization (l10n) / Internationalization (i18n)
|
||||
---
|
||||
|
||||
Adding Localization To UI Widgets
|
||||
@@ -14,7 +14,7 @@ We have a dedicated package for adding localization to our UI widgets. It's call
|
||||
|
||||
## What is Localization?
|
||||
|
||||
If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/**internationalization**).
|
||||
If you deploy your app to users who speak another language, you'll need to internationalize (localize) it. That means you need to write the app in a way that makes it possible to localize values like text and layouts for each language or locale that the app supports. For more information, see the [Flutter documentation](https://flutter.dev/docs/development/accessibility-and-localization/internationalization).
|
||||
|
||||
What this package allows you to do is to provide localized strings for the Stream chat widgets. For example, depending on the application locale, the Stream Chat widgets will display the appropriate language. The locale will be set automatically, based on system preferences, or you could set it programmatically in your app. The package supports several different languages, with more to be added. The package allows you to override any supported language or add a new language that isn't supported.
|
||||
|
||||
@@ -42,7 +42,7 @@ Then run `flutter packages get`
|
||||
|
||||
### Usage
|
||||
|
||||
Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en`.
|
||||
Generally, Flutter and the Stream Chat SDK will use the system locale of the user's device, if that locale is supported (see below). If the locale is not supported we will default to `en` (however it's always possible to [customize that](#changing-the-default-language)).
|
||||
Make sure to read more about localization in the [official Flutter docs](https://flutter.dev/docs/development/accessibility-and-localization/internationalization).
|
||||
|
||||
```dart
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
id: customize_message_actions
|
||||
sidebar_position: 8
|
||||
title: Customize Message Actions
|
||||
---
|
||||
|
||||
Customizing Message Actions
|
||||
|
||||
### Introduction
|
||||
|
||||
Message actions pop up in message overlay, when you long-press a message.
|
||||
|
||||

|
||||
|
||||
We have provided granular control over these actions.
|
||||
|
||||
By default we render the following message actions:
|
||||
|
||||
* edit message
|
||||
|
||||
* delete message
|
||||
|
||||
* reply
|
||||
|
||||
* thread reply
|
||||
|
||||
* copy message
|
||||
|
||||
* flag message
|
||||
|
||||
* pin message
|
||||
|
||||
:::note
|
||||
Edit and delete message are only available on messages sent by the user.
|
||||
Additionally, pinning a message requires you to add the roles which are allowed to pin messages.
|
||||
:::
|
||||
|
||||
### Partially remove some message actions
|
||||
|
||||
For example, if you only want to keep "copy message" and "delete message",
|
||||
here is how to do it using the `messageBuilder` with our `MessageWidget`.
|
||||
|
||||
```dart
|
||||
MessageListView(
|
||||
messageBuilder: (context, details, messages, defaultMessage) {
|
||||
return defaultMessage.copyWith(
|
||||
showFlagButton: false,
|
||||
showEditMessage: false,
|
||||
showCopyMessage: true,
|
||||
showDeleteMessage: details.isMyMessage,
|
||||
showReplyMessage: false,
|
||||
showThreadReplyMessage: false,
|
||||
);
|
||||
},
|
||||
)
|
||||
```
|
||||
|
||||
### Add a new custom message action
|
||||
|
||||
The SDK also allows you to add new actions into the dialog.
|
||||
|
||||
For example, let's suppose you want to introduce a new message action - "Demo Action":
|
||||
|
||||
We use the `customActions` parameter of the `MessageWidget` to add extra actions.
|
||||
|
||||
```dart
|
||||
MessageListView(
|
||||
messageBuilder: (context, details, messages, defaultMessage) {
|
||||
return defaultMessage.copyWith(
|
||||
customActions: [
|
||||
MessageAction(
|
||||
leading: Icon(Icons.add),
|
||||
title: Text('Demo Action'),
|
||||
onTap: (message) {
|
||||
/// Complete action here
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
)
|
||||
```
|
||||
@@ -0,0 +1,143 @@
|
||||
---
|
||||
id: understanding_filters
|
||||
sidebar_position: 10
|
||||
title: Understanding Filters
|
||||
---
|
||||
|
||||
Understanding Filters
|
||||
|
||||
### Introduction
|
||||
|
||||
Filters are used to get a specific subset of objects (channels, users, messages, members, etc) which
|
||||
fit the conditions specified. Earlier versions of the SDK contained String-based filters which are now replaced by type-safe
|
||||
filters. This guide aims to explain the different types of filters and how to use them.
|
||||
|
||||
### Types Of Filters
|
||||
|
||||
#### Filter.equal
|
||||
|
||||
The 'equal' filter gets the objects where the given key has the specified value.
|
||||
|
||||
```dart
|
||||
Filter.equal('type', 'messaging'),
|
||||
```
|
||||
|
||||
#### Filter.notEqual
|
||||
|
||||
The 'notEqual' filter gets the objects where the given key does not have the specified value.
|
||||
|
||||
```dart
|
||||
Filter.notEqual('type', 'messaging'),
|
||||
```
|
||||
|
||||
#### Filter.greater
|
||||
|
||||
The 'greater' filter gets the objects where the given key has a higher value than the specified value.
|
||||
|
||||
```dart
|
||||
Filter.greater('count', 5),
|
||||
```
|
||||
|
||||
#### Filter.greaterOrEqual
|
||||
|
||||
The 'greaterOrEqual' filter gets the objects where the given key has an equal or higher value than the specified value.
|
||||
|
||||
```dart
|
||||
Filter.greaterOrEqual('count', 5),
|
||||
```
|
||||
|
||||
#### Filter.less
|
||||
|
||||
The 'less' filter gets the objects where the given key has a lesser value than the specified value.
|
||||
|
||||
```dart
|
||||
Filter.less('count', 5),
|
||||
```
|
||||
|
||||
#### Filter.lessOrEqual
|
||||
|
||||
The 'lessOrEqual' filter gets the objects where the given key has a lesser or equal value than the specified value.
|
||||
|
||||
```dart
|
||||
Filter.lessOrEqual('count', 5),
|
||||
```
|
||||
|
||||
#### Filter.in_
|
||||
|
||||
The 'in_' filter allows getting objects where the key matches any in a specified array.
|
||||
|
||||
```dart
|
||||
Filter.in_('members', [user.id])
|
||||
```
|
||||
|
||||
:::note
|
||||
Since 'in' is a keyword in Dart, the filter has an underscore added. This does not apply to the 'notIn'
|
||||
keyword.
|
||||
:::
|
||||
|
||||
#### Filter.notIn
|
||||
|
||||
The 'notIn' filter allows getting objects where the key matches none in a specified array.
|
||||
|
||||
```dart
|
||||
Filter.notIn('members', [user.id])
|
||||
```
|
||||
|
||||
#### Filter.query
|
||||
|
||||
The 'query' filter matches values by performing text search with the specified value.
|
||||
|
||||
```dart
|
||||
Filter.query('name', 'demo')
|
||||
```
|
||||
|
||||
#### Filter.autoComplete
|
||||
|
||||
The 'autoComplete' filter matches values with the specified prefix.
|
||||
|
||||
```dart
|
||||
Filter.autoComplete('name', 'demo')
|
||||
```
|
||||
|
||||
#### Filter.exists
|
||||
|
||||
The 'exists' filter matches values that exist, or don't exist, based on the specified boolean value.
|
||||
|
||||
```dart
|
||||
Filter.exists('name', true)
|
||||
```
|
||||
|
||||
### Group Queries
|
||||
|
||||
#### Filter.and
|
||||
|
||||
The 'and' operator combines multiple queries.
|
||||
|
||||
```dart
|
||||
final filter = Filter.and([
|
||||
Filter.equal('type', 'messaging'),
|
||||
Filter.in_('members', [user.id])
|
||||
])
|
||||
```
|
||||
|
||||
#### Filter.or
|
||||
|
||||
Combines the provided filters and matches the values matched by at least one of the filters.
|
||||
|
||||
```dart
|
||||
final filter = Filter.or([
|
||||
Filter.in_('bannedUsers', [user.id]),
|
||||
Filter.in_('shadowBannedUsers', [user.id])
|
||||
])
|
||||
```
|
||||
|
||||
#### Filter.nor
|
||||
|
||||
Combines the provided filters and matches the values not matched by all the filters.
|
||||
|
||||
```dart
|
||||
final filter = Filter.nor([
|
||||
Filter.in_('bannedUsers', [user.id]),
|
||||
Filter.in_('shadowBannedUsers', [user.id])
|
||||
])
|
||||
```
|
||||
Reference in New Issue
Block a user