Migrated llc Lists to be nullable instead of being an empty array

This commit is contained in:
Ayush Shekhar
2022-04-26 21:11:24 +05:30
parent 381e1c06f5
commit b6bb3608e5
23 changed files with 178 additions and 153 deletions
@@ -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);
}