diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 6117b5d7..7359c343 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -274,28 +274,111 @@ class Channel { bool enforceUnique = false, }) async { final messageId = message.id; + final now = DateTime.now(); + final user = _client.state.user; + + final latestReactions = [...message.latestReactions ?? []]; + if (enforceUnique) { + latestReactions.removeWhere((it) => it.userId == user.id); + } + + final newReaction = Reaction( + messageId: messageId, + createdAt: now, + type: type, + user: user, + score: 1, + extraData: extraData, + ); + + // Inserting at the 0th index as it's the latest reaction + latestReactions.insert(0, newReaction); + final ownReactions = [...latestReactions] + ..removeWhere((it) => it.userId != user.id); + + final newMessage = message.copyWith( + reactionCounts: {...message?.reactionCounts ?? {}} + ..update(type, (value) { + if (enforceUnique) return value; + return value + 1; + }, ifAbsent: () => 1), + reactionScores: {...message.reactionScores ?? {}} + ..update(type, (value) { + if (enforceUnique) return value; + return value + 1; + }, ifAbsent: () => 1), + latestReactions: latestReactions, + ownReactions: ownReactions, + ); + + state?.addMessage(newMessage); + final data = Map.from(extraData) ..addAll({ 'type': type, }); - final res = await _client.post( - '/messages/$messageId/reaction', - data: { - 'reaction': data, - 'enforce_unique': enforceUnique, - }, - ); - return _client.decode(res.data, SendReactionResponse.fromJson); + try { + final res = await _client.post( + '/messages/$messageId/reaction', + data: { + 'reaction': data, + 'enforce_unique': enforceUnique, + }, + ); + final reactionResp = + _client.decode(res.data, SendReactionResponse.fromJson); + return reactionResp; + } catch (_) { + // Reset the message if the update fails + state?.addMessage(message); + rethrow; + } } /// Delete a reaction from this channel - Future deleteReaction(Message message, Reaction reaction) { - _checkInitialized(); + Future deleteReaction( + Message message, Reaction reaction) async { + final type = reaction.type; + final user = _client.state.user; - return client - .delete('/messages/${message.id}/reaction/${reaction.type}') - .then((res) => _client.decode(res.data, EmptyResponse.fromJson)); + final reactionCounts = {...message.reactionCounts ?? {}}; + if (reactionCounts.containsKey(type)) { + reactionCounts.update(type, (value) => value - 1); + } + final reactionScores = {...message.reactionScores ?? {}}; + if (reactionScores.containsKey(type)) { + reactionScores.update(type, (value) => value - 1); + } + + final latestReactions = [...message.latestReactions ?? []] + ..removeWhere((r) { + return r.userId == reaction.userId && + r.type == reaction.type && + r.messageId == reaction.messageId; + }); + + final ownReactions = [...latestReactions ?? []] + ..removeWhere((it) => it.userId != user.id); + + final newMessage = message.copyWith( + reactionCounts: reactionCounts..removeWhere((_, value) => value == 0), + reactionScores: reactionScores..removeWhere((_, value) => value == 0), + latestReactions: latestReactions, + ownReactions: ownReactions, + ); + + state?.addMessage(newMessage); + + try { + final res = await client + .delete('/messages/${message.id}/reaction/${reaction.type}'); + return _client.decode(res.data, EmptyResponse.fromJson); + } catch (_) { + // Reset the message if the update fails + state?.addMessage(message); + rethrow; + } } /// Edit the channel custom data @@ -998,73 +1081,24 @@ class ChannelClientState { void _listenReactionDeleted() { _subscriptions.add(_channel.on(EventType.reactionDeleted).listen((event) { - final reaction = event.reaction; - final message = event.message; - _removeMessageReaction(message, reaction); - })); - } - - void _removeMessageReaction(Message message, Reaction reaction) { - if (message.parentId == null || message.showInChannel == true) { - _channelState = _channelState.copyWith( - messages: _channelState?.messages?.map((m) { - if (m.id == message.id) { - return _removeReactionFromMessage(m, reaction); - } - return m; - })?.toList(), + final userId = _channel.client.state.user.id; + final message = event.message.copyWith( + ownReactions: [...event.message.latestReactions] + ..removeWhere((it) => it.userId != userId), ); - } - - if (message.parentId != null) { - final newThreads = threads; - if (newThreads.containsKey(message.parentId)) { - newThreads[message.parentId] = newThreads[message.parentId].map((m) { - if (m.id == message.id) { - return _removeReactionFromMessage(m, reaction); - } - return m; - }).toList(); - _threads = newThreads; - } - } + addMessage(message); + })); } void _listenReactions() { - _subscriptions.add(_channel - .on( - EventType.reactionNew, - ) - .listen((event) { - final message = event.message; - _addMessageReaction(message, event.reaction); - })); - } - - void _addMessageReaction(Message message, Reaction reaction) { - if (message.parentId == null || message.showInChannel == true) { - _channelState = _channelState.copyWith( - messages: _channelState.messages.map((m) { - if (message.id == m.id) { - return _addReactionToMessage(m, reaction); - } - return m; - }).toList(), + _subscriptions.add(_channel.on(EventType.reactionNew).listen((event) { + final userId = _channel.client.state.user.id; + final message = event.message.copyWith( + ownReactions: [...event.message.latestReactions] + ..removeWhere((it) => it.userId != userId), ); - } - - if (message.parentId != null) { - final newThreads = threads; - if (newThreads.containsKey(message.parentId)) { - newThreads[message.parentId] = newThreads[message.parentId].map((m) { - if (message.id == m.id) { - return _addReactionToMessage(m, reaction); - } - return m; - }).toList(); - _threads = newThreads; - } - } + addMessage(message); + })); } void _listenMessageUpdated() { @@ -1074,13 +1108,12 @@ class ChannelClientState { EventType.reactionUpdated, ) .listen((event) { - final message = event.message; - addMessage(message.copyWith( - ownReactions: message.latestReactions - .where( - (element) => element.user?.id == _channel._client.state.user.id) - .toList(), - )); + final userId = _channel.client.state.user.id; + final message = event.message.copyWith( + ownReactions: [...event.message.latestReactions] + ..removeWhere((it) => it.userId != userId), + ); + addMessage(message); })); } @@ -1163,66 +1196,6 @@ class ChannelClientState { })); } - Message _addReactionToMessage(Message message, Reaction reaction) { - final newMessage = message.copyWith( - latestReactions: message.latestReactions..add(reaction), - reactionCounts: { - ...message.reactionCounts ?? {}, - reaction.type: (message.reactionCounts == null - ? 0 - : message.reactionCounts[reaction.type] ?? 0) + - 1, - }, - reactionScores: { - ...message.reactionScores ?? {}, - reaction.type: (message.reactionScores == null - ? 0 - : message.reactionScores[reaction.type] ?? 0) + - reaction.score, - }, - ); - - if (reaction.user.id == _channel.client.state.user.id) { - return newMessage.copyWith( - ownReactions: message.ownReactions..add(reaction), - ); - } - - return newMessage; - } - - Message _removeReactionFromMessage(Message message, Reaction reaction) { - final newMessage = message.copyWith( - latestReactions: message.latestReactions - ..removeWhere( - (r) => r.type == reaction.type && r.userId == reaction.userId), - reactionCounts: { - ...message.reactionCounts, - reaction.type: (message.reactionCounts[reaction.type] ?? 0) - 1, - }, - reactionScores: { - ...message.reactionScores ?? {}, - reaction.type: max( - (message.reactionScores == null - ? 0 - : message.reactionScores[reaction.type] ?? 0) - - reaction.score, - 0), - }, - ); - - newMessage.reactionCounts.removeWhere((_, v) => v <= 0); - - if (reaction.user.id == _channel.client.state.user.id) { - return newMessage.copyWith( - ownReactions: message.ownReactions - ..removeWhere((r) => r.type == reaction.type), - ); - } - - return newMessage; - } - /// Channel message list List get messages => _channelState.messages; diff --git a/packages/stream_chat/lib/src/models/reaction.dart b/packages/stream_chat/lib/src/models/reaction.dart index 9a4869f7..f0957761 100644 --- a/packages/stream_chat/lib/src/models/reaction.dart +++ b/packages/stream_chat/lib/src/models/reaction.dart @@ -49,10 +49,10 @@ class Reaction { this.createdAt, this.type, this.user, - this.userId, + String userId, this.score, this.extraData, - }); + }) : userId = userId ?? user?.id; /// Create a new instance from a json factory Reaction.fromJson(Map json) { @@ -65,4 +65,40 @@ class Reaction { return Serialization.moveFromExtraDataToRoot( _$ReactionToJson(this), topLevelFields); } + + /// Creates a copy of [Reaction] with specified attributes overridden. + Reaction copyWith({ + String messageId, + DateTime createdAt, + String type, + User user, + String userId, + int score, + Map extraData, + }) { + return Reaction( + messageId: messageId ?? this.messageId, + createdAt: createdAt ?? this.createdAt, + type: type ?? this.type, + user: user ?? this.user, + userId: userId ?? this.userId, + score: score ?? this.score, + extraData: extraData ?? this.extraData, + ); + } + + /// Returns a new [Reaction] that is a combination of this reaction and the given + /// [other] reaction. + Reaction merge(Reaction other) { + if (other == null) return this; + return copyWith( + messageId: other.messageId, + createdAt: other.createdAt, + type: other.type, + user: other.user, + userId: other.userId, + score: other.score, + extraData: other.extraData, + ); + } } diff --git a/packages/stream_chat/test/src/api/channel_test.dart b/packages/stream_chat/test/src/api/channel_test.dart index 4b274a94..32ac65c2 100644 --- a/packages/stream_chat/test/src/api/channel_test.dart +++ b/packages/stream_chat/test/src/api/channel_test.dart @@ -7,6 +7,7 @@ import 'package:stream_chat/src/event_type.dart'; import 'package:stream_chat/src/models/event.dart'; import 'package:stream_chat/src/models/message.dart'; import 'package:stream_chat/src/models/reaction.dart'; +import 'package:stream_chat/src/models/own_user.dart'; import 'package:test/test.dart'; class MockDio extends Mock implements DioForNative {} @@ -379,7 +380,8 @@ void main() { 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', - ); + )..state.user = OwnUser(id: 'test-id'); + final channelClient = client.channel('messaging', id: 'testid'); final reactionType = 'test'; @@ -396,6 +398,10 @@ void main() { await channelClient.sendReaction( Message( id: 'messageid', + reactionCounts: const {}, + reactionScores: const {}, + latestReactions: const [], + ownReactions: const [], ), reactionType, ); @@ -418,23 +424,21 @@ void main() { 'api-key', httpClient: mockDio, tokenProvider: (_) async => '', - ); - final channelClient = client.channel('messaging', id: 'testid'); + )..state.user = OwnUser(id: 'test-id'); - when(mockDio.post( - any, - data: anyNamed('data'), - )).thenAnswer((_) async => Response( - data: '{}', - statusCode: 200, - )); - await channelClient.watch(); + final channelClient = client.channel('messaging', id: 'testid'); when(mockDio.delete('/messages/messageid/reaction/test')) .thenAnswer((_) async => Response(data: '{}', statusCode: 200)); await channelClient.deleteReaction( - Message(id: 'messageid'), + Message( + id: 'messageid', + reactionCounts: const {}, + reactionScores: const {}, + latestReactions: const [], + ownReactions: const [], + ), Reaction(type: 'test'), ); diff --git a/packages/stream_chat_flutter/lib/src/channel_media_display_screen.dart b/packages/stream_chat_flutter/lib/src/channel_media_display_screen.dart index 85b571bc..8e9f566c 100644 --- a/packages/stream_chat_flutter/lib/src/channel_media_display_screen.dart +++ b/packages/stream_chat_flutter/lib/src/channel_media_display_screen.dart @@ -33,6 +33,8 @@ class ChannelMediaDisplayScreen extends StatefulWidget { } class _ChannelMediaDisplayScreenState extends State { + Map controllerCache = {}; + @override void initState() { super.initState(); @@ -147,8 +149,15 @@ class _ChannelMediaDisplayScreenState extends State { .forEach((e) { VideoPlayerController controller; if (e.type == 'video') { - controller = VideoPlayerController.network(e.assetUrl); - controller.initialize(); + var cachedController = controllerCache[e.assetUrl]; + + if (cachedController == null) { + controller = VideoPlayerController.network(e.assetUrl); + controller.initialize(); + controllerCache[e.assetUrl] = controller; + } else { + controller = cachedController; + } } media.add(_AssetPackage(e, item.message, controller)); }); @@ -221,6 +230,14 @@ class _ChannelMediaDisplayScreenState extends State { stream: messageSearchBloc.messagesStream, ); } + + @override + void dispose() { + super.dispose(); + for (var c in controllerCache.values) { + c.dispose(); + } + } } class _AssetPackage { diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index 16ab0da5..bee8f2ba 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -61,9 +61,14 @@ class _FullScreenMediaState extends State .where((element) => element.type == 'video') .toList() .forEach((element) { - videoPackages.add(VideoPackage(context, element, () { - setState(() {}); - })); + videoPackages.add(VideoPackage( + context, + element, + () { + setState(() {}); + }, + showControls: true, + )); }); } @@ -233,15 +238,18 @@ class VideoPackage { bool initialised = false; VoidCallback onInit; BuildContext context; + bool showControls; /// - VideoPackage(this.context, Attachment attachment, this.onInit) { + VideoPackage(this.context, Attachment attachment, this.onInit, + {this.showControls = false}) { _videoPlayerController = VideoPlayerController.network(attachment.assetUrl); _videoPlayerController.initialize().whenComplete(() { initialised = true; _chewieController = ChewieController( videoPlayerController: _videoPlayerController, - autoInitialize: false, + autoInitialize: true, + showControls: showControls, aspectRatio: _videoPlayerController.value.aspectRatio, ); onInit(); diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 9551ff71..9214befb 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -4,10 +4,10 @@ import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; -import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'extension.dart'; import 'message_input.dart'; @@ -33,6 +33,7 @@ class MessageActionsModal extends StatefulWidget { final ShapeBorder messageShape; final ShapeBorder attachmentShape; final DisplayWidget showUserAvatar; + final Map videoPackages; const MessageActionsModal({ Key key, @@ -53,6 +54,7 @@ class MessageActionsModal extends StatefulWidget { this.messageShape, this.attachmentShape, this.reverse = false, + this.videoPackages, }) : super(key: key); @override @@ -180,6 +182,7 @@ class _MessageActionsModalState extends State { showSendingIndicator: false, shape: widget.messageShape, attachmentShape: widget.attachmentShape, + videoPackages: widget.videoPackages, ), ), SizedBox(height: 8), diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 3bb6b716..2929c2d7 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -239,6 +239,8 @@ class _MessageListViewState extends State { final MessageListController _messageListController = MessageListController(); + final Map videoPackages = {}; + @override Widget build(BuildContext context) { return MessageListCore( @@ -776,6 +778,7 @@ class _MessageListViewState extends State { break; } }, + videoPackages: videoPackages, ); } @@ -936,6 +939,7 @@ class _MessageListViewState extends State { break; } }, + videoPackages: videoPackages, ); if (!message.isDeleted && !message.isSystem && !message.isEphemeral) { @@ -1052,6 +1056,7 @@ class _MessageListViewState extends State { streamChannel.reloadChannel(); } _messageNewListener?.cancel(); + videoPackages.values.forEach((e) => e.dispose()); super.dispose(); } } diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index e3d4f201..c44022bf 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; @@ -22,6 +23,7 @@ class MessageReactionsModal extends StatelessWidget { final ShapeBorder messageShape; final ShapeBorder attachmentShape; final void Function(User) onUserAvatarTap; + final Map videoPackages; const MessageReactionsModal({ Key key, @@ -35,6 +37,7 @@ class MessageReactionsModal extends StatelessWidget { this.reverse = false, this.showUserAvatar = DisplayWidget.show, this.onUserAvatarTap, + this.videoPackages, }) : super(key: key); @override @@ -143,6 +146,7 @@ class MessageReactionsModal extends StatelessWidget { (message.status == MessageSendingStatus.sent || message.status == null), + videoPackages: videoPackages, ), ), if (message.latestReactions?.isNotEmpty == true) ...[ @@ -257,7 +261,7 @@ class MessageReactionsModal extends StatelessWidget { ), const SizedBox(height: 8), Text( - reaction.user.name, + reaction.user.name.split(' ')[0], style: StreamChatTheme.of(context).textTheme.footnoteBold, textAlign: TextAlign.center, ), diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index c2cbdc35..d4a6702a 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -142,6 +142,9 @@ class MessageWidget extends StatefulWidget { /// Function called when quotedMessage is tapped final OnQuotedMessageTap onQuotedMessageTap; + /// The cache for the video controllers of attachments IDed as message ID + attachment index + final Map videoPackages; + /// MessageWidget({ Key key, @@ -190,6 +193,7 @@ class MessageWidget extends StatefulWidget { this.attachmentPadding = EdgeInsets.zero, this.allRead = false, this.onQuotedMessageTap, + this.videoPackages, }) : attachmentBuilders = { 'image': (context, message, attachment) { return ImageAttachment( @@ -740,6 +744,7 @@ class _MessageWidgetState extends State { !isFailedState && widget.onThreadTap != null, showFlagButton: widget.showFlagButton, + videoPackages: widget.videoPackages, ), ); }); @@ -768,6 +773,7 @@ class _MessageWidgetState extends State { editMessageInputBuilder: widget.editMessageInputBuilder, onThreadTap: widget.onThreadTap, showReactions: widget.showReactions, + videoPackages: widget.videoPackages, ), ); }); @@ -832,6 +838,41 @@ class _MessageWidgetState extends State { children: widget.message.attachments ?.where((element) => element.ogScrapeUrl == null) ?.map((attachment) { + if (attachment.type == 'video') { + VideoPackage package; + + if (widget.videoPackages == null) { + package = VideoPackage(context, attachment, () {}); + } else { + package = widget?.videoPackages[ + '${widget.message.id}${widget.message.attachments.indexOf(attachment)}'] ?? + VideoPackage(context, attachment, () {}); + } + + if (widget.videoPackages != null) { + widget.videoPackages[ + '${widget.message.id}${widget.message.attachments.indexOf(attachment)}'] = + package; + } + + return Transform( + transform: Matrix4.rotationY(widget.reverse ? pi : 0), + alignment: Alignment.center, + child: VideoAttachment( + attachment: attachment, + messageTheme: widget.messageTheme, + size: Size( + MediaQuery.of(context).size.width * 0.8, + MediaQuery.of(context).size.height * 0.3, + ), + message: widget.message, + onShowMessage: widget.onShowMessage, + onReturnAction: widget.onReturnAction, + videoPackage: package, + ), + ); + } + final attachmentBuilder = widget.attachmentBuilders[attachment.type]; diff --git a/packages/stream_chat_flutter/lib/src/video_attachment.dart b/packages/stream_chat_flutter/lib/src/video_attachment.dart index b775109f..107776bf 100644 --- a/packages/stream_chat_flutter/lib/src/video_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/video_attachment.dart @@ -1,12 +1,8 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:chewie/chewie.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/full_screen_media.dart'; -import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'package:video_player/video_player.dart'; -import 'attachment_error.dart'; import 'attachment_title.dart'; class VideoAttachment extends StatefulWidget { @@ -16,11 +12,13 @@ class VideoAttachment extends StatefulWidget { final Message message; final ShowMessageCallback onShowMessage; final ValueChanged onReturnAction; + final VideoPackage videoPackage; VideoAttachment({ Key key, @required this.attachment, @required this.messageTheme, + this.videoPackage, this.message, this.size, this.onShowMessage, @@ -32,13 +30,21 @@ class VideoAttachment extends StatefulWidget { } class _VideoAttachmentState extends State { - ChewieController _chewieController; - VideoPlayerController _videoPlayerController; bool initialized = false; + @override + void initState() { + super.initState(); + widget.videoPackage.onInit = () { + setState(() { + initialized = true; + }); + }; + } + @override Widget build(BuildContext context) { - if (!initialized) { + if (!widget.videoPackage.initialised) { return Container( height: widget.size?.height ?? 100, width: widget.size?.width ?? 100, @@ -47,43 +53,6 @@ class _VideoAttachmentState extends State { ), ); } - _chewieController = ChewieController( - videoPlayerController: _videoPlayerController, - autoInitialize: true, - showControls: false, - aspectRatio: _videoPlayerController.value.aspectRatio, - errorBuilder: (_, e) { - if (widget.attachment.thumbUrl != null) { - return Stack( - children: [ - Container( - height: widget.size?.height, - width: widget.size?.width, - decoration: BoxDecoration( - image: DecorationImage( - fit: BoxFit.cover, - image: CachedNetworkImageProvider( - widget.attachment.thumbUrl, - ), - ), - ), - ), - if (widget.attachment.titleLink != null) - Material( - color: Colors.transparent, - child: InkWell( - onTap: () => - launchURL(context, widget.attachment.titleLink), - ), - ), - ], - ); - } - return AttachmentError( - attachment: widget.attachment, - size: widget.size, - ); - }); return GestureDetector( onTap: () async { @@ -123,7 +92,7 @@ class _VideoAttachmentState extends State { child: Stack( children: [ Chewie( - controller: _chewieController, + controller: widget.videoPackage.chewieController, ), Positioned.fill( child: Center( @@ -153,23 +122,4 @@ class _VideoAttachmentState extends State { ), ); } - - @override - void initState() { - super.initState(); - _videoPlayerController = - VideoPlayerController.network(widget.attachment.assetUrl); - _videoPlayerController.initialize().whenComplete(() { - setState(() { - initialized = true; - }); - }); - } - - @override - void dispose() { - _videoPlayerController?.dispose(); - _chewieController?.dispose(); - super.dispose(); - } } diff --git a/packages/stream_chat_flutter/test/src/message_reaction_modal_test.dart b/packages/stream_chat_flutter/test/src/message_reaction_modal_test.dart index c023b20d..4e515a09 100644 --- a/packages/stream_chat_flutter/test/src/message_reaction_modal_test.dart +++ b/packages/stream_chat_flutter/test/src/message_reaction_modal_test.dart @@ -96,7 +96,7 @@ void main() { findsNWidgets(2)); expect(find.byKey(Key('StreamSvgIcon-Icon_love_reaction.svg')), findsNWidgets(2)); - expect(find.text(testUserId), findsNWidgets(2)); + expect(find.text(testUserId.split(' ')[0]), findsNWidgets(2)); }, ); } diff --git a/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart index a8d7e227..40880dfc 100644 --- a/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart +++ b/packages/stream_chat_flutter_core/test/stream_chat_core_test.dart @@ -86,7 +86,7 @@ void main() { testWidgets( 'StreamChatCore should disconnect on background', (WidgetTester tester) async { - await fakeAsync((_async) { + fakeAsync((_async) { final client = MockClient(); final clientState = MockClientState(); final channel = MockChannel(); @@ -123,6 +123,7 @@ void main() { _async.elapse(Duration(seconds: 5)); verify(client.disconnect()).called(1); + eventStreamController.close(); }); }, ); @@ -174,6 +175,7 @@ void main() { await untilCalled(showLocalNotificationMock(event)); verify(showLocalNotificationMock(event)).called(1); + eventStreamController.close(); }, ); }