Merge branch 'develop' of github.com:GetStream/stream-chat-flutter into develop
This commit is contained in:
@@ -294,6 +294,18 @@ class Channel {
|
||||
return data;
|
||||
}
|
||||
|
||||
/// List of user permissions on this channel
|
||||
List<String> get ownCapabilities =>
|
||||
state?._channelState.channel?.ownCapabilities ?? [];
|
||||
|
||||
/// List of user permissions on this channel
|
||||
Stream<List<String>> get ownCapabilitiesStream {
|
||||
_checkInitialized();
|
||||
return state!.channelStateStream
|
||||
.map((cs) => cs.channel?.ownCapabilities ?? [])
|
||||
.distinct();
|
||||
}
|
||||
|
||||
/// Channel extra data as a stream.
|
||||
Stream<Map<String, Object?>> get extraDataStream {
|
||||
_checkInitialized();
|
||||
@@ -489,6 +501,7 @@ class Channel {
|
||||
Future<SendMessageResponse> sendMessage(
|
||||
Message message, {
|
||||
bool skipPush = false,
|
||||
bool skipEnrichUrl = false,
|
||||
}) async {
|
||||
_checkInitialized();
|
||||
// Cancelling previous completer in case it's called again in the process
|
||||
@@ -536,6 +549,7 @@ class Channel {
|
||||
id!,
|
||||
type,
|
||||
skipPush: skipPush,
|
||||
skipEnrichUrl: skipEnrichUrl,
|
||||
);
|
||||
state!.updateMessage(response.message);
|
||||
if (cooldown > 0) cooldownStartedAt = DateTime.now();
|
||||
@@ -552,7 +566,10 @@ class Channel {
|
||||
///
|
||||
/// Waits for a [_messageAttachmentsUploadCompleter] to complete
|
||||
/// before actually updating the message.
|
||||
Future<UpdateMessageResponse> updateMessage(Message message) async {
|
||||
Future<UpdateMessageResponse> updateMessage(
|
||||
Message message, {
|
||||
bool skipEnrichUrl = false,
|
||||
}) async {
|
||||
final originalMessage = message;
|
||||
|
||||
// Cancelling previous completer in case it's called again in the process
|
||||
@@ -590,7 +607,10 @@ class Channel {
|
||||
message = await attachmentsUploadCompleter.future;
|
||||
}
|
||||
|
||||
final response = await _client.updateMessage(message);
|
||||
final response = await _client.updateMessage(
|
||||
message,
|
||||
skipEnrichUrl: skipEnrichUrl,
|
||||
);
|
||||
|
||||
final m = response.message.copyWith(
|
||||
ownReactions: message.ownReactions,
|
||||
@@ -620,12 +640,14 @@ class Channel {
|
||||
Message message, {
|
||||
Map<String, Object?>? set,
|
||||
List<String>? unset,
|
||||
bool skipEnrichUrl = false,
|
||||
}) async {
|
||||
try {
|
||||
final response = await _client.partialUpdateMessage(
|
||||
message.id,
|
||||
set: set,
|
||||
unset: unset,
|
||||
skipEnrichUrl: skipEnrichUrl,
|
||||
);
|
||||
|
||||
final updatedMessage = response.message.copyWith(
|
||||
@@ -1247,7 +1269,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 {
|
||||
@@ -1330,14 +1354,6 @@ class Channel {
|
||||
return _client.unmuteChannel(cid!);
|
||||
}
|
||||
|
||||
/// Bans the user with given [userID] from the channel.
|
||||
@Deprecated("Use 'banMember' instead. This method will be removed in v4.0.0")
|
||||
Future<EmptyResponse> banUser(
|
||||
String userID,
|
||||
Map<String, dynamic> options,
|
||||
) =>
|
||||
banMember(userID, options);
|
||||
|
||||
/// Bans the member with given [userID] from the channel.
|
||||
Future<EmptyResponse> banMember(
|
||||
String userID,
|
||||
@@ -1352,12 +1368,6 @@ class Channel {
|
||||
return _client.banUser(userID, opts);
|
||||
}
|
||||
|
||||
/// Remove the ban for the user with given [userID] in the channel.
|
||||
@Deprecated(
|
||||
"Use 'unbanMember' instead. This method will be removed in v4.0.0",
|
||||
)
|
||||
Future<EmptyResponse> unbanUser(String userID) => unbanMember(userID);
|
||||
|
||||
/// Remove the ban for the member with given [userID] in the channel.
|
||||
Future<EmptyResponse> unbanMember(String userID) async {
|
||||
_checkInitialized();
|
||||
@@ -1558,7 +1568,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) {
|
||||
@@ -1585,7 +1595,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);
|
||||
@@ -1595,9 +1606,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!,
|
||||
],
|
||||
));
|
||||
@@ -1607,11 +1619,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),
|
||||
));
|
||||
@@ -1781,9 +1795,10 @@ class ChannelClientState {
|
||||
updateMessage(message);
|
||||
|
||||
if (message.pinned) {
|
||||
final _existingPinnedMessages = _channelState.pinnedMessages ?? [];
|
||||
_channelState = _channelState.copyWith(
|
||||
pinnedMessages: [
|
||||
..._channelState.pinnedMessages,
|
||||
..._existingPinnedMessages,
|
||||
message,
|
||||
],
|
||||
);
|
||||
@@ -1821,10 +1836,6 @@ class ChannelClientState {
|
||||
}));
|
||||
}
|
||||
|
||||
/// Add a [message] to this [channelState].
|
||||
@Deprecated('Use updateMessage instead')
|
||||
void addMessage(Message message) => updateMessage(message);
|
||||
|
||||
/// Updates the [message] in the state if it exists. Adds it otherwise.
|
||||
void updateMessage(Message message) {
|
||||
if (message.parentId == null || message.showInChannel == true) {
|
||||
@@ -1919,7 +1930,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);
|
||||
|
||||
@@ -1940,31 +1951,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();
|
||||
|
||||
@@ -1985,7 +1999,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();
|
||||
|
||||
@@ -1997,11 +2011,20 @@ class ChannelClientState {
|
||||
(watchers, users) => watchers!.map((e) => users[e.id] ?? e).toList(),
|
||||
);
|
||||
|
||||
/// Channel member for the current user.
|
||||
Member? get currentUserMember => members.firstWhereOrNull(
|
||||
(m) => m.user?.id == _channel.client.state.currentUser?.id,
|
||||
);
|
||||
|
||||
/// User role for the current user.
|
||||
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;
|
||||
@@ -2022,7 +2045,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;
|
||||
@@ -2077,31 +2100,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(),
|
||||
];
|
||||
|
||||
@@ -2253,9 +2282,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,
|
||||
|
||||
Reference in New Issue
Block a user