major refactoring

Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
Sahil Kumar
2021-05-27 19:59:34 +05:30
parent 99afb0ba8e
commit 839ced618b
106 changed files with 4263 additions and 1937 deletions
@@ -0,0 +1,168 @@
import 'package:dio/dio.dart';
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/extensions/string_extension.dart';
import 'package:stream_chat/src/core/models/attachment_file.dart';
/// Class responsible for uploading images and files to a given channel
abstract class AttachmentFileUploader {
/// Uploads a [image] to the given channel.
/// Returns [SendImageResponse] once sent successfully.
///
/// Optionally, access upload progress using [onSendProgress]
/// and cancel the request using [cancelToken]
Future<SendImageResponse> sendImage(
AttachmentFile image,
String channelId,
String channelType, {
ProgressCallback? onSendProgress,
CancelToken? cancelToken,
});
/// Uploads a [file] to the given channel.
/// Returns [SendFileResponse] once sent successfully.
///
/// Optionally, access upload progress using [onSendProgress]
/// and cancel the request using [cancelToken]
Future<SendFileResponse> sendFile(
AttachmentFile file,
String channelId,
String channelType, {
ProgressCallback? onSendProgress,
CancelToken? cancelToken,
});
/// Deletes a image using its [url] from the given channel.
/// Returns [EmptyResponse] once deleted successfully.
///
/// Optionally, cancel the request using [cancelToken]
Future<EmptyResponse> deleteImage(
String url,
String channelId,
String channelType, {
CancelToken? cancelToken,
});
/// Deletes a file using its [url] from the given channel.
/// Returns [EmptyResponse] once deleted successfully.
///
/// Optionally, cancel the request using [cancelToken]
Future<EmptyResponse> deleteFile(
String url,
String channelId,
String channelType, {
CancelToken? cancelToken,
});
}
/// Stream's default implementation of [AttachmentFileUploader]
class StreamAttachmentFileUploader implements AttachmentFileUploader {
/// Creates a new [StreamAttachmentFileUploader] instance.
const StreamAttachmentFileUploader(this._client);
final StreamHttpClient _client;
@override
Future<SendImageResponse> sendImage(
AttachmentFile file,
String channelId,
String channelType, {
ProgressCallback? onSendProgress,
CancelToken? cancelToken,
}) async {
final filename = file.path?.split('/').last ?? file.name;
final mimeType = filename?.mimeType;
MultipartFile? multiPartFile;
if (file.path != null) {
multiPartFile = await MultipartFile.fromFile(
file.path!,
filename: filename,
contentType: mimeType,
);
} else if (file.bytes != null) {
multiPartFile = MultipartFile.fromBytes(
file.bytes!,
filename: filename,
contentType: mimeType,
);
}
final response = await _client.post(
'/channels/$channelType/$channelId/image',
data: FormData.fromMap({
'file': multiPartFile,
}),
onSendProgress: onSendProgress,
cancelToken: cancelToken,
);
return SendImageResponse.fromJson(response.data);
}
@override
Future<SendFileResponse> sendFile(
AttachmentFile file,
String channelId,
String channelType, {
ProgressCallback? onSendProgress,
CancelToken? cancelToken,
}) async {
final filename = file.path?.split('/').last ?? file.name;
final mimeType = filename?.mimeType;
MultipartFile? multiPartFile;
if (file.path != null) {
multiPartFile = await MultipartFile.fromFile(
file.path!,
filename: filename,
contentType: mimeType,
);
} else if (file.bytes != null) {
multiPartFile = MultipartFile.fromBytes(
file.bytes!,
filename: filename,
contentType: mimeType,
);
}
final response = await _client.post(
'/channels/$channelType/$channelId/file',
data: FormData.fromMap({
'file': multiPartFile,
}),
onSendProgress: onSendProgress,
cancelToken: cancelToken,
);
return SendFileResponse.fromJson(response.data);
}
@override
Future<EmptyResponse> deleteImage(
String url,
String channelId,
String channelType, {
CancelToken? cancelToken,
}) async {
final response = await _client.delete(
'/channels/$channelType/$channelId/image',
queryParameters: {'url': url},
cancelToken: cancelToken,
);
return EmptyResponse.fromJson(response.data);
}
@override
Future<EmptyResponse> deleteFile(
String url,
String channelId,
String channelType, {
CancelToken? cancelToken,
}) async {
final response = await _client.delete(
'/channels/$channelType/$channelId/file',
queryParameters: {'url': url},
cancelToken: cancelToken,
);
return EmptyResponse.fromJson(response.data);
}
}
@@ -0,0 +1,293 @@
import 'dart:convert';
import 'package:stream_chat/src/core/api/requests.dart';
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/models/channel_model.dart';
import 'package:stream_chat/src/core/models/channel_state.dart';
import 'package:stream_chat/src/core/models/event.dart';
import 'package:stream_chat/src/core/models/filter.dart';
import 'package:stream_chat/src/core/models/message.dart';
///
class ChannelApi {
///
ChannelApi(this._client);
final StreamHttpClient _client;
String _getChannelUrl(String channelId, String channelType) =>
'/channels/$channelType/$channelId';
/// Query the API, get messages, members or other channel fields
Future<ChannelState> queryChannel(
String channelType, {
bool state = true,
bool watch = false,
bool presence = false,
String? channelId,
Map<String, Object?>? channelData,
PaginationParams? messagesPagination,
PaginationParams? membersPagination,
PaginationParams? watchersPagination,
}) async {
var channelPath = '/channels/$channelType';
if (channelId != null) channelPath = '$channelPath/$channelId';
final response = await _client.post(
'$channelPath/query',
data: {
'state': state,
'watch': watch,
'presence': presence,
if (channelData != null) 'data': channelData,
if (messagesPagination != null) 'messages': messagesPagination,
if (membersPagination != null) 'members': membersPagination,
if (watchersPagination != null) 'watchers': watchersPagination,
},
);
return ChannelState.fromJson(response.data);
}
/// Requests channels with a given query from the API.
Future<QueryChannelsResponse> queryChannels({
Filter? filter,
List<SortOption<ChannelModel>>? sort,
int? memberLimit,
int? messageLimit,
bool state = true,
bool watch = true,
bool presence = false,
PaginationParams paginationParams = const PaginationParams(),
}) async {
print('Query Channel Started 2 : ${DateTime.now()}');
final response = await _client.get(
'/channels',
queryParameters: {
'payload': jsonEncode({
// default options
'state': state,
'watch': watch,
'presence': presence,
// passed options
if (sort != null) 'sort': sort,
if (filter != null) 'filter_conditions': filter,
if (memberLimit != null) 'member_limit': memberLimit,
if (messageLimit != null) 'message_limit': messageLimit,
// pagination
...paginationParams.toJson()
})
},
);
print('Query Channel Completed 2 : ${DateTime.now()}');
return QueryChannelsResponse.fromJson(response.data);
}
/// Mark all channels for this user as read
Future<EmptyResponse> markAllRead() async {
final response = await _client.post('channels/read');
return EmptyResponse.fromJson(response.data);
}
/// Replaces the [channelId] of type [ChannelType] data with [data]
Future<UpdateChannelResponse> updateChannel(
String channelId,
String channelType,
Map<String, dynamic> data, {
Message? message,
}) async {
final response = await _client.post(
_getChannelUrl(channelId, channelType),
data: {
'data': data,
if (message != null)
'message': message.copyWith(updatedAt: DateTime.now()),
},
);
return UpdateChannelResponse.fromJson(response.data);
}
/// Updates the [channelId] of type [ChannelType] data with [data]
Future<PartialUpdateChannelResponse> updateChannelPartial(
String channelId,
String channelType,
Map<String, dynamic> data,
) async {
final response = await _client.patch(
_getChannelUrl(channelId, channelType),
data: data,
);
return PartialUpdateChannelResponse.fromJson(response.data);
}
/// Accept invitation to the channel
Future<AcceptInviteResponse> acceptChannelInvite(
String channelId,
String channelType, {
Message? message,
}) async {
final response = await _client.post(
_getChannelUrl(channelId, channelType),
data: {
'accept_invite': true,
'message': message,
},
);
return AcceptInviteResponse.fromJson(response.data);
}
/// Reject invitation to the channel
Future<RejectInviteResponse> rejectChannelInvite(
String channelId,
String channelType, {
Message? message,
}) async {
final response = await _client.post(
_getChannelUrl(channelId, channelType),
data: {
'reject_invite': true,
'message': message,
},
);
return RejectInviteResponse.fromJson(response.data);
}
/// Invite members to the channel
Future<InviteMembersResponse> inviteChannelMembers(
String channelId,
String channelType,
List<String> memberIds, {
Message? message,
}) async {
final response = await _client.post(
_getChannelUrl(channelId, channelType),
data: {
'invites': memberIds,
'message': message,
},
);
return InviteMembersResponse.fromJson(response.data);
}
/// Add members to the channel
Future<AddMembersResponse> addMembers(
String channelId,
String channelType,
List<String> memberIds, {
Message? message,
}) async {
final response = await _client.post(
_getChannelUrl(channelId, channelType),
data: {
'add_members': memberIds,
'message': message,
},
);
return AddMembersResponse.fromJson(response.data);
}
/// Remove members from the channel
Future<RemoveMembersResponse> removeMembers(
String channelId,
String channelType,
List<String> memberIds, {
Message? message,
}) async {
final response = await _client.post(
_getChannelUrl(channelId, channelType),
data: {
'remove_members': memberIds,
'message': message,
},
);
return RemoveMembersResponse.fromJson(response.data);
}
/// Send an event on this channel
Future<EmptyResponse> sendEvent(
String channelId,
String channelType,
Event event,
) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/event',
data: {'event': event},
);
return EmptyResponse.fromJson(response.data);
}
/// Delete this channel. Messages are permanently removed.
Future<EmptyResponse> deleteChannel(
String channelId,
String channelType,
) async {
final response = await _client.delete(
_getChannelUrl(channelId, channelType),
);
return EmptyResponse.fromJson(response.data);
}
/// Removes all messages from the channel
Future<EmptyResponse> truncateChannel(
String channelId,
String channelType,
) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/truncate',
);
return EmptyResponse.fromJson(response.data);
}
/// Hides the channel from [StreamChatClient.queryChannels] for the user
/// until a message is added If [clearHistory] is set to true - all messages
/// will be removed for the user
Future<EmptyResponse> hideChannel(
String channelId,
String channelType, {
bool clearHistory = false,
}) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/hide',
data: {'clear_history': clearHistory},
);
return EmptyResponse.fromJson(response.data);
}
/// Removes the hidden status for the channel
Future<EmptyResponse> showChannel(
String channelId,
String channelType,
) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/show',
);
return EmptyResponse.fromJson(response.data);
}
/// Mark [channelId] of type [channelType] all messages as read
/// Optionally provide a [messageId] if you want to mark a
/// particular message as read
Future<EmptyResponse> markRead(
String channelId,
String channelType, {
String? messageId,
}) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/read',
data: {if (messageId != null) 'message_id': messageId},
);
return EmptyResponse.fromJson(response.data);
}
/// Stop watching the channel
Future<EmptyResponse> stopWatching(
String channelId,
String channelType,
) async {
final response = await _client.post(
'${_getChannelUrl(channelId, channelType)}/stop-watching',
);
return EmptyResponse.fromJson(response.data);
}
}
@@ -0,0 +1,59 @@
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
/// Provider used to send push notifications.
enum PushProvider {
/// Send notifications using Google's Firebase Cloud Messaging
firebase,
/// Send notifications using Apple's Push Notification service
apn
}
extension on PushProvider {
/// Returns the string notion for [PushProvider].
String get name => {
PushProvider.apn: 'apn',
PushProvider.firebase: 'firebase',
}[this]!;
}
///
class DeviceApi {
///
DeviceApi(this._client);
final StreamHttpClient _client;
/// Add a device for Push Notifications.
Future<EmptyResponse> addDevice(
String deviceId,
PushProvider pushProvider,
) async {
final response = await _client.post(
'/devices',
data: {
'id': deviceId,
'push_provider': pushProvider.name,
},
);
return EmptyResponse.fromJson(response.data);
}
/// Gets a list of user devices.
Future<ListDevicesResponse> getDevices() async {
final response = await _client.get('/devices');
return ListDevicesResponse.fromJson(response.data);
}
/// Remove a user's device.
Future<EmptyResponse> removeDevice(
String deviceId,
) async {
final response = await _client.delete(
'/devices',
queryParameters: {'id': deviceId},
);
return EmptyResponse.fromJson(response.data);
}
}
@@ -0,0 +1,94 @@
import 'dart:convert';
import 'package:stream_chat/src/core/api/requests.dart';
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/models/filter.dart';
import 'package:stream_chat/src/core/models/member.dart';
///
class GeneralApi {
///
GeneralApi(this._client);
final StreamHttpClient _client;
/// Get all the missed events
Future<SyncResponse> sync(
List<String> cids,
DateTime lastSyncAt,
) async {
final response = await _client.post(
'/sync',
data: {
'channel_cids': cids,
'last_sync_at': lastSyncAt.toUtc().toIso8601String(),
},
);
return SyncResponse.fromJson(response.data);
}
/// A message search.
Future<SearchMessagesResponse> searchMessages(
Filter filter, {
String? query,
List<SortOption>? sort,
PaginationParams? pagination,
Filter? messageFilters,
}) async {
assert(() {
if (query == null && messageFilters == null) {
throw ArgumentError('Provide at least `query` or `messageFilters`');
}
if (query != null && messageFilters != null) {
throw ArgumentError(
"Can't provide both `query` and `messageFilters` at the same time",
);
}
return true;
}(), 'Check incoming params.');
final response = await _client.get(
'/search',
queryParameters: {
'payload': jsonEncode({
'filter_conditions': filter,
if (sort != null) 'sort': sort,
if (query != null) 'query': query,
if (messageFilters != null)
'message_filter_conditions': messageFilters,
if (pagination != null) ...pagination.toJson(),
}),
},
);
return SearchMessagesResponse.fromJson(response.data);
}
/// Query channel members
Future<QueryMembersResponse> queryMembers(
String channelType, {
Filter? filter,
String? channelId,
List<Member>? members,
List<SortOption>? sort,
PaginationParams? pagination,
}) async {
final response = await _client.get(
'/members',
queryParameters: {
'payload': jsonEncode({
'type': channelType,
if (channelId != null)
'id': channelId
else if (members != null)
'members': members,
if (sort != null) 'sort': sort,
if (filter != null) 'filter': filter,
if (pagination != null) ...pagination.toJson(),
}),
},
);
return QueryMembersResponse.fromJson(response.data);
}
}
@@ -0,0 +1,20 @@
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/models/user.dart';
///
class GuestApi {
///
GuestApi(this._client);
final StreamHttpClient _client;
///
Future<ConnectGuestUserResponse> getGuestUser(User user) async {
final response = await _client.post(
'/guest',
data: {'user': user},
);
return ConnectGuestUserResponse.fromJson(response.data);
}
}
@@ -0,0 +1,160 @@
import 'package:stream_chat/src/core/api/requests.dart';
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/models/message.dart';
///
class MessageApi {
///
MessageApi(this._client);
final StreamHttpClient _client;
/// Sends the [message] to the given [channelId] of given [channelType]
Future<SendMessageResponse> sendMessage(
String channelId,
String channelType,
Message message,
) async {
final response = await _client.post(
'/channels/$channelType/$channelId/message',
data: {'message': message},
);
return SendMessageResponse.fromJson(response.data);
}
/// Retrieves a list of messages by [messageIDs]
/// from the given [channelId] of type [channelType]
Future<GetMessagesByIdResponse> getMessagesById(
String channelId,
String channelType,
List<String> messageIDs,
) async {
final response = await _client.get(
'/channels/$channelType/$channelId/messages',
queryParameters: {'ids': messageIDs.join(',')},
);
return GetMessagesByIdResponse.fromJson(response.data);
}
/// Get a message by [messageId]
Future<GetMessageResponse> getMessage(String messageId) async {
final response = await _client.get(
'/messages/$messageId',
);
return GetMessageResponse.fromJson(response.data);
}
/// Updates the given [message]
Future<UpdateMessageResponse> updateMessage(
Message message,
) async {
final response = await _client.post(
'/messages/${message.id}',
data: {'message': message},
);
return UpdateMessageResponse.fromJson(response.data);
}
/// Deletes the given [messageId]
Future<EmptyResponse> deleteMessage(
String messageId,
) async {
final response = await _client.delete(
'/messages/$messageId',
);
return EmptyResponse.fromJson(response.data);
}
/// Send action for a specific [messageId]
/// of the given [channelId] of given [channelType]
Future<SendActionResponse> sendAction(
String channelId,
String channelType,
String messageId,
Map<String, Object?> formData,
) async {
final response = await _client.post(
'/messages/$messageId/action',
data: {
'id': channelId,
'type': channelType,
'form_data': formData,
'message_id': messageId,
},
);
return SendActionResponse.fromJson(response.data);
}
/// Send a [reactionType] for this [messageId]
/// Set [enforceUnique] to true to remove the existing user reaction
Future<SendReactionResponse> sendReaction(
String messageId,
String reactionType, {
Map<String, Object?> extraData = const {},
bool enforceUnique = false,
}) async {
final reaction = Map<String, Object?>.from(extraData)
..addAll({'type': reactionType});
final response = await _client.post(
'/messages/$messageId/reaction',
data: {
'reaction': reaction,
'enforce_unique': enforceUnique,
},
);
return SendReactionResponse.fromJson(response.data);
}
/// Delete a [reactionType] from this [messageId]
Future<EmptyResponse> deleteReaction(
String messageId,
String reactionType,
) async {
final response = await _client.delete(
'/messages/$messageId/reaction/$reactionType',
);
return EmptyResponse.fromJson(response.data);
}
/// Get all the reactions for a [messageId]
Future<QueryReactionsResponse> getReactions(
String messageId,
PaginationParams options,
) async {
final response = await _client.get(
'/messages/$messageId/reactions',
queryParameters: {
...options.toJson(),
},
);
return QueryReactionsResponse.fromJson(response.data);
}
/// Translates the [messageId] in provided [language]
Future<TranslateMessageResponse> translateMessage(
String messageId,
String language,
) async {
final response = await _client.post(
'/messages/$messageId/translate',
data: {'language': language},
);
return TranslateMessageResponse.fromJson(response.data);
}
/// Lists all the message replies for the [parentId]
Future<QueryRepliesResponse> getReplies(
String parentId,
PaginationParams options,
) async {
final response = await _client.get(
'/messages/$parentId/replies',
queryParameters: {
...options.toJson(),
},
);
return QueryRepliesResponse.fromJson(response.data);
}
}
@@ -0,0 +1,128 @@
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
///
class ModerationApi {
///
ModerationApi(this._client);
final StreamHttpClient _client;
/// Mutes a user
Future<EmptyResponse> muteUser(String userId) async {
final response = await _client.post(
'/moderation/mute',
data: {'target_id': userId},
);
return EmptyResponse.fromJson(response.data);
}
/// Unmutes a user
Future<EmptyResponse> unmuteUser(String userId) async {
final response = await _client.post(
'/moderation/unmute',
data: {'target_id': userId},
);
return EmptyResponse.fromJson(response.data);
}
/// Mutes the channel
Future<EmptyResponse> muteChannel(
String channelCid, {
Duration? expiration,
}) async {
final response = await _client.post(
'/moderation/mute/channel',
data: {
'channel_cid': channelCid,
if (expiration != null) 'expiration': expiration.inMilliseconds,
},
);
return EmptyResponse.fromJson(response.data);
}
/// Unmutes the channel
Future<EmptyResponse> unmuteChannel(
String channelCid,
) async {
final response = await _client.post(
'/moderation/unmute/channel',
data: {'channel_cid': channelCid},
);
return EmptyResponse.fromJson(response.data);
}
/// Flag a message
Future<EmptyResponse> flagMessage(
String messageId,
) async {
final response = await _client.post(
'/moderation/flag',
data: {'target_message_id': messageId},
);
return EmptyResponse.fromJson(response.data);
}
/// Unflag a message
Future<EmptyResponse> unflagMessage(
String messageId,
) async {
final response = await _client.post(
'/moderation/unflag',
data: {'target_message_id': messageId},
);
return EmptyResponse.fromJson(response.data);
}
/// Flag a user
Future<EmptyResponse> flagUser(
String userId,
) async {
final response = await _client.post(
'/moderation/flag',
data: {'target_user_id': userId},
);
return EmptyResponse.fromJson(response.data);
}
/// Unflag a user
Future<EmptyResponse> unflagUser(
String userId,
) async {
final response = await _client.post(
'/moderation/unflag',
data: {'target_user_id': userId},
);
return EmptyResponse.fromJson(response.data);
}
/// Bans a user from all channels
Future<EmptyResponse> banUser(
String targetUserId, {
Map<String, Object?>? options,
}) async {
final response = await _client.post(
'/moderation/ban',
data: {
'target_user_id': targetUserId,
if (options != null) ...options,
},
);
return EmptyResponse.fromJson(response.data);
}
/// Remove global ban for a user
Future<EmptyResponse> unbanUser(
String targetUserId, {
Map<String, Object?>? options,
}) async {
final response = await _client.delete(
'/moderation/ban',
queryParameters: {
'target_user_id': targetUserId,
if (options != null) ...options,
},
);
return EmptyResponse.fromJson(response.data);
}
}
@@ -0,0 +1,126 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
part 'requests.g.dart';
/// Sorting options
@JsonSerializable(includeIfNull: false)
class SortOption<T> {
/// Creates a new SortOption instance
///
/// For example:
/// ```dart
/// // Sort channels by the last message date:
/// final sorting = SortOption("last_message_at")
/// ```
const SortOption(
this.field, {
this.direction = DESC,
this.comparator,
});
/// Create a new instance from a json
factory SortOption.fromJson(Map<String, dynamic> json) =>
_$SortOptionFromJson(json);
/// Ascending order
// ignore: constant_identifier_names
static const ASC = 1;
/// Descending order
// ignore: constant_identifier_names
static const DESC = -1;
/// A sorting field name
final String field;
/// A sorting direction
final int direction;
/// Sorting field Comparator required for offline sorting
@JsonKey(ignore: true)
final Comparator<T>? comparator;
/// Serialize model to json
Map<String, dynamic> toJson() => _$SortOptionToJson(this);
}
/// Pagination options.
@JsonSerializable(includeIfNull: false)
class PaginationParams extends Equatable {
/// Creates a new PaginationParams instance
///
/// For example:
/// ```dart
/// // limit to 50
/// final paginationParams = PaginationParams(limit: 50);
///
/// // limit to 50 with offset
/// final paginationParams = PaginationParams(limit: 50, offset: 50);
/// ```
const PaginationParams({
this.limit = 10,
this.offset = 0,
this.greaterThan,
this.greaterThanOrEqual,
this.lessThan,
this.lessThanOrEqual,
});
/// Create a new instance from a json
factory PaginationParams.fromJson(Map<String, dynamic> json) =>
_$PaginationParamsFromJson(json);
/// The amount of items requested from the APIs.
final int limit;
/// The offset of requesting items.
final int offset;
/// Filter on ids greater than the given value.
@JsonKey(name: 'id_gt')
final String? greaterThan;
/// Filter on ids greater than or equal to the given value.
@JsonKey(name: 'id_gte')
final String? greaterThanOrEqual;
/// Filter on ids smaller than the given value.
@JsonKey(name: 'id_lt')
final String? lessThan;
/// Filter on ids smaller than or equal to the given value.
@JsonKey(name: 'id_lte')
final String? lessThanOrEqual;
/// Serialize model to json
Map<String, dynamic> toJson() => _$PaginationParamsToJson(this);
/// Creates a copy of [PaginationParams] with specified attributes overridden.
PaginationParams copyWith({
int? limit,
int? offset,
String? greaterThan,
String? greaterThanOrEqual,
String? lessThan,
String? lessThanOrEqual,
}) =>
PaginationParams(
limit: limit ?? this.limit,
offset: offset ?? this.offset,
greaterThan: greaterThan ?? this.greaterThan,
greaterThanOrEqual: greaterThanOrEqual ?? this.greaterThanOrEqual,
lessThan: lessThan ?? this.lessThan,
lessThanOrEqual: lessThanOrEqual ?? this.lessThanOrEqual,
);
@override
List<Object?> get props => [
limit,
offset,
greaterThan,
greaterThanOrEqual,
lessThan,
lessThanOrEqual,
];
}
@@ -0,0 +1,50 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'requests.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
SortOption<T> _$SortOptionFromJson<T>(Map<String, dynamic> json) {
return SortOption<T>(
json['field'] as String,
direction: json['direction'] as int,
);
}
Map<String, dynamic> _$SortOptionToJson<T>(SortOption<T> instance) =>
<String, dynamic>{
'field': instance.field,
'direction': instance.direction,
};
PaginationParams _$PaginationParamsFromJson(Map<String, dynamic> json) {
return PaginationParams(
limit: json['limit'] as int,
offset: json['offset'] as int,
greaterThan: json['id_gt'] as String?,
greaterThanOrEqual: json['id_gte'] as String?,
lessThan: json['id_lt'] as String?,
lessThanOrEqual: json['id_lte'] as String?,
);
}
Map<String, dynamic> _$PaginationParamsToJson(PaginationParams instance) {
final val = <String, dynamic>{
'limit': instance.limit,
'offset': instance.offset,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('id_gt', instance.greaterThan);
writeNotNull('id_gte', instance.greaterThanOrEqual);
writeNotNull('id_lt', instance.lessThan);
writeNotNull('id_lte', instance.lessThanOrEqual);
return val;
}
@@ -0,0 +1,435 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/client.dart';
import 'package:stream_chat/src/core/models/channel_model.dart';
import 'package:stream_chat/src/core/models/channel_state.dart';
import 'package:stream_chat/src/core/models/device.dart';
import 'package:stream_chat/src/core/models/event.dart';
import 'package:stream_chat/src/core/models/member.dart';
import 'package:stream_chat/src/core/models/message.dart';
import 'package:stream_chat/src/core/models/reaction.dart';
import 'package:stream_chat/src/core/models/read.dart';
import 'package:stream_chat/src/core/models/user.dart';
import 'package:stream_chat/src/errors/stream_chat_error.dart';
part 'responses.g.dart';
class _BaseResponse {
String? duration;
}
/// Model response for [StreamChatNetworkError] data
@JsonSerializable(createToJson: false)
class ErrorResponse extends _BaseResponse {
///
int? code;
///
String? message;
///
@JsonKey(name: 'StatusCode')
int? statusCode;
///
String? moreInfo;
/// Create a new instance from a json
static ErrorResponse fromJson(Map<String, dynamic> json) =>
_$ErrorResponseFromJson(json);
@override
String toString() => 'ErrorResponse(code: $code, '
'message: $message, '
'statusCode: $statusCode, '
'moreInfo: $moreInfo)';
}
/// Model response for [StreamChatClient.sync] api call
@JsonSerializable(createToJson: false)
class SyncResponse extends _BaseResponse {
/// The list of events
@JsonKey(defaultValue: [])
late List<Event> events;
/// Create a new instance from a json
static SyncResponse fromJson(Map<String, dynamic> json) =>
_$SyncResponseFromJson(json);
}
/// Model response for [StreamChatClient.queryChannels] api call
@JsonSerializable(createToJson: false)
class QueryChannelsResponse extends _BaseResponse {
/// List of channels state returned by the query
@JsonKey(defaultValue: [])
late List<ChannelState> channels;
/// Create a new instance from a json
static QueryChannelsResponse fromJson(Map<String, dynamic> json) =>
_$QueryChannelsResponseFromJson(json);
}
/// Model response for [StreamChatClient.queryChannels] api call
@JsonSerializable(createToJson: false)
class TranslateMessageResponse extends _BaseResponse {
/// Translated message
late TranslatedMessage message;
/// Create a new instance from a json
static TranslateMessageResponse fromJson(Map<String, dynamic> json) =>
_$TranslateMessageResponseFromJson(json);
}
/// Model response for [StreamChatClient.queryChannels] api call
@JsonSerializable(createToJson: false)
class QueryMembersResponse extends _BaseResponse {
/// List of channels state returned by the query
@JsonKey(defaultValue: [])
late List<Member> members;
/// Create a new instance from a json
static QueryMembersResponse fromJson(Map<String, dynamic> json) =>
_$QueryMembersResponseFromJson(json);
}
/// Model response for [StreamChatClient.queryUsers] api call
@JsonSerializable(createToJson: false)
class QueryUsersResponse extends _BaseResponse {
/// List of users returned by the query
@JsonKey(defaultValue: [])
late List<User> users;
/// Create a new instance from a json
static QueryUsersResponse fromJson(Map<String, dynamic> json) =>
_$QueryUsersResponseFromJson(json);
}
/// Model response for [channel.getReactions] api call
@JsonSerializable(createToJson: false)
class QueryReactionsResponse extends _BaseResponse {
/// List of reactions returned by the query
@JsonKey(defaultValue: [])
late List<Reaction> reactions;
/// Create a new instance from a json
static QueryReactionsResponse fromJson(Map<String, dynamic> json) =>
_$QueryReactionsResponseFromJson(json);
}
/// Model response for [Channel.getReplies] api call
@JsonSerializable(createToJson: false)
class QueryRepliesResponse extends _BaseResponse {
/// List of messages returned by the api call
@JsonKey(defaultValue: [])
late List<Message> messages;
/// Create a new instance from a json
static QueryRepliesResponse fromJson(Map<String, dynamic> json) =>
_$QueryRepliesResponseFromJson(json);
}
/// Model response for [StreamChatClient.getDevices] api call
@JsonSerializable(createToJson: false)
class ListDevicesResponse extends _BaseResponse {
/// List of user devices
@JsonKey(defaultValue: [])
late List<Device> devices;
/// Create a new instance from a json
static ListDevicesResponse fromJson(Map<String, dynamic> json) =>
_$ListDevicesResponseFromJson(json);
}
/// Model response for [Channel.sendFile] api call
@JsonSerializable(createToJson: false)
class SendFileResponse extends _BaseResponse {
/// The url of the uploaded file
late String file;
/// Create a new instance from a json
static SendFileResponse fromJson(Map<String, dynamic> json) =>
_$SendFileResponseFromJson(json);
}
/// Model response for [Channel.sendImage] api call
@JsonSerializable(createToJson: false)
class SendImageResponse extends _BaseResponse {
/// The url of the uploaded file
late String file;
/// Create a new instance from a json
static SendImageResponse fromJson(Map<String, dynamic> json) =>
_$SendImageResponseFromJson(json);
}
/// Model response for [Channel.sendReaction] api call
@JsonSerializable(createToJson: false)
class SendReactionResponse extends _BaseResponse {
/// Message returned by the api call
late Message message;
/// The reaction created by the api call
late Reaction reaction;
/// Create a new instance from a json
static SendReactionResponse fromJson(Map<String, dynamic> json) =>
_$SendReactionResponseFromJson(json);
}
/// Model response for [StreamChatClient.connectGuestUser] api call
@JsonSerializable(createToJson: false)
class ConnectGuestUserResponse extends _BaseResponse {
/// Guest user access token
late String accessToken;
/// Guest user
late User user;
/// Create a new instance from a json
static ConnectGuestUserResponse fromJson(Map<String, dynamic> json) =>
_$ConnectGuestUserResponseFromJson(json);
}
/// Model response for [StreamChatClient.updateUser] api call
@JsonSerializable(createToJson: false)
class UpdateUsersResponse extends _BaseResponse {
/// Updated users
@JsonKey(defaultValue: {})
late Map<String, User> users;
/// Create a new instance from a json
static UpdateUsersResponse fromJson(Map<String, dynamic> json) =>
_$UpdateUsersResponseFromJson(json);
}
/// Model response for [StreamChatClient.updateMessage] api call
@JsonSerializable(createToJson: false)
class UpdateMessageResponse extends _BaseResponse {
/// Message returned by the api call
late Message message;
/// Create a new instance from a json
static UpdateMessageResponse fromJson(Map<String, dynamic> json) =>
_$UpdateMessageResponseFromJson(json);
}
/// Model response for [Channel.sendMessage] api call
@JsonSerializable(createToJson: false)
class SendMessageResponse extends _BaseResponse {
/// Message returned by the api call
late Message message;
/// Create a new instance from a json
static SendMessageResponse fromJson(Map<String, dynamic> json) =>
_$SendMessageResponseFromJson(json);
}
/// Model response for [StreamChatClient.getMessage] api call
@JsonSerializable(createToJson: false)
class GetMessageResponse extends _BaseResponse {
/// Message returned by the api call
late Message message;
/// Channel of the message
ChannelModel? channel;
/// Create a new instance from a json
static GetMessageResponse fromJson(Map<String, dynamic> json) {
final res = _$GetMessageResponseFromJson(json);
final jsonChannel = res.message.extraData.remove('channel');
if (jsonChannel != null) {
res.channel = ChannelModel.fromJson(jsonChannel as Map<String, dynamic>);
}
return res;
}
}
/// Model response for [StreamChatClient.search] api call
@JsonSerializable(createToJson: false)
class SearchMessagesResponse extends _BaseResponse {
/// List of messages returned by the api call
@JsonKey(defaultValue: [])
late List<GetMessageResponse> results;
/// Create a new instance from a json
static SearchMessagesResponse fromJson(Map<String, dynamic> json) =>
_$SearchMessagesResponseFromJson(json);
}
/// Model response for [Channel.getMessagesById] api call
@JsonSerializable(createToJson: false)
class GetMessagesByIdResponse extends _BaseResponse {
/// Message returned by the api call
@JsonKey(defaultValue: [])
late List<Message> messages;
/// Create a new instance from a json
static GetMessagesByIdResponse fromJson(Map<String, dynamic> json) =>
_$GetMessagesByIdResponseFromJson(json);
}
/// Model response for [Channel.update] api call
@JsonSerializable(createToJson: false)
class UpdateChannelResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
List<Member>? members;
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static UpdateChannelResponse fromJson(Map<String, dynamic> json) =>
_$UpdateChannelResponseFromJson(json);
}
/// Model response for [Channel.updatePartial] api call
@JsonSerializable(createToJson: false)
class PartialUpdateChannelResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
List<Member>? members;
/// Create a new instance from a json
static PartialUpdateChannelResponse fromJson(Map<String, dynamic> json) =>
_$PartialUpdateChannelResponseFromJson(json);
}
/// Model response for [Channel.inviteMembers] api call
@JsonSerializable(createToJson: false)
class InviteMembersResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
@JsonKey(defaultValue: [])
late List<Member> members;
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static InviteMembersResponse fromJson(Map<String, dynamic> json) =>
_$InviteMembersResponseFromJson(json);
}
/// Model response for [Channel.removeMembers] api call
@JsonSerializable(createToJson: false)
class RemoveMembersResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
@JsonKey(defaultValue: [])
late List<Member> members;
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static RemoveMembersResponse fromJson(Map<String, dynamic> json) =>
_$RemoveMembersResponseFromJson(json);
}
/// Model response for [Channel.sendAction] api call
@JsonSerializable(createToJson: false)
class SendActionResponse extends _BaseResponse {
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static SendActionResponse fromJson(Map<String, dynamic> json) =>
_$SendActionResponseFromJson(json);
}
/// Model response for [Channel.addMembers] api call
@JsonSerializable(createToJson: false)
class AddMembersResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
@JsonKey(defaultValue: [])
late List<Member> members;
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static AddMembersResponse fromJson(Map<String, dynamic> json) =>
_$AddMembersResponseFromJson(json);
}
/// Model response for [Channel.acceptInvite] api call
@JsonSerializable(createToJson: false)
class AcceptInviteResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
@JsonKey(defaultValue: [])
late List<Member> members;
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static AcceptInviteResponse fromJson(Map<String, dynamic> json) =>
_$AcceptInviteResponseFromJson(json);
}
/// Model response for [Channel.rejectInvite] api call
@JsonSerializable(createToJson: false)
class RejectInviteResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// Channel members
@JsonKey(defaultValue: [])
late List<Member> members;
/// Message returned by the api call
Message? message;
/// Create a new instance from a json
static RejectInviteResponse fromJson(Map<String, dynamic> json) =>
_$RejectInviteResponseFromJson(json);
}
/// Model response for empty responses
@JsonSerializable(createToJson: false)
class EmptyResponse extends _BaseResponse {
/// Create a new instance from a json
static EmptyResponse fromJson(Map<String, dynamic> json) =>
_$EmptyResponseFromJson(json);
}
/// Model response for [Channel.query] api call
@JsonSerializable(createToJson: false)
class ChannelStateResponse extends _BaseResponse {
/// Updated channel
late ChannelModel channel;
/// List of messages returned by the api call
@JsonKey(defaultValue: [])
late List<Message> messages;
/// Channel members
@JsonKey(defaultValue: [])
late List<Member> members;
/// Number of users watching the channel
@JsonKey(defaultValue: 0)
late int watcherCount;
/// List of read states
@JsonKey(defaultValue: [])
late List<Read> read;
/// Create a new instance from a json
static ChannelStateResponse fromJson(Map<String, dynamic> json) =>
_$ChannelStateResponseFromJson(json);
}
@@ -0,0 +1,288 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'responses.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ErrorResponse _$ErrorResponseFromJson(Map<String, dynamic> json) {
return ErrorResponse()
..duration = json['duration'] as String?
..code = json['code'] as int?
..message = json['message'] as String?
..statusCode = json['StatusCode'] as int?
..moreInfo = json['more_info'] as String?;
}
SyncResponse _$SyncResponseFromJson(Map<String, dynamic> json) {
return SyncResponse()
..duration = json['duration'] as String?
..events = (json['events'] as List<dynamic>?)
?.map((e) => Event.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
QueryChannelsResponse _$QueryChannelsResponseFromJson(
Map<String, dynamic> json) {
return QueryChannelsResponse()
..duration = json['duration'] as String?
..channels = (json['channels'] as List<dynamic>?)
?.map((e) => ChannelState.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
TranslateMessageResponse _$TranslateMessageResponseFromJson(
Map<String, dynamic> json) {
return TranslateMessageResponse()
..duration = json['duration'] as String?
..message =
TranslatedMessage.fromJson(json['message'] as Map<String, dynamic>);
}
QueryMembersResponse _$QueryMembersResponseFromJson(Map<String, dynamic> json) {
return QueryMembersResponse()
..duration = json['duration'] as String?
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
QueryUsersResponse _$QueryUsersResponseFromJson(Map<String, dynamic> json) {
return QueryUsersResponse()
..duration = json['duration'] as String?
..users = (json['users'] as List<dynamic>?)
?.map((e) => User.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
QueryReactionsResponse _$QueryReactionsResponseFromJson(
Map<String, dynamic> json) {
return QueryReactionsResponse()
..duration = json['duration'] as String?
..reactions = (json['reactions'] as List<dynamic>?)
?.map((e) => Reaction.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
QueryRepliesResponse _$QueryRepliesResponseFromJson(Map<String, dynamic> json) {
return QueryRepliesResponse()
..duration = json['duration'] as String?
..messages = (json['messages'] as List<dynamic>?)
?.map((e) => Message.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
ListDevicesResponse _$ListDevicesResponseFromJson(Map<String, dynamic> json) {
return ListDevicesResponse()
..duration = json['duration'] as String?
..devices = (json['devices'] as List<dynamic>?)
?.map((e) => Device.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
SendFileResponse _$SendFileResponseFromJson(Map<String, dynamic> json) {
return SendFileResponse()
..duration = json['duration'] as String?
..file = json['file'] as String;
}
SendImageResponse _$SendImageResponseFromJson(Map<String, dynamic> json) {
return SendImageResponse()
..duration = json['duration'] as String?
..file = json['file'] as String;
}
SendReactionResponse _$SendReactionResponseFromJson(Map<String, dynamic> json) {
return SendReactionResponse()
..duration = json['duration'] as String?
..message = Message.fromJson(json['message'] as Map<String, dynamic>)
..reaction = Reaction.fromJson(json['reaction'] as Map<String, dynamic>);
}
ConnectGuestUserResponse _$ConnectGuestUserResponseFromJson(
Map<String, dynamic> json) {
return ConnectGuestUserResponse()
..duration = json['duration'] as String?
..accessToken = json['access_token'] as String
..user = User.fromJson(json['user'] as Map<String, dynamic>);
}
UpdateUsersResponse _$UpdateUsersResponseFromJson(Map<String, dynamic> json) {
return UpdateUsersResponse()
..duration = json['duration'] as String?
..users = (json['users'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, User.fromJson(e as Map<String, dynamic>)),
) ??
{};
}
UpdateMessageResponse _$UpdateMessageResponseFromJson(
Map<String, dynamic> json) {
return UpdateMessageResponse()
..duration = json['duration'] as String?
..message = Message.fromJson(json['message'] as Map<String, dynamic>);
}
SendMessageResponse _$SendMessageResponseFromJson(Map<String, dynamic> json) {
return SendMessageResponse()
..duration = json['duration'] as String?
..message = Message.fromJson(json['message'] as Map<String, dynamic>);
}
GetMessageResponse _$GetMessageResponseFromJson(Map<String, dynamic> json) {
return GetMessageResponse()
..duration = json['duration'] as String?
..message = Message.fromJson(json['message'] as Map<String, dynamic>)
..channel = json['channel'] == null
? null
: ChannelModel.fromJson(json['channel'] as Map<String, dynamic>);
}
SearchMessagesResponse _$SearchMessagesResponseFromJson(
Map<String, dynamic> json) {
return SearchMessagesResponse()
..duration = json['duration'] as String?
..results = (json['results'] as List<dynamic>?)
?.map((e) => GetMessageResponse.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
GetMessagesByIdResponse _$GetMessagesByIdResponseFromJson(
Map<String, dynamic> json) {
return GetMessagesByIdResponse()
..duration = json['duration'] as String?
..messages = (json['messages'] as List<dynamic>?)
?.map((e) => Message.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
UpdateChannelResponse _$UpdateChannelResponseFromJson(
Map<String, dynamic> json) {
return UpdateChannelResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList()
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
PartialUpdateChannelResponse _$PartialUpdateChannelResponseFromJson(
Map<String, dynamic> json) {
return PartialUpdateChannelResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList();
}
InviteMembersResponse _$InviteMembersResponseFromJson(
Map<String, dynamic> json) {
return InviteMembersResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
RemoveMembersResponse _$RemoveMembersResponseFromJson(
Map<String, dynamic> json) {
return RemoveMembersResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
SendActionResponse _$SendActionResponseFromJson(Map<String, dynamic> json) {
return SendActionResponse()
..duration = json['duration'] as String?
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
AddMembersResponse _$AddMembersResponseFromJson(Map<String, dynamic> json) {
return AddMembersResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
AcceptInviteResponse _$AcceptInviteResponseFromJson(Map<String, dynamic> json) {
return AcceptInviteResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
RejectInviteResponse _$RejectInviteResponseFromJson(Map<String, dynamic> json) {
return RejectInviteResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..message = json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>);
}
EmptyResponse _$EmptyResponseFromJson(Map<String, dynamic> json) {
return EmptyResponse()..duration = json['duration'] as String?;
}
ChannelStateResponse _$ChannelStateResponseFromJson(Map<String, dynamic> json) {
return ChannelStateResponse()
..duration = json['duration'] as String?
..channel = ChannelModel.fromJson(json['channel'] as Map<String, dynamic>)
..messages = (json['messages'] as List<dynamic>?)
?.map((e) => Message.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..members = (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[]
..watcherCount = json['watcher_count'] as int? ?? 0
..read = (json['read'] as List<dynamic>?)
?.map((e) => Read.fromJson(e as Map<String, dynamic>))
.toList() ??
[];
}
@@ -0,0 +1,79 @@
import 'package:logging/logging.dart';
import 'package:stream_chat/src/core/api/channel_api.dart';
import 'package:stream_chat/src/core/api/device_api.dart';
import 'package:stream_chat/src/core/api/general_api.dart';
import 'package:stream_chat/src/core/api/guest_api.dart';
import 'package:stream_chat/src/core/api/message_api.dart';
import 'package:stream_chat/src/core/api/moderation_api.dart';
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/api/user_api.dart';
import 'package:stream_chat/src/core/http/token_manager.dart';
import 'package:stream_chat/src/core/api/attachment_file_uploader.dart';
export 'device_api.dart' show PushProvider;
///
class StreamChatApi {
///
StreamChatApi(
String apiKey, {
StreamHttpClient? client,
StreamHttpClientOptions? options,
TokenManager? tokenManager,
ConnectionIdManager? connectionIdManager,
AttachmentFileUploader? attachmentFileUploader,
Logger? logger,
}) : _fileUploader = attachmentFileUploader,
_client = client ??
StreamHttpClient(
apiKey,
options: options,
tokenManager: tokenManager,
connectionIdManager: connectionIdManager,
logger: logger,
);
final StreamHttpClient _client;
UserApi? _user;
///
UserApi get user => _user ??= UserApi(_client);
GuestApi? _guest;
///
GuestApi get guest => _guest ??= GuestApi(_client);
MessageApi? _message;
///
MessageApi get message => _message ??= MessageApi(_client);
ChannelApi? _channel;
///
ChannelApi get channel => _channel ??= ChannelApi(_client);
DeviceApi? _device;
///
DeviceApi get device => _device ??= DeviceApi(_client);
ModerationApi? _moderation;
///
ModerationApi get moderation => _moderation ??= ModerationApi(_client);
GeneralApi? _general;
///
GeneralApi get general => _general ??= GeneralApi(_client);
AttachmentFileUploader? _fileUploader;
///
AttachmentFileUploader get fileUploader =>
_fileUploader ??= StreamAttachmentFileUploader(_client);
}
@@ -0,0 +1,49 @@
import 'dart:convert';
import 'package:stream_chat/src/core/api/requests.dart';
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_http_client.dart';
import 'package:stream_chat/src/core/models/filter.dart';
import 'package:stream_chat/src/core/models/user.dart';
///
class UserApi {
///
UserApi(this._client);
final StreamHttpClient _client;
/// Requests users with a given query.
Future<QueryUsersResponse> queryUsers({
bool presence = false,
Filter? filter,
List<SortOption>? sort,
PaginationParams? pagination,
}) async {
final response = await _client.get(
'/users',
queryParameters: {
'payload': jsonEncode({
'presence': presence,
if (sort != null) 'sort': sort,
if (filter != null) 'filter_conditions': filter,
if (pagination != null) ...pagination.toJson(),
}),
},
);
return QueryUsersResponse.fromJson(response.data);
}
/// Batch update a list of users
Future<UpdateUsersResponse> updateUsers(
List<User> users,
) async {
final response = await _client.post(
'/users',
data: {
'users': {for (final user in users) user.id: user},
},
);
return UpdateUsersResponse.fromJson(response.data);
}
}
@@ -0,0 +1,27 @@
// ignore_for_file: use_setters_to_change_properties
///
class ConnectionIdManager {
///
ConnectionIdManager({
String? connectionId,
}) : _connectionId = connectionId;
String? _connectionId;
///
String? get connectionId => _connectionId;
///
bool get hasConnectionId => _connectionId != null;
///
void setConnectionId(String connectionId) {
_connectionId = connectionId;
}
///
void reset() {
_connectionId = null;
}
}
@@ -0,0 +1,91 @@
import 'package:dio/dio.dart';
import 'package:stream_chat/src/core/api/responses.dart';
import 'package:stream_chat/src/core/http/stream_chat_dio_error.dart';
import 'package:stream_chat/src/core/http/token.dart';
import 'package:stream_chat/src/core/http/token_manager.dart';
import 'package:stream_chat/src/errors/chat_error_code.dart';
import 'package:stream_chat/src/errors/stream_chat_error.dart';
///
class AuthInterceptor extends Interceptor {
///
AuthInterceptor(this._httpClient, this._tokenManager);
final Dio _httpClient;
///
final TokenManager _tokenManager;
@override
Future<void> onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
late Token token;
try {
token = await _tokenManager.loadToken();
} catch (_) {
final error = StreamChatError(ChatErrorCode.undefinedToken);
final dioError = StreamChatDioError(
error: error,
requestOptions: options,
);
return handler.reject(dioError);
}
final params = {'user_id': token.userId};
final headers = {
'Authorization': token.rawValue,
'stream-auth-type': token.authType.raw,
};
options..queryParameters.addAll(params)..headers.addAll(headers);
return handler.next(options);
}
@override
void onError(
DioError err,
ErrorInterceptorHandler handler,
) async {
ErrorResponse? error;
final data = err.response?.data;
if (data != null) error = ErrorResponse.fromJson(data);
if (error?.code == ChatErrorCode.tokenExpired.code) {
if (_tokenManager.isStatic) return handler.next(err);
_httpClient.lock();
await _tokenManager.loadToken(refresh: true);
_httpClient.unlock();
try {
final options = err.requestOptions;
final response = await _httpClient.request(
options.path,
cancelToken: options.cancelToken,
data: options.data,
onReceiveProgress: options.onReceiveProgress,
onSendProgress: options.onSendProgress,
queryParameters: options.queryParameters,
options: Options(
method: options.method,
sendTimeout: options.sendTimeout,
receiveTimeout: options.receiveTimeout,
extra: options.extra,
headers: options.headers,
responseType: options.responseType,
contentType: options.contentType,
validateStatus: options.validateStatus,
receiveDataWhenStatusError: options.receiveDataWhenStatusError,
followRedirects: options.followRedirects,
maxRedirects: options.maxRedirects,
requestEncoder: options.requestEncoder,
responseDecoder: options.responseDecoder,
listFormat: options.listFormat,
),
);
return handler.resolve(response);
} on DioError catch (error) {
return handler.reject(error);
}
}
return handler.next(err);
}
}
@@ -0,0 +1,25 @@
import 'package:dio/dio.dart';
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
///
class ConnectionIdInterceptor extends Interceptor {
///
ConnectionIdInterceptor(this.connectionIdManager);
///
final ConnectionIdManager connectionIdManager;
@override
void onRequest(
RequestOptions options,
RequestInterceptorHandler handler,
) async {
if (connectionIdManager.hasConnectionId) {
options.queryParameters.addAll({
'connection_id': connectionIdManager.connectionId,
});
}
handler.next(options);
}
}
@@ -0,0 +1,338 @@
// ignore_for_file: lines_longer_than_80_chars
import 'dart:math' as math;
import 'package:dio/dio.dart';
///
enum InterceptStep {
///
request,
///
response,
///
error,
}
///
typedef LogPrint = void Function(InterceptStep step, Object object);
void _defaultLogPrint(InterceptStep step, Object object) => print(object);
///
class LoggingInterceptor extends Interceptor {
///
LoggingInterceptor({
this.request = true,
this.requestHeader = false,
this.requestBody = true,
this.responseHeader = false,
this.responseBody = true,
this.error = true,
this.maxWidth = 120,
this.compact = true,
this.logPrint = _defaultLogPrint,
});
/// Print request [Options]
final bool request;
/// Print request header [Options.headers]
final bool requestHeader;
/// Print request data [Options.data]
final bool requestBody;
/// Print [Response.data]
final bool responseBody;
/// Print [Response.headers]
final bool responseHeader;
/// Print error message
final bool error;
/// InitialTab count to logPrint json response
static const int initialTab = 1;
/// 1 tab length
static const String tabStep = ' ';
/// Print compact json response
final bool compact;
/// Width size per logPrint
final int maxWidth;
/// Log printer; defaults logPrint log to console.
/// In flutter, you'd better use debugPrint.
/// you can also write log in a file.
void Function(InterceptStep step, Object object) logPrint;
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
if (request) {
_printRequestHeader(_logPrintRequest, options);
}
if (requestHeader) {
_printMapAsTable(
_logPrintRequest,
options.queryParameters,
header: 'Query Parameters',
);
final requestHeaders = <String, Object?>{...options.headers};
requestHeaders['contentType'] = options.contentType?.toString();
requestHeaders['responseType'] = options.responseType.toString();
requestHeaders['followRedirects'] = options.followRedirects;
requestHeaders['connectTimeout'] = options.connectTimeout;
requestHeaders['receiveTimeout'] = options.receiveTimeout;
_printMapAsTable(_logPrintRequest, requestHeaders, header: 'Headers');
_printMapAsTable(_logPrintRequest, options.extra, header: 'Extras');
}
if (requestBody && options.method != 'GET') {
final dynamic data = options.data;
if (data != null) {
if (data is Map) {
_printMapAsTable(
_logPrintRequest,
options.data as Map?,
header: 'Body',
);
} else if (data is FormData) {
final formDataMap = <String, dynamic>{}
..addEntries(data.fields)
..addEntries(data.files);
_printMapAsTable(_logPrintRequest, formDataMap,
header: 'Form data | ${data.boundary}');
} else {
_printBlock(_logPrintRequest, data.toString());
}
}
}
super.onRequest(options, handler);
}
@override
void onError(DioError err, ErrorInterceptorHandler handler) {
if (error) {
if (err.type == DioErrorType.response) {
final uri = err.response?.requestOptions.uri;
_printBoxed(
_logPrintError,
header:
'DioError ║ Status: ${err.response?.statusCode} ${err.response?.statusMessage}',
text: uri.toString(),
);
if (err.response != null && err.response?.data != null) {
_logPrintError('${err.type.toString()}');
_printResponse(_logPrintError, err.response!);
}
_printLine(_logPrintError, '');
_logPrintError('');
} else {
_printBoxed(
_logPrintError,
header: 'DioError ║ ${err.type}',
text: err.message,
);
_printRequestHeader(_logPrintError, err.requestOptions);
}
}
super.onError(err, handler);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
_printResponseHeader(_logPrintResponse, response);
if (responseHeader) {
final responseHeaders = <String, String>{};
response.headers
.forEach((k, list) => responseHeaders[k] = list.toString());
_printMapAsTable(_logPrintResponse, responseHeaders, header: 'Headers');
}
if (responseBody) {
_logPrintResponse('╔ Body');
_logPrintResponse('');
_printResponse(_logPrintResponse, response);
_logPrintResponse('');
_printLine(_logPrintResponse, '');
}
super.onResponse(response, handler);
}
void _printBoxed(
void Function(Object) logPrint, {
String? header,
String? text,
}) {
logPrint('');
logPrint('╔╣ $header');
logPrint('$text');
_printLine(logPrint, '');
}
void _printResponse(void Function(Object) logPrint, Response response) {
if (response.data != null) {
if (response.data is Map) {
_printPrettyMap(logPrint, response.data as Map);
} else if (response.data is List) {
logPrint('${_indent()}[');
_printList(logPrint, response.data as List);
logPrint('${_indent()}[');
} else {
_printBlock(logPrint, response.data.toString());
}
}
}
void _printResponseHeader(void Function(Object) logPrint, Response response) {
final uri = response.requestOptions.uri;
final method = response.requestOptions.method;
_printBoxed(
logPrint,
header:
'Response ║ $method ║ Status: ${response.statusCode} ${response.statusMessage}',
text: uri.toString(),
);
}
void _printRequestHeader(
void Function(Object) logPrint, RequestOptions options) {
final uri = options.uri;
final method = options.method;
_printBoxed(logPrint, header: 'Request ║ $method ', text: uri.toString());
}
void _printLine(void Function(Object) logPrint,
[String pre = '', String suf = '']) =>
logPrint('$pre${'' * maxWidth}$suf');
void _printKV(void Function(Object) logPrint, String? key, Object? v) {
final pre = '$key: ';
final msg = v.toString();
if (pre.length + msg.length > maxWidth) {
logPrint(pre);
_printBlock(logPrint, msg);
} else {
logPrint('$pre$msg');
}
}
void _printBlock(void Function(Object) logPrint, String msg) {
final lines = (msg.length / maxWidth).ceil();
for (var i = 0; i < lines; ++i) {
logPrint((i >= 0 ? '' : '') +
msg.substring(i * maxWidth,
math.min<int>(i * maxWidth + maxWidth, msg.length)));
}
}
String _indent([int tabCount = initialTab]) => tabStep * tabCount;
void _printPrettyMap(
void Function(Object) logPrint,
Map data, {
int tabs = initialTab,
bool isListItem = false,
bool isLast = false,
}) {
var _tabs = tabs;
final isRoot = _tabs == initialTab;
final initialIndent = _indent(_tabs);
_tabs++;
if (isRoot || isListItem) logPrint('$initialIndent{');
data.keys.toList().asMap().forEach((index, dynamic key) {
final isLast = index == data.length - 1;
dynamic value = data[key];
if (value is String) {
value = '"${value.toString().replaceAll(RegExp(r'(\r|\n)+'), " ")}"';
}
if (value is Map) {
if (compact) {
logPrint('${_indent(_tabs)} $key: $value${!isLast ? ',' : ''}');
} else {
logPrint('${_indent(_tabs)} $key: {');
_printPrettyMap(logPrint, value, tabs: _tabs);
}
} else if (value is List) {
if (compact) {
logPrint('${_indent(_tabs)} $key: ${value.toString()}');
} else {
logPrint('${_indent(_tabs)} $key: [');
_printList(logPrint, value, tabs: _tabs);
logPrint('${_indent(_tabs)} ]${isLast ? '' : ','}');
}
} else {
final msg = value.toString().replaceAll('\n', '');
final indent = _indent(_tabs);
final linWidth = maxWidth - indent.length;
if (msg.length + indent.length > linWidth) {
final lines = (msg.length / linWidth).ceil();
for (var i = 0; i < lines; ++i) {
logPrint('${_indent(_tabs)} ${msg.substring(
i * linWidth,
math.min<int>(i * linWidth + linWidth, msg.length),
)}');
}
} else {
logPrint('${_indent(_tabs)} $key: $msg${!isLast ? ',' : ''}');
}
}
});
logPrint('$initialIndent}${isListItem && !isLast ? ',' : ''}');
}
void _printList(
void Function(Object) logPrint,
List list, {
int tabs = initialTab,
}) {
list.asMap().forEach((i, dynamic e) {
final isLast = i == list.length - 1;
if (e is Map) {
if (compact) {
logPrint('${_indent(tabs)} $e${!isLast ? ',' : ''}');
} else {
_printPrettyMap(logPrint, e,
tabs: tabs + 1, isListItem: true, isLast: isLast);
}
} else {
logPrint('${_indent(tabs + 2)} $e${isLast ? '' : ','}');
}
});
}
bool _canFlattenMap(Map map) =>
map.values.where((dynamic val) => val is Map || val is List).isEmpty &&
map.toString().length < maxWidth;
bool _canFlattenList(List list) =>
list.length < 10 && list.toString().length < maxWidth;
void _printMapAsTable(
void Function(Object) logPrint,
Map? map, {
String? header,
}) {
if (map == null || map.isEmpty) return;
logPrint('$header ');
map.forEach((dynamic key, dynamic value) =>
_printKV(logPrint, key.toString(), value));
_printLine(logPrint, '');
}
void _logPrintRequest(Object object) =>
logPrint(InterceptStep.request, object);
void _logPrintResponse(Object object) =>
logPrint(InterceptStep.response, object);
void _logPrintError(Object object) => logPrint(InterceptStep.error, object);
}
@@ -0,0 +1,21 @@
import 'package:dio/dio.dart';
import 'package:stream_chat/src/errors/stream_chat_error.dart';
///
class StreamChatDioError extends DioError {
///
StreamChatDioError({
required this.error,
required RequestOptions requestOptions,
Response? response,
DioErrorType type = DioErrorType.other,
}) : super(
error: error,
requestOptions: requestOptions,
response: response,
type: type,
);
@override
final StreamChatError error;
}
@@ -0,0 +1,241 @@
import 'dart:async';
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:logging/logging.dart';
import 'package:meta/meta.dart';
import 'package:stream_chat/src/core/http/interceptor/auth_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/connection_id_interceptor.dart';
import 'package:stream_chat/src/core/http/interceptor/logging_interceptor.dart';
import 'package:stream_chat/src/core/http/stream_chat_dio_error.dart';
import 'package:stream_chat/src/core/http/token_manager.dart';
import 'package:stream_chat/src/errors/stream_chat_error.dart';
import 'package:stream_chat/src/platform_detector/platform_detector.dart';
import 'package:stream_chat/version.dart';
import 'package:stream_chat/src/core/http/connection_id_manager.dart';
part 'stream_http_client_options.dart';
/// This is where we configure the base url, headers,
/// query parameters and convenient methods for http verbs with error parsing.
class StreamHttpClient {
/// [StreamHttpClient] constructor
StreamHttpClient(
this.apiKey, {
Dio? dio,
StreamHttpClientOptions? options,
TokenManager? tokenManager,
ConnectionIdManager? connectionIdManager,
Logger? logger,
}) : _options = options ?? const StreamHttpClientOptions(),
httpClient = dio ?? Dio() {
httpClient
..options.baseUrl = _options.baseUrl
..options.receiveTimeout = _options.receiveTimeout.inMilliseconds
..options.connectTimeout = _options.connectTimeout.inMilliseconds
..options.queryParameters = {'api_key': apiKey}
..options.headers = {
'Content-Type': 'application/json',
'X-Stream-Client': _options.userAgent,
'Content-Encoding': 'application/gzip',
}
..interceptors.addAll([
if (tokenManager != null) AuthInterceptor(httpClient, tokenManager),
if (connectionIdManager != null)
ConnectionIdInterceptor(connectionIdManager),
if (logger != null && logger.level != Level.OFF)
LoggingInterceptor(
requestHeader: true,
logPrint: (step, message) {
switch (step) {
case InterceptStep.request:
return logger.info(message);
case InterceptStep.response:
return logger.info(message);
case InterceptStep.error:
return logger.severe(message);
}
},
),
]);
}
/// Your project Stream Chat api key.
/// Find your API keys here https://getstream.io/dashboard/
final String apiKey;
/// Your project Stream Chat ClientOptions
final StreamHttpClientOptions _options;
/// [Dio] httpClient
/// It's been chosen because it's easy to use
/// and supports interesting features out of the box
/// (Interceptors, Global configuration, FormData, File downloading etc.)
@visibleForTesting
final Dio httpClient;
/// Shuts down the [httpClient].
///
/// If [force] is `false` (the default) the [httpClient] will be kept alive
/// until all active connections are done. If [force] is `true` any active
/// connections will be closed to immediately release all resources. These
/// closed connections will receive an error event to indicate that the client
/// was shut down. In both cases trying to establish a new connection after
/// calling [close] will throw an exception.
void close({bool force = false}) => httpClient.close(force: force);
StreamChatNetworkError _parseError(DioError err) {
// locally thrown dio error
if (err is StreamChatDioError) {
final code = err.error.code;
final message = err.error.message;
return StreamChatNetworkError.raw(code: code, message: message);
}
// real network request dio error
return StreamChatNetworkError.fromDioError(err);
}
/// Handy method to make http GET request with error parsing.
Future<Response<T>> get<T>(
String path, {
Map<String, Object?>? queryParameters,
Map<String, Object?>? headers,
ProgressCallback? onReceiveProgress,
CancelToken? cancelToken,
}) async {
try {
final response = await httpClient.get<T>(
path,
queryParameters: queryParameters,
options: Options(headers: headers),
onReceiveProgress: onReceiveProgress,
cancelToken: cancelToken,
);
return response;
} on DioError catch (error) {
throw _parseError(error);
}
}
/// Handy method to make http POST request with error parsing.
Future<Response<T>> post<T>(
String path, {
Object? data,
Map<String, Object?>? queryParameters,
Map<String, Object?>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
CancelToken? cancelToken,
}) async {
try {
final response = await httpClient.post<T>(
path,
queryParameters: queryParameters,
data: data,
options: Options(headers: headers),
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
cancelToken: cancelToken,
);
return response;
} on DioError catch (error) {
throw _parseError(error);
}
}
/// Handy method to make http DELETE request with error parsing.
Future<Response<T>> delete<T>(
String path, {
Map<String, Object?>? queryParameters,
Map<String, Object?>? headers,
CancelToken? cancelToken,
}) async {
try {
final response = await httpClient.delete<T>(
path,
queryParameters: queryParameters,
options: Options(headers: headers),
cancelToken: cancelToken,
);
return response;
} on DioError catch (error) {
throw _parseError(error);
}
}
/// Handy method to make http PATCH request with error parsing.
Future<Response<T>> patch<T>(
String path, {
Object? data,
Map<String, Object?>? queryParameters,
Map<String, Object?>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
CancelToken? cancelToken,
}) async {
try {
final response = await httpClient.patch<T>(
path,
queryParameters: queryParameters,
data: data,
options: Options(headers: headers),
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
cancelToken: cancelToken,
);
return response;
} on DioError catch (error) {
throw _parseError(error);
}
}
/// Handy method to make http PUT request with error parsing.
Future<Response<T>> put<T>(
String path, {
Object? data,
Map<String, Object?>? queryParameters,
Map<String, Object?>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
CancelToken? cancelToken,
}) async {
try {
final response = await httpClient.put<T>(
path,
queryParameters: queryParameters,
data: data,
options: Options(headers: headers),
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
cancelToken: cancelToken,
);
return response;
} on DioError catch (error) {
throw _parseError(error);
}
}
/// Handy method to post files with error parsing.
Future<Response<T>> postFile<T>(
String path,
MultipartFile file, {
Map<String, Object?>? queryParameters,
Map<String, Object?>? headers,
ProgressCallback? onSendProgress,
ProgressCallback? onReceiveProgress,
CancelToken? cancelToken,
}) async {
final formData = FormData.fromMap({'file': file});
final response = await post<T>(
path,
data: formData,
queryParameters: queryParameters,
headers: headers,
onSendProgress: onSendProgress,
onReceiveProgress: onReceiveProgress,
cancelToken: cancelToken,
);
return response;
}
}
@@ -0,0 +1,69 @@
part of 'stream_http_client.dart';
///
enum Location {
///
usEast,
///
euWest,
///
mumbai,
///
sydney,
///
singapore,
}
///
extension LocationX on Location {
///
String get name => {
Location.usEast: 'us-east',
Location.euWest: 'dublin',
Location.mumbai: 'mumbai',
Location.sydney: 'sydney',
Location.singapore: 'singapore',
}[this]!;
}
const _defaultBaseURL = 'https://chat-us-east-1.stream-io-api.com';
/// Client options to modify [StreamHttpClient]
class StreamHttpClientOptions {
/// Instantiates a new [StreamHttpClientOptions]
const StreamHttpClientOptions({
String? baseUrl,
this.location,
this.connectTimeout = const Duration(seconds: 6),
this.receiveTimeout = const Duration(seconds: 6),
}) : _baseUrl = baseUrl ?? _defaultBaseURL;
final String _baseUrl;
/// base url to use with client.
String get baseUrl {
if (location == null) return _baseUrl;
const serviceName = 'chat';
final locationName = location!.name;
const baseDomainName = 'stream-io-api.com';
return 'https://$serviceName-proxy-$locationName.$baseDomainName';
}
/// data center to use with client
final Location? location;
/// connect timeout, default to 6s
final Duration connectTimeout;
/// received timeout, default to 6s
final Duration receiveTimeout;
/// Get the current user agent
String get userAgent => 'stream-chat-dart-client-'
'${CurrentPlatform.name}-'
'${PACKAGE_VERSION.split('+')[0]}';
}
@@ -0,0 +1,85 @@
import 'dart:convert';
import 'package:equatable/equatable.dart';
import 'package:jose/jose.dart';
import 'package:stream_chat/src/core/models/user.dart';
import 'package:stream_chat/src/core/utils.dart';
///
typedef GuestTokenProvider = Future<String> Function(User user);
///
enum AuthType {
///
jwt,
///
anonymous,
}
///
extension AuthTypeX on AuthType {
///
String get raw => {
AuthType.jwt: 'jwt',
AuthType.anonymous: 'anonymous',
}[this]!;
}
/// Token designed to store the JWT and the user it is related to.
class Token extends Equatable {
const Token._({
required this.rawValue,
required this.userId,
required this.authType,
});
/// The token that can be used when user is unknown.
/// Is used by `anonymous` token provider.
factory Token.anonymous({String? userId}) => Token._(
rawValue: '',
userId: userId ?? randomId(),
authType: AuthType.anonymous,
);
/// Creates a [Token] instance from the provided [rawValue] if it's valid.
factory Token.fromRawValue(String rawValue) {
final jwtBody = JsonWebToken.unverified(rawValue);
final userId = jwtBody.claims.getTyped<String>('user_id');
assert(
userId != null,
'Invalid `token`, It should contain `user_id`',
);
return Token._(rawValue: rawValue, userId: userId!, authType: AuthType.jwt);
}
/// The token which can be used during the development.
/// Is used by `development(userId:)` token provider.
factory Token.development(String userId) {
const devSignature = 'devtoken';
const header = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9';
final payload = json.encode({'user_id': userId});
final payloadBytes = utf8.encode(payload);
final payloadB64 = base64.encode(payloadBytes);
final jwt = '$header.$payloadB64.$devSignature';
return Token._(rawValue: jwt, userId: userId, authType: AuthType.jwt);
}
/// The token which designed to be used for guest users.
static Future<Token> guest(User user, GuestTokenProvider provider) async {
final rawToken = await provider(user);
return Token.fromRawValue(rawToken);
}
///
final AuthType authType;
///
final String rawValue;
///
final String userId;
@override
List<Object?> get props => [authType, rawValue, userId];
}
@@ -0,0 +1,80 @@
import 'package:stream_chat/src/core/http/token.dart';
/// A function which can be used to request a Stream Chat API token from your
/// own backend server. Function requires a single [userId].
typedef TokenProvider = Future<String> Function(String userId);
///
class TokenManager {
///
TokenManager({
String? userId,
Token? token,
TokenProvider? tokenProvider,
}) : _userId = userId,
_token = token,
_provider = tokenProvider;
String? _type;
Token? _token;
TokenProvider? _provider;
String? _userId;
/// User id to which this TokenManager is configured to
String? get userId => _userId;
///
bool get isStatic => _type == 'static';
///
Future<Token> setTokenOrProvider(
String userId, {
Token? token,
TokenProvider? provider,
}) async {
assert(() {
if (token == null && provider == null) {
throw AssertionError('Provide at-least token or provider');
}
if (token != null && provider != null) {
throw AssertionError("Can't set both token and provider");
}
return true;
}(), '');
_userId = userId;
if (token != null) {
_type = 'static';
_token = token;
}
if (provider != null) {
_type = 'provider';
_provider = provider;
}
return loadToken();
}
///
Future<Token> loadToken({bool refresh = false}) async {
assert(
_userId != null && _type != null,
'Please call `setTokenOrProvider` before calling `loadToken`',
);
if (refresh || _token == null) {
final rawValue = await _provider!(_userId!);
_token = Token.fromRawValue(rawValue);
}
return _token!;
}
///
void reset() {
_userId = null;
_token = null;
_provider = null;
}
}
@@ -0,0 +1,38 @@
import 'package:json_annotation/json_annotation.dart';
part 'action.g.dart';
/// The class that contains the information about an action
@JsonSerializable()
class Action {
/// Constructor used for json serialization
Action({
required this.name,
this.style = 'default',
required this.text,
required this.type,
this.value,
});
/// Create a new instance from a json
factory Action.fromJson(Map<String, dynamic> json) => _$ActionFromJson(json);
/// The name of the action
final String name;
/// The style of the action
@JsonKey(defaultValue: 'default')
final String style;
/// The test of the action
final String text;
/// The type of the action
final String type;
/// The value of the action
final String? value;
/// Serialize to json
Map<String, dynamic> toJson() => _$ActionToJson(this);
}
@@ -0,0 +1,25 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'action.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Action _$ActionFromJson(Map<String, dynamic> json) {
return Action(
name: json['name'] as String,
style: json['style'] as String? ?? 'default',
text: json['text'] as String,
type: json['type'] as String,
value: json['value'] as String?,
);
}
Map<String, dynamic> _$ActionToJson(Action instance) => <String, dynamic>{
'name': instance.name,
'style': instance.style,
'text': instance.text,
'type': instance.type,
'value': instance.value,
};
@@ -0,0 +1,238 @@
// ignore_for_file: public_member_api_docs
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/action.dart';
import 'package:stream_chat/src/core/models/attachment_file.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:uuid/uuid.dart';
part 'attachment.g.dart';
/// The class that contains the information about an attachment
@JsonSerializable(includeIfNull: false)
class Attachment extends Equatable {
/// Constructor used for json serialization
Attachment({
String? id,
this.type,
this.titleLink,
String? title,
this.thumbUrl,
this.text,
this.pretext,
this.ogScrapeUrl,
this.imageUrl,
this.footerIcon,
this.footer,
this.fields,
this.fallback,
this.color,
this.authorName,
this.authorLink,
this.authorIcon,
this.assetUrl,
List<Action>? actions,
this.extraData = const {},
this.file,
UploadState? uploadState,
}) : id = id ?? const Uuid().v4(),
title = title ?? file?.name,
localUri = file?.path != null ? Uri.parse(file!.path!) : null,
actions = actions ?? [] {
this.uploadState = uploadState ??
((assetUrl != null || imageUrl != null)
? const UploadState.success()
: const UploadState.preparing());
}
/// Create a new instance from a json
factory Attachment.fromJson(Map<String, dynamic> json) =>
_$AttachmentFromJson(
Serialization.moveToExtraDataFromRoot(json, topLevelFields));
/// Create a new instance from a db data
factory Attachment.fromData(Map<String, dynamic> json) =>
_$AttachmentFromJson(Serialization.moveToExtraDataFromRoot(
json, topLevelFields + dbSpecificTopLevelFields));
///The attachment type based on the URL resource. This can be: audio,
///image or video
final String? type;
///The link to which the attachment message points to.
final String? titleLink;
/// The attachment title
final String? title;
/// The URL to the attached file thumbnail. You can use this to represent the
/// attached link.
final String? thumbUrl;
/// The attachment text. It will be displayed in the channel next to the
/// original message.
final String? text;
/// Optional text that appears above the attachment block
final String? pretext;
/// The original URL that was used to scrape this attachment.
final String? ogScrapeUrl;
/// The URL to the attached image. This is present for URL pointing to an
/// image article (eg. Unsplash)
final String? imageUrl;
final String? footerIcon;
final String? footer;
final dynamic fields;
final String? fallback;
final String? color;
/// The name of the author.
final String? authorName;
final String? authorLink;
final String? authorIcon;
/// The URL to the audio, video or image related to the URL.
final String? assetUrl;
/// Actions from a command
@JsonKey(defaultValue: [])
final List<Action> actions;
final Uri? localUri;
/// The file present inside this attachment.
final AttachmentFile? file;
/// The current upload state of the attachment
late final UploadState uploadState;
/// Map of custom channel extraData
@JsonKey(
includeIfNull: false,
defaultValue: {},
)
final Map<String, Object?> extraData;
/// The attachment ID.
///
/// This is created locally for uniquely identifying a attachment.
final String id;
/// Known top level fields.
/// Useful for [Serialization] methods.
static const topLevelFields = [
'type',
'title_link',
'title',
'thumb_url',
'text',
'pretext',
'og_scrape_url',
'image_url',
'footer_icon',
'footer',
'fields',
'fallback',
'color',
'author_name',
'author_link',
'author_icon',
'asset_url',
'actions',
];
/// Known db specific top level fields.
/// Useful for [Serialization] methods.
static const dbSpecificTopLevelFields = [
'id',
'upload_state',
'file',
];
/// Serialize to json
Map<String, dynamic> toJson() =>
Serialization.moveFromExtraDataToRoot(_$AttachmentToJson(this))
..removeWhere((key, value) => dbSpecificTopLevelFields.contains(key));
/// Serialize to db data
Map<String, dynamic> toData() =>
Serialization.moveFromExtraDataToRoot(_$AttachmentToJson(this));
Attachment copyWith({
String? id,
String? type,
String? titleLink,
String? title,
String? thumbUrl,
String? text,
String? pretext,
String? ogScrapeUrl,
String? imageUrl,
String? footerIcon,
String? footer,
dynamic fields,
String? fallback,
String? color,
String? authorName,
String? authorLink,
String? authorIcon,
String? assetUrl,
List<Action>? actions,
AttachmentFile? file,
UploadState? uploadState,
Map<String, Object?>? extraData,
}) =>
Attachment(
id: id ?? this.id,
type: type ?? this.type,
titleLink: titleLink ?? this.titleLink,
title: title ?? this.title,
thumbUrl: thumbUrl ?? this.thumbUrl,
text: text ?? this.text,
pretext: pretext ?? this.pretext,
ogScrapeUrl: ogScrapeUrl ?? this.ogScrapeUrl,
imageUrl: imageUrl ?? this.imageUrl,
footerIcon: footerIcon ?? this.footerIcon,
footer: footer ?? this.footer,
fields: fields ?? this.fields,
fallback: fallback ?? this.fallback,
color: color ?? this.color,
authorName: authorName ?? this.authorName,
authorLink: authorLink ?? this.authorLink,
authorIcon: authorIcon ?? this.authorIcon,
assetUrl: assetUrl ?? this.assetUrl,
actions: actions ?? this.actions,
file: file ?? this.file,
uploadState: uploadState ?? this.uploadState,
extraData: extraData ?? this.extraData,
);
@override
List<Object?> get props => [
id,
type,
titleLink,
title,
thumbUrl,
text,
pretext,
ogScrapeUrl,
imageUrl,
footerIcon,
footer,
fields,
fallback,
color,
authorName,
authorLink,
authorIcon,
assetUrl,
actions,
file,
uploadState,
extraData,
];
}
@@ -0,0 +1,75 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'attachment.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Attachment _$AttachmentFromJson(Map<String, dynamic> json) {
return Attachment(
id: json['id'] as String?,
type: json['type'] as String?,
titleLink: json['title_link'] as String?,
title: json['title'] as String?,
thumbUrl: json['thumb_url'] as String?,
text: json['text'] as String?,
pretext: json['pretext'] as String?,
ogScrapeUrl: json['og_scrape_url'] as String?,
imageUrl: json['image_url'] as String?,
footerIcon: json['footer_icon'] as String?,
footer: json['footer'] as String?,
fields: json['fields'],
fallback: json['fallback'] as String?,
color: json['color'] as String?,
authorName: json['author_name'] as String?,
authorLink: json['author_link'] as String?,
authorIcon: json['author_icon'] as String?,
assetUrl: json['asset_url'] as String?,
actions: (json['actions'] as List<dynamic>?)
?.map((e) => Action.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
file: json['file'] == null
? null
: AttachmentFile.fromJson(json['file'] as Map<String, dynamic>),
uploadState: json['upload_state'] == null
? null
: UploadState.fromJson(json['upload_state'] as Map<String, dynamic>),
);
}
Map<String, dynamic> _$AttachmentToJson(Attachment instance) {
final val = <String, dynamic>{};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('type', instance.type);
writeNotNull('title_link', instance.titleLink);
writeNotNull('title', instance.title);
writeNotNull('thumb_url', instance.thumbUrl);
writeNotNull('text', instance.text);
writeNotNull('pretext', instance.pretext);
writeNotNull('og_scrape_url', instance.ogScrapeUrl);
writeNotNull('image_url', instance.imageUrl);
writeNotNull('footer_icon', instance.footerIcon);
writeNotNull('footer', instance.footer);
writeNotNull('fields', instance.fields);
writeNotNull('fallback', instance.fallback);
writeNotNull('color', instance.color);
writeNotNull('author_name', instance.authorName);
writeNotNull('author_link', instance.authorLink);
writeNotNull('author_icon', instance.authorIcon);
writeNotNull('asset_url', instance.assetUrl);
val['actions'] = instance.actions.map((e) => e.toJson()).toList();
writeNotNull('file', instance.file?.toJson());
val['upload_state'] = instance.uploadState.toJson();
val['extra_data'] = instance.extraData;
val['id'] = instance.id;
return val;
}
@@ -0,0 +1,98 @@
import 'dart:typed_data';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:meta/meta.dart';
part 'attachment_file.freezed.dart';
part 'attachment_file.g.dart';
/// Union class to hold various [UploadState] of a attachment.
@freezed
class UploadState with _$UploadState {
/// Preparing state of the union
const factory UploadState.preparing() = Preparing;
/// InProgress state of the union
const factory UploadState.inProgress({
required int uploaded,
required int total,
}) = InProgress;
/// Success state of the union
const factory UploadState.success() = Success;
/// Failed state of the union
const factory UploadState.failed({required String error}) = Failed;
/// Creates a new instance from a json
factory UploadState.fromJson(Map<String, dynamic> json) =>
_$UploadStateFromJson(json);
}
/// Helper extension for UploadState
extension UploadStateX on UploadState? {
/// Returns true if state is [Preparing]
bool get isPreparing => this is Preparing;
/// Returns true if state is [InProgress]
bool get isInProgress => this is InProgress;
/// Returns true if state is [Success]
bool get isSuccess => this is Success;
/// Returns true if state is [Failed]
bool get isFailed => this is Failed;
}
Uint8List? _fromString(String? bytes) {
if (bytes == null) return null;
return Uint8List.fromList(bytes.codeUnits);
}
String? _toString(Uint8List? bytes) {
if (bytes == null) return null;
return String.fromCharCodes(bytes);
}
/// The class that contains the information about an attachment file
@JsonSerializable()
class AttachmentFile {
/// Creates a new [AttachmentFile] instance.
const AttachmentFile({
required this.size,
this.path,
this.name,
this.bytes,
}) : assert(
path != null || bytes != null,
'Either path or bytes should be != null',
);
/// Create a new instance from a json
factory AttachmentFile.fromJson(Map<String, dynamic> json) =>
_$AttachmentFileFromJson(json);
/// The absolute path for a cached copy of this file. It can be used to
/// create a file instance with a descriptor for the given path.
/// ```
/// final File myFile = File(platformFile.path);
/// ```
final String? path;
/// File name including its extension.
final String? name;
/// Byte data for this file. Particularly useful if you want to manipulate
/// its data or easily upload to somewhere else.
@JsonKey(toJson: _toString, fromJson: _fromString)
final Uint8List? bytes;
/// The file size in bytes.
final int? size;
/// File extension for this file.
String? get extension => name?.split('.').last;
/// Serialize to json
Map<String, dynamic> toJson() => _$AttachmentFileToJson(this);
}
@@ -0,0 +1,596 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// 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
part of 'attachment_file.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
UploadState _$UploadStateFromJson(Map<String, dynamic> json) {
switch (json['runtimeType'] as String) {
case 'preparing':
return Preparing.fromJson(json);
case 'inProgress':
return InProgress.fromJson(json);
case 'success':
return Success.fromJson(json);
case 'failed':
return Failed.fromJson(json);
default:
throw FallThroughError();
}
}
/// @nodoc
class _$UploadStateTearOff {
const _$UploadStateTearOff();
Preparing preparing() {
return const Preparing();
}
InProgress inProgress({required int uploaded, required int total}) {
return InProgress(
uploaded: uploaded,
total: total,
);
}
Success success() {
return const Success();
}
Failed failed({required String error}) {
return Failed(
error: error,
);
}
UploadState fromJson(Map<String, Object> json) {
return UploadState.fromJson(json);
}
}
/// @nodoc
const $UploadState = _$UploadStateTearOff();
/// @nodoc
mixin _$UploadState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() preparing,
required TResult Function(int uploaded, int total) inProgress,
required TResult Function() success,
required TResult Function(String error) failed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Preparing value) preparing,
required TResult Function(InProgress value) inProgress,
required TResult Function(Success value) success,
required TResult Function(Failed value) failed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $UploadStateCopyWith<$Res> {
factory $UploadStateCopyWith(
UploadState value, $Res Function(UploadState) then) =
_$UploadStateCopyWithImpl<$Res>;
}
/// @nodoc
class _$UploadStateCopyWithImpl<$Res> implements $UploadStateCopyWith<$Res> {
_$UploadStateCopyWithImpl(this._value, this._then);
final UploadState _value;
// ignore: unused_field
final $Res Function(UploadState) _then;
}
/// @nodoc
abstract class $PreparingCopyWith<$Res> {
factory $PreparingCopyWith(Preparing value, $Res Function(Preparing) then) =
_$PreparingCopyWithImpl<$Res>;
}
/// @nodoc
class _$PreparingCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
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;
}
/// @nodoc
@JsonSerializable()
class _$Preparing implements Preparing {
const _$Preparing();
factory _$Preparing.fromJson(Map<String, dynamic> json) =>
_$_$PreparingFromJson(json);
@override
String toString() {
return 'UploadState.preparing()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is Preparing);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() preparing,
required TResult Function(int uploaded, int total) inProgress,
required TResult Function() success,
required TResult Function(String error) failed,
}) {
return preparing();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
required TResult orElse(),
}) {
if (preparing != null) {
return preparing();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Preparing value) preparing,
required TResult Function(InProgress value) inProgress,
required TResult Function(Success value) success,
required TResult Function(Failed value) failed,
}) {
return preparing(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
required TResult orElse(),
}) {
if (preparing != null) {
return preparing(this);
}
return orElse();
}
@override
Map<String, dynamic> toJson() {
return _$_$PreparingToJson(this)..['runtimeType'] = 'preparing';
}
}
abstract class Preparing implements UploadState {
const factory Preparing() = _$Preparing;
factory Preparing.fromJson(Map<String, dynamic> json) = _$Preparing.fromJson;
}
/// @nodoc
abstract class $InProgressCopyWith<$Res> {
factory $InProgressCopyWith(
InProgress value, $Res Function(InProgress) then) =
_$InProgressCopyWithImpl<$Res>;
$Res call({int uploaded, int total});
}
/// @nodoc
class _$InProgressCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
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;
@override
$Res call({
Object? uploaded = freezed,
Object? total = freezed,
}) {
return _then(InProgress(
uploaded: uploaded == freezed
? _value.uploaded
: uploaded // ignore: cast_nullable_to_non_nullable
as int,
total: total == freezed
? _value.total
: total // ignore: cast_nullable_to_non_nullable
as int,
));
}
}
/// @nodoc
@JsonSerializable()
class _$InProgress implements InProgress {
const _$InProgress({required this.uploaded, required this.total});
factory _$InProgress.fromJson(Map<String, dynamic> json) =>
_$_$InProgressFromJson(json);
@override
final int uploaded;
@override
final int total;
@override
String toString() {
return 'UploadState.inProgress(uploaded: $uploaded, total: $total)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is InProgress &&
(identical(other.uploaded, uploaded) ||
const DeepCollectionEquality()
.equals(other.uploaded, uploaded)) &&
(identical(other.total, total) ||
const DeepCollectionEquality().equals(other.total, total)));
}
@override
int get hashCode =>
runtimeType.hashCode ^
const DeepCollectionEquality().hash(uploaded) ^
const DeepCollectionEquality().hash(total);
@JsonKey(ignore: true)
@override
$InProgressCopyWith<InProgress> get copyWith =>
_$InProgressCopyWithImpl<InProgress>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() preparing,
required TResult Function(int uploaded, int total) inProgress,
required TResult Function() success,
required TResult Function(String error) failed,
}) {
return inProgress(uploaded, total);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
required TResult orElse(),
}) {
if (inProgress != null) {
return inProgress(uploaded, total);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Preparing value) preparing,
required TResult Function(InProgress value) inProgress,
required TResult Function(Success value) success,
required TResult Function(Failed value) failed,
}) {
return inProgress(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
required TResult orElse(),
}) {
if (inProgress != null) {
return inProgress(this);
}
return orElse();
}
@override
Map<String, dynamic> toJson() {
return _$_$InProgressToJson(this)..['runtimeType'] = 'inProgress';
}
}
abstract class InProgress implements UploadState {
const factory InProgress({required int uploaded, required int total}) =
_$InProgress;
factory InProgress.fromJson(Map<String, dynamic> json) =
_$InProgress.fromJson;
int get uploaded => throw _privateConstructorUsedError;
int get total => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$InProgressCopyWith<InProgress> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SuccessCopyWith<$Res> {
factory $SuccessCopyWith(Success value, $Res Function(Success) then) =
_$SuccessCopyWithImpl<$Res>;
}
/// @nodoc
class _$SuccessCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
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;
}
/// @nodoc
@JsonSerializable()
class _$Success implements Success {
const _$Success();
factory _$Success.fromJson(Map<String, dynamic> json) =>
_$_$SuccessFromJson(json);
@override
String toString() {
return 'UploadState.success()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is Success);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() preparing,
required TResult Function(int uploaded, int total) inProgress,
required TResult Function() success,
required TResult Function(String error) failed,
}) {
return success();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
required TResult orElse(),
}) {
if (success != null) {
return success();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Preparing value) preparing,
required TResult Function(InProgress value) inProgress,
required TResult Function(Success value) success,
required TResult Function(Failed value) failed,
}) {
return success(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
required TResult orElse(),
}) {
if (success != null) {
return success(this);
}
return orElse();
}
@override
Map<String, dynamic> toJson() {
return _$_$SuccessToJson(this)..['runtimeType'] = 'success';
}
}
abstract class Success implements UploadState {
const factory Success() = _$Success;
factory Success.fromJson(Map<String, dynamic> json) = _$Success.fromJson;
}
/// @nodoc
abstract class $FailedCopyWith<$Res> {
factory $FailedCopyWith(Failed value, $Res Function(Failed) then) =
_$FailedCopyWithImpl<$Res>;
$Res call({String error});
}
/// @nodoc
class _$FailedCopyWithImpl<$Res> extends _$UploadStateCopyWithImpl<$Res>
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;
@override
$Res call({
Object? error = freezed,
}) {
return _then(Failed(
error: error == freezed
? _value.error
: error // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
@JsonSerializable()
class _$Failed implements Failed {
const _$Failed({required this.error});
factory _$Failed.fromJson(Map<String, dynamic> json) =>
_$_$FailedFromJson(json);
@override
final String error;
@override
String toString() {
return 'UploadState.failed(error: $error)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is Failed &&
(identical(other.error, error) ||
const DeepCollectionEquality().equals(other.error, error)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(error);
@JsonKey(ignore: true)
@override
$FailedCopyWith<Failed> get copyWith =>
_$FailedCopyWithImpl<Failed>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() preparing,
required TResult Function(int uploaded, int total) inProgress,
required TResult Function() success,
required TResult Function(String error) failed,
}) {
return failed(error);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? preparing,
TResult Function(int uploaded, int total)? inProgress,
TResult Function()? success,
TResult Function(String error)? failed,
required TResult orElse(),
}) {
if (failed != null) {
return failed(error);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Preparing value) preparing,
required TResult Function(InProgress value) inProgress,
required TResult Function(Success value) success,
required TResult Function(Failed value) failed,
}) {
return failed(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Preparing value)? preparing,
TResult Function(InProgress value)? inProgress,
TResult Function(Success value)? success,
TResult Function(Failed value)? failed,
required TResult orElse(),
}) {
if (failed != null) {
return failed(this);
}
return orElse();
}
@override
Map<String, dynamic> toJson() {
return _$_$FailedToJson(this)..['runtimeType'] = 'failed';
}
}
abstract class Failed implements UploadState {
const factory Failed({required String error}) = _$Failed;
factory Failed.fromJson(Map<String, dynamic> json) = _$Failed.fromJson;
String get error => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$FailedCopyWith<Failed> get copyWith => throw _privateConstructorUsedError;
}
@@ -0,0 +1,61 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'attachment_file.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
AttachmentFile _$AttachmentFileFromJson(Map<String, dynamic> json) {
return AttachmentFile(
size: json['size'] as int?,
path: json['path'] as String?,
name: json['name'] as String?,
bytes: _fromString(json['bytes'] as String?),
);
}
Map<String, dynamic> _$AttachmentFileToJson(AttachmentFile instance) =>
<String, dynamic>{
'path': instance.path,
'name': instance.name,
'bytes': _toString(instance.bytes),
'size': instance.size,
};
_$Preparing _$_$PreparingFromJson(Map<String, dynamic> json) {
return _$Preparing();
}
Map<String, dynamic> _$_$PreparingToJson(_$Preparing instance) =>
<String, dynamic>{};
_$InProgress _$_$InProgressFromJson(Map<String, dynamic> json) {
return _$InProgress(
uploaded: json['uploaded'] as int,
total: json['total'] as int,
);
}
Map<String, dynamic> _$_$InProgressToJson(_$InProgress instance) =>
<String, dynamic>{
'uploaded': instance.uploaded,
'total': instance.total,
};
_$Success _$_$SuccessFromJson(Map<String, dynamic> json) {
return _$Success();
}
Map<String, dynamic> _$_$SuccessToJson(_$Success instance) =>
<String, dynamic>{};
_$Failed _$_$FailedFromJson(Map<String, dynamic> json) {
return _$Failed(
error: json['error'] as String,
);
}
Map<String, dynamic> _$_$FailedToJson(_$Failed instance) => <String, dynamic>{
'error': instance.error,
};
@@ -0,0 +1,93 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/command.dart';
part 'channel_config.g.dart';
/// The class that contains the information about the configuration of a channel
@JsonSerializable()
class ChannelConfig {
/// Constructor used for json serialization
ChannelConfig({
this.automod = 'flag',
this.commands = const [],
this.connectEvents = false,
DateTime? createdAt,
DateTime? updatedAt,
this.maxMessageLength = 0,
this.messageRetention = '',
this.mutes = false,
this.reactions = false,
this.readEvents = false,
this.replies = false,
this.search = false,
this.typingEvents = false,
this.uploads = false,
this.urlEnrichment = false,
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
/// Create a new instance from a json
factory ChannelConfig.fromJson(Map<String, dynamic> json) =>
_$ChannelConfigFromJson(json);
/// Moderation configuration
@JsonKey(defaultValue: 'flag')
final String automod;
/// List of available commands
@JsonKey(defaultValue: [])
final List<Command> commands;
/// True if the channel should send connect events
@JsonKey(defaultValue: false)
final bool connectEvents;
/// Date of channel creation
final DateTime createdAt;
/// Date of last channel update
final DateTime updatedAt;
/// Max channel message length
@JsonKey(defaultValue: 0)
final int maxMessageLength;
/// Duration of message retention
@JsonKey(defaultValue: '')
final String messageRetention;
/// True if users can be muted
@JsonKey(defaultValue: false)
final bool mutes;
/// True if reaction are active for this channel
@JsonKey(defaultValue: false)
final bool reactions;
/// True if readEvents are active for this channel
@JsonKey(defaultValue: false)
final bool readEvents;
/// True if reply message are active for this channel
@JsonKey(defaultValue: false)
final bool replies;
/// True if it's possible to perform a search in this channel
@JsonKey(defaultValue: false)
final bool search;
/// True if typing events should be sent for this channel
@JsonKey(defaultValue: false)
final bool typingEvents;
/// True if it's possible to upload files to this channel
@JsonKey(defaultValue: false)
final bool uploads;
/// True if urls appears as attachments
@JsonKey(defaultValue: false)
final bool urlEnrichment;
/// Serialize to json
Map<String, dynamic> toJson() => _$ChannelConfigToJson(this);
}
@@ -0,0 +1,53 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'channel_config.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ChannelConfig _$ChannelConfigFromJson(Map<String, dynamic> json) {
return ChannelConfig(
automod: json['automod'] as String? ?? 'flag',
commands: (json['commands'] as List<dynamic>?)
?.map((e) => Command.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
connectEvents: json['connect_events'] as bool? ?? false,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
maxMessageLength: json['max_message_length'] as int? ?? 0,
messageRetention: json['message_retention'] as String? ?? '',
mutes: json['mutes'] as bool? ?? false,
reactions: json['reactions'] as bool? ?? false,
readEvents: json['read_events'] as bool? ?? false,
replies: json['replies'] as bool? ?? false,
search: json['search'] as bool? ?? false,
typingEvents: json['typing_events'] as bool? ?? false,
uploads: json['uploads'] as bool? ?? false,
urlEnrichment: json['url_enrichment'] as bool? ?? false,
);
}
Map<String, dynamic> _$ChannelConfigToJson(ChannelConfig instance) =>
<String, dynamic>{
'automod': instance.automod,
'commands': instance.commands.map((e) => e.toJson()).toList(),
'connect_events': instance.connectEvents,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
'max_message_length': instance.maxMessageLength,
'message_retention': instance.messageRetention,
'mutes': instance.mutes,
'reactions': instance.reactions,
'read_events': instance.readEvents,
'replies': instance.replies,
'search': instance.search,
'typing_events': instance.typingEvents,
'uploads': instance.uploads,
'url_enrichment': instance.urlEnrichment,
};
@@ -0,0 +1,174 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/channel_config.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'channel_model.g.dart';
/// The class that contains the information about a channel
@JsonSerializable()
class ChannelModel {
/// Constructor used for json serialization
ChannelModel({
String? id,
String? type,
String? cid,
ChannelConfig? config,
this.createdBy,
this.frozen = false,
this.lastMessageAt,
DateTime? createdAt,
DateTime? updatedAt,
this.deletedAt,
this.memberCount = 0,
this.extraData = const {},
this.team,
}) : assert(
(cid != null && cid.contains(':')) || (id != null && type != null),
'provide either a cid or an id and type',
),
id = id ?? cid!.split(':')[1],
type = type ?? cid!.split(':')[0],
cid = cid ?? '$type:$id',
config = config ?? ChannelConfig(),
createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
/// Create a new instance from a json
factory ChannelModel.fromJson(Map<String, dynamic> json) =>
_$ChannelModelFromJson(
Serialization.moveToExtraDataFromRoot(json, topLevelFields));
/// The id of this channel
final String id;
/// The type of this channel
final String type;
/// The cid of this channel
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final String cid;
/// The channel configuration data
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final ChannelConfig config;
/// The user that created this channel
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final User? createdBy;
/// True if this channel is frozen
@JsonKey(includeIfNull: false, defaultValue: false)
final bool frozen;
/// The date of the last message
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime? lastMessageAt;
/// The date of channel creation
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime createdAt;
/// The date of the last channel update
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime updatedAt;
/// The date of channel deletion
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime? deletedAt;
/// The count of this channel members
@JsonKey(
includeIfNull: false, toJson: Serialization.readOnly, defaultValue: 0)
final int memberCount;
/// Map of custom channel extraData
@JsonKey(
includeIfNull: false,
defaultValue: {},
)
final Map<String, Object?> extraData;
/// The team the channel belongs to
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final String? team;
/// Known top level fields.
/// Useful for [Serialization] methods.
static const topLevelFields = [
'id',
'type',
'cid',
'config',
'created_by',
'frozen',
'last_message_at',
'created_at',
'updated_at',
'deleted_at',
'member_count',
'team',
];
/// Shortcut for channel name
String get name =>
extraData.containsKey('name') ? extraData['name']! as String : cid;
/// Serialize to json
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$ChannelModelToJson(this),
);
/// Creates a copy of [ChannelModel] with specified attributes overridden.
ChannelModel copyWith({
String? id,
String? type,
String? cid,
ChannelConfig? config,
User? createdBy,
bool? frozen,
DateTime? lastMessageAt,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? deletedAt,
int? memberCount,
Map<String, Object?>? extraData,
String? team,
}) =>
ChannelModel(
id: id ?? this.id,
type: type ?? this.type,
cid: cid ?? this.cid,
config: config ?? this.config,
createdBy: createdBy ?? this.createdBy,
frozen: frozen ?? this.frozen,
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
memberCount: memberCount ?? this.memberCount,
extraData: extraData ?? this.extraData,
team: team ?? this.team,
);
/// Returns a new [ChannelModel] that is a combination of this channelModel
/// and the given [other] channelModel.
ChannelModel merge(ChannelModel? other) {
if (other == null) return this;
return copyWith(
id: other.id,
type: other.type,
cid: other.cid,
config: other.config,
createdBy: other.createdBy,
frozen: other.frozen,
lastMessageAt: other.lastMessageAt,
createdAt: other.createdAt,
updatedAt: other.updatedAt,
deletedAt: other.deletedAt,
memberCount: other.memberCount,
extraData: other.extraData,
team: other.team,
);
}
}
@@ -0,0 +1,63 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'channel_model.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ChannelModel _$ChannelModelFromJson(Map<String, dynamic> json) {
return ChannelModel(
id: json['id'] as String?,
type: json['type'] as String?,
cid: json['cid'] as String?,
config: json['config'] == null
? null
: ChannelConfig.fromJson(json['config'] as Map<String, dynamic>),
createdBy: json['created_by'] == null
? null
: User.fromJson(json['created_by'] as Map<String, dynamic>),
frozen: json['frozen'] as bool? ?? false,
lastMessageAt: json['last_message_at'] == null
? null
: DateTime.parse(json['last_message_at'] as String),
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
deletedAt: json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
memberCount: json['member_count'] as int? ?? 0,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
team: json['team'] as String?,
);
}
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('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['extra_data'] = instance.extraData;
writeNotNull('team', readonly(instance.team));
return val;
}
@@ -0,0 +1,76 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/channel_model.dart';
import 'package:stream_chat/src/core/models/member.dart';
import 'package:stream_chat/src/core/models/message.dart';
import 'package:stream_chat/src/core/models/read.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'channel_state.g.dart';
/// The class that contains the information about a channel
@JsonSerializable()
class ChannelState {
/// Constructor used for json serialization
ChannelState({
this.channel,
this.messages = const [],
this.members = const [],
this.pinnedMessages = const [],
this.watcherCount,
this.watchers = const [],
this.read = const [],
});
/// The channel to which this state belongs
final ChannelModel? channel;
/// A paginated list of channel messages
@JsonKey(defaultValue: <Message>[])
final List<Message> messages;
/// A paginated list of channel members
@JsonKey(defaultValue: <Member>[])
final List<Member> members;
/// A paginated list of pinned messages
@JsonKey(defaultValue: <Message>[])
final List<Message> pinnedMessages;
/// The count of users watching the channel
final int? watcherCount;
/// A paginated list of users watching the channel
@JsonKey(defaultValue: <User>[])
final List<User> watchers;
/// The list of channel reads
@JsonKey(defaultValue: <Read>[])
final List<Read> read;
/// Create a new instance from a json
static ChannelState fromJson(Map<String, dynamic> json) =>
_$ChannelStateFromJson(json);
/// Serialize to json
Map<String, dynamic> toJson() => _$ChannelStateToJson(this);
/// Creates a copy of [ChannelState] with specified attributes overridden.
ChannelState copyWith({
ChannelModel? channel,
List<Message>? messages,
List<Member>? members,
List<Message>? pinnedMessages,
int? watcherCount,
List<User>? watchers,
List<Read>? read,
}) =>
ChannelState(
channel: channel ?? this.channel,
messages: messages ?? this.messages,
members: members ?? this.members,
pinnedMessages: pinnedMessages ?? this.pinnedMessages,
watcherCount: watcherCount ?? this.watcherCount,
watchers: watchers ?? this.watchers,
read: read ?? this.read,
);
}
@@ -0,0 +1,48 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'channel_state.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ChannelState _$ChannelStateFromJson(Map<String, dynamic> json) {
return ChannelState(
channel: json['channel'] == null
? null
: ChannelModel.fromJson(json['channel'] as Map<String, dynamic>),
messages: (json['messages'] as List<dynamic>?)
?.map((e) => Message.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
members: (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
pinnedMessages: (json['pinned_messages'] as List<dynamic>?)
?.map((e) => Message.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
watcherCount: json['watcher_count'] as int?,
watchers: (json['watchers'] as List<dynamic>?)
?.map((e) => User.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
read: (json['read'] as List<dynamic>?)
?.map((e) => Read.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
);
}
Map<String, dynamic> _$ChannelStateToJson(ChannelState instance) =>
<String, dynamic>{
'channel': instance.channel?.toJson(),
'messages': instance.messages.map((e) => e.toJson()).toList(),
'members': instance.members.map((e) => e.toJson()).toList(),
'pinned_messages':
instance.pinnedMessages.map((e) => e.toJson()).toList(),
'watcher_count': instance.watcherCount,
'watchers': instance.watchers.map((e) => e.toJson()).toList(),
'read': instance.read.map((e) => e.toJson()).toList(),
};
@@ -0,0 +1,30 @@
import 'package:json_annotation/json_annotation.dart';
part 'command.g.dart';
/// The class that contains the information about a command
@JsonSerializable()
class Command {
/// Constructor used for json serialization
Command({
required this.name,
required this.description,
required this.args,
});
/// Create a new instance from a json
factory Command.fromJson(Map<String, dynamic> json) =>
_$CommandFromJson(json);
/// The name of the command
final String name;
/// The description explaining the command
final String description;
/// The arguments of the command
final String args;
/// Serialize to json
Map<String, dynamic> toJson() => _$CommandToJson(this);
}
@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'command.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Command _$CommandFromJson(Map<String, dynamic> json) {
return Command(
name: json['name'] as String,
description: json['description'] as String,
args: json['args'] as String,
);
}
Map<String, dynamic> _$CommandToJson(Command instance) => <String, dynamic>{
'name': instance.name,
'description': instance.description,
'args': instance.args,
};
@@ -0,0 +1,25 @@
import 'package:json_annotation/json_annotation.dart';
part 'device.g.dart';
/// The class that contains the information about a device
@JsonSerializable()
class Device {
/// Constructor used for json serialization
Device({
required this.id,
required this.pushProvider,
});
/// Create a new instance from a json
factory Device.fromJson(Map<String, dynamic> json) => _$DeviceFromJson(json);
/// The id of the device
final String id;
/// The notification push provider
final String pushProvider;
/// Serialize to json
Map<String, dynamic> toJson() => _$DeviceToJson(this);
}
@@ -0,0 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'device.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Device _$DeviceFromJson(Map<String, dynamic> json) {
return Device(
id: json['id'] as String,
pushProvider: json['push_provider'] as String,
);
}
Map<String, dynamic> _$DeviceToJson(Device instance) => <String, dynamic>{
'id': instance.id,
'push_provider': instance.pushProvider,
};
@@ -0,0 +1,221 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/channel_model.dart';
import 'package:stream_chat/src/core/models/message.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:stream_chat/stream_chat.dart';
part 'event.g.dart';
/// The class that contains the information about an event
@JsonSerializable()
class Event {
/// Constructor used for json serialization
Event({
this.type = 'local.event',
this.cid,
this.connectionId,
DateTime? createdAt,
this.me,
this.user,
this.message,
this.totalUnreadCount,
this.unreadChannels,
this.reaction,
this.online,
this.channel,
this.member,
this.channelId,
this.channelType,
this.parentId,
this.extraData = const {},
this.isLocal = true,
}) : createdAt = createdAt ?? DateTime.now();
/// Create a new instance from a json
factory Event.fromJson(Map<String, dynamic> json) =>
_$EventFromJson(Serialization.moveToExtraDataFromRoot(
json,
topLevelFields,
));
/// The type of the event
/// [EventType] contains some predefined constant types
final String type;
/// The channel cid to which the event belongs
final String? cid;
/// The channel id to which the event belongs
final String? channelId;
/// The channel type to which the event belongs
final String? channelType;
/// The connection id in which the event has been sent
final String? connectionId;
/// The date of creation of the event
final DateTime createdAt;
/// User object of the health check user
final OwnUser? me;
/// User object of the current user
final User? user;
/// The message sent with the event
final Message? message;
/// The channel sent with the event
final EventChannel? channel;
/// The member sent with the event
final Member? member;
/// The reaction sent with the event
final Reaction? reaction;
/// The number of unread messages for current user
final int? totalUnreadCount;
/// User total unread channels
final int? unreadChannels;
/// Online status
final bool? online;
/// The id of the parent message of a thread
final String? parentId;
/// True if the event is generated by this client
@JsonKey(defaultValue: false)
final bool isLocal;
/// Map of custom channel extraData
@JsonKey(defaultValue: {})
final Map<String, Object?> extraData;
/// Known top level fields.
/// Useful for [Serialization] methods.
static final topLevelFields = [
'type',
'cid',
'connection_id',
'created_at',
'me',
'user',
'message',
'total_unread_count',
'unread_channels',
'reaction',
'online',
'channel',
'member',
'channel_id',
'channel_type',
'parent_id',
'is_local',
];
/// Serialize to json
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$EventToJson(this),
);
/// Creates a copy of [Event] with specified attributes overridden.
Event copyWith({
String? type,
String? cid,
String? channelId,
String? channelType,
String? connectionId,
DateTime? createdAt,
OwnUser? me,
User? user,
Message? message,
EventChannel? channel,
Member? member,
Reaction? reaction,
int? totalUnreadCount,
int? unreadChannels,
bool? online,
String? parentId,
Map<String, Object?>? extraData,
}) =>
Event(
type: type ?? this.type,
cid: cid ?? this.cid,
connectionId: connectionId ?? this.connectionId,
createdAt: createdAt ?? this.createdAt,
me: me ?? this.me,
user: user ?? this.user,
message: message ?? this.message,
totalUnreadCount: totalUnreadCount ?? this.totalUnreadCount,
unreadChannels: unreadChannels ?? this.unreadChannels,
reaction: reaction ?? this.reaction,
online: online ?? this.online,
channel: channel ?? this.channel,
member: member ?? this.member,
channelId: channelId ?? this.channelId,
channelType: channelType ?? this.channelType,
parentId: parentId ?? this.parentId,
extraData: extraData ?? this.extraData,
);
}
/// The channel embedded in the event object
@JsonSerializable()
class EventChannel extends ChannelModel {
/// Constructor used for json serialization
EventChannel({
this.members,
String? id,
String? type,
required String cid,
required ChannelConfig config,
User? createdBy,
bool frozen = false,
DateTime? lastMessageAt,
required DateTime createdAt,
required DateTime updatedAt,
DateTime? deletedAt,
required int memberCount,
Map<String, Object?>? extraData,
}) : super(
id: id,
type: type,
cid: cid,
config: config,
createdBy: createdBy,
frozen: frozen,
lastMessageAt: lastMessageAt,
createdAt: createdAt,
updatedAt: updatedAt,
deletedAt: deletedAt,
memberCount: memberCount,
extraData: extraData ?? {},
);
/// Create a new instance from a json
factory EventChannel.fromJson(Map<String, dynamic> json) =>
_$EventChannelFromJson(Serialization.moveToExtraDataFromRoot(
json,
topLevelFields,
));
/// A paginated list of channel members
final List<Member>? members;
/// Known top level fields.
/// Useful for [Serialization] methods.
static final topLevelFields = [
'members',
...ChannelModel.topLevelFields,
];
/// Serialize to json
@override
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$EventChannelToJson(this),
);
}
@@ -0,0 +1,117 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'event.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Event _$EventFromJson(Map<String, dynamic> json) {
return Event(
type: json['type'] as String,
cid: json['cid'] as String?,
connectionId: json['connection_id'] as String?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
me: json['me'] == null
? null
: OwnUser.fromJson(json['me'] as Map<String, dynamic>),
user: json['user'] == null
? null
: User.fromJson(json['user'] as Map<String, dynamic>),
message: json['message'] == null
? null
: Message.fromJson(json['message'] as Map<String, dynamic>),
totalUnreadCount: json['total_unread_count'] as int?,
unreadChannels: json['unread_channels'] as int?,
reaction: json['reaction'] == null
? null
: Reaction.fromJson(json['reaction'] as Map<String, dynamic>),
online: json['online'] as bool?,
channel: json['channel'] == null
? null
: EventChannel.fromJson(json['channel'] as Map<String, dynamic>),
member: json['member'] == null
? null
: Member.fromJson(json['member'] as Map<String, dynamic>),
channelId: json['channel_id'] as String?,
channelType: json['channel_type'] as String?,
parentId: json['parent_id'] as String?,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
isLocal: json['is_local'] as bool? ?? false,
);
}
Map<String, dynamic> _$EventToJson(Event instance) => <String, dynamic>{
'type': instance.type,
'cid': instance.cid,
'channel_id': instance.channelId,
'channel_type': instance.channelType,
'connection_id': instance.connectionId,
'created_at': instance.createdAt.toIso8601String(),
'me': instance.me?.toJson(),
'user': instance.user?.toJson(),
'message': instance.message?.toJson(),
'channel': instance.channel?.toJson(),
'member': instance.member?.toJson(),
'reaction': instance.reaction?.toJson(),
'total_unread_count': instance.totalUnreadCount,
'unread_channels': instance.unreadChannels,
'online': instance.online,
'parent_id': instance.parentId,
'is_local': instance.isLocal,
'extra_data': instance.extraData,
};
EventChannel _$EventChannelFromJson(Map<String, dynamic> json) {
return EventChannel(
members: (json['members'] as List<dynamic>?)
?.map((e) => Member.fromJson(e as Map<String, dynamic>))
.toList(),
id: json['id'] as String?,
type: json['type'] as String?,
cid: json['cid'] as String,
config: ChannelConfig.fromJson(json['config'] as Map<String, dynamic>),
createdBy: json['created_by'] == null
? null
: User.fromJson(json['created_by'] as Map<String, dynamic>),
frozen: json['frozen'] as bool? ?? false,
lastMessageAt: json['last_message_at'] == null
? null
: DateTime.parse(json['last_message_at'] as String),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
deletedAt: json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
memberCount: json['member_count'] as int? ?? 0,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
);
}
Map<String, dynamic> _$EventChannelToJson(EventChannel 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('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['extra_data'] = instance.extraData;
val['members'] = instance.members?.map((e) => e.toJson()).toList();
return val;
}
@@ -0,0 +1,219 @@
// ignore_for_file: non_constant_identifier_names, constant_identifier_names
import 'package:equatable/equatable.dart';
const _groupOperators = [
FilterOperator.and,
FilterOperator.or,
FilterOperator.nor,
];
/// Possible operators to use in filters.
enum FilterOperator {
/// Matches values that are equal to a specified value.
equal,
/// Matches all values that are not equal to a specified value.
notEqual,
/// Matches values that are greater than a specified value.
greater,
/// Matches values that are greater than a specified value.
greaterOrEqual,
/// Matches values that are less than a specified value.
less,
/// Matches values that are less than or equal to a specified value.
lessOrEqual,
/// Matches any of the values specified in an array.
in_,
/// Matches none of the values specified in an array.
notIn,
/// Matches values by performing text search with the specified value.
query,
/// Matches values with the specified prefix.
autoComplete,
/// Matches values that exist/don't exist based on the specified boolean value.
exists,
/// Matches all the values specified in an array.
and,
/// Matches at least one of the values specified in an array.
or,
/// Matches none of the values specified in an array.
nor,
}
/// Helper extension for [FilterOperator]
extension FilterOperatorX on FilterOperator {
/// Converts [FilterOperator] into rew values
String get rawValue => {
FilterOperator.equal: '\$eq',
FilterOperator.notEqual: '\$ne',
FilterOperator.greater: '\$gt',
FilterOperator.greaterOrEqual: '\$gte',
FilterOperator.less: '\$lt',
FilterOperator.lessOrEqual: '\$lte',
FilterOperator.in_: '\$in',
FilterOperator.notIn: '\$nin',
FilterOperator.query: '\$q',
FilterOperator.autoComplete: '\$autocomplete',
FilterOperator.exists: '\$exists',
FilterOperator.and: '\$and',
FilterOperator.or: '\$or',
FilterOperator.nor: '\$nor',
}[this]!;
}
/// Stream supports a limited set of filters for querying channels,
/// users and members. The example below shows how to filter for channels
/// of type messaging where the current user is a member
///
/// ```dart
/// final filter = Filter.and(
/// Filter.equal('type', 'messaging'),
/// Filter.in_('members', [user.id])
/// )
/// ```
/// See <a href="https://getstream.io/chat/docs/query_channels/?language=dart" target="_top">Query Channels Documentation</a>
class Filter extends Equatable {
const Filter.__({
required this.value,
this.operator,
this.key,
});
Filter._({
required FilterOperator operator,
required this.value,
this.key,
}) : operator = operator.rawValue;
/// Combines the provided filters and matches the values
/// matched by all filters.
factory Filter.and(List<Filter> filters) =>
Filter._(operator: FilterOperator.and, value: filters);
/// Combines the provided filters and matches the values
/// matched by at least one of the filters.
factory Filter.or(List<Filter> filters) =>
Filter._(operator: FilterOperator.or, value: filters);
/// Combines the provided filters and matches the values
/// not matched by all the filters.
factory Filter.nor(List<Filter> filters) =>
Filter._(operator: FilterOperator.nor, value: filters);
/// Matches values that are equal to a specified value.
factory Filter.equal(String key, Object value) =>
Filter._(operator: FilterOperator.equal, key: key, value: value);
/// Matches all values that are not equal to a specified value.
factory Filter.notEqual(String key, Object value) =>
Filter._(operator: FilterOperator.notEqual, key: key, value: value);
/// Matches values that are greater than a specified value.
factory Filter.greater(String key, Object value) =>
Filter._(operator: FilterOperator.greater, key: key, value: value);
/// Matches values that are greater than a specified value.
factory Filter.greaterOrEqual(String key, Object value) =>
Filter._(operator: FilterOperator.greaterOrEqual, key: key, value: value);
/// Matches values that are less than a specified value.
factory Filter.less(String key, Object value) =>
Filter._(operator: FilterOperator.less, key: key, value: value);
/// Matches values that are less than or equal to a specified value.
factory Filter.lessOrEqual(String key, Object value) =>
Filter._(operator: FilterOperator.lessOrEqual, key: key, value: value);
/// Matches any of the values specified in an array.
factory Filter.in_(String key, List<Object> values) =>
Filter._(operator: FilterOperator.in_, key: key, value: values);
/// Matches none of the values specified in an array.
factory Filter.notIn(String key, List<Object> values) =>
Filter._(operator: FilterOperator.notIn, key: key, value: values);
/// Matches values by performing text search with the specified value.
factory Filter.query(String key, String text) =>
Filter._(operator: FilterOperator.query, key: key, value: text);
/// Matches values with the specified prefix.
factory Filter.autoComplete(String key, String text) =>
Filter._(operator: FilterOperator.autoComplete, key: key, value: text);
/// Matches values that exist/don't exist based on the specified boolean value.
factory Filter.exists(String key, {bool exists = true}) =>
Filter._(operator: FilterOperator.exists, key: key, value: exists);
/// Creates a custom [Filter] if there isn't one already available.
const factory Filter.custom({
required Object value,
String? operator,
String? key,
}) = Filter.__;
/// Creates a custom [Filter] from a raw map value
///
/// ```dart
/// final filter = Filter.raw(
/// {
/// 'members': [user1.id, user2.id],
/// }
/// )
/// ```
const factory Filter.raw({
required Map<String, Object?> value,
}) = Filter.__;
/// An operator used for the filter. The operator string must start with `$`
final String? operator;
/// The "left-hand" side of the filter.
/// Specifies the name of the field the filter should match.
///
/// Some operators like `and` or `or`,
/// don't require the key value to be present.
/// see-more : [_groupOperators]
final String? key;
/// The "right-hand" side of the filter.
/// Specifies the [value] the filter should match.
final Object /*List<Object>|List<Filter>|String*/ value;
@override
List<Object?> get props => [operator, key, value];
/// Serializes to json object
Map<String, Object?> toJson() {
final json = <String, Object?>{};
final groupOperators = _groupOperators.map((it) => it.rawValue);
if (groupOperators.contains(operator)) {
// Filters with group operators are encoded in the following form:
// { $<operator>: [ <filter 1>, <filter 2> ] }
json[operator!] = value;
} else if (operator != null) {
// Normal filters are encoded in the following form:
// { key: { $<operator>: <value> } }
json[key!] = {operator: value};
} else if (key != null) {
json[key!] = value;
} else {
return value as Map<String, Object?>;
}
return json;
}
}
@@ -0,0 +1,101 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'member.g.dart';
/// The class that contains the information about the user membership
/// in a channel
@JsonSerializable()
class Member {
/// Constructor used for json serialization
Member({
this.user,
this.inviteAcceptedAt,
this.inviteRejectedAt,
this.invited = false,
this.role,
this.userId,
this.isModerator = false,
DateTime? createdAt,
DateTime? updatedAt,
this.banned = false,
this.shadowBanned = false,
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
/// Create a new instance from a json
factory Member.fromJson(Map<String, dynamic> json) {
final member = _$MemberFromJson(json);
return member.copyWith(
userId: member.user?.id,
);
}
/// The interested user
final User? user;
/// The date in which the user accepted the invite to the channel
final DateTime? inviteAcceptedAt;
/// The date in which the user rejected the invite to the channel
final DateTime? inviteRejectedAt;
/// True if the user has been invited to the channel
@JsonKey(defaultValue: false)
final bool invited;
/// The role of the user in the channel
final String? role;
/// The id of the interested user
final String? userId;
/// True if the user is a moderator of the channel
@JsonKey(defaultValue: false)
final bool isModerator;
/// True if the member is banned from the channel
@JsonKey(defaultValue: false)
final bool banned;
/// True if the member is shadow banned from the channel
@JsonKey(defaultValue: false)
final bool shadowBanned;
/// The date of creation
final DateTime createdAt;
/// The last date of update
final DateTime updatedAt;
/// Creates a copy of [Member] with specified attributes overridden.
Member copyWith({
User? user,
DateTime? inviteAcceptedAt,
DateTime? inviteRejectedAt,
bool? invited,
String? role,
String? userId,
bool? isModerator,
DateTime? createdAt,
DateTime? updatedAt,
bool? banned,
bool? shadowBanned,
}) =>
Member(
user: user ?? this.user,
inviteAcceptedAt: inviteAcceptedAt ?? this.inviteAcceptedAt,
inviteRejectedAt: inviteRejectedAt ?? this.inviteRejectedAt,
invited: invited ?? this.invited,
banned: banned ?? this.banned,
shadowBanned: shadowBanned ?? this.shadowBanned,
role: role ?? this.role,
userId: userId ?? this.userId,
isModerator: isModerator ?? this.isModerator,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
/// Serialize to json
Map<String, dynamic> toJson() => _$MemberToJson(this);
}
@@ -0,0 +1,47 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'member.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Member _$MemberFromJson(Map<String, dynamic> json) {
return Member(
user: json['user'] == null
? null
: User.fromJson(json['user'] as Map<String, dynamic>),
inviteAcceptedAt: json['invite_accepted_at'] == null
? null
: DateTime.parse(json['invite_accepted_at'] as String),
inviteRejectedAt: json['invite_rejected_at'] == null
? null
: DateTime.parse(json['invite_rejected_at'] as String),
invited: json['invited'] as bool? ?? false,
role: json['role'] as String?,
userId: json['user_id'] as String?,
isModerator: json['is_moderator'] as bool? ?? false,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
banned: json['banned'] as bool? ?? false,
shadowBanned: json['shadow_banned'] as bool? ?? false,
);
}
Map<String, dynamic> _$MemberToJson(Member instance) => <String, dynamic>{
'user': instance.user?.toJson(),
'invite_accepted_at': instance.inviteAcceptedAt?.toIso8601String(),
'invite_rejected_at': instance.inviteRejectedAt?.toIso8601String(),
'invited': instance.invited,
'role': instance.role,
'user_id': instance.userId,
'is_moderator': instance.isModerator,
'banned': instance.banned,
'shadow_banned': instance.shadowBanned,
'created_at': instance.createdAt.toIso8601String(),
'updated_at': instance.updatedAt.toIso8601String(),
};
@@ -0,0 +1,433 @@
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/attachment.dart';
import 'package:stream_chat/src/core/models/reaction.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:stream_chat/src/core/models/user.dart';
import 'package:uuid/uuid.dart';
part 'message.g.dart';
class _PinExpires {
const _PinExpires();
}
const _pinExpires = _PinExpires();
/// Enum defining the status of a sending message
enum MessageSendingStatus {
/// Message is being sent
sending,
/// Message is being updated
updating,
/// Message is being deleted
deleting,
/// Message failed to send
failed,
/// Message failed to updated
// ignore: constant_identifier_names
failed_update,
/// Message failed to delete
// ignore: constant_identifier_names
failed_delete,
/// Message correctly sent
sent,
}
/// The class that contains the information about a message
@JsonSerializable()
class Message extends Equatable {
/// Constructor used for json serialization
Message({
String? id,
this.text,
this.type = 'regular',
this.attachments = const [],
this.mentionedUsers = const [],
this.silent = false,
this.shadowed = false,
this.reactionCounts,
this.reactionScores,
this.latestReactions,
this.ownReactions,
this.parentId,
this.quotedMessage,
this.quotedMessageId,
this.replyCount = 0,
this.threadParticipants,
this.showInChannel,
this.command,
DateTime? createdAt,
DateTime? updatedAt,
this.user,
this.pinned = false,
this.pinnedAt,
DateTime? pinExpires,
this.pinnedBy,
this.extraData = const {},
this.deletedAt,
this.status = MessageSendingStatus.sent,
this.skipPush = false,
}) : id = id ?? const Uuid().v4(),
pinExpires = pinExpires?.toUtc(),
createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
/// Create a new instance from a json
factory Message.fromJson(Map<String, dynamic> json) => _$MessageFromJson(
Serialization.moveToExtraDataFromRoot(json, topLevelFields));
/// The message ID. This is either created by Stream or set client side when
/// the message is added.
final String id;
/// The text of this message
final String? text;
/// The status of a sending message
@JsonKey(ignore: true)
final MessageSendingStatus status;
/// The message type
@JsonKey(
includeIfNull: false,
toJson: Serialization.readOnly,
defaultValue: 'regular',
)
final String type;
/// The list of attachments, either provided by the user or generated from a
/// command or as a result of URL scraping.
@JsonKey(
includeIfNull: false,
defaultValue: [],
)
final List<Attachment> attachments;
/// The list of user mentioned in the message
@JsonKey(
toJson: Serialization.userIds,
defaultValue: [],
)
final List<User> mentionedUsers;
/// A map describing the count of number of every reaction
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final Map<String, int>? reactionCounts;
/// A map describing the count of score of every reaction
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final Map<String, int>? reactionScores;
/// The latest reactions to the message created by any user.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final List<Reaction>? latestReactions;
/// The reactions added to the message by the current user.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
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: Serialization.readOnly)
final Message? quotedMessage;
/// The ID of the quoted message, if the message is a quoted reply.
final String? quotedMessageId;
/// Reserved field indicating the number of replies for this message.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final int? replyCount;
/// Reserved field indicating the thread participants for this message.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final List<User>? threadParticipants;
/// Check if this message needs to show in the channel.
final bool? showInChannel;
/// If true the message is silent
@JsonKey(defaultValue: false)
final bool silent;
/// If true the message will not send a push notification
@JsonKey(defaultValue: false)
final bool skipPush;
/// If true the message is shadowed
@JsonKey(
includeIfNull: false,
toJson: Serialization.readOnly,
defaultValue: false,
)
final bool shadowed;
/// A used command name.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final String? command;
/// Reserved field indicating when the message was created.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime createdAt;
/// Reserved field indicating when the message was updated last time.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime updatedAt;
/// User who sent the message
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final User? user;
/// If true the message is pinned
@JsonKey(defaultValue: false)
final bool pinned;
/// Reserved field indicating when the message was pinned
@JsonKey(toJson: Serialization.readOnly)
final DateTime? pinnedAt;
/// Reserved field indicating when the message will expire
///
/// if `null` message has no expiry
final DateTime? pinExpires;
/// Reserved field indicating who pinned the message
@JsonKey(toJson: Serialization.readOnly)
final User? pinnedBy;
/// Message custom extraData
@JsonKey(
includeIfNull: false,
defaultValue: {},
)
final Map<String, Object?> extraData;
/// True if the message is a system info
bool get isSystem => type == 'system';
/// True if the message has been deleted
bool get isDeleted => type == 'deleted';
/// True if the message is ephemeral
bool get isEphemeral => type == 'ephemeral';
/// Reserved field indicating when the message was deleted.
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime? deletedAt;
/// Known top level fields.
/// Useful for [Serialization] methods.
static const topLevelFields = [
'id',
'text',
'type',
'silent',
'attachments',
'latest_reactions',
'shadowed',
'own_reactions',
'mentioned_users',
'reaction_counts',
'reaction_scores',
'silent',
'parent_id',
'quoted_message',
'quoted_message_id',
'reply_count',
'thread_participants',
'show_in_channel',
'command',
'created_at',
'updated_at',
'deleted_at',
'user',
'pinned',
'pinned_at',
'pin_expires',
'pinned_by',
'skip_push',
];
/// Serialize to json
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$MessageToJson(this),
);
/// Creates a copy of [Message] with specified attributes overridden.
Message copyWith({
String? id,
String? text,
String? type,
List<Attachment>? attachments,
List<User>? mentionedUsers,
Map<String, int>? reactionCounts,
Map<String, int>? reactionScores,
List<Reaction>? latestReactions,
List<Reaction>? ownReactions,
String? parentId,
Message? quotedMessage,
String? quotedMessageId,
int? replyCount,
List<User>? threadParticipants,
bool? showInChannel,
bool? shadowed,
bool? silent,
String? command,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? deletedAt,
User? user,
bool? pinned,
DateTime? pinnedAt,
Object? pinExpires = _pinExpires,
User? pinnedBy,
Map<String, Object?>? extraData,
MessageSendingStatus? status,
bool? skipPush,
}) {
assert(() {
if (pinExpires is! DateTime &&
pinExpires != null &&
pinExpires is! _PinExpires) {
throw ArgumentError('`pinExpires` can only be set as DateTime or null');
}
return true;
}(), 'Validate type for pinExpires');
return Message(
id: id ?? this.id,
text: text ?? this.text,
type: type ?? this.type,
attachments: attachments ?? this.attachments,
mentionedUsers: mentionedUsers ?? this.mentionedUsers,
reactionCounts: reactionCounts ?? this.reactionCounts,
reactionScores: reactionScores ?? this.reactionScores,
latestReactions: latestReactions ?? this.latestReactions,
ownReactions: ownReactions ?? this.ownReactions,
parentId: parentId ?? this.parentId,
quotedMessage: quotedMessage ?? this.quotedMessage,
quotedMessageId: quotedMessageId ?? this.quotedMessageId,
replyCount: replyCount ?? this.replyCount,
threadParticipants: threadParticipants ?? this.threadParticipants,
showInChannel: showInChannel ?? this.showInChannel,
command: command ?? this.command,
createdAt: createdAt ?? this.createdAt,
silent: silent ?? this.silent,
extraData: extraData ?? this.extraData,
user: user ?? this.user,
shadowed: shadowed ?? this.shadowed,
updatedAt: updatedAt ?? this.updatedAt,
deletedAt: deletedAt ?? this.deletedAt,
status: status ?? this.status,
pinned: pinned ?? this.pinned,
pinnedAt: pinnedAt ?? this.pinnedAt,
pinnedBy: pinnedBy ?? this.pinnedBy,
pinExpires:
pinExpires == _pinExpires ? this.pinExpires : pinExpires as DateTime?,
skipPush: skipPush ?? this.skipPush,
);
}
/// Returns a new [Message] that is a combination of this message and the
/// given [other] message.
Message merge(Message other) => copyWith(
id: other.id,
text: other.text,
type: other.type,
attachments: other.attachments,
mentionedUsers: other.mentionedUsers,
reactionCounts: other.reactionCounts,
reactionScores: other.reactionScores,
latestReactions: other.latestReactions,
ownReactions: other.ownReactions,
parentId: other.parentId,
quotedMessage: other.quotedMessage,
quotedMessageId: other.quotedMessageId,
replyCount: other.replyCount,
threadParticipants: other.threadParticipants,
showInChannel: other.showInChannel,
command: other.command,
createdAt: other.createdAt,
silent: other.silent,
extraData: other.extraData,
user: other.user,
shadowed: other.shadowed,
updatedAt: other.updatedAt,
deletedAt: other.deletedAt,
status: other.status,
pinned: other.pinned,
pinnedAt: other.pinnedAt,
pinExpires: other.pinExpires,
pinnedBy: other.pinnedBy,
);
@override
List<Object?> get props => [
id,
text,
type,
attachments,
mentionedUsers,
reactionCounts,
reactionScores,
latestReactions,
ownReactions,
parentId,
quotedMessage,
quotedMessageId,
replyCount,
threadParticipants,
showInChannel,
shadowed,
silent,
command,
createdAt,
updatedAt,
deletedAt,
user,
pinned,
pinnedAt,
pinExpires,
pinnedBy,
extraData,
status,
skipPush,
];
}
/// A translated message
/// It has an additional property called [i18n]
@JsonSerializable()
class TranslatedMessage extends Message {
/// Constructor used for json serialization
TranslatedMessage(this.i18n) : super();
/// Create a new instance from a json
factory TranslatedMessage.fromJson(Map<String, dynamic> json) =>
_$TranslatedMessageFromJson(
Serialization.moveToExtraDataFromRoot(json, topLevelFields),
);
/// A Map of
final Map<String, String>? i18n;
/// Known top level fields.
/// Useful for [Serialization] methods.
static final topLevelFields = [
'i18n',
...Message.topLevelFields,
];
/// Serialize to json
@override
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$TranslatedMessageToJson(this),
);
}
@@ -0,0 +1,126 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'message.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Message _$MessageFromJson(Map<String, dynamic> json) {
return Message(
id: json['id'] as String?,
text: json['text'] as String?,
type: json['type'] as String? ?? 'regular',
attachments: (json['attachments'] as List<dynamic>?)
?.map((e) => Attachment.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
mentionedUsers: (json['mentioned_users'] as List<dynamic>?)
?.map((e) => User.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
silent: json['silent'] as bool? ?? false,
shadowed: json['shadowed'] as bool? ?? false,
reactionCounts: (json['reaction_counts'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as int),
),
reactionScores: (json['reaction_scores'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as int),
),
latestReactions: (json['latest_reactions'] as List<dynamic>?)
?.map((e) => Reaction.fromJson(e as Map<String, dynamic>))
.toList(),
ownReactions: (json['own_reactions'] as List<dynamic>?)
?.map((e) => Reaction.fromJson(e as Map<String, dynamic>))
.toList(),
parentId: json['parent_id'] as String?,
quotedMessage: json['quoted_message'] == null
? null
: Message.fromJson(json['quoted_message'] as Map<String, dynamic>),
quotedMessageId: json['quoted_message_id'] as String?,
replyCount: json['reply_count'] as int?,
threadParticipants: (json['thread_participants'] as List<dynamic>?)
?.map((e) => User.fromJson(e as Map<String, dynamic>))
.toList(),
showInChannel: json['show_in_channel'] as bool?,
command: json['command'] as String?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
user: json['user'] == null
? null
: User.fromJson(json['user'] as Map<String, dynamic>),
pinned: json['pinned'] as bool? ?? false,
pinnedAt: json['pinned_at'] == null
? null
: DateTime.parse(json['pinned_at'] as String),
pinExpires: json['pin_expires'] == null
? null
: DateTime.parse(json['pin_expires'] as String),
pinnedBy: json['pinned_by'] == null
? null
: User.fromJson(json['pinned_by'] as Map<String, dynamic>),
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
deletedAt: json['deleted_at'] == null
? null
: DateTime.parse(json['deleted_at'] as String),
skipPush: json['skip_push'] as bool? ?? false,
);
}
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'] = Serialization.userIds(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;
val['skip_push'] = instance.skipPush;
writeNotNull('shadowed', readonly(instance.shadowed));
writeNotNull('command', readonly(instance.command));
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('deleted_at', readonly(instance.deletedAt));
return val;
}
TranslatedMessage _$TranslatedMessageFromJson(Map<String, dynamic> json) {
return TranslatedMessage(
(json['i18n'] as Map<String, dynamic>?)?.map(
(k, e) => MapEntry(k, e as String),
),
);
}
Map<String, dynamic> _$TranslatedMessageToJson(TranslatedMessage instance) =>
<String, dynamic>{
'i18n': instance.i18n,
};
@@ -0,0 +1,40 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/channel_model.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'mute.g.dart';
/// The class that contains the information about a muted user
@JsonSerializable()
class Mute {
/// Constructor used for json serialization
Mute({
required this.user,
required this.channel,
required this.createdAt,
required this.updatedAt,
});
/// Create a new instance from a json
factory Mute.fromJson(Map<String, dynamic> json) => _$MuteFromJson(json);
/// The user that performed the muting action
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final User user;
/// The target user
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final ChannelModel channel;
/// The date in which the use was muted
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime createdAt;
/// The date of the last update
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime updatedAt;
/// Serialize to json
Map<String, dynamic> toJson() => _$MuteToJson(this);
}
@@ -0,0 +1,32 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'mute.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Mute _$MuteFromJson(Map<String, dynamic> json) {
return Mute(
user: User.fromJson(json['user'] as Map<String, dynamic>),
channel: ChannelModel.fromJson(json['channel'] as Map<String, dynamic>),
createdAt: DateTime.parse(json['created_at'] as String),
updatedAt: DateTime.parse(json['updated_at'] as String),
);
}
Map<String, dynamic> _$MuteToJson(Mute instance) {
final val = <String, dynamic>{};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('user', readonly(instance.user));
writeNotNull('channel', readonly(instance.channel));
writeNotNull('created_at', readonly(instance.createdAt));
writeNotNull('updated_at', readonly(instance.updatedAt));
return val;
}
@@ -0,0 +1,101 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/device.dart';
import 'package:stream_chat/src/core/models/mute.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'own_user.g.dart';
/// The class that defines the own user model
/// This object can be found in [Event]
@JsonSerializable()
class OwnUser extends User {
/// Constructor used for json serialization
OwnUser({
this.devices = const [],
this.mutes = const [],
this.totalUnreadCount = 0,
this.unreadChannels,
this.channelMutes = const [],
required String id,
String? role,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? lastActive,
bool online = false,
Map<String, Object?> extraData = const {},
bool banned = false,
}) : super(
id: id,
role: role,
createdAt: createdAt,
updatedAt: updatedAt,
lastActive: lastActive,
online: online,
extraData: extraData,
banned: banned,
);
/// Create a new instance from a json
factory OwnUser.fromJson(Map<String, dynamic> json) => _$OwnUserFromJson(
Serialization.moveToExtraDataFromRoot(json, topLevelFields));
/// Create a new instance from [User] object
factory OwnUser.fromUser(User user) => OwnUser(
id: user.id,
role: user.role,
createdAt: user.createdAt,
updatedAt: user.updatedAt,
lastActive: user.lastActive,
online: user.online,
banned: user.banned,
extraData: user.extraData,
);
/// List of user devices
@JsonKey(
includeIfNull: false,
toJson: Serialization.readOnly,
defaultValue: <Device>[])
final List<Device> devices;
/// List of users muted by the user
@JsonKey(
includeIfNull: false,
toJson: Serialization.readOnly,
defaultValue: <Mute>[])
final List<Mute> mutes;
/// List of users muted by the user
@JsonKey(
includeIfNull: false,
toJson: Serialization.readOnly,
defaultValue: <Mute>[])
final List<Mute> channelMutes;
/// Total unread messages by the user
@JsonKey(
includeIfNull: false, toJson: Serialization.readOnly, defaultValue: 0)
final int totalUnreadCount;
/// Total unread channels by the user
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final int? unreadChannels;
/// Known top level fields.
/// Useful for [Serialization] methods.
static final topLevelFields = [
'devices',
'mutes',
'total_unread_count',
'unread_channels',
'channel_mutes',
...User.topLevelFields,
];
/// Serialize to json
@override
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$OwnUserToJson(this),
);
}
@@ -0,0 +1,66 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'own_user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
OwnUser _$OwnUserFromJson(Map<String, dynamic> json) {
return OwnUser(
devices: (json['devices'] as List<dynamic>?)
?.map((e) => Device.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
mutes: (json['mutes'] as List<dynamic>?)
?.map((e) => Mute.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
totalUnreadCount: json['total_unread_count'] as int? ?? 0,
unreadChannels: json['unread_channels'] as int?,
channelMutes: (json['channel_mutes'] as List<dynamic>?)
?.map((e) => Mute.fromJson(e as Map<String, dynamic>))
.toList() ??
[],
id: json['id'] as String,
role: json['role'] as String?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
lastActive: json['last_active'] == null
? null
: DateTime.parse(json['last_active'] as String),
online: json['online'] as bool? ?? false,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
banned: json['banned'] as bool? ?? false,
);
}
Map<String, dynamic> _$OwnUserToJson(OwnUser instance) {
final val = <String, dynamic>{
'id': instance.id,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
writeNotNull('role', readonly(instance.role));
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));
val['extra_data'] = instance.extraData;
writeNotNull('devices', readonly(instance.devices));
writeNotNull('mutes', readonly(instance.mutes));
writeNotNull('channel_mutes', readonly(instance.channelMutes));
writeNotNull('total_unread_count', readonly(instance.totalUnreadCount));
writeNotNull('unread_channels', readonly(instance.unreadChannels));
return val;
}
@@ -0,0 +1,104 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'reaction.g.dart';
/// The class that defines a reaction
@JsonSerializable()
class Reaction {
/// Constructor used for json serialization
Reaction({
this.messageId,
DateTime? createdAt,
required this.type,
this.user,
String? userId,
this.score = 0,
this.extraData = const {},
}) : userId = userId ?? user?.id,
createdAt = createdAt ?? DateTime.now();
/// Create a new instance from a json
factory Reaction.fromJson(Map<String, dynamic> json) =>
_$ReactionFromJson(Serialization.moveToExtraDataFromRoot(
json,
topLevelFields,
));
/// The messageId to which the reaction belongs
final String? messageId;
/// The type of the reaction
final String type;
/// The date of the reaction
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime createdAt;
/// The user that sent the reaction
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final User? user;
/// The score of the reaction (ie. number of reactions sent)
@JsonKey(defaultValue: 0)
final int score;
/// The userId that sent the reaction
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final String? userId;
/// Reaction custom extraData
@JsonKey(
includeIfNull: false,
defaultValue: {},
)
final Map<String, Object?> extraData;
/// Map of custom user extraData
static const topLevelFields = [
'message_id',
'created_at',
'type',
'user',
'user_id',
'score',
];
/// Serialize to json
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$ReactionToJson(this),
);
/// Creates a copy of [Reaction] with specified attributes overridden.
Reaction copyWith({
String? messageId,
DateTime? createdAt,
String? type,
User? user,
String? userId,
int? score,
Map<String, Object?>? extraData,
}) =>
Reaction(
messageId: messageId ?? this.messageId,
createdAt: createdAt ?? this.createdAt,
type: type ?? this.type,
user: user ?? this.user,
userId: userId ?? this.userId,
score: score ?? this.score,
extraData: extraData ?? this.extraData,
);
/// Returns a new [Reaction] that is a combination of this reaction and the
/// given [other] reaction.
Reaction merge(Reaction other) => copyWith(
messageId: other.messageId,
createdAt: other.createdAt,
type: other.type,
user: other.user,
userId: other.userId,
score: other.score,
extraData: other.extraData,
);
}
@@ -0,0 +1,43 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'reaction.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Reaction _$ReactionFromJson(Map<String, dynamic> json) {
return Reaction(
messageId: json['message_id'] as String?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
type: json['type'] as String,
user: json['user'] == null
? null
: User.fromJson(json['user'] as Map<String, dynamic>),
userId: json['user_id'] as String?,
score: json['score'] as int? ?? 0,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
);
}
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;
}
@@ -0,0 +1,43 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/user.dart';
part 'read.g.dart';
/// The class that defines a read event
@JsonSerializable()
class Read {
/// Constructor used for json serialization
Read({
required this.lastRead,
required this.user,
this.unreadMessages = 0,
});
/// Create a new instance from a json
factory Read.fromJson(Map<String, dynamic> json) => _$ReadFromJson(json);
/// Date of the read event
final DateTime lastRead;
/// User who sent the event
final User user;
/// Number of unread messages
@JsonKey(defaultValue: 0)
final int unreadMessages;
/// Serialize to json
Map<String, dynamic> toJson() => _$ReadToJson(this);
/// Creates a copy of [Read] with specified attributes overridden.
Read copyWith({
DateTime? lastRead,
User? user,
int? unreadMessages,
}) =>
Read(
lastRead: lastRead ?? this.lastRead,
user: user ?? this.user,
unreadMessages: unreadMessages ?? this.unreadMessages,
);
}
@@ -0,0 +1,21 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'read.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
Read _$ReadFromJson(Map<String, dynamic> json) {
return Read(
lastRead: DateTime.parse(json['last_read'] as String),
user: User.fromJson(json['user'] as Map<String, dynamic>),
unreadMessages: json['unread_messages'] as int? ?? 0,
);
}
Map<String, dynamic> _$ReadToJson(Read instance) => <String, dynamic>{
'last_read': instance.lastRead.toIso8601String(),
'user': instance.user.toJson(),
'unread_messages': instance.unreadMessages,
};
@@ -0,0 +1,47 @@
import 'package:stream_chat/src/core/models/user.dart';
/// 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 Serialization {
/// Used to avoid to serialize properties to json
static const Function readOnly = readonly;
/// List of users to list of userIds
static List<String>? userIds(List<User>? users) =>
users?.map((u) => u.id).toList();
/// Takes unknown json keys and puts them in the `extra_data` key
static Map<String, dynamic> moveToExtraDataFromRoot(
Map<String, dynamic> json,
List<String> topLevelFields,
) {
final jsonClone = Map<String, dynamic>.from(json);
final extraDataMap = Map<String, dynamic>.from(json)
..removeWhere(
(key, value) => topLevelFields.contains(key),
);
final rootFields = jsonClone
..removeWhere((key, value) => extraDataMap.keys.contains(key));
return rootFields
..addAll({
'extra_data': extraDataMap,
});
}
/// Takes values in `extra_data` key and puts them on the root level of
/// the json map
static Map<String, dynamic> moveFromExtraDataToRoot(
Map<String, dynamic> json,
) {
final jsonClone = Map<String, dynamic>.from(json);
return jsonClone
..addAll({
if (json['extra_data'] != null) ...json['extra_data'],
})
..remove('extra_data');
}
}
@@ -0,0 +1,128 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:stream_chat/src/core/models/serialization.dart';
part 'user.g.dart';
/// The class that defines the user model
@JsonSerializable()
class User {
/// Constructor used for json serialization
User({
required this.id,
this.role,
DateTime? createdAt,
DateTime? updatedAt,
this.lastActive,
this.online = false,
this.extraData = const {},
this.banned = false,
this.teams = const [],
}) : createdAt = createdAt ?? DateTime.now(),
updatedAt = updatedAt ?? DateTime.now();
/// Create a new instance from a json
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(
Serialization.moveToExtraDataFromRoot(json, topLevelFields));
/// Known top level fields.
/// Useful for [Serialization] methods.
static const topLevelFields = [
'id',
'role',
'created_at',
'updated_at',
'last_active',
'online',
'banned',
'teams',
];
/// User id
final String id;
/// User role
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final String? role;
/// User role
@JsonKey(
includeIfNull: false,
toJson: Serialization.readOnly,
defaultValue: <String>[])
final List<String> teams;
/// Date of user creation
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime createdAt;
/// Date of last user update
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime updatedAt;
/// Date of last user connection
@JsonKey(includeIfNull: false, toJson: Serialization.readOnly)
final DateTime? lastActive;
/// True if user is online
@JsonKey(
includeIfNull: false, toJson: Serialization.readOnly, defaultValue: false)
final bool online;
/// True if user is banned from the chat
@JsonKey(
includeIfNull: false, toJson: Serialization.readOnly, defaultValue: false)
final bool banned;
/// Map of custom user extraData
@JsonKey(
includeIfNull: false,
defaultValue: {},
)
final Map<String, Object?> extraData;
@override
int get hashCode => id.hashCode;
/// Shortcut for user name
String get name {
if (extraData.containsKey('name')) {
final name = extraData['name']! as String;
if (name.isNotEmpty) return name;
}
return id;
}
@override
bool operator ==(Object other) =>
identical(this, other) ||
other is User && runtimeType == other.runtimeType && id == other.id;
/// Serialize to json
Map<String, dynamic> toJson() => Serialization.moveFromExtraDataToRoot(
_$UserToJson(this),
);
/// Creates a copy of [User] with specified attributes overridden.
User copyWith({
String? id,
String? role,
DateTime? createdAt,
DateTime? updatedAt,
DateTime? lastActive,
bool? online,
Map<String, Object?>? extraData,
bool? banned,
List<String>? teams,
}) =>
User(
id: id ?? this.id,
role: role ?? this.role,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
lastActive: lastActive ?? this.lastActive,
online: online ?? this.online,
extraData: extraData ?? this.extraData,
banned: banned ?? this.banned,
teams: teams ?? this.teams,
);
}
@@ -0,0 +1,51 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
User _$UserFromJson(Map<String, dynamic> json) {
return User(
id: json['id'] as String,
role: json['role'] as String?,
createdAt: json['created_at'] == null
? null
: DateTime.parse(json['created_at'] as String),
updatedAt: json['updated_at'] == null
? null
: DateTime.parse(json['updated_at'] as String),
lastActive: json['last_active'] == null
? null
: DateTime.parse(json['last_active'] as String),
online: json['online'] as bool? ?? false,
extraData: json['extra_data'] as Map<String, dynamic>? ?? {},
banned: json['banned'] as bool? ?? false,
teams:
(json['teams'] as List<dynamic>?)?.map((e) => e as String).toList() ??
[],
);
}
Map<String, dynamic> _$UserToJson(User instance) {
final val = <String, dynamic>{
'id': instance.id,
};
void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}
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));
val['extra_data'] = instance.extraData;
return val;
}
@@ -0,0 +1,16 @@
import 'dart:math' as math;
// This alphabet uses `A-Za-z0-9_-` symbols. The genetic algorithm helped
// optimize the gzip compression for this alphabet.
const _alphabet =
'ModuleSymbhasOwnPr0123456789ABCDEFGHNRVfgctiUvzKqYTJkLxpZXIjQW';
/// Generates a random String id
/// Adopted from: https://github.com/ai/nanoid/blob/main/non-secure/index.js
String randomId({int size = 21}) {
var id = '';
for (var i = 0; i < size; i++) {
id += _alphabet[(math.Random().nextInt(32) * 64) | 0];
}
return id;
}