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

This commit is contained in:
Ayush Shekhar
2022-03-07 17:43:34 +05:30
15 changed files with 149 additions and 101 deletions
+4 -1
View File
@@ -1,4 +1,4 @@
## Upcoming ## 3.5.0
✅ Added ✅ Added
@@ -10,6 +10,9 @@
- [[#890]](https://github.com/GetStream/stream-chat-flutter/pull/890) Fixed Reactions not updating on thread messages. - [[#890]](https://github.com/GetStream/stream-chat-flutter/pull/890) Fixed Reactions not updating on thread messages.
Thanks [bstolinski](https://github.com/bstolinski). Thanks [bstolinski](https://github.com/bstolinski).
- [[#897]](https://github.com/GetStream/stream-chat-flutter/issues/897) Fixed error type mis-match in `AuthInterceptor`. - [[#897]](https://github.com/GetStream/stream-chat-flutter/issues/897) Fixed error type mis-match in `AuthInterceptor`.
- [[#891]](https://github.com/GetStream/stream-chat-flutter/pull/891) Fixed reply counter for parent message not
updating correctly after deleting thread message.
- Fix `channelState.copyWith` with respect to pinnedMessages.
## 3.4.0 ## 3.4.0
@@ -407,7 +407,7 @@ class Channel {
if (index != -1) { if (index != -1) {
final newAttachments = [...message!.attachments]..[index] = attachment; final newAttachments = [...message!.attachments]..[index] = attachment;
final updatedMessage = message!.copyWith(attachments: newAttachments); final updatedMessage = message!.copyWith(attachments: newAttachments);
state?.addMessage(updatedMessage); state?.updateMessage(updatedMessage);
// updating original message for next iteration // updating original message for next iteration
message = message!.merge(updatedMessage); message = message!.merge(updatedMessage);
} }
@@ -512,7 +512,7 @@ class Channel {
).toList(), ).toList(),
); );
state!.addMessage(message); state!.updateMessage(message);
try { try {
if (message.attachments.any((it) => !it.uploadState.isSuccess)) { if (message.attachments.any((it) => !it.uploadState.isSuccess)) {
@@ -535,7 +535,7 @@ class Channel {
type, type,
skipPush: skipPush, skipPush: skipPush,
); );
state!.addMessage(response.message); state!.updateMessage(response.message);
if (cooldown > 0) cooldownStartedAt = DateTime.now(); if (cooldown > 0) cooldownStartedAt = DateTime.now();
return response; return response;
} catch (e) { } catch (e) {
@@ -571,7 +571,7 @@ class Channel {
).toList(), ).toList(),
); );
state?.addMessage(message); state?.updateMessage(message);
try { try {
if (message.attachments.any((it) => !it.uploadState.isSuccess)) { if (message.attachments.any((it) => !it.uploadState.isSuccess)) {
@@ -594,7 +594,7 @@ class Channel {
ownReactions: message.ownReactions, ownReactions: message.ownReactions,
); );
state?.addMessage(m); state?.updateMessage(m);
return response; return response;
} catch (e) { } catch (e) {
@@ -602,7 +602,7 @@ class Channel {
if (e.isRetriable) { if (e.isRetriable) {
state!._retryQueue.add([message]); state!._retryQueue.add([message]);
} else { } else {
state?.addMessage(originalMessage); state?.updateMessage(originalMessage);
} }
} }
rethrow; rethrow;
@@ -630,7 +630,7 @@ class Channel {
ownReactions: message.ownReactions, ownReactions: message.ownReactions,
); );
state?.addMessage(updatedMessage); state?.updateMessage(updatedMessage);
return response; return response;
} catch (e) { } catch (e) {
@@ -643,13 +643,18 @@ class Channel {
/// Deletes the [message] from the channel. /// Deletes the [message] from the channel.
Future<EmptyResponse> deleteMessage(Message message, {bool? hard}) async { Future<EmptyResponse> deleteMessage(Message message, {bool? hard}) async {
final hardDelete = hard ?? false;
// Directly deleting the local messages which are not yet sent to server // Directly deleting the local messages which are not yet sent to server
if (message.status == MessageSendingStatus.sending || if (message.status == MessageSendingStatus.sending ||
message.status == MessageSendingStatus.failed) { message.status == MessageSendingStatus.failed) {
state!.addMessage(message.copyWith( state!.deleteMessage(
type: 'deleted', message.copyWith(
status: MessageSendingStatus.sent, type: 'deleted',
)); status: MessageSendingStatus.sent,
),
hardDelete: hardDelete,
);
// Removing the attachments upload completer to stop the `sendMessage` // Removing the attachments upload completer to stop the `sendMessage`
// waiting for attachments to complete. // waiting for attachments to complete.
@@ -667,11 +672,14 @@ class Channel {
deletedAt: message.deletedAt ?? DateTime.now(), deletedAt: message.deletedAt ?? DateTime.now(),
); );
state?.addMessage(message); state?.deleteMessage(message, hardDelete: hardDelete);
final response = await _client.deleteMessage(message.id, hard: hard); final response = await _client.deleteMessage(message.id, hard: hard);
state?.addMessage(message.copyWith(status: MessageSendingStatus.sent)); state?.deleteMessage(
message.copyWith(status: MessageSendingStatus.sent),
hardDelete: hardDelete,
);
return response; return response;
} catch (e) { } catch (e) {
@@ -861,7 +869,7 @@ class Channel {
ownReactions: ownReactions, ownReactions: ownReactions,
); );
state?.addMessage(newMessage); state?.updateMessage(newMessage);
try { try {
final reactionResp = await _client.sendReaction( final reactionResp = await _client.sendReaction(
@@ -874,7 +882,7 @@ class Channel {
return reactionResp; return reactionResp;
} catch (_) { } catch (_) {
// Reset the message if the update fails // Reset the message if the update fails
state?.addMessage(message); state?.updateMessage(message);
rethrow; rethrow;
} }
} }
@@ -914,7 +922,7 @@ class Channel {
ownReactions: ownReactions, ownReactions: ownReactions,
); );
state?.addMessage(newMessage); state?.updateMessage(newMessage);
try { try {
final deleteResponse = await _client.deleteReaction( final deleteResponse = await _client.deleteReaction(
@@ -924,7 +932,7 @@ class Channel {
return deleteResponse; return deleteResponse;
} catch (_) { } catch (_) {
// Reset the message if the update fails // Reset the message if the update fails
state?.addMessage(message); state?.updateMessage(message);
rethrow; rethrow;
} }
} }
@@ -1081,7 +1089,7 @@ class Channel {
// update the passed message with response message // update the passed message with response message
if (res.message != null) { if (res.message != null) {
state!.addMessage(res.message!); state!.updateMessage(res.message!);
} else { } else {
// remove the passed message if response does // remove the passed message if response does
// not contain message // not contain message
@@ -1712,7 +1720,7 @@ class ChannelClientState {
final message = event.message!.copyWith( final message = event.message!.copyWith(
ownReactions: ownReactions, ownReactions: ownReactions,
); );
addMessage(message); updateMessage(message);
})); }));
} }
@@ -1725,7 +1733,7 @@ class ChannelClientState {
final message = event.message!.copyWith( final message = event.message!.copyWith(
ownReactions: oldMessage?.ownReactions, ownReactions: oldMessage?.ownReactions,
); );
addMessage(message); updateMessage(message);
})); }));
} }
@@ -1743,7 +1751,7 @@ class ChannelClientState {
final message = event.message!.copyWith( final message = event.message!.copyWith(
ownReactions: oldMessage?.ownReactions, ownReactions: oldMessage?.ownReactions,
); );
addMessage(message); updateMessage(message);
if (message.pinned) { if (message.pinned) {
_channelState = _channelState.copyWith( _channelState = _channelState.copyWith(
@@ -1760,9 +1768,9 @@ class ChannelClientState {
_subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) { _subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) {
final message = event.message!; final message = event.message!;
if (event.hardDelete == true) { if (event.hardDelete == true) {
removeMessage(message, hardDelete: true); removeMessage(message);
} else { } else {
addMessage(message); updateMessage(message);
} }
})); }));
} }
@@ -1777,7 +1785,7 @@ class ChannelClientState {
final message = event.message!; final message = event.message!;
if (isUpToDate || if (isUpToDate ||
(message.parentId != null && message.showInChannel != true)) { (message.parentId != null && message.showInChannel != true)) {
addMessage(message); updateMessage(message);
} }
if (_countMessageAsUnread(message)) { if (_countMessageAsUnread(message)) {
@@ -1787,9 +1795,13 @@ class ChannelClientState {
} }
/// Add a [message] to this [channelState]. /// Add a [message] to this [channelState].
void addMessage(Message message) { @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) { if (message.parentId == null || message.showInChannel == true) {
final newMessages = List<Message>.from(_channelState.messages); final newMessages = [...messages];
final oldIndex = newMessages.indexWhere((m) => m.id == message.id); final oldIndex = newMessages.indexWhere((m) => m.id == message.id);
if (oldIndex != -1) { if (oldIndex != -1) {
Message? m; Message? m;
@@ -1804,8 +1816,24 @@ class ChannelClientState {
newMessages.add(message); newMessages.add(message);
} }
final newPinnedMessages = [...pinnedMessages];
final oldPinnedIndex =
newPinnedMessages.indexWhere((m) => m.id == message.id);
// Handle pinned messages
if (message.pinned) {
if (oldPinnedIndex != -1) {
newPinnedMessages[oldPinnedIndex] = message;
} else {
newPinnedMessages.add(message);
}
} else {
newPinnedMessages.removeWhere((m) => m.id == message.id);
}
_channelState = _channelState.copyWith( _channelState = _channelState.copyWith(
messages: newMessages..sort(_sortByCreatedAt), messages: newMessages..sort(_sortByCreatedAt),
pinnedMessages: newPinnedMessages,
channel: _channelState.channel?.copyWith( channel: _channelState.channel?.copyWith(
lastMessageAt: message.createdAt, lastMessageAt: message.createdAt,
), ),
@@ -1818,41 +1846,35 @@ class ChannelClientState {
} }
/// Remove a [message] from this [channelState]. /// Remove a [message] from this [channelState].
void removeMessage(Message message, {bool hardDelete = false}) { void removeMessage(Message message) {
final parentId = message.parentId; final parentId = message.parentId;
// i.e. it's a thread message // i.e. it's a thread message, Remove it
// 1. Remove the thread message
// 2. Reduce total reply count of parent message
if (parentId != null) { if (parentId != null) {
final allMessages = [...messages]; final newThreads = {...threads};
final parentMessage = allMessages.firstWhereOrNull( // Early return in case the thread is not available
(it) => it.id == parentId, if (!newThreads.containsKey(parentId)) return;
);
// return if message not available in the memory _threads = newThreads
if (parentMessage == null) return; ..update(
final replyCount = parentMessage.replyCount; parentId,
// return if reply count is null or zero (messages) => messages..removeWhere((e) => e.id == message.id),
if (replyCount == null || replyCount == 0) return; );
addMessage(parentMessage.copyWith(replyCount: replyCount - 1)); // Early return if the thread message is not shown in channel.
updateThreadInfo( if (message.showInChannel == false) return;
parentId,
threads[parentId]!
..removeWhere(
(e) => e.id == message.id,
),
);
} else {
// Remove regular message
final allMessages = [...messages];
if (hardDelete) {
allMessages.removeWhere((e) => e.id == message.id);
_channelState = _channelState.copyWith(messages: allMessages);
} else if (allMessages.remove(message)) {
_channelState = _channelState.copyWith(messages: allMessages);
}
} }
// Remove regular message, thread message shown in channel
final allMessages = [...messages];
_channelState = _channelState.copyWith(
messages: allMessages..removeWhere((e) => e.id == message.id),
);
}
/// Removes/Updates the [message] based on the [hardDelete] value.
void deleteMessage(Message message, {bool hardDelete = false}) {
if (hardDelete) return removeMessage(message);
return updateMessage(message);
} }
void _listenReadEvents() { void _listenReadEvents() {
@@ -1898,11 +1920,12 @@ class ChannelClientState {
.distinct(const ListEquality().equals); .distinct(const ListEquality().equals);
/// Channel pinned message list. /// Channel pinned message list.
List<Message> get pinnedMessages => _channelState.pinnedMessages.toList(); List<Message> get pinnedMessages => _channelState.pinnedMessages;
/// Channel pinned message list as a stream. /// Channel pinned message list as a stream.
Stream<List<Message>> get pinnedMessagesStream => Stream<List<Message>> get pinnedMessagesStream => channelStateStream
channelStateStream.map((cs) => cs.pinnedMessages.toList()); .map((cs) => cs.pinnedMessages)
.distinct(const ListEquality().equals);
/// Get channel last message. /// Get channel last message.
Message? get lastMessage => Message? get lastMessage =>
@@ -2213,7 +2236,7 @@ class ChannelClientState {
.toList(); .toList();
updateChannelState(_channelState.copyWith( updateChannelState(_channelState.copyWith(
pinnedMessages: pinnedMessages.where(_pinIsValid()).toList(), pinnedMessages: pinnedMessages.where(_pinIsValid).toList(),
messages: expiredMessages, messages: expiredMessages,
)); ));
} }
@@ -2250,7 +2273,7 @@ class ChannelClientState {
} }
} }
bool Function(Message) _pinIsValid() { bool _pinIsValid(Message message) {
final now = DateTime.now(); final now = DateTime.now();
return (Message m) => m.pinExpires!.isAfter(now); return message.pinExpires!.isAfter(now);
} }
@@ -158,7 +158,7 @@ class RetryQueue {
: message.status == MessageSendingStatus.updating : message.status == MessageSendingStatus.updating
? MessageSendingStatus.failed_update ? MessageSendingStatus.failed_update
: MessageSendingStatus.failed_delete; : MessageSendingStatus.failed_delete;
channel.state?.addMessage(message.copyWith(status: newStatus)); channel.state?.updateMessage(message.copyWith(status: newStatus));
} }
Future<void> _retryMessage(Message message) async { Future<void> _retryMessage(Message message) async {
@@ -56,7 +56,7 @@ class ChannelState {
ChannelModel? channel, ChannelModel? channel,
List<Message>? messages, List<Message>? messages,
List<Member>? members, List<Member>? members,
List<Message>? pinnedMessages, List<Message> pinnedMessages = _emptyPinnedMessages,
int? watcherCount, int? watcherCount,
List<User>? watchers, List<User>? watchers,
List<Read>? read, List<Read>? read,
@@ -69,7 +69,7 @@ class ChannelState {
// FIXME: Use non-nullable by default instead of empty list. // FIXME: Use non-nullable by default instead of empty list.
pinnedMessages: pinnedMessages == _emptyPinnedMessages pinnedMessages: pinnedMessages == _emptyPinnedMessages
? this.pinnedMessages ? this.pinnedMessages
: pinnedMessages ?? _emptyPinnedMessages, : pinnedMessages,
watcherCount: watcherCount ?? this.watcherCount, watcherCount: watcherCount ?? this.watcherCount,
watchers: watchers ?? this.watchers, watchers: watchers ?? this.watchers,
read: read ?? this.read, read: read ?? this.read,
+1 -1
View File
@@ -3,4 +3,4 @@ import 'package:stream_chat/src/client/client.dart';
/// Current package version /// Current package version
/// Used in [StreamChatClient] to build the `x-stream-client` header /// Used in [StreamChatClient] to build the `x-stream-client` header
// ignore: constant_identifier_names // ignore: constant_identifier_names
const PACKAGE_VERSION = '3.4.0'; const PACKAGE_VERSION = '3.5.0';
+1 -1
View File
@@ -1,7 +1,7 @@
name: stream_chat name: stream_chat
homepage: https://getstream.io/ homepage: https://getstream.io/
description: The official Dart client for Stream Chat, a service for building chat applications. description: The official Dart client for Stream Chat, a service for building chat applications.
version: 3.4.0 version: 3.5.0
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -2,6 +2,12 @@
🐞 Fixed 🐞 Fixed
- Mentions overlay now doesn't overflow when not enough height available
## 3.5.0
🐞 Fixed
- [[#888]](https://github.com/GetStream/stream-chat-flutter/issues/888) Fix `unban` command not working in `MessageInput`. - [[#888]](https://github.com/GetStream/stream-chat-flutter/issues/888) Fix `unban` command not working in `MessageInput`.
- [[#805]](https://github.com/GetStream/stream-chat-flutter/issues/805) Updated chewie dependency version to 1.3.0 - [[#805]](https://github.com/GetStream/stream-chat-flutter/issues/805) Updated chewie dependency version to 1.3.0
- Fix `showScrollToBottom` in `MessageListView` not respecting false value. - Fix `showScrollToBottom` in `MessageListView` not respecting false value.
@@ -26,7 +26,7 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android { android {
compileSdkVersion 30 compileSdkVersion 31
sourceSets { sourceSets {
main.java.srcDirs += 'src/main/kotlin' main.java.srcDirs += 'src/main/kotlin'
@@ -41,7 +41,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.example.example" applicationId "com.example.example"
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 30 targetSdkVersion 31
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
} }
@@ -16,6 +16,7 @@
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true" android:hardwareAccelerated="true"
android:exported="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
@@ -1,5 +1,5 @@
buildscript { buildscript {
ext.kotlin_version = '1.5.20' ext.kotlin_version = '1.6.0'
repositories { repositories {
google() google()
jcenter() jcenter()
@@ -27,9 +27,12 @@ dependencies:
cupertino_icons: ^1.0.3 cupertino_icons: ^1.0.3
flutter: flutter:
sdk: flutter sdk: flutter
stream_chat_flutter: ^2.2.1 stream_chat_flutter:
stream_chat_localizations: ^1.1.0 path: ../
stream_chat_persistence: ^2.2.0 stream_chat_localizations:
path: ../../stream_chat_localizations
stream_chat_persistence:
path: ../../stream_chat_persistence
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
@@ -347,6 +347,7 @@ class MessageInputState extends State<MessageInput> {
final _imagePicker = ImagePicker(); final _imagePicker = ImagePicker();
late final _focusNode = widget.focusNode ?? FocusNode(); late final _focusNode = widget.focusNode ?? FocusNode();
late final _isInternalFocusNode = widget.focusNode == null;
bool _inputEnabled = true; bool _inputEnabled = true;
bool _commandEnabled = false; bool _commandEnabled = false;
bool _showCommandsOverlay = false; bool _showCommandsOverlay = false;
@@ -1195,30 +1196,36 @@ class MessageInputState extends State<MessageInput> {
}; };
} }
return UserMentionsOverlay( return LayoutBuilder(
query: query, builder: (context, snapshot) => UserMentionsOverlay(
mentionAllAppUsers: widget.mentionAllAppUsers, query: query,
client: StreamChat.of(context).client, mentionAllAppUsers: widget.mentionAllAppUsers,
channel: channel, client: StreamChat.of(context).client,
size: Size(renderObject.size.width - 16, 400), channel: channel,
mentionsTileBuilder: tileBuilder, size: Size(
onMentionUserTap: (user) { renderObject.size.width - 16,
_mentionedUsers.add(user); min(400, (snapshot.maxHeight - renderObject.size.height - 16).abs()),
splits[splits.length - 1] = user.name; ),
final rejoin = splits.join('@'); mentionsTileBuilder: tileBuilder,
onMentionUserTap: (user) {
_mentionedUsers.add(user);
splits[splits.length - 1] = user.name;
final rejoin = splits.join('@');
textEditingController.value = TextEditingValue( textEditingController.value = TextEditingValue(
text: rejoin + text: rejoin +
textEditingController.text.substring( textEditingController.text.substring(
textEditingController.selection.start, textEditingController.selection.start,
), ),
selection: TextSelection.collapsed( selection: TextSelection.collapsed(
offset: rejoin.length, offset: rejoin.length,
), ),
); );
_onChangedDebounced.cancel(); _onChangedDebounced.cancel();
setState(() => _showMentionsOverlay = false);
}, setState(() => _showMentionsOverlay = false);
},
),
); );
} }
@@ -1929,6 +1936,7 @@ class MessageInputState extends State<MessageInput> {
void dispose() { void dispose() {
textEditingController.dispose(); textEditingController.dispose();
_focusNode.removeListener(_focusNodeListener); _focusNode.removeListener(_focusNodeListener);
if (_isInternalFocusNode) _focusNode.dispose();
_stopSlowMode(); _stopSlowMode();
_onChangedDebounced.cancel(); _onChangedDebounced.cancel();
super.dispose(); super.dispose();
+2 -2
View File
@@ -1,7 +1,7 @@
name: stream_chat_flutter name: stream_chat_flutter
homepage: https://github.com/GetStream/stream-chat-flutter homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter. description: Stream Chat official Flutter SDK. Build your own chat experience using Dart and Flutter.
version: 3.4.0 version: 3.5.0
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -36,7 +36,7 @@ dependencies:
rxdart: ^0.27.0 rxdart: ^0.27.0
share_plus: ^3.0.4 share_plus: ^3.0.4
shimmer: ^2.0.0 shimmer: ^2.0.0
stream_chat_flutter_core: ^3.4.0 stream_chat_flutter_core: ^3.5.0
substring_highlight: ^1.0.26 substring_highlight: ^1.0.26
synchronized: ^3.0.0 synchronized: ^3.0.0
url_launcher: ^6.0.3 url_launcher: ^6.0.3
@@ -1,3 +1,7 @@
## 3.5.0
- Updated `stream_chat` dependency to [`3.5.0`](https://pub.dev/packages/stream_chat/changelog).
## 3.4.0 ## 3.4.0
- Updated `stream_chat` dependency to [`3.4.0`](https://pub.dev/packages/stream_chat/changelog). - Updated `stream_chat` dependency to [`3.4.0`](https://pub.dev/packages/stream_chat/changelog).
@@ -1,7 +1,7 @@
name: stream_chat_flutter_core name: stream_chat_flutter_core
homepage: https://github.com/GetStream/stream-chat-flutter homepage: https://github.com/GetStream/stream-chat-flutter
description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter. description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter.
version: 3.4.0 version: 3.5.0
repository: https://github.com/GetStream/stream-chat-flutter repository: https://github.com/GetStream/stream-chat-flutter
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
@@ -16,7 +16,7 @@ dependencies:
sdk: flutter sdk: flutter
meta: ^1.3.0 meta: ^1.3.0
rxdart: ^0.27.0 rxdart: ^0.27.0
stream_chat: ^3.4.0 stream_chat: ^3.5.0
dev_dependencies: dev_dependencies:
dart_code_metrics: ^4.4.0 dart_code_metrics: ^4.4.0