fix rebuild message list view

This commit is contained in:
Salvatore Giordano
2021-06-01 15:42:45 +02:00
parent 847e5120af
commit 06bf2cdfe5
10 changed files with 65 additions and 26 deletions
+10 -5
View File
@@ -70,8 +70,11 @@ class Channel {
true;
/// Returns true if the channel is muted as a stream
Stream<bool>? get isMutedStream => _client.state.userStream.map((event) =>
event!.channelMutes.any((element) => element.channel.cid == cid) == true);
Stream<bool>? 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<List<Message>?> get messagesStream => channelStateStream
.map((cs) => cs.messages)
.distinct((prev, next) => const ListEquality().equals(prev, next));
.distinct(const ListEquality().equals);
/// Channel pinned message list
List<Message>? 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<User> get typingEvents => _typingEventsController.value;
/// Channel related typing users stream
Stream<List<User>> get typingEventsStream => _typingEventsController.stream;
Stream<List<User>> get typingEventsStream =>
_typingEventsController.stream.distinct(const ListEquality().equals);
final BehaviorSubject<List<User>> _typingEventsController =
BehaviorSubject.seeded([]);
+1 -1
View File
@@ -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<ConnectionStatus> get wsConnectionStatusStream =>
_wsConnectionStatusController.stream;
_wsConnectionStatusController.stream.distinct();
/// The current user token
String? token;
@@ -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<String, dynamic> toJson() => _$MemberToJson(this);
@override
List<Object?> get props => [
user,
inviteAcceptedAt,
inviteRejectedAt,
invited,
role,
userId,
isModerator,
banned,
shadowBanned,
createdAt,
updatedAt,
];
}
+15 -1
View File
@@ -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<Object?> get props => [
id,
role,
teams,
createdAt,
updatedAt,
lastActive,
online,
banned,
extraData,
];
}
@@ -3,10 +3,10 @@ analyzer:
- extension-methods
exclude:
- lib/**/*.g.dart
- example/**
# - example/**
- lib/src/emoji
- lib/**/*.freezed.dart
- test/**
# - test/**
linter:
rules:
@@ -27,7 +27,6 @@ class ChannelInfo extends StatelessWidget {
final client = StreamChat.of(context).client;
return StreamBuilder<List<Member>>(
stream: channel.state?.membersStream,
initialData: channel.state?.members,
builder: (context, snapshot) => ConnectionStatusBuilder(
statusBuilder: (context, status) {
switch (status) {
@@ -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<ConnectionStatus>(
initialData: initialStatus,
stream: stream,
builder: (context, snapshot) {
if (snapshot.hasError) {
@@ -690,7 +690,7 @@ class _MessageListViewState extends State<MessageListView> {
? streamChannel.queryTopMessages
: streamChannel.queryBottomMessages;
return StreamBuilder<bool>(
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<MessageListView> {
}
}
if (mounted) {
setState(() => _showScrollToBottom = !isVisible);
if (_showScrollToBottom == isVisible) {
setState(() => _showScrollToBottom = !isVisible);
}
}
},
child: messageWidget,
@@ -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<List<User>>(
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,
),
);
}
@@ -135,10 +135,12 @@ class MessageListCoreState extends State<MessageListCore> {
}
return StreamBuilder<List<Message>?>(
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!);