diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml
index eddb2ac1..4e7c3b5f 100644
--- a/.github/workflows/pr_title.yml
+++ b/.github/workflows/pr_title.yml
@@ -1,4 +1,4 @@
-name: 'PR Title is Conventional'
+name: 'PR is Conventional and Semantic'
on:
pull_request_target:
types:
@@ -9,7 +9,7 @@ on:
- develop
jobs:
- main:
+ conventional_pr_title:
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v3.4.0
@@ -25,3 +25,20 @@ jobs:
requireScope: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ semantic_changelog_update:
+ needs: conventional_pr_title # Trigger after the [conventional_pr_title] completes
+ runs-on: ubuntu-latest
+ steps:
+ - uses: GetStream/verify-semantic-changelog-update@main
+ with:
+ scopes: |
+ {
+ "llc": "packages/stream_chat",
+ "ui": "packages/stream_chat_flutter",
+ "core": "packages/stream_chat_flutter_core",
+ "localization": "packages/stream_chat_flutter_localizations",
+ "persistence": "packages/stream_chat_persistence"
+ }
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 0faad799..3bb5a923 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -52,6 +52,8 @@ Stream's Flutter code is kept in a single mono-repository consisting of multiple
`stream_chat_persistence` - This package provides a persistence client for fetching and saving chat data locally. Stream Chat Persistence uses Moor as a disk cache.
+`stream_chat_localizations` - This package provides a set of localizations for the SDK.
+
### Local Setup
Congratulations! 🎉. You've successfully cloned our repo, and you are ready to make your first contribution. Before you can start making code changes, there are a few things to configure.
diff --git a/README.md b/README.md
index 6758b189..62358d57 100644
--- a/README.md
+++ b/README.md
@@ -17,7 +17,7 @@ This repository contains code for our [Dart](https://dart.dev/) and [Flutter](ht
Stream allows developers to rapidly deploy scalable feeds and chat messaging with an industry leading 99.999% uptime SLA guarantee.
## Sample apps and demos
-Our team maintains a dedicated repository for fully-fledged sample applications and demos. Consider checking out [GetStream/flutter-samples](https://github.com/GetStream/flutter-samples) to learn more or get started by looking at our latest [Stream Chat demo](https://github.com/GetStream/flutter-samples/tree/main/stream_chat_v1).
+Our team maintains a dedicated repository for fully-fledged sample applications and demos. Consider checking out [GetStream/flutter-samples](https://github.com/GetStream/flutter-samples) to learn more or get started by looking at our latest [Stream Chat demo](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1).
## Free for Makers
diff --git a/docusaurus/docs/Flutter/basics/introduction.mdx b/docusaurus/docs/Flutter/basics/introduction.mdx
index 756bd33f..99170774 100644
--- a/docusaurus/docs/Flutter/basics/introduction.mdx
+++ b/docusaurus/docs/Flutter/basics/introduction.mdx
@@ -8,13 +8,14 @@ Exploring The Basics Of Stream Chat

-Stream Chat is a service that helps you easily build a full chat experience in your Flutter (and more) apps.
+Stream Chat is a service that helps you easily build a full chat experience in your Flutter apps.
+We also support a variety of other SDKs.
This section of the documentation focuses on our Flutter SDK which helps you easily
-ship high quality messaging experiences in apps and programs built with the [Flutter toolkit made
-by Google](https://flutter.dev).
+ship high quality messaging experiences in apps and programs built with the [Flutter toolkit
+made by Google](https://flutter.dev).
-The Stream Chat Flutter SDK comprises of four different packages to choose from ranging from ones
+The Stream Chat Flutter SDK comprises five different packages to choose from, ranging from ones
giving you complete control to ones that give you a rich out-of-the-box chat experience.
The packages that make up the Stream Chat SDK are:
@@ -30,28 +31,28 @@ reusable and customisable UI components.
saving chat data locally.
5. Localizations (stream_chat_localizations): provides a set of localizations for the SDK.
-We recommend building prototypes using the full UI package since it contains UI widgets already
-integrated with Stream's API. [stream_chat_flutter](https://pub.dev/packages/stream_chat_flutter)
-is the fastest way to get up and running using Stream chat in your app.
+We recommend building prototypes using the full UI package, [stream_chat_flutter](https://pub.dev/packages/stream_chat_flutter),
+since it contains UI widgets already integrated with Stream's API. It is the fastest way to get up
+and running using Stream chat in your app.
The Flutter SDK enables you to build any type of chat or messaging experience for Android, iOS, Web
and Desktop.
If you're building a very custom UI and would prefer a more lean package,
-our [core package](https://pub.dev/packages/stream_chat_flutter) will be suited to this use case. Core allows you to build custom,
-expressive UIs while retaining the benefits of our full Flutter SDK.
-APIs for accessing and controlling users, sending messages, etc are seamlessly integrated into
-this package and accessible via providers and builders.
+[stream_chat_flutter_core](https://pub.dev/packages/stream_chat_flutter_core) will be suited to this
+use case. Core allows you to build custom, expressive UIs while retaining the benefits of our full
+Flutter SDK. APIs for accessing and controlling users, sending messages, and so forth are seamlessly integrated
+into this package and accessible via providers and builders.
Before going into the docs, let's take a small detour to look at how the elements of Stream Chat are structured.
### Basic Structure
-There are two core elements in chat, Users and Channels.
+There are two core elements in chat, Users and Channels.
Channels are groups of one or more users that can message each other.
In an app, you need to have a user connected to query channels.
-There is no specific distinction between a chat between two people and a group chat,
+There is no specific distinction between a chat with only two people and a group chat,
but there is a way to create a unique chat between a certain number of people by creating a distinct channel.

@@ -68,7 +69,7 @@ While this is a simplistic overview of the service, the Flutter SDK handles the
Before reading the docs, consider trying our [online API tour](https://getstream.io/chat/get_started/),
it is a nice way to learn how the API works.
-It's in-browser so Javascript-based but the ideas are pretty much the same as Dart.
+It's in-browser so you'll need to use Javascript but the core conceps are pretty much the same as Dart.
You may also like to look at the [Flutter tutorial](https://getstream.io/chat/flutter/tutorial/)
which focuses on using the UI package to get Stream Chat integrated into a Flutter app.
diff --git a/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx b/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx
index fb1f7bbe..9fe7f6aa 100644
--- a/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx
+++ b/docusaurus/docs/Flutter/guides/adding_custom_attachments.mdx
@@ -146,21 +146,25 @@ Next, we build the Static Maps URL (Add your API key before using the code snipp
}
```
-And then modify the MessageListView and tell it how to build a location attachment:
+And then modify the `MessageListView` and tell it how to build a location attachment, using the `messageBuilder` property and copying the default message implementation overriding the `customAttachmentBuilders` property:
```dart
MessageListView(
- customAttachmentBuilders: {
- 'location': (context, message, attachments) {
- var attachmentWidget = Image.network(
- _buildMapAttachment(
- attachments[0].extraData['latitude'],
- attachments[0].extraData['longitude'],
- ),
- );
+ messageBuilder: (context, details, messages, defaultMessage) {
+ return defaultMessage.copyWith(
+ customAttachmentBuilders: {
+ 'location': (context, message, attachments) {
+ final attachmentWidget = Image.network(
+ _buildMapAttachment(
+ attachments[0].extraData['latitude'],
+ attachments[0].extraData['longitude'],
+ ),
+ );
- return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0));
- }
+ return wrapAttachmentWidget(context, attachmentWidget, null, true, BorderRadius.circular(8.0));
+ }
+ },
+ );
},
),
```
diff --git a/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx b/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx
new file mode 100644
index 00000000..e6283ca0
--- /dev/null
+++ b/docusaurus/docs/Flutter/guides/adding_local_data_persistence.mdx
@@ -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.
diff --git a/docusaurus/docs/Flutter/guides/adding_localization.mdx b/docusaurus/docs/Flutter/guides/adding_localization.mdx
index 37f7299d..4ad5eede 100644
--- a/docusaurus/docs/Flutter/guides/adding_localization.mdx
+++ b/docusaurus/docs/Flutter/guides/adding_localization.mdx
@@ -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.
@@ -26,7 +26,8 @@ At the moment we support the following languages:
- [Italian](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_it.dart)
- [French](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_fr.dart)
- [Spanish](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_es.dart)
-
+- [Japanese](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ja.dart)
+- [Korean](https://github.com/GetStream/stream-chat-flutter/blob/master/packages/stream_chat_localizations/lib/src/stream_chat_localizations_ko.dart)
More languages will be added in the future. Feel free to [contribute](https://github.com/GetStream/stream-chat-flutter/blob/master/CONTRIBUTING.md) to add more languages.
### Add dependency
@@ -64,6 +65,8 @@ class MyApp extends StatelessWidget {
Locale('fr'),
Locale('it'),
Locale('es'),
+ Locale('ja'),
+ Locale('ko'),
],
// Add GlobalStreamChatLocalizations.delegates
localizationsDelegates: GlobalStreamChatLocalizations.delegates,
@@ -133,6 +136,8 @@ Here is an example of how that would look like:
Locale('fr'),
Locale('it'),
Locale('es'),
+ Locale('ja'),
+ Locale('ko'),
],
// locales are the locales of the device
// supportedLocales are the app supported locales
@@ -175,6 +180,8 @@ Example:
nb
fr
it
- es
+ es
+ ja
+ ko
```
diff --git a/docusaurus/docs/Flutter/guides/understanding_filters.mdx b/docusaurus/docs/Flutter/guides/understanding_filters.mdx
new file mode 100644
index 00000000..9d169a80
--- /dev/null
+++ b/docusaurus/docs/Flutter/guides/understanding_filters.mdx
@@ -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])
+])
+```
diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md
index e3e31db6..85bc73ef 100644
--- a/packages/stream_chat/CHANGELOG.md
+++ b/packages/stream_chat/CHANGELOG.md
@@ -8,7 +8,9 @@
- `User` and `OwnUser` classes now have an `image` property. Setting an image will also set the 'image' key on `extraData`, so `user.image` and `user.extraData['image']` is the same.
- `User` and `OwnUser` classes now have a `name` property. Setting a name will also set the 'name' key on `extraData`, so `user.name` and `user.extraData['name']` is the same.
-
+- `Channel` class now has extra `image` getter and setter. As well as an `updateImage` to do a partial update after a channel has been initialized.
+- `Channel` class now has extra `name` getter and setter. As well as an `updateName` to do a partial update after a channel has been initialized.
+- Added slow mode which allows a cooldown period after a user sends a message.
## 2.1.1
🐞 Fixed
diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart
index a05587ab..22738794 100644
--- a/packages/stream_chat/lib/src/client/channel.dart
+++ b/packages/stream_chat/lib/src/client/channel.dart
@@ -15,20 +15,77 @@ import 'package:stream_chat/src/core/util/utils.dart';
import 'package:stream_chat/src/event_type.dart';
import 'package:stream_chat/stream_chat.dart';
-/// This a the class that manages a specific channel.
+/// Class that manages a specific channel.
+///
+/// #### Channel name
+///
+/// {@template name}
+/// If an optional [name] argument is provided in the constructor then it
+/// will be set on [extraData] with a key of 'name'.
+///
+/// ```dart
+/// final channel = Channel(client, type, id, name: 'Channel name');
+/// print(channel.name == channel.extraData['name']); // true
+/// ```
+///
+/// Before the channel is initialized the name can be set directly:
+/// ```dart
+/// channel.name = 'New channel name';
+/// ```
+///
+/// To update the name after the channel has been initialized, call:
+/// ```dart
+/// channel.updateName('Updated channel name');
+/// ```
+///
+/// This will do a partial update to update the name.
+/// {@endtemplate}
+///
+/// #### Channel image
+///
+/// {@template image}
+/// If an optional [image] argument is provided in the constructor then it
+/// will be set on [extraData] with a key of 'image'.
+///
+/// ```dart
+/// final channel = Channel(client, type, id, image: 'https://getstream.io/image.png');
+/// print(channel.image == channel.extraData['image']); // true
+/// ```
+///
+/// Before the channel is initialized the image can be set directly:
+/// ```dart
+/// channel.image = 'https://getstream.io/new-image';
+/// ```
+///
+/// To update the image after the channel has been initialized, call:
+/// ```dart
+/// channel.updateImage('https://getstream.io/new-image');
+/// ```
+///
+/// This will do a partial update to update the image.
+/// {@endtemplate}
class Channel {
- /// Create a channel client instance.
+ /// Class that manages a specific channel.
+ ///
+ /// Optional [extraData] and [image] properties can be provided. The [image]
+ /// is exposed to easily set a key of 'image' on [extraData].
Channel(
this._client,
this._type,
this._id, {
+ String? name,
+ String? image,
Map? extraData,
}) : _cid = _id != null ? '$_type:$_id' : null,
- _extraData = extraData ?? {} {
- _client.logger.info('New Channel instance not initialized created');
+ _extraData = {
+ ...?extraData,
+ if (name != null) 'name': name,
+ if (image != null) 'image': image,
+ } {
+ _client.logger.info('New Channel instance created, not yet initialized');
}
- /// Create a channel client instance from a [ChannelState] object
+ /// Create a channel client instance from a [ChannelState] object.
Channel.fromState(this._client, ChannelState channelState)
: assert(
channelState.channel != null,
@@ -40,7 +97,7 @@ class Channel {
_extraData = channelState.channel!.extraData {
state = ChannelClientState(this, channelState);
_initializedCompleter.complete(true);
- _client.logger.info('New Channel instance initialized created');
+ _client.logger.info('New Channel instance initialized');
}
/// This client state
@@ -53,155 +110,188 @@ class Channel {
String? _cid;
final Map _extraData;
+ /// Shortcut to set channel name.
+ ///
+ /// {@macro name}
+ set name(String? name) {
+ if (_initializedCompleter.isCompleted) {
+ throw StateError(
+ 'Once the channel is initialized you should use `channel.updateName` '
+ 'to update the channel name',
+ );
+ }
+ _extraData.addAll({'name': name});
+ }
+
+ /// Shortcut to set channel image.
+ ///
+ /// {@macro image}
+ set image(String? image) {
+ if (_initializedCompleter.isCompleted) {
+ throw StateError(
+ 'Once the channel is initialized you should use `channel.updateImage` '
+ 'to update the channel image',
+ );
+ }
+ _extraData.addAll({'image': image});
+ }
+
set extraData(Map extraData) {
if (_initializedCompleter.isCompleted) {
throw StateError(
- 'Once the channel is initialized you should use channel.update '
+ 'Once the channel is initialized you should use `channel.update` '
'to update channel data',
);
}
_extraData.addAll(extraData);
}
- /// Returns true if the channel is muted
+ /// Returns true if the channel is muted.
bool get isMuted =>
_client.state.currentUser?.channelMutes
.any((element) => element.channel.cid == cid) ==
true;
- /// Returns true if the channel is muted as a stream
- Stream? get isMutedStream => _client.state.currentUserStream
+ /// Returns true if the channel is muted, as a stream.
+ Stream get isMutedStream => _client.state.currentUserStream
.map((event) =>
- event!.channelMutes.any((element) => element.channel.cid == cid) ==
+ event?.channelMutes.any((element) => element.channel.cid == cid) ==
true)
.distinct();
- /// True if the channel is a group
+ /// True if the channel is a group.
bool get isGroup => memberCount != 2;
- /// True if the channel is distinct
+ /// True if the channel is distinct.
bool get isDistinct => id?.startsWith('!members') == true;
- /// Channel configuration
+ /// Channel configuration.
ChannelConfig? get config {
_checkInitialized();
- return state?._channelState.channel?.config;
+ return state!._channelState.channel?.config;
}
- /// Channel configuration as a stream
- Stream? get configStream {
+ /// Channel configuration as a stream.
+ Stream get configStream {
_checkInitialized();
- return state?.channelStateStream.map((cs) => cs.channel?.config);
+ return state!.channelStateStream.map((cs) => cs.channel?.config);
}
- /// Channel user creator
+ /// Channel user creator.
User? get createdBy {
_checkInitialized();
- return state?._channelState.channel?.createdBy;
+ return state!._channelState.channel?.createdBy;
}
- /// Channel user creator as a stream
- Stream? get createdByStream {
+ /// Channel user creator as a stream.
+ Stream get createdByStream {
_checkInitialized();
- return state?.channelStateStream.map((cs) => cs.channel?.createdBy);
+ return state!.channelStateStream.map((cs) => cs.channel?.createdBy);
}
- /// Channel frozen status
- bool? get frozen {
+ /// Channel frozen status.
+ bool get frozen {
_checkInitialized();
- return state?._channelState.channel?.frozen;
+ return state!._channelState.channel?.frozen == true;
}
- /// Channel frozen status as a stream
- Stream? get frozenStream {
+ /// Channel frozen status as a stream.
+ Stream get frozenStream {
_checkInitialized();
- return state?.channelStateStream.map((cs) => cs.channel?.frozen);
+ return state!.channelStateStream.map((cs) => cs.channel?.frozen == true);
}
- /// Channel creation date
+ /// Cooldown count
+ int? get cooldown {
+ _checkInitialized();
+ return state?._channelState.channel?.cooldown;
+ }
+
+ /// Cooldown count as a stream
+ Stream? get cooldownStream {
+ _checkInitialized();
+ return state?.channelStateStream.map((cs) => cs.channel?.cooldown);
+ }
+
+ /// Stores time at which cooldown was started
+ DateTime? cooldownStartedAt;
+
+ /// Channel creation date.
DateTime? get createdAt {
_checkInitialized();
- return state?._channelState.channel?.createdAt;
+ return state!._channelState.channel?.createdAt;
}
- /// Channel creation date as a stream
- Stream? get createdAtStream {
+ /// Channel creation date as a stream.
+ Stream get createdAtStream {
_checkInitialized();
- return state?.channelStateStream.map((cs) => cs.channel?.createdAt);
+ return state!.channelStateStream.map((cs) => cs.channel?.createdAt);
}
- /// Channel last message date
+ /// Channel last message date.
DateTime? get lastMessageAt {
_checkInitialized();
-
- return state?._channelState.channel?.lastMessageAt;
+ return state!._channelState.channel?.lastMessageAt;
}
- /// Channel last message date as a stream
- Stream? get lastMessageAtStream {
+ /// Channel last message date as a stream.
+ Stream get lastMessageAtStream {
_checkInitialized();
-
- return state?.channelStateStream.map((cs) => cs.channel?.lastMessageAt);
+ return state!.channelStateStream.map((cs) => cs.channel?.lastMessageAt);
}
- /// Channel updated date
+ /// Channel updated date.
DateTime? get updatedAt {
_checkInitialized();
-
- return state?._channelState.channel?.updatedAt;
+ return state!._channelState.channel?.updatedAt;
}
- /// Channel updated date as a stream
- Stream? get updatedAtStream {
+ /// Channel updated date as a stream.
+ Stream get updatedAtStream {
_checkInitialized();
-
- return state?.channelStateStream.map((cs) => cs.channel?.updatedAt);
+ return state!.channelStateStream.map((cs) => cs.channel?.updatedAt);
}
- /// Channel deletion date
+ /// Channel deletion date.
DateTime? get deletedAt {
_checkInitialized();
-
- return state?._channelState.channel?.deletedAt;
+ return state!._channelState.channel?.deletedAt;
}
- /// Channel deletion date as a stream
- Stream? get deletedAtStream {
+ /// Channel deletion date as a stream.
+ Stream get deletedAtStream {
_checkInitialized();
-
- return state?.channelStateStream.map((cs) => cs.channel?.deletedAt);
+ return state!.channelStateStream.map((cs) => cs.channel?.deletedAt);
}
- /// Channel member count
+ /// Channel member count.
int? get memberCount {
_checkInitialized();
-
- return state?._channelState.channel?.memberCount;
+ return state!._channelState.channel?.memberCount;
}
- /// Channel member count as a stream
- Stream? get memberCountStream {
+ /// Channel member count as a stream.
+ Stream get memberCountStream {
_checkInitialized();
-
- return state?.channelStateStream.map((cs) => cs.channel?.memberCount);
+ return state!.channelStateStream.map((cs) => cs.channel?.memberCount);
}
- /// Channel id
+ /// Channel id.
String? get id => state?._channelState.channel?.id ?? _id;
- /// Channel type
+ /// Channel type.
String get type => state?._channelState.channel?.type ?? _type;
- /// Channel cid
+ /// Channel cid.
String? get cid => state?._channelState.channel?.cid ?? _cid;
- /// Channel team
+ /// Channel team.
String? get team {
_checkInitialized();
- return state?._channelState.channel?.team;
+ return state!._channelState.channel?.team;
}
- /// Channel extra data
+ /// Channel extra data.
Map get extraData {
var data = state?._channelState.channel?.extraData;
if (data == null || data.isEmpty) {
@@ -210,23 +300,54 @@ class Channel {
return data;
}
- /// Channel extra data as a stream
- Stream