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
@@ -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,
+1 -1
View File
@@ -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 -1
View File
@@ -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();
+2 -2
View File
@@ -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