From 9a4677a7b852c34344722455a64a20d5af462241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartek=20Stolin=CC=81ski?= Date: Tue, 8 Feb 2022 15:47:42 +0100 Subject: [PATCH 01/14] decrease parent message reply count only once --- .../stream_chat/lib/src/client/channel.dart | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index d3900842..84f0321e 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -1083,7 +1083,7 @@ class Channel { } else { // remove the passed message if response does // not contain message - state!.removeMessage(message); + state!.removeMessage(message, decreaseReplyCount: true); await _client.chatPersistenceClient?.deleteMessageById(messageId); } return res; @@ -1752,6 +1752,7 @@ class ChannelClientState { _subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) { final message = event.message!; if (event.hardDelete == true) { + //do not decrease reply count here - it is done in _listenMessageUpdated removeMessage(message, hardDelete: true); } else { addMessage(message); @@ -1810,24 +1811,30 @@ class ChannelClientState { } /// Remove a [message] from this [channelState]. - void removeMessage(Message message, {bool hardDelete = false}) { + void removeMessage( + Message message, { + bool hardDelete = false, + bool decreaseReplyCount = false, + }) { final parentId = message.parentId; // i.e. it's a thread message // 1. Remove the thread message // 2. Reduce total reply count of parent message if (parentId != null) { - final allMessages = [...messages]; - final parentMessage = allMessages.firstWhereOrNull( - (it) => it.id == parentId, - ); + if (decreaseReplyCount) { + final allMessages = [...messages]; + final parentMessage = allMessages.firstWhereOrNull( + (it) => it.id == parentId, + ); - // 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; + // 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; - addMessage(parentMessage.copyWith(replyCount: replyCount - 1)); + addMessage(parentMessage.copyWith(replyCount: replyCount - 1)); + } updateThreadInfo( parentId, threads[parentId]! From 8f6bfd7b472acfbe007c4501b87c3b3584680fb7 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 17 Feb 2022 17:17:52 +0530 Subject: [PATCH 02/14] fix(llc): improve removeMessage logic. --- .../stream_chat/lib/src/client/channel.dart | 116 ++++++++---------- .../lib/src/client/retry_queue.dart | 2 +- 2 files changed, 51 insertions(+), 67 deletions(-) diff --git a/packages/stream_chat/lib/src/client/channel.dart b/packages/stream_chat/lib/src/client/channel.dart index 84f0321e..b5bad6cb 100644 --- a/packages/stream_chat/lib/src/client/channel.dart +++ b/packages/stream_chat/lib/src/client/channel.dart @@ -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) { @@ -646,7 +646,7 @@ class Channel { // 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( + state!.updateMessage(message.copyWith( type: 'deleted', status: MessageSendingStatus.sent, )); @@ -667,11 +667,11 @@ class Channel { deletedAt: message.deletedAt ?? DateTime.now(), ); - state?.addMessage(message); + state?.updateMessage(message); final response = await _client.deleteMessage(message.id, hard: hard); - state?.addMessage(message.copyWith(status: MessageSendingStatus.sent)); + state?.updateMessage(message.copyWith(status: MessageSendingStatus.sent)); return response; } catch (e) { @@ -860,7 +860,7 @@ class Channel { ownReactions: ownReactions, ); - state?.addMessage(newMessage); + state?.updateMessage(newMessage); try { final reactionResp = await _client.sendReaction( @@ -872,7 +872,7 @@ class Channel { return reactionResp; } catch (_) { // Reset the message if the update fails - state?.addMessage(message); + state?.updateMessage(message); rethrow; } } @@ -912,7 +912,7 @@ class Channel { ownReactions: ownReactions, ); - state?.addMessage(newMessage); + state?.updateMessage(newMessage); try { final deleteResponse = await _client.deleteReaction( @@ -922,7 +922,7 @@ class Channel { return deleteResponse; } catch (_) { // Reset the message if the update fails - state?.addMessage(message); + state?.updateMessage(message); rethrow; } } @@ -1079,11 +1079,11 @@ 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 - state!.removeMessage(message, decreaseReplyCount: true); + state!.removeMessage(message); await _client.chatPersistenceClient?.deleteMessageById(messageId); } return res; @@ -1322,7 +1322,8 @@ class Channel { /// 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") + "Use 'unbanMember' instead. This method will be removed in v4.0.0", + ) Future unbanUser(String userID) => unbanMember(userID); /// Remove the ban for the member with given [userID] in the channel. @@ -1694,7 +1695,9 @@ class ChannelClientState { void _listenReactionDeleted() { _subscriptions.add(_channel.on(EventType.reactionDeleted).listen((event) { final oldMessage = - messages.firstWhereOrNull((it) => it.id == event.message?.id); + messages.firstWhereOrNull((it) => it.id == event.message?.id) ?? + threads[event.message?.parentId] + ?.firstWhereOrNull((e) => e.id == event.message?.id); final reaction = event.reaction; final ownReactions = oldMessage?.ownReactions ?.whereNot((it) => @@ -1707,18 +1710,20 @@ class ChannelClientState { final message = event.message!.copyWith( ownReactions: ownReactions, ); - addMessage(message); + updateMessage(message); })); } void _listenReactions() { _subscriptions.add(_channel.on(EventType.reactionNew).listen((event) { final oldMessage = - messages.firstWhereOrNull((it) => it.id == event.message?.id); + messages.firstWhereOrNull((it) => it.id == event.message?.id) ?? + threads[event.message?.parentId] + ?.firstWhereOrNull((e) => e.id == event.message?.id); final message = event.message!.copyWith( ownReactions: oldMessage?.ownReactions, ); - addMessage(message); + updateMessage(message); })); } @@ -1730,12 +1735,13 @@ class ChannelClientState { ) .listen((event) { final oldMessage = - messages.firstWhereOrNull((it) => it.id == event.message?.id); - + messages.firstWhereOrNull((it) => it.id == event.message?.id) ?? + threads[event.message?.parentId] + ?.firstWhereOrNull((e) => e.id == event.message?.id); final message = event.message!.copyWith( ownReactions: oldMessage?.ownReactions, ); - addMessage(message); + updateMessage(message); if (message.pinned) { _channelState = _channelState.copyWith( @@ -1752,10 +1758,9 @@ class ChannelClientState { _subscriptions.add(_channel.on(EventType.messageDeleted).listen((event) { final message = event.message!; if (event.hardDelete == true) { - //do not decrease reply count here - it is done in _listenMessageUpdated - removeMessage(message, hardDelete: true); + removeMessage(message); } else { - addMessage(message); + updateMessage(message); } })); } @@ -1770,7 +1775,7 @@ class ChannelClientState { final message = event.message!; if (isUpToDate || (message.parentId != null && message.showInChannel != true)) { - addMessage(message); + updateMessage(message); } if (_countMessageAsUnread(message)) { @@ -1780,9 +1785,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.from(_channelState.messages); + final newMessages = [...messages]; final oldIndex = newMessages.indexWhere((m) => m.id == message.id); if (oldIndex != -1) { Message? m; @@ -1811,47 +1820,22 @@ class ChannelClientState { } /// Remove a [message] from this [channelState]. - void removeMessage( - Message message, { - bool hardDelete = false, - bool decreaseReplyCount = 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) { - if (decreaseReplyCount) { - final allMessages = [...messages]; - final parentMessage = allMessages.firstWhereOrNull( - (it) => it.id == parentId, - ); - - // 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; - - addMessage(parentMessage.copyWith(replyCount: replyCount - 1)); - } - updateThreadInfo( + final threadMessages = [...threads[parentId]!]; + return updateThreadInfo( parentId, - threads[parentId]! - ..removeWhere( - (e) => e.id == message.id, - ), + threadMessages..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 + final allMessages = [...messages]; + _channelState = _channelState.copyWith( + messages: allMessages..removeWhere((e) => e.id == message.id), + ); } void _listenReadEvents() { diff --git a/packages/stream_chat/lib/src/client/retry_queue.dart b/packages/stream_chat/lib/src/client/retry_queue.dart index 17b019a5..5dfa9aa3 100644 --- a/packages/stream_chat/lib/src/client/retry_queue.dart +++ b/packages/stream_chat/lib/src/client/retry_queue.dart @@ -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 _retryMessage(Message message) async { From ae44406b96ec39a9cc275c8d51ddf841bf7df9eb Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Mon, 21 Feb 2022 15:31:23 +0530 Subject: [PATCH 03/14] fix(llc): Fix `channelState.copyWith` with respect to pinnedMessages. Signed-off-by: xsahil03x --- packages/stream_chat/CHANGELOG.md | 1 + .../stream_chat/lib/src/core/models/channel_state.dart | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat/CHANGELOG.md b/packages/stream_chat/CHANGELOG.md index 82225b27..ef66f835 100644 --- a/packages/stream_chat/CHANGELOG.md +++ b/packages/stream_chat/CHANGELOG.md @@ -10,6 +10,7 @@ - [[#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`. +- Fix `channelState.copyWith` with respect to pinnedMessages. ## 3.4.0 diff --git a/packages/stream_chat/lib/src/core/models/channel_state.dart b/packages/stream_chat/lib/src/core/models/channel_state.dart index 3ddc2b68..8b500d18 100644 --- a/packages/stream_chat/lib/src/core/models/channel_state.dart +++ b/packages/stream_chat/lib/src/core/models/channel_state.dart @@ -67,9 +67,10 @@ class ChannelState { members: members ?? this.members, // Hack to avoid using the default value in case nothing is provided. // FIXME: Use non-nullable by default instead of empty list. - pinnedMessages: pinnedMessages == _emptyPinnedMessages - ? this.pinnedMessages - : pinnedMessages ?? _emptyPinnedMessages, + pinnedMessages: + pinnedMessages == null || pinnedMessages == _emptyPinnedMessages + ? this.pinnedMessages + : pinnedMessages, watcherCount: watcherCount ?? this.watcherCount, watchers: watchers ?? this.watchers, read: read ?? this.read, From de4f531af114f506ac8f92695265e7dbe288ba22 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 21 Feb 2022 14:29:12 -0400 Subject: [PATCH 04/14] fix(ui): sample app version bump --- packages/stream_chat_flutter/example/pubspec.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter/example/pubspec.yaml b/packages/stream_chat_flutter/example/pubspec.yaml index 9977c198..75aba62c 100644 --- a/packages/stream_chat_flutter/example/pubspec.yaml +++ b/packages/stream_chat_flutter/example/pubspec.yaml @@ -27,9 +27,9 @@ 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: ^3.4.0 + stream_chat_localizations: ^2.1.0 + stream_chat_persistence: ^3.1.0 dev_dependencies: flutter_test: From 68643da42b257bf060501fdcd4b70b0890292383 Mon Sep 17 00:00:00 2001 From: Sacha Arbonel Date: Mon, 21 Feb 2022 14:29:50 -0400 Subject: [PATCH 05/14] fix(ui): sample app gradle fixes --- packages/stream_chat_flutter/example/android/app/build.gradle | 4 ++-- .../example/android/app/src/main/AndroidManifest.xml | 1 + packages/stream_chat_flutter/example/android/build.gradle | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter/example/android/app/build.gradle b/packages/stream_chat_flutter/example/android/app/build.gradle index fbd6268e..3974f949 100644 --- a/packages/stream_chat_flutter/example/android/app/build.gradle +++ b/packages/stream_chat_flutter/example/android/app/build.gradle @@ -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 } diff --git a/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml b/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml index 42c5fa1e..5e2f5ec0 100644 --- a/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml +++ b/packages/stream_chat_flutter/example/android/app/src/main/AndroidManifest.xml @@ -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">