Merge branch 'develop' of github.com:GetStream/stream-chat-flutter into fix/message-search-pagination
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
## 2.2.1
|
||||
|
||||
- Updated `stream_chat` dependency to 2.2.1
|
||||
|
||||
## 2.2.0
|
||||
|
||||
🛑️ Breaking Changes from `2.1.1`
|
||||
- Renamed `BetterStreamBuilder.loadingBuilder` to `.noDataBuilder`
|
||||
|
||||
🔄 Changed
|
||||
- `BetterStreamBuilder.initialData` is now nullable/not-required.
|
||||
|
||||
🐞 Fixed
|
||||
- [#612](https://github.com/GetStream/stream-chat-flutter/issues/612) `ChannelListView` pagination doesn't work after refresh
|
||||
|
||||
## 2.1.1
|
||||
|
||||
- Updated llc dependency
|
||||
|
||||
@@ -26,7 +26,7 @@ It teaches you how to use this SDK and also shows how to make frequently require
|
||||
## Example App
|
||||
|
||||
This repo includes a fully functional example app with setup instructions.
|
||||
The example is available under the [example](https://github.com/GetStream/stream-chat-flutter-core/tree/master/example) folder.
|
||||
The example is available under the [example](https://github.com/GetStream/stream-chat-flutter/tree/main/packages/stream_chat_flutter_core/example) folder.
|
||||
|
||||
## Add dependency
|
||||
Add this to your package's pubspec.yaml file, use the latest version [](https://pub.dartlang.org/packages/stream_chat_flutter_core)
|
||||
|
||||
@@ -329,21 +329,9 @@ class _MessageScreenState extends State<MessageScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Extensions can be used to add functionality to the SDK. In the examples
|
||||
/// below, we add two simple extensions to the [StreamChatClient] and [Channel].
|
||||
/// Extensions can be used to add functionality to the SDK. In the example
|
||||
/// below, we add a simple extensions to the [StreamChatClient].
|
||||
extension on StreamChatClient {
|
||||
/// Fetches the current user id.
|
||||
String get uid => state.currentUser!.id;
|
||||
}
|
||||
|
||||
extension on Channel {
|
||||
/// Fetches the name of the channel by accessing [extraData] or [cid].
|
||||
String? get name {
|
||||
final _channelName = extraData['name'];
|
||||
if (_channelName != null) {
|
||||
return _channelName as String;
|
||||
} else {
|
||||
return cid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,23 +6,23 @@ import 'package:flutter/widgets.dart';
|
||||
/// 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 {
|
||||
class BetterStreamBuilder<T extends Object> extends StatefulWidget {
|
||||
/// Creates a new BetterStreamBuilder
|
||||
const BetterStreamBuilder({
|
||||
required this.stream,
|
||||
required this.initialData,
|
||||
required this.builder,
|
||||
this.loadingBuilder,
|
||||
this.initialData,
|
||||
this.noDataBuilder,
|
||||
this.errorBuilder,
|
||||
this.comparator,
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The stream to listen to
|
||||
final Stream<T>? stream;
|
||||
final Stream<T?>? stream;
|
||||
|
||||
/// The initial data available
|
||||
final T initialData;
|
||||
final T? initialData;
|
||||
|
||||
/// Comparator used to check if the new data is different than the last one
|
||||
final bool Function(T?, T?)? comparator;
|
||||
@@ -31,7 +31,7 @@ class BetterStreamBuilder<T> extends StatefulWidget {
|
||||
final Widget Function(BuildContext context, T data) builder;
|
||||
|
||||
/// Builder that builds when the data is null
|
||||
final Widget Function(BuildContext context)? loadingBuilder;
|
||||
final Widget Function(BuildContext context)? noDataBuilder;
|
||||
|
||||
/// Builder used when there is an error
|
||||
final Widget Function(BuildContext context, Object error)? errorBuilder;
|
||||
@@ -40,21 +40,26 @@ class BetterStreamBuilder<T> extends StatefulWidget {
|
||||
_BetterStreamBuilderState createState() => _BetterStreamBuilderState<T>();
|
||||
}
|
||||
|
||||
class _BetterStreamBuilderState<T> extends State<BetterStreamBuilder<T>> {
|
||||
class _BetterStreamBuilderState<T extends Object>
|
||||
extends State<BetterStreamBuilder<T>> {
|
||||
T? _lastEvent;
|
||||
StreamSubscription? _subscription;
|
||||
StreamSubscription<T?>? _subscription;
|
||||
Object? _lastError;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_lastError != null) {
|
||||
return widget.errorBuilder!(context, _lastError!);
|
||||
final error = _lastError;
|
||||
if (error != null) {
|
||||
final errorBuilder = widget.errorBuilder;
|
||||
if (errorBuilder != null) {
|
||||
return errorBuilder(context, error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_lastEvent == null) {
|
||||
return widget.loadingBuilder?.call(context) ?? const Offstage();
|
||||
final event = _lastEvent;
|
||||
if (event == null) {
|
||||
return widget.noDataBuilder?.call(context) ?? const Offstage();
|
||||
}
|
||||
return widget.builder(context, _lastEvent ?? widget.initialData);
|
||||
return widget.builder(context, event);
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -87,22 +92,22 @@ class _BetterStreamBuilderState<T> extends State<BetterStreamBuilder<T>> {
|
||||
|
||||
void _onError(error) {
|
||||
if (widget.errorBuilder != null && error != _lastError) {
|
||||
_lastError = error;
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
_lastError = error;
|
||||
}
|
||||
}
|
||||
|
||||
void _onEvent(T event) {
|
||||
void _onEvent(T? event) {
|
||||
_lastError = null;
|
||||
final isEqual =
|
||||
widget.comparator?.call(_lastEvent, event) ?? event == _lastEvent;
|
||||
if (!isEqual) {
|
||||
_lastEvent = event;
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
_lastEvent = event;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'dart:convert';
|
||||
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/channels_bloc.dart';
|
||||
import 'package:stream_chat_flutter_core/src/stream_chat_core.dart';
|
||||
import 'package:stream_chat_flutter_core/src/typedef.dart';
|
||||
@@ -137,19 +138,14 @@ class ChannelListCoreState extends State<ChannelListCore> {
|
||||
@override
|
||||
Widget build(BuildContext context) => _buildListView(_channelsBloc);
|
||||
|
||||
StreamBuilder<List<Channel>> _buildListView(
|
||||
BetterStreamBuilder<List<Channel>> _buildListView(
|
||||
ChannelsBlocState channelsBlocState,
|
||||
) =>
|
||||
StreamBuilder<List<Channel>>(
|
||||
BetterStreamBuilder<List<Channel>>(
|
||||
stream: channelsBlocState.channelsStream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return widget.errorBuilder(context, snapshot.error!);
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return widget.loadingBuilder(context);
|
||||
}
|
||||
final channels = snapshot.data!;
|
||||
errorBuilder: widget.errorBuilder,
|
||||
noDataBuilder: widget.loadingBuilder,
|
||||
builder: (context, channels) {
|
||||
if (channels.isEmpty) {
|
||||
return widget.emptyBuilder(context);
|
||||
}
|
||||
|
||||
@@ -106,6 +106,9 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
||||
final client = _streamChatCoreState!.client;
|
||||
|
||||
final clear = paginationParams.offset == 0;
|
||||
if (clear && _paginationEnded) {
|
||||
_paginationEnded = false;
|
||||
}
|
||||
|
||||
if ((!clear && _paginationEnded) ||
|
||||
_queryChannelsLoadingController.value == true) {
|
||||
|
||||
@@ -138,7 +138,7 @@ class MessageListCoreState extends State<MessageListCore> {
|
||||
return true;
|
||||
}
|
||||
|
||||
return BetterStreamBuilder<List<Message>?>(
|
||||
return BetterStreamBuilder<List<Message>>(
|
||||
initialData: initialData,
|
||||
comparator: const ListEquality().equals,
|
||||
stream: messagesStream!.map(
|
||||
@@ -148,9 +148,9 @@ class MessageListCoreState extends State<MessageListCore> {
|
||||
),
|
||||
),
|
||||
errorBuilder: widget.errorBuilder,
|
||||
loadingBuilder: widget.loadingBuilder,
|
||||
noDataBuilder: widget.loadingBuilder,
|
||||
builder: (context, data) {
|
||||
final messageList = data?.reversed.toList(growable: false) ?? [];
|
||||
final messageList = data.reversed.toList(growable: false);
|
||||
if (messageList.isEmpty && !_isThreadConversation) {
|
||||
if (_upToDate) {
|
||||
return widget.emptyBuilder(context);
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:convert';
|
||||
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/message_search_bloc.dart';
|
||||
import 'package:stream_chat_flutter_core/src/typedef.dart';
|
||||
|
||||
@@ -145,16 +146,11 @@ class MessageSearchListCoreState extends State<MessageSearchListCore> {
|
||||
Widget build(BuildContext context) => _buildListView(_messageSearchBloc!);
|
||||
|
||||
Widget _buildListView(MessageSearchBlocState messageSearchBloc) =>
|
||||
StreamBuilder<List<GetMessageResponse>>(
|
||||
BetterStreamBuilder<List<GetMessageResponse>>(
|
||||
stream: messageSearchBloc.messagesStream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return widget.errorBuilder(context, snapshot.error!);
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return widget.loadingBuilder(context);
|
||||
}
|
||||
final items = snapshot.data!;
|
||||
errorBuilder: widget.errorBuilder,
|
||||
noDataBuilder: widget.loadingBuilder,
|
||||
builder: (context, items) {
|
||||
if (items.isEmpty) {
|
||||
return widget.emptyBuilder(context);
|
||||
}
|
||||
|
||||
@@ -176,16 +176,11 @@ class UserListCoreState extends State<UserListCore>
|
||||
},
|
||||
);
|
||||
|
||||
StreamBuilder<List<ListItem>> _buildListView() => StreamBuilder(
|
||||
BetterStreamBuilder<List<ListItem>> _buildListView() => BetterStreamBuilder(
|
||||
stream: _buildUserStream(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
return widget.errorBuilder(context, snapshot.error!);
|
||||
}
|
||||
if (!snapshot.hasData) {
|
||||
return widget.loadingBuilder(context);
|
||||
}
|
||||
final items = snapshot.data!;
|
||||
errorBuilder: widget.errorBuilder,
|
||||
noDataBuilder: widget.loadingBuilder,
|
||||
builder: (context, items) {
|
||||
if (items.isEmpty) {
|
||||
return widget.emptyBuilder(context);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: stream_chat_flutter_core
|
||||
homepage: https://github.com/GetStream/stream-chat-flutter
|
||||
description: Stream Chat official Flutter SDK Core. Build your own chat experience using Dart and Flutter.
|
||||
version: 2.1.1
|
||||
version: 2.2.1
|
||||
repository: https://github.com/GetStream/stream-chat-flutter
|
||||
issue_tracker: https://github.com/GetStream/stream-chat-flutter/issues
|
||||
|
||||
@@ -16,7 +16,7 @@ dependencies:
|
||||
sdk: flutter
|
||||
meta: ^1.3.0
|
||||
rxdart: ^0.27.0
|
||||
stream_chat: ^2.1.1
|
||||
stream_chat: ^2.2.1
|
||||
|
||||
dev_dependencies:
|
||||
fake_async: ^1.2.0
|
||||
|
||||
@@ -558,6 +558,7 @@ void main() {
|
||||
config: ChannelConfig(),
|
||||
createdAt: DateTime.now(),
|
||||
memberCount: 1,
|
||||
cooldown: 0,
|
||||
),
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user