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