Merge remote-tracking branch 'origin/develop' into vale-linting

# Conflicts:
#	docusaurus/docs/Flutter/05-guides/05-push-notifications/adding_push_notifications_v2.mdx
#	packages/stream_chat_flutter/CHANGELOG.md
This commit is contained in:
xsahil03x
2023-04-07 02:01:22 +05:30
141 changed files with 1746 additions and 1233 deletions
+32
View File
@@ -1,3 +1,35 @@
## Upcoming
🐞 Fixed
- Fixed streamWatchers. Before it was always new, now it is possible to follow the watchers of a channel.
- Make `Message.i18n` field read-only.
🔄 Changed
- Cancelling a attachment upload now removes the attachment from the message.
- Updated `dio` and other dependencies to resolvable versions.
✅ Added
- Added `presence` property to `Channel::watch` method.
## 5.3.0
🔄 Changed
- Updated `rate_limiter` dependency to `^1.0.0`
## 5.2.0
✅ Added
- Added `Huawei` and `Xiaomi` PushProviders.
🐞 Fixed
- Fixed initializing last synced date.
## 5.1.0
✅ Added
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 29
compileSdkVersion 33
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@@ -40,7 +40,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.example"
minSdkVersion 16
targetSdkVersion 29
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
@@ -6,15 +6,16 @@
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="example"
android:icon="@mipmap/ic_launcher">
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
android:label="example">
<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
@@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.3.50'
ext.kotlin_version = '1.7.21'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.0'
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip
@@ -6,6 +6,7 @@ version: 1.0.0+1
environment:
sdk: '>=2.17.0 <3.0.0'
flutter: ">=1.17.0"
dependencies:
cupertino_icons: ^1.0.0
@@ -463,12 +463,19 @@ class Channel {
client.logger.info('Found ${attachments.length} attachments');
void updateAttachment(Attachment attachment) {
void updateAttachment(Attachment attachment, {bool remove = false}) {
final index = message!.attachments.indexWhere(
(it) => it.id == attachment.id,
);
if (index != -1) {
final newAttachments = [...message!.attachments]..[index] = attachment;
// update or remove attachment from message.
final List<Attachment> newAttachments;
if (remove) {
newAttachments = [...message!.attachments]..removeAt(index);
} else {
newAttachments = [...message!.attachments]..[index] = attachment;
}
final updatedMessage = message!.copyWith(attachments: newAttachments);
state?.updateMessage(updatedMessage);
// updating original message for next iteration
@@ -533,6 +540,14 @@ class Channel {
);
}
}).catchError((e, stk) {
if (e is StreamChatNetworkError && e.isRequestCancelledError) {
client.logger.info('Attachment ${it.id} upload cancelled');
// remove attachment from message if cancelled.
updateAttachment(it, remove: true);
return;
}
client.logger.severe('error uploading the attachment', e, stk);
updateAttachment(
it.copyWith(uploadState: UploadState.failed(error: e.toString())),
@@ -1219,11 +1234,11 @@ class Channel {
}
/// Loads the initial channel state and watches for changes.
Future<ChannelState> watch() async {
Future<ChannelState> watch({bool presence = false}) async {
ChannelState response;
try {
response = await query(watch: true);
response = await query(watch: true, presence: presence);
} catch (error, stackTrace) {
if (!_initializedCompleter.isCompleted) {
_initializedCompleter.completeError(error, stackTrace);
@@ -1613,6 +1628,10 @@ class ChannelClientState {
_listenMemberUnbanned();
_listenUserStartWatching();
_listenUserStopWatching();
_startCleaningStaleTypingEvents();
_startCleaningStalePinnedMessages();
@@ -1754,6 +1773,39 @@ class ChannelClientState {
));
}
void _listenUserStartWatching() {
_subscriptions.add(
_channel.on(EventType.userWatchingStart).listen((event) {
final watcher = event.user;
if (watcher != null) {
final existingWatchers = channelState.watchers;
updateChannelState(channelState.copyWith(
watchers: [
...?existingWatchers,
watcher,
],
));
}
}),
);
}
void _listenUserStopWatching() {
_subscriptions.add(
_channel.on(EventType.userWatchingStop).listen((event) {
final watcher = event.user;
if (watcher != null) {
final existingWatchers = channelState.watchers;
updateChannelState(channelState.copyWith(
watchers: existingWatchers
?.where((user) => user.id != watcher.id)
.toList(growable: false),
));
}
}),
);
}
void _listenMemberUnbanned() {
_subscriptions.add(_channel
.on(EventType.userUnbanned)
@@ -2083,7 +2135,7 @@ class ChannelClientState {
channelStateStream.map((cs) => cs.watchers),
_channel.client.state.usersStream,
(watchers, users) => watchers!.map((e) => users[e.id] ?? e).toList(),
);
).distinct(const ListEquality().equals);
/// Channel member for the current user.
Member? get currentUserMember => members.firstWhereOrNull(
@@ -453,6 +453,15 @@ class StreamChatClient {
if (persistenceEnabled) {
await sync(cids: cids, lastSyncAt: _lastSyncedAt);
}
} else {
// channels are empty, assuming it's a fresh start
// and making sure `lastSyncAt` is initialized
if (persistenceEnabled) {
final lastSyncAt = await _chatPersistenceClient?.getLastSyncAt();
if (lastSyncAt == null) {
await _chatPersistenceClient?.updateLastSyncAt(DateTime.now());
}
}
}
handleEvent(Event(
type: EventType.connectionRecovered,
@@ -6,6 +6,12 @@ enum PushProvider {
/// Send notifications using Google's Firebase Cloud Messaging
firebase,
/// Send notifications using Huawei's Push Kit
huawei,
/// Send notifications using Xiaomi's Mi Push Service
xiaomi,
/// Send notifications using Apple's Push Notification service
apn,
}
@@ -40,7 +40,7 @@ class SortOption<T> {
final int direction;
/// Sorting field Comparator required for offline sorting
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
final Comparator<T>? comparator;
/// Serialize model to json
@@ -74,6 +74,7 @@ class StreamChatNetworkError extends StreamChatError {
ChatErrorCode errorCode, {
int? statusCode,
this.data,
this.isRequestCancelledError = false,
}) : code = errorCode.code,
statusCode = statusCode ?? data?.statusCode,
super(errorCode.message);
@@ -84,6 +85,7 @@ class StreamChatNetworkError extends StreamChatError {
required String message,
this.statusCode,
this.data,
this.isRequestCancelledError = false,
}) : super(message);
///
@@ -96,10 +98,13 @@ class StreamChatNetworkError extends StreamChatError {
}
return StreamChatNetworkError.raw(
code: errorResponse?.code ?? -1,
message:
errorResponse?.message ?? response?.statusMessage ?? error.message,
message: errorResponse?.message ??
response?.statusMessage ??
error.message ??
'',
statusCode: errorResponse?.statusCode ?? response?.statusCode,
data: errorResponse,
isRequestCancelledError: error.type == DioErrorType.cancel,
)..stackTrace = error.stackTrace;
}
@@ -112,6 +117,9 @@ class StreamChatNetworkError extends StreamChatError {
/// Response body. please refer to [ErrorResponse].
final ErrorResponse? data;
/// True, in case the error is due to a cancelled network request.
final bool isRequestCancelledError;
StackTrace? _stackTrace;
///
@@ -87,8 +87,8 @@ class LoggingInterceptor extends Interceptor {
requestHeaders['contentType'] = options.contentType?.toString();
requestHeaders['responseType'] = options.responseType.toString();
requestHeaders['followRedirects'] = options.followRedirects;
requestHeaders['connectTimeout'] = options.connectTimeout;
requestHeaders['receiveTimeout'] = options.receiveTimeout;
requestHeaders['connectTimeout'] = options.connectTimeout?.toString();
requestHeaders['receiveTimeout'] = options.receiveTimeout?.toString();
_printMapAsTable(_logPrintRequest, requestHeaders, header: 'Headers');
_printMapAsTable(_logPrintRequest, options.extra, header: 'Extras');
}
@@ -101,7 +101,8 @@ class LoggingInterceptor extends Interceptor {
options.data as Map?,
header: 'Body',
);
} else if (data is FormData) {
}
if (data is FormData) {
final formDataMap = <String, dynamic>{}
..addEntries(data.fields)
..addEntries(data.files);
@@ -121,7 +122,7 @@ class LoggingInterceptor extends Interceptor {
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
if (error) {
if (err.type == DioErrorType.response) {
if (err.type == DioErrorType.badResponse) {
final uri = err.response?.requestOptions.uri;
_printBoxed(
_logPrintError,
@@ -162,7 +163,7 @@ class LoggingInterceptor extends Interceptor {
_logPrintResponse('');
_printResponse(_logPrintResponse, response);
_logPrintResponse('');
_printLine(_logPrintResponse, '');
_logPrintResponse('');
}
super.onResponse(response, handler);
}
@@ -29,8 +29,8 @@ class StreamHttpClient {
httpClient = dio ?? Dio() {
httpClient
..options.baseUrl = _options.baseUrl
..options.receiveTimeout = _options.receiveTimeout.inMilliseconds
..options.connectTimeout = _options.connectTimeout.inMilliseconds
..options.receiveTimeout = _options.receiveTimeout
..options.connectTimeout = _options.connectTimeout
..options.queryParameters = {
'api_key': apiKey,
..._options.queryParameters,
@@ -135,7 +135,6 @@ class Attachment extends Equatable {
late final UploadState uploadState;
/// Map of custom channel extraData
@JsonKey(includeIfNull: false)
final Map<String, Object?> extraData;
/// The attachment ID.
@@ -146,13 +145,13 @@ class Attachment extends Equatable {
/// Shortcut for file size.
///
/// {@macro fileSize}
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
int? get fileSize => extraData['file_size'] as int?;
/// Shortcut for file mimeType.
///
/// {@macro mimeType}
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
String? get mimeType => extraData['mime_type'] as String?;
/// Known top level fields.
@@ -52,7 +52,7 @@ class AttachmentFile {
/// Byte data for this file. Particularly useful if you want to manipulate
/// its data or easily upload to somewhere else.
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
final Uint8List? bytes;
/// The file size in bytes.
@@ -1,7 +1,7 @@
// coverage:ignore-file
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'attachment_file.dart';
@@ -43,10 +43,10 @@ mixin _$UploadState {
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
TResult? Function()? preparing,
TResult? Function(int uploaded, int total)? inProgress,
TResult? Function()? success,
TResult? Function(String error)? failed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
@@ -68,10 +68,10 @@ mixin _$UploadState {
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
TResult? Function(Preparing value)? preparing,
TResult? Function(InProgress value)? inProgress,
TResult? Function(Success value)? success,
TResult? Function(Failed value)? failed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
@@ -90,16 +90,18 @@ mixin _$UploadState {
abstract class $UploadStateCopyWith<$Res> {
factory $UploadStateCopyWith(
UploadState value, $Res Function(UploadState) then) =
_$UploadStateCopyWithImpl<$Res>;
_$UploadStateCopyWithImpl<$Res, UploadState>;
}
/// @nodoc
class _$UploadStateCopyWithImpl<$Res> implements $UploadStateCopyWith<$Res> {
class _$UploadStateCopyWithImpl<$Res, $Val extends UploadState>
implements $UploadStateCopyWith<$Res> {
_$UploadStateCopyWithImpl(this._value, this._then);
final UploadState _value;
// ignore: unused_field
final $Res Function(UploadState) _then;
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
}
/// @nodoc
@@ -110,14 +112,12 @@ abstract class _$$PreparingCopyWith<$Res> {
}
/// @nodoc
class __$$PreparingCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
class __$$PreparingCopyWithImpl<$Res>
extends _$UploadStateCopyWithImpl<$Res, _$Preparing>
implements _$$PreparingCopyWith<$Res> {
__$$PreparingCopyWithImpl(
_$Preparing _value, $Res Function(_$Preparing) _then)
: super(_value, (v) => _then(v as _$Preparing));
@override
_$Preparing get _value => super._value as _$Preparing;
: super(_value, _then);
}
/// @nodoc
@@ -162,10 +162,10 @@ class _$Preparing extends Preparing {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
TResult? Function()? preparing,
TResult? Function(int uploaded, int total)? inProgress,
TResult? Function()? success,
TResult? Function(String error)? failed,
}) {
return preparing?.call();
}
@@ -199,10 +199,10 @@ class _$Preparing extends Preparing {
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
TResult? Function(Preparing value)? preparing,
TResult? Function(InProgress value)? inProgress,
TResult? Function(Success value)? success,
TResult? Function(Failed value)? failed,
}) {
return preparing?.call(this);
}
@@ -242,30 +242,30 @@ abstract class _$$InProgressCopyWith<$Res> {
factory _$$InProgressCopyWith(
_$InProgress value, $Res Function(_$InProgress) then) =
__$$InProgressCopyWithImpl<$Res>;
@useResult
$Res call({int uploaded, int total});
}
/// @nodoc
class __$$InProgressCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
class __$$InProgressCopyWithImpl<$Res>
extends _$UploadStateCopyWithImpl<$Res, _$InProgress>
implements _$$InProgressCopyWith<$Res> {
__$$InProgressCopyWithImpl(
_$InProgress _value, $Res Function(_$InProgress) _then)
: super(_value, (v) => _then(v as _$InProgress));
@override
_$InProgress get _value => super._value as _$InProgress;
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? uploaded = freezed,
Object? total = freezed,
Object? uploaded = null,
Object? total = null,
}) {
return _then(_$InProgress(
uploaded: uploaded == freezed
uploaded: null == uploaded
? _value.uploaded
: uploaded // ignore: cast_nullable_to_non_nullable
as int,
total: total == freezed
total: null == total
? _value.total
: total // ignore: cast_nullable_to_non_nullable
as int,
@@ -302,19 +302,18 @@ class _$InProgress extends InProgress {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$InProgress &&
const DeepCollectionEquality().equals(other.uploaded, uploaded) &&
const DeepCollectionEquality().equals(other.total, total));
(identical(other.uploaded, uploaded) ||
other.uploaded == uploaded) &&
(identical(other.total, total) || other.total == total));
}
@JsonKey(ignore: true)
@override
int get hashCode => Object.hash(
runtimeType,
const DeepCollectionEquality().hash(uploaded),
const DeepCollectionEquality().hash(total));
int get hashCode => Object.hash(runtimeType, uploaded, total);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$InProgressCopyWith<_$InProgress> get copyWith =>
__$$InProgressCopyWithImpl<_$InProgress>(this, _$identity);
@@ -332,10 +331,10 @@ class _$InProgress extends InProgress {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
TResult? Function()? preparing,
TResult? Function(int uploaded, int total)? inProgress,
TResult? Function()? success,
TResult? Function(String error)? failed,
}) {
return inProgress?.call(uploaded, total);
}
@@ -369,10 +368,10 @@ class _$InProgress extends InProgress {
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
TResult? Function(Preparing value)? preparing,
TResult? Function(InProgress value)? inProgress,
TResult? Function(Success value)? success,
TResult? Function(Failed value)? failed,
}) {
return inProgress?.call(this);
}
@@ -422,13 +421,11 @@ abstract class _$$SuccessCopyWith<$Res> {
}
/// @nodoc
class __$$SuccessCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
class __$$SuccessCopyWithImpl<$Res>
extends _$UploadStateCopyWithImpl<$Res, _$Success>
implements _$$SuccessCopyWith<$Res> {
__$$SuccessCopyWithImpl(_$Success _value, $Res Function(_$Success) _then)
: super(_value, (v) => _then(v as _$Success));
@override
_$Success get _value => super._value as _$Success;
: super(_value, _then);
}
/// @nodoc
@@ -473,10 +470,10 @@ class _$Success extends Success {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
TResult? Function()? preparing,
TResult? Function(int uploaded, int total)? inProgress,
TResult? Function()? success,
TResult? Function(String error)? failed,
}) {
return success?.call();
}
@@ -510,10 +507,10 @@ class _$Success extends Success {
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
TResult? Function(Preparing value)? preparing,
TResult? Function(InProgress value)? inProgress,
TResult? Function(Success value)? success,
TResult? Function(Failed value)? failed,
}) {
return success?.call(this);
}
@@ -552,24 +549,24 @@ abstract class Success extends UploadState {
abstract class _$$FailedCopyWith<$Res> {
factory _$$FailedCopyWith(_$Failed value, $Res Function(_$Failed) then) =
__$$FailedCopyWithImpl<$Res>;
@useResult
$Res call({String error});
}
/// @nodoc
class __$$FailedCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
class __$$FailedCopyWithImpl<$Res>
extends _$UploadStateCopyWithImpl<$Res, _$Failed>
implements _$$FailedCopyWith<$Res> {
__$$FailedCopyWithImpl(_$Failed _value, $Res Function(_$Failed) _then)
: super(_value, (v) => _then(v as _$Failed));
@override
_$Failed get _value => super._value as _$Failed;
: super(_value, _then);
@pragma('vm:prefer-inline')
@override
$Res call({
Object? error = freezed,
Object? error = null,
}) {
return _then(_$Failed(
error: error == freezed
error: null == error
? _value.error
: error // ignore: cast_nullable_to_non_nullable
as String,
@@ -603,16 +600,16 @@ class _$Failed extends Failed {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$Failed &&
const DeepCollectionEquality().equals(other.error, error));
(identical(other.error, error) || other.error == error));
}
@JsonKey(ignore: true)
@override
int get hashCode =>
Object.hash(runtimeType, const DeepCollectionEquality().hash(error));
int get hashCode => Object.hash(runtimeType, error);
@JsonKey(ignore: true)
@override
@pragma('vm:prefer-inline')
_$$FailedCopyWith<_$Failed> get copyWith =>
__$$FailedCopyWithImpl<_$Failed>(this, _$identity);
@@ -630,10 +627,10 @@ class _$Failed extends Failed {
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
TResult? Function()? preparing,
TResult? Function(int uploaded, int total)? inProgress,
TResult? Function()? success,
TResult? Function(String error)? failed,
}) {
return failed?.call(error);
}
@@ -667,10 +664,10 @@ class _$Failed extends Failed {
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
TResult? Function(Preparing value)? preparing,
TResult? Function(InProgress value)? inProgress,
TResult? Function(Success value)? success,
TResult? Function(Failed value)? failed,
}) {
return failed?.call(this);
}
@@ -62,19 +62,19 @@ class ChannelModel {
final String type;
/// The cid of this channel
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final String cid;
/// List of user permissions on this channel
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final List<String>? ownCapabilities;
/// The channel configuration data
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final ChannelConfig config;
/// The user that created this channel
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final User? createdBy;
/// True if this channel is frozen
@@ -82,23 +82,23 @@ class ChannelModel {
final bool frozen;
/// The date of the last message
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime? lastMessageAt;
/// The date of channel creation
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime createdAt;
/// The date of the last channel update
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime updatedAt;
/// The date of channel deletion
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime? deletedAt;
/// The count of this channel members
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final int memberCount;
/// The number of seconds in a cooldown
@@ -106,15 +106,15 @@ class ChannelModel {
final int cooldown;
/// True if the channel is disabled
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
bool? get disabled => extraData['disabled'] as bool?;
/// True if the channel is hidden
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
bool? get hidden => extraData['hidden'] as bool?;
/// The date of the last time channel got truncated
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
DateTime? get truncatedAt {
final truncatedAt = extraData['truncated_at'] as String?;
if (truncatedAt == null) return null;
@@ -122,11 +122,10 @@ class ChannelModel {
}
/// Map of custom channel extraData
@JsonKey(includeIfNull: false)
final Map<String, Object?> extraData;
/// The team the channel belongs to
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final String? team;
/// Known top level fields.
@@ -38,30 +38,11 @@ ChannelModel _$ChannelModelFromJson(Map<String, dynamic> json) => ChannelModel(
cooldown: json['cooldown'] as int? ?? 0,
);
Map<String, dynamic> _$ChannelModelToJson(ChannelModel instance) {
final val = <String, dynamic>{
'id': instance.id,
'type': instance.type,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('cid', readonly(instance.cid));
writeNotNull('own_capabilities', readonly(instance.ownCapabilities));
writeNotNull('config', readonly(instance.config));
writeNotNull('created_by', readonly(instance.createdBy));
val['frozen'] = instance.frozen;
writeNotNull('last_message_at', readonly(instance.lastMessageAt));
writeNotNull('created_at', readonly(instance.createdAt));
writeNotNull('updated_at', readonly(instance.updatedAt));
writeNotNull('deleted_at', readonly(instance.deletedAt));
writeNotNull('member_count', readonly(instance.memberCount));
val['cooldown'] = instance.cooldown;
val['extra_data'] = instance.extraData;
writeNotNull('team', readonly(instance.team));
return val;
}
Map<String, dynamic> _$ChannelModelToJson(ChannelModel instance) =>
<String, dynamic>{
'id': instance.id,
'type': instance.type,
'frozen': instance.frozen,
'cooldown': instance.cooldown,
'extra_data': instance.extraData,
};
@@ -95,14 +95,11 @@ class Message extends Equatable {
final String? text;
/// The status of a sending message.
@JsonKey(ignore: true)
@JsonKey(includeFromJson: false, includeToJson: false)
final MessageSendingStatus status;
/// The message type.
@JsonKey(
includeIfNull: false,
toJson: Serializer.readOnly,
)
@JsonKey(includeToJson: false)
final String type;
/// The list of attachments, either provided by the user or generated from a
@@ -115,26 +112,26 @@ class Message extends Equatable {
final List<User> mentionedUsers;
/// A map describing the count of number of every reaction.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final Map<String, int>? reactionCounts;
/// A map describing the count of score of every reaction.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final Map<String, int>? reactionScores;
/// The latest reactions to the message created by any user.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final List<Reaction>? latestReactions;
/// The reactions added to the message by the current user.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final List<Reaction>? ownReactions;
/// The ID of the parent message, if the message is a thread reply.
final String? parentId;
/// A quoted reply message.
@JsonKey(toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final Message? quotedMessage;
final String? _quotedMessageId;
@@ -143,11 +140,11 @@ class Message extends Equatable {
String? get quotedMessageId => _quotedMessageId ?? quotedMessage?.id;
/// Reserved field indicating the number of replies for this message.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final int? replyCount;
/// Reserved field indicating the thread participants for this message.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final List<User>? threadParticipants;
/// Check if this message needs to show in the channel.
@@ -157,41 +154,38 @@ class Message extends Equatable {
final bool silent;
/// If true the message is shadowed.
@JsonKey(
includeIfNull: false,
toJson: Serializer.readOnly,
)
@JsonKey(includeToJson: false)
final bool shadowed;
/// A used command name.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final String? command;
final DateTime? _createdAt;
/// Reserved field indicating when the message was deleted.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime? deletedAt;
/// Reserved field indicating when the message was created.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
DateTime get createdAt => _createdAt ?? DateTime.now();
final DateTime? _updatedAt;
/// Reserved field indicating when the message was updated last time.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
DateTime get updatedAt => _updatedAt ?? DateTime.now();
/// User who sent the message.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final User? user;
/// If true the message is pinned.
final bool pinned;
/// Reserved field indicating when the message was pinned.
@JsonKey(toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime? pinnedAt;
/// Reserved field indicating when the message will expire.
@@ -200,11 +194,10 @@ class Message extends Equatable {
final DateTime? pinExpires;
/// Reserved field indicating who pinned the message.
@JsonKey(toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final User? pinnedBy;
/// Message custom extraData.
@JsonKey(includeIfNull: false)
final Map<String, Object?> extraData;
/// True if the message is a system info.
@@ -217,7 +210,7 @@ class Message extends Equatable {
bool get isEphemeral => type == 'ephemeral';
/// A Map of translations.
@JsonKey(includeIfNull: false)
@JsonKey(includeToJson: false)
final Map<String, String>? i18n;
/// Known top level fields.
@@ -71,43 +71,16 @@ Message _$MessageFromJson(Map<String, dynamic> json) => Message(
),
);
Map<String, dynamic> _$MessageToJson(Message instance) {
final val = <String, dynamic>{
'id': instance.id,
'text': instance.text,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('type', readonly(instance.type));
val['attachments'] = instance.attachments.map((e) => e.toJson()).toList();
val['mentioned_users'] = User.toIds(instance.mentionedUsers);
writeNotNull('reaction_counts', readonly(instance.reactionCounts));
writeNotNull('reaction_scores', readonly(instance.reactionScores));
writeNotNull('latest_reactions', readonly(instance.latestReactions));
writeNotNull('own_reactions', readonly(instance.ownReactions));
val['parent_id'] = instance.parentId;
val['quoted_message'] = readonly(instance.quotedMessage);
val['quoted_message_id'] = instance.quotedMessageId;
writeNotNull('reply_count', readonly(instance.replyCount));
writeNotNull('thread_participants', readonly(instance.threadParticipants));
val['show_in_channel'] = instance.showInChannel;
val['silent'] = instance.silent;
writeNotNull('shadowed', readonly(instance.shadowed));
writeNotNull('command', readonly(instance.command));
writeNotNull('deleted_at', readonly(instance.deletedAt));
writeNotNull('created_at', readonly(instance.createdAt));
writeNotNull('updated_at', readonly(instance.updatedAt));
writeNotNull('user', readonly(instance.user));
val['pinned'] = instance.pinned;
val['pinned_at'] = readonly(instance.pinnedAt);
val['pin_expires'] = instance.pinExpires?.toIso8601String();
val['pinned_by'] = readonly(instance.pinnedBy);
val['extra_data'] = instance.extraData;
writeNotNull('i18n', instance.i18n);
return val;
}
Map<String, dynamic> _$MessageToJson(Message instance) => <String, dynamic>{
'id': instance.id,
'text': instance.text,
'attachments': instance.attachments.map((e) => e.toJson()).toList(),
'mentioned_users': User.toIds(instance.mentionedUsers),
'parent_id': instance.parentId,
'quoted_message_id': instance.quotedMessageId,
'show_in_channel': instance.showInChannel,
'silent': instance.silent,
'pinned': instance.pinned,
'pin_expires': instance.pinExpires?.toIso8601String(),
'extra_data': instance.extraData,
};
@@ -33,22 +33,21 @@ class Reaction {
final String type;
/// The date of the reaction
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime createdAt;
/// The user that sent the reaction
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final User? user;
/// The score of the reaction (ie. number of reactions sent)
final int score;
/// The userId that sent the reaction
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final String? userId;
/// Reaction custom extraData
@JsonKey(includeIfNull: false)
final Map<String, Object?> extraData;
/// Map of custom user extraData
@@ -20,22 +20,9 @@ Reaction _$ReactionFromJson(Map<String, dynamic> json) => Reaction(
extraData: json['extra_data'] as Map<String, dynamic>? ?? const {},
);
Map<String, dynamic> _$ReactionToJson(Reaction instance) {
final val = <String, dynamic>{
'message_id': instance.messageId,
'type': instance.type,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('created_at', readonly(instance.createdAt));
writeNotNull('user', readonly(instance.user));
val['score'] = instance.score;
writeNotNull('user_id', readonly(instance.userId));
val['extra_data'] = instance.extraData;
return val;
}
Map<String, dynamic> _$ReactionToJson(Reaction instance) => <String, dynamic>{
'message_id': instance.messageId,
'type': instance.type,
'score': instance.score,
'extra_data': instance.extraData,
};
@@ -79,7 +79,7 @@ class User extends Equatable {
/// Shortcut for user name.
///
/// {@macro name}
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
String get name {
if (extraData.containsKey('name') && extraData['name'] != null) {
final name = extraData['name']! as String;
@@ -91,48 +91,39 @@ class User extends Equatable {
/// Shortcut for user image.
///
/// {@macro image}
@JsonKey(ignore: true)
@JsonKey(includeToJson: false, includeFromJson: false)
String? get image => extraData['image'] as String?;
/// User role.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final String? role;
/// User teams
@JsonKey(
includeIfNull: false,
toJson: Serializer.readOnly,
)
@JsonKey(includeToJson: false)
final List<String> teams;
/// Date of user creation.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime createdAt;
/// Date of last user update.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime updatedAt;
/// Date of last user connection.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime? lastActive;
/// True if user is online.
@JsonKey(
includeIfNull: false,
toJson: Serializer.readOnly,
)
@JsonKey(includeToJson: false)
final bool online;
/// True if user is banned from the chat.
@JsonKey(
includeIfNull: false,
toJson: Serializer.readOnly,
)
@JsonKey(includeToJson: false)
final bool banned;
/// The date at which the ban will expire.
@JsonKey(includeIfNull: false, toJson: Serializer.readOnly)
@JsonKey(includeToJson: false)
final DateTime? banExpires;
/// The language this user prefers.
@@ -140,7 +131,6 @@ class User extends Equatable {
final String? language;
/// Map of custom user extraData.
@JsonKey(includeIfNull: false)
final Map<String, Object?> extraData;
/// List of users to list of userIds.
@@ -41,14 +41,6 @@ Map<String, dynamic> _$UserToJson(User instance) {
}
}
writeNotNull('role', readonly(instance.role));
writeNotNull('teams', readonly(instance.teams));
writeNotNull('created_at', readonly(instance.createdAt));
writeNotNull('updated_at', readonly(instance.updatedAt));
writeNotNull('last_active', readonly(instance.lastActive));
writeNotNull('online', readonly(instance.online));
writeNotNull('banned', readonly(instance.banned));
writeNotNull('ban_expires', readonly(instance.banExpires));
writeNotNull('language', instance.language);
val['extra_data'] = instance.extraData;
return val;
@@ -1,12 +1,5 @@
/// Used to avoid to serialize properties to json
// ignore: prefer_void_to_null
Null readonly(_) => null;
/// Helper class for serialization to and from json
class Serializer {
/// Used to avoid to serialize properties to json
static const Function readOnly = readonly;
/// Takes unknown json keys and puts them in the `extra_data` key
static Map<String, dynamic> moveToExtraDataFromRoot(
Map<String, dynamic> json,
@@ -36,6 +36,12 @@ class EventType {
/// Event sent when updating a message
static const String messageUpdated = 'message.updated';
/// Event sent when a user starts watching a channel
static const String userWatchingStart = 'user.watching.start';
/// Event sent when a user stops watching a channel
static const String userWatchingStop = 'user.watching.stop';
/// Event sent when reading a message
static const String messageRead = 'message.read';
+3 -30
View File
@@ -10,41 +10,13 @@ export 'package:logging/logging.dart' show Logger, Level, LogRecord;
export 'package:rate_limiter/rate_limiter.dart';
export 'package:uuid/uuid.dart';
export './src/core/api/attachment_file_uploader.dart';
export './src/core/api/requests.dart';
export './src/core/api/requests.dart';
export './src/core/api/responses.dart';
export './src/core/api/stream_chat_api.dart' show PushProvider;
export './src/core/error/error.dart';
export './src/core/models/action.dart';
export './src/core/models/attachment.dart';
export './src/core/models/attachment_file.dart';
export './src/core/models/channel_config.dart';
export './src/core/models/channel_model.dart';
export './src/core/models/channel_state.dart';
export './src/core/models/command.dart';
export './src/core/models/device.dart';
export './src/core/models/event.dart';
export './src/core/models/filter.dart' show Filter;
export './src/core/models/member.dart';
export './src/core/models/message.dart';
export './src/core/models/mute.dart';
export './src/core/models/own_user.dart';
export './src/core/models/reaction.dart';
export './src/core/models/read.dart';
export './src/core/models/user.dart';
export './src/core/util/extension.dart';
export './src/db/chat_persistence_client.dart';
export './src/event_type.dart';
export './src/permission_type.dart';
export './src/ws/connection_status.dart';
export 'src/client/channel.dart';
export 'src/client/client.dart';
export 'src/client/key_stroke_handler.dart';
export 'src/core/api/attachment_file_uploader.dart' show AttachmentFileUploader;
export 'src/core/api/requests.dart';
export 'src/core/api/attachment_file_uploader.dart';
export 'src/core/api/requests.dart';
export 'src/core/api/responses.dart';
export 'src/core/api/stream_chat_api.dart' show PushProvider;
export 'src/core/api/stream_chat_api.dart';
export 'src/core/error/error.dart';
export 'src/core/models/action.dart';
@@ -68,4 +40,5 @@ export 'src/core/platform_detector/platform_detector.dart';
export 'src/core/util/extension.dart';
export 'src/db/chat_persistence_client.dart';
export 'src/event_type.dart';
export 'src/permission_type.dart';
export 'src/ws/connection_status.dart';
+1 -1
View File
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
/// Current package version
/// Used in [StreamChatClient] to build the `x-stream-client` header
// ignore: constant_identifier_names
const PACKAGE_VERSION = '5.1.0';
const PACKAGE_VERSION = '5.3.0';
+21 -21
View File
@@ -1,7 +1,7 @@
name: stream_chat
homepage: https://getstream.io/
description: The official Dart client for Stream Chat, a service for building chat applications.
version: 5.1.0
version: 5.3.0
repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -9,26 +9,26 @@ environment:
sdk: '>=2.17.0 <3.0.0'
dependencies:
async: ^2.5.0
collection: ^1.15.0
dio: ^4.0.0
equatable: ^2.0.0
freezed_annotation: ^2.0.3
http_parser: ^4.0.0
jose: ^0.3.2
json_annotation: ^4.5.0
logging: ^1.0.1
meta: ^1.3.0
mime: ^1.0.0
rate_limiter: ^0.1.1
rxdart: ^0.27.0
uuid: ^3.0.4
web_socket_channel: ^2.0.0
async: ^2.10.0
collection: ^1.17.0
dio: ^5.1.1
equatable: ^2.0.5
freezed_annotation: ^2.2.0
http_parser: ^4.0.2
jose: ^0.3.3
json_annotation: ^4.8.0
logging: ^1.1.1
meta: ^1.8.0
mime: ^1.0.4
rate_limiter: ^1.0.0
rxdart: ^0.27.7
uuid: ^3.0.7
web_socket_channel: ^2.3.0
dev_dependencies:
build_runner: ^2.0.1
dart_code_metrics: ^4.4.0
freezed: ^2.0.3
json_serializable: ^6.2.0
build_runner: ^2.3.3
dart_code_metrics: ^5.7.0
freezed: ^2.3.2
json_serializable: ^6.6.1
mocktail: ^0.3.0
test: ^1.17.12
test: ^1.24.1
+25 -101
View File
@@ -1,4 +1,3 @@
{
"channel": {
"id": "dev",
@@ -18,400 +17,325 @@
"text": "fasdfa",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-e8e74482-b4cd-48db-9d1e-30e6c191786f",
"text": "test message",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-53e6299f-9b97-4a9c-a27e-7e2dde49b7e0",
"text": "test message",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-80925be0-786e-40a5-b225-486518dafd35",
"text": "asdfadf",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-64d7970f-ede8-4b31-9738-1bc1756d2bfe",
"text": "test",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "withered-cell-0-84cbd760-cf55-4f7e-9207-c5f66cccc6dc",
"text": "hi",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-e9203588-43c3-40b1-91f7-f217fc42aa53",
"text": "fantastic",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "withered-cell-0-7e3552d7-7a0d-45f2-a856-e91b23a7e240",
"text": "nice to meet you",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-1ffeafd4-e4fc-4c84-9394-9d7cb10fff42",
"text": "hey",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-3f147324-12c8-4b41-9fb5-2db88d065efa",
"text": "hello, everyone",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "dry-meadow-0-51a348ae-0c0a-44de-a556-eac7891c0cf0",
"text": "who is there?",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "icy-recipe-7-a29e237b-8d81-4a97-9bc8-d42bca3f1356",
"text": "하이",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "icy-recipe-7-935c396e-ddf8-4a9a-951c-0a12fa5bf055",
"text": "what are you doing?",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "throbbing-boat-5-1e4d5730-5ff0-4d25-9948-9f34ffda43e4",
"text": "👍",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "snowy-credit-3-3e0c1a0d-d22f-42ee-b2a1-f9f49477bf21",
"text": "sdasas",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "snowy-credit-3-3319537e-2d0e-4876-8170-a54f046e4b7d",
"text": "cjshsa",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "snowy-credit-3-cfaf0b46-1daa-49c5-947c-b16d6697487d",
"text": "nhisagdhsadz",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "snowy-credit-3-cebe25a7-a3a3-49fc-9919-91c6725e81f3",
"text": "hvadhsahzd",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "divine-glade-9-0cea9262-5766-48e9-8b22-311870aed3bf",
"text": "hello",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "red-firefly-9-c4e9007b-bb7d-4238-ae08-5f8e3cd03d73",
"text": "hello",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "bitter-glade-2-02aee4eb-4093-4736-808b-2de75820e854",
"text": "hello",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "morning-sea-1-0c700bcb-46dd-4224-b590-e77bdbccc480",
"text": "http://jaeger.ui.gtstrm.com/",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "ancient-salad-0-53e8b4e6-5b7b-43ad-aeee-8bfb6a9ed0be",
"text": "hi",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "ancient-salad-0-8c225075-bd4c-42e2-8024-530aae13cd40",
"text": "hi",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
},
{
"id": "proud-sea-7-17802096-cbf8-4e3c-addd-4ee31f4c8b5c",
"text": "😃",
"attachments": [],
"parent_id": null,
"quoted_message": null,
"quoted_message_id": null,
"show_in_channel": null,
"mentioned_users": [],
"status": "SENT",
"silent": false,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null
"pin_expires": null
}
],
"pinned_messages": [],
@@ -18,12 +18,9 @@
],
"mentioned_users": [],
"parent_id": "parentId",
"quoted_message": null,
"quoted_message_id": null,
"pinned": false,
"pinned_at": null,
"pin_expires": null,
"pinned_by": null,
"show_in_channel": true,
"hey": "test"
}
@@ -516,6 +516,9 @@ void main() {
});
setUp(() async {
when(() => persistence.updateLastSyncAt(any()))
.thenAnswer((_) => Future.value());
when(persistence.getLastSyncAt).thenAnswer((_) async => null);
client = StreamChatClient(apiKey, chatApi: api, ws: ws)
..chatPersistenceClient = persistence;
await client.connectUser(user, token);
@@ -532,9 +535,12 @@ void main() {
test(
'''should update persistence connectionInfo and lastSync when sync succeeds''',
() async {
// persistence.updateLastSyncAt might be called
// when connecting the user.
// Resetting the logs so we start counting invocations correctly.
reset(persistence);
const cids = ['test-cid-1', 'test-cid-2', 'test-cid-3'];
final lastSyncAt = DateTime.now();
when(() => api.general.sync(cids, lastSyncAt))
.thenAnswer((_) async => SyncResponse()
..events = [
@@ -567,6 +573,10 @@ void main() {
test(
'should work fine if persistence contains sync params',
() async {
// persistence.updateLastSyncAt might be called
// when connecting the user.
// Resetting the logs so we start counting invocations correctly.
reset(persistence);
const cids = ['test-cid-1', 'test-cid-2', 'test-cid-3'];
final lastSyncAt = DateTime.now();
@@ -22,26 +22,37 @@ void main() {
test('addDevice should work', () async {
const deviceId = 'test-device-id';
const pushProvider = PushProvider.firebase;
const pushProvidersMap = {
'apn': PushProvider.apn,
'firebase': PushProvider.firebase,
'huawei': PushProvider.huawei,
'xiaomi': PushProvider.xiaomi,
};
const path = '/devices';
when(() => client.post(
path,
data: {
'id': deviceId,
'push_provider': pushProvider.name,
},
))
.thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
for (final pushProviderMapEntry in pushProvidersMap.entries) {
final data = {
'id': deviceId,
'push_provider': pushProviderMapEntry.key,
};
when(() {
return client.post(
path,
data: data,
);
}).thenAnswer(
(_) async => successResponse(path, data: <String, dynamic>{}));
final res = await deviceApi.addDevice(deviceId, pushProvider);
final res =
await deviceApi.addDevice(deviceId, pushProviderMapEntry.value);
expect(res, isNotNull);
expect(res, isNotNull);
verify(() => client.post(path, data: any(named: 'data'))).called(1);
verify(() => client.post(path, data: data)).called(1);
}
verifyNoMoreInteractions(client);
expect(pushProvidersMap.length, PushProvider.values.length,
reason: 'All PushProvider should be tested');
});
test('addDevice should work with pushProviderName', () async {
@@ -394,7 +394,12 @@ void main() {
path,
data: {'language': language},
)).thenAnswer((_) async => successResponse(path, data: {
'message': translatedMessage.toJson(),
'message': {
...translatedMessage.toJson(),
'i18n': {
language: translatedMessageText,
},
},
}));
final res = await messageApi.translateMessage(messageId, language);
@@ -129,7 +129,11 @@ void main() {
await client.get('path');
} on StreamChatNetworkError catch (e) {
expect(e, isA<StreamChatNetworkError>());
expect(e.message, "Dio can't establish new connection after closed.");
expect(
e.message,
"The connection errored: Dio can't establish a new connection"
' after it was closed.',
);
}
});