Migrated llc Lists to be nullable instead of being an empty array
This commit is contained in:
@@ -1259,7 +1259,9 @@ class Channel {
|
||||
if (preferOffline && cid != null) {
|
||||
final updatedState = await _client.chatPersistenceClient
|
||||
?.getChannelStateByCid(cid!, messagePagination: messagesPagination);
|
||||
if (updatedState != null && updatedState.messages.isNotEmpty) {
|
||||
if (updatedState != null &&
|
||||
updatedState.messages != null &&
|
||||
updatedState.messages!.isNotEmpty) {
|
||||
if (this.state == null) {
|
||||
_initState(updatedState);
|
||||
} else {
|
||||
@@ -1570,7 +1572,7 @@ class ChannelClientState {
|
||||
|
||||
void _checkExpiredAttachmentMessages(ChannelState channelState) async {
|
||||
final expiredAttachmentMessagesId = channelState.messages
|
||||
.where((m) =>
|
||||
?.where((m) =>
|
||||
!_updatedMessagesIds.contains(m.id) &&
|
||||
m.attachments.isNotEmpty &&
|
||||
m.attachments.any((e) {
|
||||
@@ -1597,7 +1599,8 @@ class ChannelClientState {
|
||||
.map((e) => e.id)
|
||||
.toList();
|
||||
|
||||
if (expiredAttachmentMessagesId.isNotEmpty) {
|
||||
if (expiredAttachmentMessagesId != null &&
|
||||
expiredAttachmentMessagesId.isNotEmpty) {
|
||||
await _channel._initializedCompleter.future;
|
||||
_updatedMessagesIds.addAll(expiredAttachmentMessagesId);
|
||||
_channel.getMessagesById(expiredAttachmentMessagesId);
|
||||
@@ -1607,9 +1610,10 @@ class ChannelClientState {
|
||||
void _listenMemberAdded() {
|
||||
_subscriptions.add(_channel.on(EventType.memberAdded).listen((Event e) {
|
||||
final member = e.member;
|
||||
final existingMembers = channelState.members ?? [];
|
||||
updateChannelState(channelState.copyWith(
|
||||
members: [
|
||||
...channelState.members,
|
||||
...existingMembers,
|
||||
member!,
|
||||
],
|
||||
));
|
||||
@@ -1619,11 +1623,13 @@ class ChannelClientState {
|
||||
void _listenMemberRemoved() {
|
||||
_subscriptions.add(_channel.on(EventType.memberRemoved).listen((Event e) {
|
||||
final user = e.user;
|
||||
final existingMembers = channelState.members ?? [];
|
||||
final existingRead = channelState.read ?? [];
|
||||
updateChannelState(channelState.copyWith(
|
||||
members: channelState.members
|
||||
members: existingMembers
|
||||
.where((m) => m.userId != user!.id)
|
||||
.toList(growable: false),
|
||||
read: channelState.read
|
||||
read: existingRead
|
||||
.where((r) => r.user.id != user!.id)
|
||||
.toList(growable: false),
|
||||
));
|
||||
@@ -1793,9 +1799,10 @@ class ChannelClientState {
|
||||
updateMessage(message);
|
||||
|
||||
if (message.pinned) {
|
||||
final _existingPinnedMessages = _channelState.pinnedMessages ?? [];
|
||||
_channelState = _channelState.copyWith(
|
||||
pinnedMessages: [
|
||||
..._channelState.pinnedMessages,
|
||||
..._existingPinnedMessages,
|
||||
message,
|
||||
],
|
||||
);
|
||||
@@ -1931,7 +1938,7 @@ class ChannelClientState {
|
||||
)
|
||||
.listen(
|
||||
(event) {
|
||||
final readList = List<Read>.from(_channelState.read);
|
||||
final readList = List<Read>.from(_channelState.read ?? []);
|
||||
final userReadIndex =
|
||||
read.indexWhere((r) => r.user.id == event.user!.id);
|
||||
|
||||
@@ -1952,31 +1959,34 @@ class ChannelClientState {
|
||||
}
|
||||
|
||||
/// Channel message list.
|
||||
List<Message> get messages => _channelState.messages;
|
||||
List<Message> get messages => _channelState.messages ?? <Message>[];
|
||||
|
||||
/// Channel message list as a stream.
|
||||
Stream<List<Message>> get messagesStream => channelStateStream
|
||||
.map((cs) => cs.messages)
|
||||
.map((cs) => cs.messages ?? <Message>[])
|
||||
.distinct(const ListEquality().equals);
|
||||
|
||||
/// Channel pinned message list.
|
||||
List<Message> get pinnedMessages => _channelState.pinnedMessages;
|
||||
List<Message> get pinnedMessages =>
|
||||
_channelState.pinnedMessages ?? <Message>[];
|
||||
|
||||
/// Channel pinned message list as a stream.
|
||||
Stream<List<Message>> get pinnedMessagesStream => channelStateStream
|
||||
.map((cs) => cs.pinnedMessages)
|
||||
.map((cs) => cs.pinnedMessages ?? <Message>[])
|
||||
.distinct(const ListEquality().equals);
|
||||
|
||||
/// Get channel last message.
|
||||
Message? get lastMessage =>
|
||||
_channelState.messages.isNotEmpty ? _channelState.messages.last : null;
|
||||
_channelState.messages != null && _channelState.messages!.isNotEmpty
|
||||
? _channelState.messages!.last
|
||||
: null;
|
||||
|
||||
/// Get channel last message.
|
||||
Stream<Message?> get lastMessageStream =>
|
||||
messagesStream.map((event) => event.isNotEmpty ? event.last : null);
|
||||
|
||||
/// Channel members list.
|
||||
List<Member> get members => _channelState.members
|
||||
List<Member> get members => (_channelState.members ?? <Member>[])
|
||||
.map((e) => e.copyWith(user: _channel.client.state.users[e.user!.id]))
|
||||
.toList();
|
||||
|
||||
@@ -1997,7 +2007,7 @@ class ChannelClientState {
|
||||
channelStateStream.map((cs) => cs.watcherCount);
|
||||
|
||||
/// Channel watchers list.
|
||||
List<User> get watchers => _channelState.watchers
|
||||
List<User> get watchers => (_channelState.watchers ?? <User>[])
|
||||
.map((e) => _channel.client.state.users[e.id] ?? e)
|
||||
.toList();
|
||||
|
||||
@@ -2018,10 +2028,11 @@ class ChannelClientState {
|
||||
String? get currentUserRole => currentUserMember?.role;
|
||||
|
||||
/// Channel read list.
|
||||
List<Read> get read => _channelState.read;
|
||||
List<Read> get read => _channelState.read ?? <Read>[];
|
||||
|
||||
/// Channel read list as a stream.
|
||||
Stream<List<Read>> get readStream => channelStateStream.map((cs) => cs.read);
|
||||
Stream<List<Read>> get readStream =>
|
||||
channelStateStream.map((cs) => cs.read ?? <Read>[]);
|
||||
|
||||
bool _isCurrentUserRead(Read read) =>
|
||||
read.user.id == _channel._client.state.currentUser!.id;
|
||||
@@ -2042,7 +2053,7 @@ class ChannelClientState {
|
||||
|
||||
/// Setter for unread count.
|
||||
set unreadCount(int count) {
|
||||
final reads = [..._channelState.read];
|
||||
final reads = [...read];
|
||||
final currentUserReadIndex = reads.indexWhere(_isCurrentUserRead);
|
||||
|
||||
if (currentUserReadIndex < 0) return;
|
||||
@@ -2097,31 +2108,37 @@ class ChannelClientState {
|
||||
|
||||
/// Update channelState with updated information.
|
||||
void updateChannelState(ChannelState updatedState) {
|
||||
final _existingStateMessages = _channelState.messages ?? [];
|
||||
final _updatedStateMessages = updatedState.messages ?? [];
|
||||
final newMessages = <Message>[
|
||||
...updatedState.messages,
|
||||
..._channelState.messages
|
||||
..._updatedStateMessages,
|
||||
..._existingStateMessages
|
||||
.where((m) =>
|
||||
!updatedState.messages.any((newMessage) => newMessage.id == m.id))
|
||||
!_updatedStateMessages.any((newMessage) => newMessage.id == m.id))
|
||||
.toList(),
|
||||
]..sort(_sortByCreatedAt);
|
||||
|
||||
final _existingStateWatchers = _channelState.watchers ?? [];
|
||||
final _updatedStateWatchers = updatedState.watchers ?? [];
|
||||
final newWatchers = <User>[
|
||||
...updatedState.watchers,
|
||||
..._channelState.watchers
|
||||
..._updatedStateWatchers,
|
||||
..._existingStateWatchers
|
||||
.where((w) =>
|
||||
!updatedState.watchers.any((newWatcher) => newWatcher.id == w.id))
|
||||
!_updatedStateWatchers.any((newWatcher) => newWatcher.id == w.id))
|
||||
.toList(),
|
||||
];
|
||||
|
||||
final newMembers = <Member>[
|
||||
...updatedState.members,
|
||||
...updatedState.members ?? [],
|
||||
];
|
||||
|
||||
final _existingStateRead = _channelState.read ?? [];
|
||||
final _updatedStateRead = updatedState.read ?? [];
|
||||
final newReads = <Read>[
|
||||
...updatedState.read,
|
||||
..._channelState.read
|
||||
..._updatedStateRead,
|
||||
..._existingStateRead
|
||||
.where((r) =>
|
||||
!updatedState.read.any((newRead) => newRead.user.id == r.user.id))
|
||||
!_updatedStateRead.any((newRead) => newRead.user.id == r.user.id))
|
||||
.toList(),
|
||||
];
|
||||
|
||||
@@ -2273,9 +2290,9 @@ class ChannelClientState {
|
||||
_pinnedMessagesTimer = Timer.periodic(const Duration(seconds: 30), (_) {
|
||||
final now = DateTime.now();
|
||||
var expiredMessages = channelState.pinnedMessages
|
||||
.where((m) => m.pinExpires?.isBefore(now) == true)
|
||||
?.where((m) => m.pinExpires?.isBefore(now) == true)
|
||||
.toList();
|
||||
if (expiredMessages.isNotEmpty) {
|
||||
if (expiredMessages != null && expiredMessages.isNotEmpty) {
|
||||
expiredMessages = expiredMessages
|
||||
.map((m) => m.copyWith(
|
||||
pinExpires: null,
|
||||
|
||||
@@ -623,7 +623,7 @@ class StreamChatClient {
|
||||
final channels = res.channels;
|
||||
|
||||
final users = channels
|
||||
.expand((it) => it.members)
|
||||
.expand((it) => it.members ?? <Member>[])
|
||||
.map((it) => it.user)
|
||||
.toList(growable: false);
|
||||
|
||||
|
||||
@@ -124,8 +124,7 @@ class Attachment extends Equatable {
|
||||
final String? assetUrl;
|
||||
|
||||
/// Actions from a command
|
||||
@JsonKey(defaultValue: [])
|
||||
final List<Action> actions;
|
||||
final List<Action>? actions;
|
||||
|
||||
final Uri? localUri;
|
||||
|
||||
|
||||
@@ -26,9 +26,8 @@ Attachment _$AttachmentFromJson(Map<String, dynamic> json) => Attachment(
|
||||
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() ??
|
||||
[],
|
||||
?.map((e) => Action.fromJson(e as Map<String, dynamic>))
|
||||
.toList(),
|
||||
extraData: json['extra_data'] as Map<String, dynamic>? ?? const {},
|
||||
file: json['file'] == null
|
||||
? null
|
||||
@@ -64,7 +63,7 @@ Map<String, dynamic> _$AttachmentToJson(Attachment instance) {
|
||||
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('actions', instance.actions?.map((e) => e.toJson()).toList());
|
||||
writeNotNull('file', instance.file?.toJson());
|
||||
val['upload_state'] = instance.uploadState.toJson();
|
||||
val['extra_data'] = instance.extraData;
|
||||
|
||||
@@ -7,42 +7,40 @@ import 'package:stream_chat/src/core/models/user.dart';
|
||||
|
||||
part 'channel_state.g.dart';
|
||||
|
||||
const _emptyPinnedMessages = <Message>[];
|
||||
|
||||
/// 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 = _emptyPinnedMessages,
|
||||
this.messages,
|
||||
this.members,
|
||||
this.pinnedMessages,
|
||||
this.watcherCount,
|
||||
this.watchers = const [],
|
||||
this.read = const [],
|
||||
this.watchers,
|
||||
this.read,
|
||||
});
|
||||
|
||||
/// The channel to which this state belongs
|
||||
final ChannelModel? channel;
|
||||
|
||||
/// A paginated list of channel messages
|
||||
final List<Message> messages;
|
||||
final List<Message>? messages;
|
||||
|
||||
/// A paginated list of channel members
|
||||
final List<Member> members;
|
||||
final List<Member>? members;
|
||||
|
||||
/// A paginated list of pinned messages
|
||||
final List<Message> pinnedMessages;
|
||||
final List<Message>? pinnedMessages;
|
||||
|
||||
/// The count of users watching the channel
|
||||
final int? watcherCount;
|
||||
|
||||
/// A paginated list of users watching the channel
|
||||
final List<User> watchers;
|
||||
final List<User>? watchers;
|
||||
|
||||
/// The list of channel reads
|
||||
final List<Read> read;
|
||||
final List<Read>? read;
|
||||
|
||||
/// Create a new instance from a json
|
||||
static ChannelState fromJson(Map<String, dynamic> json) =>
|
||||
@@ -56,7 +54,7 @@ class ChannelState {
|
||||
ChannelModel? channel,
|
||||
List<Message>? messages,
|
||||
List<Member>? members,
|
||||
List<Message> pinnedMessages = _emptyPinnedMessages,
|
||||
List<Message>? pinnedMessages,
|
||||
int? watcherCount,
|
||||
List<User>? watchers,
|
||||
List<Read>? read,
|
||||
@@ -65,11 +63,7 @@ class ChannelState {
|
||||
channel: channel ?? this.channel,
|
||||
messages: messages ?? this.messages,
|
||||
members: members ?? this.members,
|
||||
// Hack to avoid using the default value in case nothing is provided.
|
||||
// FIXME: Use non-nullable by default instead of empty list.
|
||||
pinnedMessages: pinnedMessages == _emptyPinnedMessages
|
||||
? this.pinnedMessages
|
||||
: pinnedMessages,
|
||||
pinnedMessages: pinnedMessages ?? this.pinnedMessages,
|
||||
watcherCount: watcherCount ?? this.watcherCount,
|
||||
watchers: watchers ?? this.watchers,
|
||||
read: read ?? this.read,
|
||||
|
||||
@@ -11,36 +11,31 @@ ChannelState _$ChannelStateFromJson(Map<String, dynamic> json) => ChannelState(
|
||||
? 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() ??
|
||||
const [],
|
||||
?.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() ??
|
||||
const [],
|
||||
?.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() ??
|
||||
_emptyPinnedMessages,
|
||||
?.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() ??
|
||||
const [],
|
||||
?.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() ??
|
||||
const [],
|
||||
?.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(),
|
||||
'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(),
|
||||
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(),
|
||||
'watchers': instance.watchers?.map((e) => e.toJson()).toList(),
|
||||
'read': instance.read?.map((e) => e.toJson()).toList(),
|
||||
};
|
||||
|
||||
@@ -49,6 +49,9 @@ Message _$MessageFromJson(Map<String, dynamic> json) => Message(
|
||||
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),
|
||||
user: json['user'] == null
|
||||
? null
|
||||
: User.fromJson(json['user'] as Map<String, dynamic>),
|
||||
@@ -63,9 +66,6 @@ Message _$MessageFromJson(Map<String, dynamic> json) => Message(
|
||||
? null
|
||||
: User.fromJson(json['pinned_by'] as Map<String, dynamic>),
|
||||
extraData: json['extra_data'] as Map<String, dynamic>? ?? const {},
|
||||
deletedAt: json['deleted_at'] == null
|
||||
? null
|
||||
: DateTime.parse(json['deleted_at'] as String),
|
||||
i18n: (json['i18n'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
),
|
||||
@@ -99,6 +99,7 @@ Map<String, dynamic> _$MessageToJson(Message instance) {
|
||||
val['silent'] = instance.silent;
|
||||
writeNotNull('shadowed', readonly(instance.shadowed));
|
||||
writeNotNull('command', readonly(instance.command));
|
||||
writeNotNull('deleted_at', readonly(instance.deletedAt));
|
||||
writeNotNull('created_at', readonly(instance.createdAt));
|
||||
writeNotNull('updated_at', readonly(instance.updatedAt));
|
||||
writeNotNull('user', readonly(instance.user));
|
||||
@@ -107,7 +108,6 @@ Map<String, dynamic> _$MessageToJson(Message instance) {
|
||||
val['pin_expires'] = instance.pinExpires?.toIso8601String();
|
||||
val['pinned_by'] = readonly(instance.pinnedBy);
|
||||
val['extra_data'] = instance.extraData;
|
||||
writeNotNull('deleted_at', readonly(instance.deletedAt));
|
||||
writeNotNull('i18n', instance.i18n);
|
||||
return val;
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ abstract class ChatPersistenceClient {
|
||||
Future<ChannelModel?> getChannelByCid(String cid);
|
||||
|
||||
/// Get stored channel [Member]s by providing channel [cid]
|
||||
Future<List<Member>> getMembersByCid(String cid);
|
||||
Future<List<Member>?> getMembersByCid(String cid);
|
||||
|
||||
/// Get stored channel [Read]s by providing channel [cid]
|
||||
Future<List<Read>> getReadsByCid(String cid);
|
||||
Future<List<Read>?> getReadsByCid(String cid);
|
||||
|
||||
/// Get stored [Message]s by providing channel [cid]
|
||||
///
|
||||
@@ -78,15 +78,11 @@ abstract class ChatPersistenceClient {
|
||||
getPinnedMessagesByCid(cid, messagePagination: pinnedMessagePagination),
|
||||
]);
|
||||
return ChannelState(
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
members: data[0] as List<Member>,
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
read: data[1] as List<Read>,
|
||||
members: data[0] as List<Member>?,
|
||||
read: data[1] as List<Read>?,
|
||||
channel: data[2] as ChannelModel?,
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
messages: data[3] as List<Message>,
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
pinnedMessages: data[4] as List<Message>,
|
||||
messages: data[3] as List<Message>?,
|
||||
pinnedMessages: data[4] as List<Message>?,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -146,7 +142,7 @@ abstract class ChatPersistenceClient {
|
||||
bulkUpdateMessages({cid: messages});
|
||||
|
||||
/// Bulk updates the message data of multiple channels.
|
||||
Future<void> bulkUpdateMessages(Map<String, List<Message>> messages);
|
||||
Future<void> bulkUpdateMessages(Map<String, List<Message>?> messages);
|
||||
|
||||
/// Updates the pinned message data of a particular channel [cid] with
|
||||
/// the new [messages] data
|
||||
@@ -154,7 +150,7 @@ abstract class ChatPersistenceClient {
|
||||
bulkUpdatePinnedMessages({cid: messages});
|
||||
|
||||
/// Bulk updates the message data of multiple channels.
|
||||
Future<void> bulkUpdatePinnedMessages(Map<String, List<Message>> messages);
|
||||
Future<void> bulkUpdatePinnedMessages(Map<String, List<Message>?> messages);
|
||||
|
||||
/// Returns all the threads by parent message of a particular channel by
|
||||
/// providing channel [cid]
|
||||
@@ -169,7 +165,7 @@ abstract class ChatPersistenceClient {
|
||||
bulkUpdateMembers({cid: members});
|
||||
|
||||
/// Bulk updates the members data of multiple channels.
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>> members);
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>?> members);
|
||||
|
||||
/// Updates the read data of a particular channel [cid] with
|
||||
/// the new [reads] data
|
||||
@@ -177,7 +173,7 @@ abstract class ChatPersistenceClient {
|
||||
bulkUpdateReads({cid: reads});
|
||||
|
||||
/// Bulk updates the read data of multiple channels.
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>> reads);
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>?> reads);
|
||||
|
||||
/// Updates the users data with the new [users] data
|
||||
Future<void> updateUsers(List<User> users);
|
||||
@@ -230,10 +226,10 @@ abstract class ChatPersistenceClient {
|
||||
final membersToDelete = <String>[];
|
||||
|
||||
final channels = <ChannelModel>[];
|
||||
final channelWithMessages = <String, List<Message>>{};
|
||||
final channelWithPinnedMessages = <String, List<Message>>{};
|
||||
final channelWithReads = <String, List<Read>>{};
|
||||
final channelWithMembers = <String, List<Member>>{};
|
||||
final channelWithMessages = <String, List<Message>?>{};
|
||||
final channelWithPinnedMessages = <String, List<Message>?>{};
|
||||
final channelWithReads = <String, List<Read>?>{};
|
||||
final channelWithMembers = <String, List<Member>?>{};
|
||||
|
||||
final users = <User>[];
|
||||
final reactions = <Reaction>[];
|
||||
@@ -252,8 +248,9 @@ abstract class ChatPersistenceClient {
|
||||
|
||||
// Preparing deletion data
|
||||
membersToDelete.add(cid);
|
||||
reactionsToDelete.addAll(state.messages.map((it) => it.id));
|
||||
pinnedReactionsToDelete.addAll(state.pinnedMessages.map((it) => it.id));
|
||||
reactionsToDelete.addAll(state.messages?.map((it) => it.id) ?? []);
|
||||
pinnedReactionsToDelete
|
||||
.addAll(state.pinnedMessages?.map((it) => it.id) ?? []);
|
||||
|
||||
// preparing addition data
|
||||
channelWithReads[cid] = reads;
|
||||
@@ -261,14 +258,14 @@ abstract class ChatPersistenceClient {
|
||||
channelWithMessages[cid] = messages;
|
||||
channelWithPinnedMessages[cid] = pinnedMessages;
|
||||
|
||||
reactions.addAll(messages.expand(_expandReactions));
|
||||
pinnedReactions.addAll(pinnedMessages.expand(_expandReactions));
|
||||
reactions.addAll(messages?.expand(_expandReactions) ?? []);
|
||||
pinnedReactions.addAll(pinnedMessages?.expand(_expandReactions) ?? []);
|
||||
|
||||
users.addAll([
|
||||
channel.createdBy,
|
||||
...messages.map((it) => it.user),
|
||||
...reads.map((it) => it.user),
|
||||
...members.map((it) => it.user),
|
||||
...messages?.map((it) => it.user) ?? <User>[],
|
||||
...reads?.map((it) => it.user) ?? <User>[],
|
||||
...members?.map((it) => it.user) ?? <User>[],
|
||||
...reactions.map((it) => it.user),
|
||||
...pinnedReactions.map((it) => it.user),
|
||||
].withNullifyer);
|
||||
|
||||
@@ -105,11 +105,11 @@ void main() {
|
||||
);
|
||||
|
||||
expect(res, isNotNull);
|
||||
expect(res.messages.length, channelState.messages.length);
|
||||
expect(res.pinnedMessages.length, channelState.pinnedMessages.length);
|
||||
expect(res.members.length, channelState.members.length);
|
||||
expect(res.read.length, channelState.read.length);
|
||||
expect(res.watchers.length, channelState.watchers.length);
|
||||
expect(res.messages?.length, channelState.messages?.length);
|
||||
expect(res.pinnedMessages?.length, channelState.pinnedMessages?.length);
|
||||
expect(res.members?.length, channelState.members?.length);
|
||||
expect(res.read?.length, channelState.read?.length);
|
||||
expect(res.watchers?.length, channelState.watchers?.length);
|
||||
expect(res.watcherCount, channelState.watcherCount);
|
||||
|
||||
verify(() => client.post(path, data: any(named: 'data'))).called(1);
|
||||
|
||||
@@ -19,8 +19,10 @@ void main() {
|
||||
attachment.thumbUrl,
|
||||
'https://media0.giphy.com/media/3o7TKnCdBx5cMg0qti/giphy.gif',
|
||||
);
|
||||
expect(attachment.actions, isNotNull);
|
||||
expect(attachment.actions, isNotEmpty);
|
||||
expect(attachment.actions, hasLength(3));
|
||||
expect(attachment.actions[0], isA<Action>());
|
||||
expect(attachment.actions![0], isA<Action>());
|
||||
});
|
||||
|
||||
test('should serialize to json correctly', () {
|
||||
|
||||
@@ -30,14 +30,16 @@ void main() {
|
||||
channelState.channel?.extraData['image'],
|
||||
'https://cdn.chrisshort.net/testing-certificate-chains-in-go/GOPHER_MIC_DROP.png',
|
||||
);
|
||||
expect(channelState.messages, isNotNull);
|
||||
expect(channelState.messages, isNotEmpty);
|
||||
expect(channelState.messages, hasLength(25));
|
||||
expect(channelState.messages[0], isA<Message>());
|
||||
expect(channelState.messages[0], isNotNull);
|
||||
expect(channelState.messages![0], isA<Message>());
|
||||
expect(channelState.messages![0], isNotNull);
|
||||
expect(
|
||||
channelState.messages[0].createdAt,
|
||||
channelState.messages![0].createdAt,
|
||||
DateTime.parse('2020-01-29T03:23:02.843948Z'),
|
||||
);
|
||||
expect(channelState.messages[0].user, isA<User>());
|
||||
expect(channelState.messages![0].user, isA<User>());
|
||||
expect(channelState.watcherCount, 5);
|
||||
});
|
||||
|
||||
|
||||
@@ -117,19 +117,20 @@ class TestPersistenceClient extends ChatPersistenceClient {
|
||||
Future<void> updateUsers(List<User> users) => Future.value();
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>> members) =>
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>?> members) =>
|
||||
Future.value();
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdateMessages(Map<String, List<Message>> messages) =>
|
||||
Future<void> bulkUpdateMessages(Map<String, List<Message>?> messages) =>
|
||||
Future.value();
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdatePinnedMessages(Map<String, List<Message>> messages) =>
|
||||
Future<void> bulkUpdatePinnedMessages(Map<String, List<Message>?> messages) =>
|
||||
Future.value();
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>> reads) => Future.value();
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>?> reads) =>
|
||||
Future.value();
|
||||
}
|
||||
|
||||
void main() {
|
||||
|
||||
@@ -45,7 +45,7 @@ class StreamGiphyAttachment extends StreamAttachmentWidget {
|
||||
if (imageUrl == null) {
|
||||
return const AttachmentError();
|
||||
}
|
||||
if (attachment.actions.isNotEmpty) {
|
||||
if (attachment.actions != null && attachment.actions!.isNotEmpty) {
|
||||
return _buildSendingAttachment(context, imageUrl);
|
||||
}
|
||||
return _buildSentAttachment(context, imageUrl);
|
||||
|
||||
@@ -106,7 +106,9 @@ class StreamChannelState extends State<StreamChannel> {
|
||||
limit: limit,
|
||||
preferOffline: preferOffline,
|
||||
);
|
||||
if (state.messages.isEmpty || state.messages.length < limit) {
|
||||
if (state.messages == null ||
|
||||
state.messages!.isEmpty ||
|
||||
state.messages!.length < limit) {
|
||||
_topPaginationEnded = true;
|
||||
}
|
||||
_queryTopMessagesController.safeAdd(false);
|
||||
@@ -137,7 +139,9 @@ class StreamChannelState extends State<StreamChannel> {
|
||||
limit: limit,
|
||||
preferOffline: preferOffline,
|
||||
);
|
||||
if (state.messages.isEmpty || state.messages.length < limit) {
|
||||
if (state.messages == null ||
|
||||
state.messages!.isEmpty ||
|
||||
state.messages!.length < limit) {
|
||||
_bottomPaginationEnded = true;
|
||||
}
|
||||
_queryBottomMessagesController.safeAdd(false);
|
||||
@@ -299,7 +303,9 @@ class StreamChannelState extends State<StreamChannel> {
|
||||
),
|
||||
preferOffline: preferOffline,
|
||||
);
|
||||
if (state.messages.isEmpty || state.messages.length < limit) {
|
||||
if (state.messages == null ||
|
||||
state.messages!.isEmpty ||
|
||||
state.messages!.length < limit) {
|
||||
channel.state?.isUpToDate = true;
|
||||
}
|
||||
return state;
|
||||
|
||||
@@ -98,8 +98,9 @@ class HomeScreen extends StatelessWidget {
|
||||
AsyncSnapshot<ChannelState?> snapshot,
|
||||
) {
|
||||
if (snapshot.hasData && snapshot.data != null) {
|
||||
final _messages = snapshot.data!.messages ?? [];
|
||||
return MessageView(
|
||||
messages: snapshot.data!.messages.reversed.toList(),
|
||||
messages: _messages.reversed.toList(),
|
||||
channel: channel,
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
|
||||
@@ -34,14 +34,20 @@ class MemberDao extends DatabaseAccessor<DriftChatDatabase>
|
||||
bulkUpdateMembers({cid: memberList});
|
||||
|
||||
/// Bulk updates the members data of multiple channels
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>> channelWithMembers) {
|
||||
Future<void> bulkUpdateMembers(
|
||||
Map<String, List<Member>?> channelWithMembers,
|
||||
) {
|
||||
final entities = channelWithMembers.entries
|
||||
.map((entry) => entry.value.map(
|
||||
.map((entry) =>
|
||||
(entry.value?.map(
|
||||
(member) => member.toEntity(cid: entry.key),
|
||||
))
|
||||
)) ??
|
||||
[])
|
||||
.expand((it) => it)
|
||||
.toList(growable: false);
|
||||
return batch((batch) => batch.insertAllOnConflictUpdate(members, entities));
|
||||
return batch(
|
||||
(batch) => batch.insertAllOnConflictUpdate(members, entities),
|
||||
);
|
||||
}
|
||||
|
||||
/// Deletes all the members whose [Members.channelCid] is present in [cids]
|
||||
|
||||
@@ -183,12 +183,14 @@ class MessageDao extends DatabaseAccessor<DriftChatDatabase>
|
||||
|
||||
/// Bulk updates the message data of multiple channels
|
||||
Future<void> bulkUpdateMessages(
|
||||
Map<String, List<Message>> channelWithMessages,
|
||||
Map<String, List<Message>?> channelWithMessages,
|
||||
) {
|
||||
final entities = channelWithMessages.entries
|
||||
.map((entry) => entry.value.map(
|
||||
.map((entry) =>
|
||||
entry.value?.map(
|
||||
(message) => message.toEntity(cid: entry.key),
|
||||
))
|
||||
) ??
|
||||
[])
|
||||
.expand((it) => it)
|
||||
.toList(growable: false);
|
||||
return batch(
|
||||
|
||||
@@ -183,12 +183,14 @@ class PinnedMessageDao extends DatabaseAccessor<DriftChatDatabase>
|
||||
|
||||
/// Bulk updates the message data of multiple channels
|
||||
Future<void> bulkUpdateMessages(
|
||||
Map<String, List<Message>> channelWithMessages,
|
||||
Map<String, List<Message>?> channelWithMessages,
|
||||
) {
|
||||
final entities = channelWithMessages.entries
|
||||
.map((entry) => entry.value.map(
|
||||
.map((entry) =>
|
||||
entry.value?.map(
|
||||
(message) => message.toPinnedEntity(cid: entry.key),
|
||||
))
|
||||
) ??
|
||||
[])
|
||||
.expand((it) => it)
|
||||
.toList(growable: false);
|
||||
return batch(
|
||||
|
||||
@@ -33,11 +33,13 @@ class ReadDao extends DatabaseAccessor<DriftChatDatabase> with _$ReadDaoMixin {
|
||||
bulkUpdateReads({cid: readList});
|
||||
|
||||
/// Bulk updates the reads data of multiple channels
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>> channelWithReads) {
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>?> channelWithReads) {
|
||||
final entities = channelWithReads.entries
|
||||
.map((entry) => entry.value.map(
|
||||
.map((entry) =>
|
||||
entry.value?.map(
|
||||
(read) => read.toEntity(cid: entry.key),
|
||||
))
|
||||
) ??
|
||||
[])
|
||||
.expand((it) => it)
|
||||
.toList(growable: false);
|
||||
return batch((batch) => batch.insertAllOnConflictUpdate(reads, entities));
|
||||
|
||||
@@ -56,7 +56,7 @@ class DriftChatDatabase extends _$DriftChatDatabase {
|
||||
|
||||
// you should bump this number whenever you change or add a table definition.
|
||||
@override
|
||||
int get schemaVersion => 6;
|
||||
int get schemaVersion => 7;
|
||||
|
||||
@override
|
||||
MigrationStrategy get migration => MigrationStrategy(
|
||||
|
||||
@@ -295,21 +295,21 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>> members) {
|
||||
Future<void> bulkUpdateMembers(Map<String, List<Member>?> members) {
|
||||
assert(_debugIsConnected, '');
|
||||
_logger.info('bulkUpdateMembers');
|
||||
return _readProtected(() => db!.memberDao.bulkUpdateMembers(members));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdateMessages(Map<String, List<Message>> messages) {
|
||||
Future<void> bulkUpdateMessages(Map<String, List<Message>?> messages) {
|
||||
assert(_debugIsConnected, '');
|
||||
_logger.info('bulkUpdateMessages');
|
||||
return _readProtected(() => db!.messageDao.bulkUpdateMessages(messages));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdatePinnedMessages(Map<String, List<Message>> messages) {
|
||||
Future<void> bulkUpdatePinnedMessages(Map<String, List<Message>?> messages) {
|
||||
assert(_debugIsConnected, '');
|
||||
_logger.info('bulkUpdatePinnedMessages');
|
||||
return _readProtected(
|
||||
@@ -334,7 +334,7 @@ class StreamChatPersistenceClient extends ChatPersistenceClient {
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>> reads) {
|
||||
Future<void> bulkUpdateReads(Map<String, List<Read>?> reads) {
|
||||
assert(_debugIsConnected, '');
|
||||
_logger.info('bulkUpdateReads');
|
||||
return _readProtected(() => db!.readDao.bulkUpdateReads(reads));
|
||||
|
||||
@@ -61,10 +61,10 @@ void main() {
|
||||
);
|
||||
|
||||
expect(channelState, isA<ChannelState>());
|
||||
expect(channelState.members.length, members.length);
|
||||
expect(channelState.read.length, reads.length);
|
||||
expect(channelState.messages.length, messages.length);
|
||||
expect(channelState.pinnedMessages.length, messages.length);
|
||||
expect(channelState.members?.length, members.length);
|
||||
expect(channelState.read?.length, reads.length);
|
||||
expect(channelState.messages?.length, messages.length);
|
||||
expect(channelState.pinnedMessages?.length, messages.length);
|
||||
|
||||
final channelModel = channelState.channel!;
|
||||
expect(channelModel.id, entity.id);
|
||||
|
||||
@@ -219,10 +219,10 @@ void main() {
|
||||
.thenAnswer((_) async => messages);
|
||||
|
||||
final fetchedChannelState = await client.getChannelStateByCid(cid);
|
||||
expect(fetchedChannelState.messages.length, messages.length);
|
||||
expect(fetchedChannelState.pinnedMessages.length, messages.length);
|
||||
expect(fetchedChannelState.members.length, members.length);
|
||||
expect(fetchedChannelState.read.length, reads.length);
|
||||
expect(fetchedChannelState.messages?.length, messages.length);
|
||||
expect(fetchedChannelState.pinnedMessages?.length, messages.length);
|
||||
expect(fetchedChannelState.members?.length, members.length);
|
||||
expect(fetchedChannelState.read?.length, reads.length);
|
||||
expect(fetchedChannelState.channel!.cid, channel.cid);
|
||||
|
||||
verify(() => mockDatabase.memberDao.getMembersByCid(cid)).called(1);
|
||||
@@ -277,10 +277,10 @@ void main() {
|
||||
for (var i = 0; i < fetchedChannelStates.length; i++) {
|
||||
final original = channelStates[i];
|
||||
final fetched = fetchedChannelStates[i];
|
||||
expect(fetched.members.length, original.members.length);
|
||||
expect(fetched.messages.length, original.messages.length);
|
||||
expect(fetched.pinnedMessages.length, original.pinnedMessages.length);
|
||||
expect(fetched.read.length, original.read.length);
|
||||
expect(fetched.members?.length, original.members?.length);
|
||||
expect(fetched.messages?.length, original.messages?.length);
|
||||
expect(fetched.pinnedMessages?.length, original.pinnedMessages?.length);
|
||||
expect(fetched.read?.length, original.read?.length);
|
||||
expect(fetched.channel!.cid, original.channel!.cid);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user