diff --git a/packages/stream_chat/lib/src/api/channel.dart b/packages/stream_chat/lib/src/api/channel.dart index 69d967fe..4a5476ee 100644 --- a/packages/stream_chat/lib/src/api/channel.dart +++ b/packages/stream_chat/lib/src/api/channel.dart @@ -70,8 +70,11 @@ class Channel { true; /// Returns true if the channel is muted as a stream - Stream? get isMutedStream => _client.state.userStream.map((event) => - event!.channelMutes.any((element) => element.channel.cid == cid) == true); + Stream? get isMutedStream => _client.state.userStream + .map((event) => + event!.channelMutes.any((element) => element.channel.cid == cid) == + true) + .distinct(); /// True if the channel is a group bool get isGroup => memberCount != 2; @@ -1604,7 +1607,7 @@ class ChannelClientState { /// Channel message list as a stream Stream?> get messagesStream => channelStateStream .map((cs) => cs.messages) - .distinct((prev, next) => const ListEquality().equals(prev, next)); + .distinct(const ListEquality().equals); /// Channel pinned message list List? get pinnedMessages => _channelState.pinnedMessages.toList(); @@ -1634,7 +1637,7 @@ class ChannelClientState { _channel.client.state.usersStream, (members, users) => members!.map((e) => e!.copyWith(user: users[e.user!.id])).toList(), - ); + ).distinct(const ListEquality().equals); /// Channel watcher count int? get watcherCount => _channelState.watcherCount; @@ -1804,7 +1807,9 @@ class ChannelClientState { List get typingEvents => _typingEventsController.value; /// Channel related typing users stream - Stream> get typingEventsStream => _typingEventsController.stream; + Stream> get typingEventsStream => + _typingEventsController.stream.distinct(const ListEquality().equals); + final BehaviorSubject> _typingEventsController = BehaviorSubject.seeded([]); diff --git a/packages/stream_chat/lib/src/client.dart b/packages/stream_chat/lib/src/client.dart index 05f2559b..52374239 100644 --- a/packages/stream_chat/lib/src/client.dart +++ b/packages/stream_chat/lib/src/client.dart @@ -219,7 +219,7 @@ class StreamChatClient { /// This notifies the connection status of the websocket connection. /// Listen to this to get notified when the websocket tries to reconnect. Stream get wsConnectionStatusStream => - _wsConnectionStatusController.stream; + _wsConnectionStatusController.stream.distinct(); /// The current user token String? token; diff --git a/packages/stream_chat/lib/src/models/member.dart b/packages/stream_chat/lib/src/models/member.dart index 49df170c..aa576cd2 100644 --- a/packages/stream_chat/lib/src/models/member.dart +++ b/packages/stream_chat/lib/src/models/member.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:stream_chat/src/models/user.dart'; @@ -6,7 +7,7 @@ part 'member.g.dart'; /// The class that contains the information about the user membership /// in a channel @JsonSerializable() -class Member { +class Member extends Equatable { /// Constructor used for json serialization Member({ this.user, @@ -98,4 +99,19 @@ class Member { /// Serialize to json Map toJson() => _$MemberToJson(this); + + @override + List get props => [ + user, + inviteAcceptedAt, + inviteRejectedAt, + invited, + role, + userId, + isModerator, + banned, + shadowBanned, + createdAt, + updatedAt, + ]; } diff --git a/packages/stream_chat/lib/src/models/user.dart b/packages/stream_chat/lib/src/models/user.dart index 9335f8c8..08f61b91 100644 --- a/packages/stream_chat/lib/src/models/user.dart +++ b/packages/stream_chat/lib/src/models/user.dart @@ -1,3 +1,4 @@ +import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:stream_chat/src/models/serialization.dart'; @@ -5,7 +6,7 @@ part 'user.g.dart'; /// The class that defines the user model @JsonSerializable() -class User { +class User extends Equatable { /// Constructor used for json serialization User({ required this.id, @@ -125,4 +126,17 @@ class User { banned: banned ?? this.banned, teams: teams ?? this.teams, ); + + @override + List get props => [ + id, + role, + teams, + createdAt, + updatedAt, + lastActive, + online, + banned, + extraData, + ]; } diff --git a/packages/stream_chat_flutter/analysis_options.yaml b/packages/stream_chat_flutter/analysis_options.yaml index f0a87ea5..a37a0fb7 100644 --- a/packages/stream_chat_flutter/analysis_options.yaml +++ b/packages/stream_chat_flutter/analysis_options.yaml @@ -3,10 +3,10 @@ analyzer: - extension-methods exclude: - lib/**/*.g.dart - - example/** +# - example/** - lib/src/emoji - lib/**/*.freezed.dart - - test/** +# - test/** linter: rules: diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index f59ac2e0..e2067f1b 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -27,7 +27,6 @@ class ChannelInfo extends StatelessWidget { final client = StreamChat.of(context).client; return StreamBuilder>( stream: channel.state?.membersStream, - initialData: channel.state?.members, builder: (context, snapshot) => ConnectionStatusBuilder( statusBuilder: (context, status) { switch (status) { diff --git a/packages/stream_chat_flutter/lib/src/connection_status_builder.dart b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart index 7e4e7f8e..cfc1b937 100644 --- a/packages/stream_chat_flutter/lib/src/connection_status_builder.dart +++ b/packages/stream_chat_flutter/lib/src/connection_status_builder.dart @@ -1,3 +1,4 @@ +import 'package:flutter/foundation.dart'; 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'; @@ -39,7 +40,6 @@ class ConnectionStatusBuilder extends StatelessWidget { final stream = connectionStatusStream ?? StreamChat.of(context).client.wsConnectionStatusStream; return StreamBuilder( - initialData: initialStatus, stream: stream, builder: (context, snapshot) { if (snapshot.hasError) { 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 a17dccf0..c13a87a7 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -690,7 +690,7 @@ class _MessageListViewState extends State { ? streamChannel.queryTopMessages : streamChannel.queryBottomMessages; return StreamBuilder( - key: const Key('LOADING-INDICATOR'), + key: Key('LOADING-INDICATOR $direction'), stream: stream, initialData: false, builder: (context, snapshot) { @@ -789,7 +789,9 @@ class _MessageListViewState extends State { } } if (mounted) { - setState(() => _showScrollToBottom = !isVisible); + if (_showScrollToBottom == isVisible) { + setState(() => _showScrollToBottom = !isVisible); + } } }, child: messageWidget, diff --git a/packages/stream_chat_flutter/lib/src/typing_indicator.dart b/packages/stream_chat_flutter/lib/src/typing_indicator.dart index e9377674..010b2c07 100644 --- a/packages/stream_chat_flutter/lib/src/typing_indicator.dart +++ b/packages/stream_chat_flutter/lib/src/typing_indicator.dart @@ -33,8 +33,15 @@ class TypingIndicator extends StatelessWidget { Widget build(BuildContext context) { final channelState = channel?.state ?? StreamChannel.of(context).channel.state!; + + final altWidget = Align( + key: const Key('alternative'), + alignment: alignment, + child: Container( + child: alternativeWidget ?? const Offstage(), + ), + ); return StreamBuilder>( - initialData: channelState.typingEvents, stream: channelState.typingEventsStream, builder: (context, snapshot) => AnimatedSwitcher( duration: const Duration(milliseconds: 300), @@ -62,13 +69,7 @@ class TypingIndicator extends StatelessWidget { ), ), ) - : Align( - key: const Key('alternative'), - alignment: alignment, - child: Container( - child: alternativeWidget ?? const Offstage(), - ), - ), + : altWidget, ), ); } diff --git a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart index cf11ef5f..9b0d3d38 100644 --- a/packages/stream_chat_flutter_core/lib/src/message_list_core.dart +++ b/packages/stream_chat_flutter_core/lib/src/message_list_core.dart @@ -135,10 +135,12 @@ class MessageListCoreState extends State { } return StreamBuilder?>( - stream: messagesStream?.map((messages) => - messages?.where(widget.messageFilter ?? defaultFilter).toList( - growable: false, - )), + stream: messagesStream?.map( + (messages) => + messages?.where(widget.messageFilter ?? defaultFilter).toList( + growable: false, + ), + ), builder: (context, snapshot) { if (snapshot.hasError) { return widget.errorWidgetBuilder(context, snapshot.error!);