Merge branch 'develop' of github.com:GetStream/stream-chat-flutter into develop

This commit is contained in:
xsahil03x
2022-05-05 20:11:43 +05:30
411 changed files with 23761 additions and 2944 deletions
@@ -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,
+16 -21
View File
@@ -29,7 +29,6 @@ import 'package:stream_chat/src/core/platform_detector/platform_detector.dart';
import 'package:stream_chat/src/core/util/utils.dart';
import 'package:stream_chat/src/db/chat_persistence_client.dart';
import 'package:stream_chat/src/event_type.dart';
import 'package:stream_chat/src/location.dart';
import 'package:stream_chat/src/ws/connection_status.dart';
import 'package:stream_chat/src/ws/websocket.dart';
import 'package:stream_chat/version.dart';
@@ -66,10 +65,6 @@ class StreamChatClient {
this.logLevel = Level.WARNING,
this.logHandlerFunction = StreamChatClient.defaultLogHandler,
RetryPolicy? retryPolicy,
@Deprecated('''
Location is now deprecated in favor of the new edge server. Will be removed in v4.0.0.
Read more here: https://getstream.io/blog/chat-edge-infrastructure
''') Location? location,
String? baseURL,
Duration connectTimeout = const Duration(seconds: 6),
Duration receiveTimeout = const Duration(seconds: 6),
@@ -426,6 +421,7 @@ class StreamChatClient {
}
void _connectionStatusHandler(ConnectionStatus status) async {
final previousState = wsConnectionStatus;
final currentState = _wsConnectionStatus = status;
handleEvent(Event(
@@ -433,7 +429,8 @@ class StreamChatClient {
online: status == ConnectionStatus.connected,
));
if (currentState == ConnectionStatus.connected) {
if (currentState == ConnectionStatus.connected &&
previousState != ConnectionStatus.connected) {
// connection recovered
final cids = state.channels.keys.toList(growable: false);
if (cids.isNotEmpty) {
@@ -621,7 +618,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);
@@ -1246,12 +1243,14 @@ class StreamChatClient {
String channelId,
String channelType, {
bool skipPush = false,
bool skipEnrichUrl = false,
}) =>
_chatApi.message.sendMessage(
channelId,
channelType,
message,
skipPush: skipPush,
skipEnrichUrl: skipEnrichUrl,
);
/// Lists all the message replies for the [parentId]
@@ -1275,8 +1274,14 @@ class StreamChatClient {
);
/// Update the given message
Future<UpdateMessageResponse> updateMessage(Message message) =>
_chatApi.message.updateMessage(message);
Future<UpdateMessageResponse> updateMessage(
Message message, {
bool skipEnrichUrl = false,
}) =>
_chatApi.message.updateMessage(
message,
skipEnrichUrl: skipEnrichUrl,
);
/// Partially update the given [messageId]
/// Use [set] to define values to be set
@@ -1285,11 +1290,13 @@ class StreamChatClient {
String messageId, {
Map<String, Object?>? set,
List<String>? unset,
bool skipEnrichUrl = false,
}) =>
_chatApi.message.partialUpdateMessage(
messageId,
set: set,
unset: unset,
skipEnrichUrl: skipEnrichUrl,
);
/// Deletes the given message
@@ -1555,18 +1562,6 @@ class ClientState {
/// The current user as a stream
Stream<OwnUser?> get currentUserStream => _currentUserController.stream;
// coverage:ignore-start
/// The current user
@Deprecated('Use `.currentUser` instead, Will be removed in future releases')
OwnUser? get user => _currentUserController.valueOrNull;
/// The current user as a stream
@Deprecated(
'Use `.currentUserStream` instead, Will be removed in future releases',
)
Stream<OwnUser?> get userStream => _currentUserController.stream;
// coverage:ignore-end
/// The current user
@@ -5,9 +5,9 @@ import 'package:rxdart/rxdart.dart';
import 'package:stream_chat/src/client/retry_policy.dart';
import 'package:stream_chat/stream_chat.dart';
/// The retry queue associated to a channel
/// The retry queue associated to a channel.
class RetryQueue {
/// Instantiate a new RetryQueue object
/// Instantiate a new RetryQueue object.
RetryQueue({
required this.channel,
this.logger,
@@ -17,13 +17,13 @@ class RetryQueue {
_listenFailedEvents();
}
/// The channel of this queue
/// The channel of this queue.
final Channel channel;
/// The client associated with this [channel]
/// The client associated with this [channel].
final StreamChatClient client;
/// The logger associated to this queue
/// The logger associated to this queue.
final Logger? logger;
late final RetryPolicy _retryPolicy;
@@ -63,7 +63,7 @@ class RetryQueue {
}).addTo(_compositeSubscription);
}
/// Add a list of messages
/// Add a list of messages.
void add(List<Message> messages) {
if (messages.isEmpty) return;
if (!_messageQueue.containsAllMessage(messages)) {
@@ -113,6 +113,7 @@ class RetryQueue {
} catch (e) {
if (e is! StreamChatNetworkError || !e.isRetriable) {
_messageQueue.removeMessage(message);
_sendFailedEvent(message);
return true;
}
// retry logic
@@ -174,10 +175,10 @@ class RetryQueue {
}
}
/// Whether our [_messageQueue] has messages or not
/// Whether our [_messageQueue] has messages or not.
bool get hasMessages => _messageQueue.isNotEmpty;
/// Call this method to dispose this object
/// Call this method to dispose this object.
void dispose() {
_messageQueue.clear();
_compositeSubscription.dispose();