@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user