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