merge origin/develop into ref/segregate-api-layer
Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
/// A more efficient [StreamBuilder]
|
||||
/// It requires [initialData] and will rebuild
|
||||
/// only when the new data is different than the current data
|
||||
/// The [comparator] is used to check if the new data is different
|
||||
class BetterStreamBuilder<T> extends StatefulWidget {
|
||||
/// Creates a new BetterStreamBuilder
|
||||
const BetterStreamBuilder({
|
||||
required this.stream,
|
||||
required this.initialData,
|
||||
required this.builder,
|
||||
this.loadingBuilder,
|
||||
this.errorBuilder,
|
||||
this.comparator,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The stream to listen to
|
||||
final Stream<T>? stream;
|
||||
|
||||
/// The initial data available
|
||||
final T initialData;
|
||||
|
||||
/// Comparator used to check if the new data is different than the last one
|
||||
final bool Function(T?, T)? comparator;
|
||||
|
||||
/// Builder that builds based on the new snapshot
|
||||
final Widget Function(BuildContext context, T data) builder;
|
||||
|
||||
/// Builder that builds when the data is null
|
||||
final Widget Function(BuildContext context)? loadingBuilder;
|
||||
|
||||
/// Builder used when there is an error
|
||||
final Widget Function(BuildContext context, Object error)? errorBuilder;
|
||||
|
||||
@override
|
||||
_BetterStreamBuilderState createState() => _BetterStreamBuilderState<T>();
|
||||
}
|
||||
|
||||
class _BetterStreamBuilderState<T> extends State<BetterStreamBuilder<T>> {
|
||||
T? _lastEvent;
|
||||
StreamSubscription? _subscription;
|
||||
Object? _lastError;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_lastError != null) {
|
||||
return widget.errorBuilder!(context, _lastError!);
|
||||
}
|
||||
|
||||
if (_lastEvent == null) {
|
||||
return widget.loadingBuilder?.call(context) ?? const Offstage();
|
||||
}
|
||||
return widget.builder(context, _lastEvent ?? widget.initialData);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_lastEvent = widget.initialData;
|
||||
_subscription = widget.stream?.listen(
|
||||
_onEvent,
|
||||
onError: _onError,
|
||||
);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void didUpdateWidget(covariant BetterStreamBuilder<T> oldWidget) {
|
||||
if (oldWidget.stream != widget.stream) {
|
||||
_subscription?.cancel();
|
||||
_subscription = widget.stream?.listen(
|
||||
_onEvent,
|
||||
onError: _onError,
|
||||
);
|
||||
}
|
||||
super.didUpdateWidget(oldWidget);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_subscription?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onError(error) {
|
||||
if (widget.errorBuilder != null && error != _lastError) {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
_lastError = error;
|
||||
}
|
||||
}
|
||||
|
||||
void _onEvent(T event) {
|
||||
_lastError = null;
|
||||
final isEqual = widget.comparator != null
|
||||
? widget.comparator!(_lastEvent, event)
|
||||
: event == _lastEvent;
|
||||
if (!isEqual) {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
_lastEvent = event;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat/stream_chat.dart';
|
||||
import 'package:stream_chat_flutter_core/src/better_stream_builder.dart';
|
||||
import 'package:stream_chat_flutter_core/src/stream_channel.dart';
|
||||
import 'package:stream_chat_flutter_core/src/typedef.dart';
|
||||
|
||||
@@ -127,6 +129,10 @@ class MessageListCoreState extends State<MessageListCore> {
|
||||
.map((threads) => threads[widget.parentMessage!.id])
|
||||
: _streamChannel!.channel.state?.messagesStream;
|
||||
|
||||
final initialData = _isThreadConversation
|
||||
? _streamChannel!.channel.state?.threads[widget.parentMessage!.id]
|
||||
: _streamChannel!.channel.state?.messages;
|
||||
|
||||
bool defaultFilter(Message m) {
|
||||
final isMyMessage = m.user?.id == _currentUser?.id;
|
||||
final isDeletedOrShadowed = m.isDeleted == true || m.shadowed == true;
|
||||
@@ -134,28 +140,27 @@ class MessageListCoreState extends State<MessageListCore> {
|
||||
return true;
|
||||
}
|
||||
|
||||
return StreamBuilder<List<Message>?>(
|
||||
stream: messagesStream?.map((messages) =>
|
||||
messages?.where(widget.messageFilter ?? defaultFilter).toList(
|
||||
growable: false,
|
||||
)),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return widget.errorWidgetBuilder(context, snapshot.error!);
|
||||
} else if (!snapshot.hasData) {
|
||||
return widget.loadingBuilder(context);
|
||||
} else {
|
||||
final messageList =
|
||||
snapshot.data?.reversed.toList(growable: false) ?? [];
|
||||
if (messageList.isEmpty && !_isThreadConversation) {
|
||||
if (_upToDate) {
|
||||
return widget.emptyBuilder(context);
|
||||
}
|
||||
} else {
|
||||
_messages = messageList;
|
||||
return BetterStreamBuilder<List<Message>?>(
|
||||
initialData: initialData,
|
||||
comparator: const ListEquality().equals,
|
||||
stream: messagesStream!.map(
|
||||
(messages) =>
|
||||
messages?.where(widget.messageFilter ?? defaultFilter).toList(
|
||||
growable: false,
|
||||
),
|
||||
),
|
||||
errorBuilder: widget.errorWidgetBuilder,
|
||||
loadingBuilder: widget.loadingBuilder,
|
||||
builder: (context, data) {
|
||||
final messageList = data?.reversed.toList(growable: false) ?? [];
|
||||
if (messageList.isEmpty && !_isThreadConversation) {
|
||||
if (_upToDate) {
|
||||
return widget.emptyBuilder(context);
|
||||
}
|
||||
return widget.messageListBuilder(context, _messages);
|
||||
} else {
|
||||
_messages = messageList;
|
||||
}
|
||||
return widget.messageListBuilder(context, _messages);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ library stream_chat_flutter_core;
|
||||
export 'package:connectivity_plus/connectivity_plus.dart';
|
||||
export 'package:stream_chat/stream_chat.dart';
|
||||
|
||||
export 'src/better_stream_builder.dart';
|
||||
export 'src/channel_list_core.dart' hide ChannelListCoreState;
|
||||
export 'src/channels_bloc.dart';
|
||||
export 'src/lazy_load_scroll_view.dart';
|
||||
|
||||
Reference in New Issue
Block a user