Merge remote-tracking branch 'origin/fix/message-search-pagination' into fix/message-search-pagination
This commit is contained in:
@@ -58,7 +58,7 @@ class MessageSearchListView extends StatefulWidget {
|
|||||||
required this.filters,
|
required this.filters,
|
||||||
this.messageQuery,
|
this.messageQuery,
|
||||||
this.sortOptions,
|
this.sortOptions,
|
||||||
this.paginationParams,
|
this.paginationParams = const PaginationParams(limit: 30),
|
||||||
this.messageFilters,
|
this.messageFilters,
|
||||||
this.separatorBuilder,
|
this.separatorBuilder,
|
||||||
this.itemBuilder,
|
this.itemBuilder,
|
||||||
@@ -93,7 +93,7 @@ class MessageSearchListView extends StatefulWidget {
|
|||||||
/// limit: the number of users to return (max is 30)
|
/// limit: the number of users to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
/// message_limit: how many messages should be included to each channel
|
/// message_limit: how many messages should be included to each channel
|
||||||
final PaginationParams? paginationParams;
|
final PaginationParams paginationParams;
|
||||||
|
|
||||||
/// The message query filters to use.
|
/// The message query filters to use.
|
||||||
/// You can query on any of the custom fields you've defined on the [Channel].
|
/// You can query on any of the custom fields you've defined on the [Channel].
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ class UserListView extends StatefulWidget {
|
|||||||
this.filter,
|
this.filter,
|
||||||
this.sort,
|
this.sort,
|
||||||
this.presence,
|
this.presence,
|
||||||
this.pagination,
|
this.pagination = const PaginationParams(limit: 30),
|
||||||
this.onUserTap,
|
this.onUserTap,
|
||||||
this.onUserLongPress,
|
this.onUserLongPress,
|
||||||
this.userWidget,
|
this.userWidget,
|
||||||
@@ -93,7 +93,7 @@ class UserListView extends StatefulWidget {
|
|||||||
/// limit: the number of users to return (max is 30)
|
/// limit: the number of users to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
/// message_limit: how many messages should be included to each channel
|
/// message_limit: how many messages should be included to each channel
|
||||||
final PaginationParams? pagination;
|
final PaginationParams pagination;
|
||||||
|
|
||||||
/// Function called when tapping on a channel
|
/// Function called when tapping on a channel
|
||||||
/// By default it calls [Navigator.push] building a [MaterialPageRoute]
|
/// By default it calls [Navigator.push] building a [MaterialPageRoute]
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
|||||||
Stream<bool> get queryMessagesLoading =>
|
Stream<bool> get queryMessagesLoading =>
|
||||||
_queryMessagesLoadingController.stream;
|
_queryMessagesLoadingController.stream;
|
||||||
|
|
||||||
|
bool _paginationEnded = false;
|
||||||
|
|
||||||
/// Calls [StreamChatClient.search] updating
|
/// Calls [StreamChatClient.search] updating
|
||||||
/// [messagesStream] and [queryMessagesLoading] stream
|
/// [messagesStream] and [queryMessagesLoading] stream
|
||||||
Future<void> search({
|
Future<void> search({
|
||||||
@@ -72,24 +74,31 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
|||||||
Filter? messageFilter,
|
Filter? messageFilter,
|
||||||
List<SortOption>? sort,
|
List<SortOption>? sort,
|
||||||
String? query,
|
String? query,
|
||||||
PaginationParams? pagination,
|
PaginationParams pagination = const PaginationParams(limit: 30),
|
||||||
}) async {
|
}) async {
|
||||||
final client = _streamChatCoreState.client;
|
final client = _streamChatCoreState.client;
|
||||||
|
|
||||||
if (_queryMessagesLoadingController.value == true) return;
|
var clear = false;
|
||||||
|
if (sort != null) {
|
||||||
|
clear |= pagination.next == null;
|
||||||
|
} else {
|
||||||
|
final offset = pagination.offset;
|
||||||
|
clear |= offset == null || offset == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear && _paginationEnded) {
|
||||||
|
_paginationEnded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!clear && _paginationEnded) ||
|
||||||
|
_queryMessagesLoadingController.value == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_messageResponses.hasValue) {
|
if (_messageResponses.hasValue) {
|
||||||
_queryMessagesLoadingController.add(true);
|
_queryMessagesLoadingController.add(true);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var clear = pagination == null;
|
|
||||||
if (sort != null) {
|
|
||||||
clear |= pagination?.next == null;
|
|
||||||
} else {
|
|
||||||
final offset = pagination?.offset;
|
|
||||||
clear |= offset == null || offset == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
final oldMessages = List<GetMessageResponse>.from(messageResponses ?? []);
|
final oldMessages = List<GetMessageResponse>.from(messageResponses ?? []);
|
||||||
|
|
||||||
final response = await client.search(
|
final response = await client.search(
|
||||||
@@ -110,15 +119,19 @@ class MessageSearchBlocState extends State<MessageSearchBloc>
|
|||||||
? previous
|
? previous
|
||||||
: /*reset previousId if we get nothing*/ null;
|
: /*reset previousId if we get nothing*/ null;
|
||||||
|
|
||||||
|
final newMessages = response.results;
|
||||||
if (clear) {
|
if (clear) {
|
||||||
_messageResponses.add(response.results);
|
_messageResponses.add(newMessages);
|
||||||
} else {
|
} else {
|
||||||
final temp = oldMessages + response.results;
|
final temp = oldMessages + newMessages;
|
||||||
_messageResponses.add(temp);
|
_messageResponses.add(temp);
|
||||||
}
|
}
|
||||||
if (_messageResponses.hasValue && _queryMessagesLoadingController.value) {
|
if (_messageResponses.hasValue && _queryMessagesLoadingController.value) {
|
||||||
_queryMessagesLoadingController.add(false);
|
_queryMessagesLoadingController.add(false);
|
||||||
}
|
}
|
||||||
|
if (newMessages.isEmpty || newMessages.length < pagination.limit) {
|
||||||
|
_paginationEnded = true;
|
||||||
|
}
|
||||||
} catch (e, stk) {
|
} catch (e, stk) {
|
||||||
// reset loading controller
|
// reset loading controller
|
||||||
_queryMessagesLoadingController.add(false);
|
_queryMessagesLoadingController.add(false);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class MessageSearchListCore extends StatefulWidget {
|
|||||||
required this.filters,
|
required this.filters,
|
||||||
this.messageQuery,
|
this.messageQuery,
|
||||||
this.sortOptions,
|
this.sortOptions,
|
||||||
this.paginationParams,
|
this.paginationParams = const PaginationParams(limit: 30),
|
||||||
this.messageFilters,
|
this.messageFilters,
|
||||||
this.messageSearchListController,
|
this.messageSearchListController,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
@@ -84,7 +84,7 @@ class MessageSearchListCore extends StatefulWidget {
|
|||||||
/// Pagination parameters
|
/// Pagination parameters
|
||||||
/// limit: the number of messages to return (max is 30)
|
/// limit: the number of messages to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
final PaginationParams? paginationParams;
|
final PaginationParams paginationParams;
|
||||||
|
|
||||||
/// The message query filters to use.
|
/// The message query filters to use.
|
||||||
/// You can query on any of the custom fields you've defined on the [Channel].
|
/// You can query on any of the custom fields you've defined on the [Channel].
|
||||||
@@ -163,13 +163,13 @@ class MessageSearchListCoreState extends State<MessageSearchListCore> {
|
|||||||
|
|
||||||
/// Fetches more messages with updated pagination and updates the widget
|
/// Fetches more messages with updated pagination and updates the widget
|
||||||
Future<void> paginateData() {
|
Future<void> paginateData() {
|
||||||
PaginationParams? pagination;
|
PaginationParams pagination;
|
||||||
if (widget.sortOptions != null) {
|
if (widget.sortOptions != null) {
|
||||||
pagination = widget.paginationParams?.copyWith(
|
pagination = widget.paginationParams.copyWith(
|
||||||
next: _messageSearchBloc?.nextId,
|
next: _messageSearchBloc?.nextId,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
pagination = widget.paginationParams?.copyWith(
|
pagination = widget.paginationParams.copyWith(
|
||||||
offset: _messageSearchBloc?.messageResponses?.length,
|
offset: _messageSearchBloc?.messageResponses?.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -190,8 +190,8 @@ class MessageSearchListCoreState extends State<MessageSearchListCore> {
|
|||||||
widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() ||
|
widget.messageQuery?.toString() != oldWidget.messageQuery?.toString() ||
|
||||||
widget.messageFilters?.toString() !=
|
widget.messageFilters?.toString() !=
|
||||||
oldWidget.messageFilters?.toString() ||
|
oldWidget.messageFilters?.toString() ||
|
||||||
widget.paginationParams?.toJson().toString() !=
|
widget.paginationParams.toJson().toString() !=
|
||||||
oldWidget.paginationParams?.toJson().toString()) {
|
oldWidget.paginationParams.toJson().toString()) {
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class UserListCore extends StatefulWidget {
|
|||||||
this.filter,
|
this.filter,
|
||||||
this.sort,
|
this.sort,
|
||||||
this.presence,
|
this.presence,
|
||||||
this.pagination,
|
this.pagination = const PaginationParams(limit: 30),
|
||||||
this.groupAlphabetically = false,
|
this.groupAlphabetically = false,
|
||||||
this.userListController,
|
this.userListController,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
@@ -106,7 +106,7 @@ class UserListCore extends StatefulWidget {
|
|||||||
/// limit: the number of users to return (max is 30)
|
/// limit: the number of users to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
/// message_limit: how many messages should be included to each channel
|
/// message_limit: how many messages should be included to each channel
|
||||||
final PaginationParams? pagination;
|
final PaginationParams pagination;
|
||||||
|
|
||||||
/// Set it to true to group users by their first character
|
/// Set it to true to group users by their first character
|
||||||
///
|
///
|
||||||
@@ -201,7 +201,7 @@ class UserListCoreState extends State<UserListCore>
|
|||||||
filter: widget.filter,
|
filter: widget.filter,
|
||||||
sort: widget.sort,
|
sort: widget.sort,
|
||||||
presence: widget.presence,
|
presence: widget.presence,
|
||||||
pagination: widget.pagination!.copyWith(
|
pagination: widget.pagination.copyWith(
|
||||||
offset: _usersBloc!.users?.length ?? 0,
|
offset: _usersBloc!.users?.length ?? 0,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -212,8 +212,8 @@ class UserListCoreState extends State<UserListCore>
|
|||||||
if (widget.filter?.toString() != oldWidget.filter?.toString() ||
|
if (widget.filter?.toString() != oldWidget.filter?.toString() ||
|
||||||
jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) ||
|
jsonEncode(widget.sort) != jsonEncode(oldWidget.sort) ||
|
||||||
widget.presence != oldWidget.presence ||
|
widget.presence != oldWidget.presence ||
|
||||||
widget.pagination?.toJson().toString() !=
|
widget.pagination.toJson().toString() !=
|
||||||
oldWidget.pagination?.toJson().toString()) {
|
oldWidget.pagination.toJson().toString()) {
|
||||||
loadData();
|
loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ class UsersBlocState extends State<UsersBloc>
|
|||||||
|
|
||||||
late StreamChatCoreState _streamChatCore;
|
late StreamChatCoreState _streamChatCore;
|
||||||
|
|
||||||
|
bool _paginationEnded = false;
|
||||||
|
|
||||||
/// The Query Users method allows you to search for users and see if they are
|
/// The Query Users method allows you to search for users and see if they are
|
||||||
/// online/offline.
|
/// online/offline.
|
||||||
/// [API Reference](https://getstream.io/chat/docs/flutter-dart/query_users/?language=dart)
|
/// [API Reference](https://getstream.io/chat/docs/flutter-dart/query_users/?language=dart)
|
||||||
@@ -64,21 +66,27 @@ class UsersBlocState extends State<UsersBloc>
|
|||||||
Filter? filter,
|
Filter? filter,
|
||||||
List<SortOption>? sort,
|
List<SortOption>? sort,
|
||||||
bool? presence,
|
bool? presence,
|
||||||
PaginationParams? pagination,
|
PaginationParams pagination = const PaginationParams(limit: 30),
|
||||||
}) async {
|
}) async {
|
||||||
final client = _streamChatCore.client;
|
final client = _streamChatCore.client;
|
||||||
|
|
||||||
if (_queryUsersLoadingController.value == true) return;
|
final offset = pagination.offset;
|
||||||
|
final clear = offset == null || offset == 0;
|
||||||
|
|
||||||
|
if (clear && _paginationEnded) {
|
||||||
|
_paginationEnded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!clear && _paginationEnded) ||
|
||||||
|
_queryUsersLoadingController.value == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (_usersController.hasValue) {
|
if (_usersController.hasValue) {
|
||||||
_queryUsersLoadingController.add(true);
|
_queryUsersLoadingController.add(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final clear = pagination == null ||
|
|
||||||
pagination.offset == null ||
|
|
||||||
pagination.offset == 0;
|
|
||||||
|
|
||||||
final oldUsers = List<User>.from(users ?? []);
|
final oldUsers = List<User>.from(users ?? []);
|
||||||
|
|
||||||
final usersResponse = await client.queryUsers(
|
final usersResponse = await client.queryUsers(
|
||||||
@@ -88,6 +96,7 @@ class UsersBlocState extends State<UsersBloc>
|
|||||||
pagination: pagination,
|
pagination: pagination,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final newUsers = usersResponse.users;
|
||||||
if (clear) {
|
if (clear) {
|
||||||
_usersController.add(usersResponse.users);
|
_usersController.add(usersResponse.users);
|
||||||
} else {
|
} else {
|
||||||
@@ -97,6 +106,9 @@ class UsersBlocState extends State<UsersBloc>
|
|||||||
if (_usersController.hasValue && _queryUsersLoadingController.value) {
|
if (_usersController.hasValue && _queryUsersLoadingController.value) {
|
||||||
_queryUsersLoadingController.add(false);
|
_queryUsersLoadingController.add(false);
|
||||||
}
|
}
|
||||||
|
if (newUsers.isEmpty || newUsers.length < pagination.limit) {
|
||||||
|
_paginationEnded = true;
|
||||||
|
}
|
||||||
} catch (e, stk) {
|
} catch (e, stk) {
|
||||||
// reset loading controller
|
// reset loading controller
|
||||||
_queryUsersLoadingController.add(false);
|
_queryUsersLoadingController.add(false);
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'messageSearchBlocState.search() should throw if used where '
|
'''messageSearchBlocState.search() should throw if used where StreamChat is not present in the widget tree''',
|
||||||
'StreamChat is not present in the widget tree',
|
|
||||||
(tester) async {
|
(tester) async {
|
||||||
const messageSearchBloc = MessageSearchBloc(
|
const messageSearchBloc = MessageSearchBloc(
|
||||||
child: Offstage(),
|
child: Offstage(),
|
||||||
@@ -98,8 +97,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'messageSearchBlocState.messagesStream should emit error '
|
'''messageSearchBlocState.messagesStream should emit error if client.search() throws''',
|
||||||
'if client.search() throws',
|
|
||||||
(tester) async {
|
(tester) async {
|
||||||
const messageSearchBlocKey = Key('messageSearchBloc');
|
const messageSearchBlocKey = Key('messageSearchBloc');
|
||||||
const childKey = Key('child');
|
const childKey = Key('child');
|
||||||
@@ -147,9 +145,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'calling messageSearchBlocState.search() again with an offset '
|
'''calling messageSearchBlocState.search() again with an offset should emit new data through messagesStream and also emit loading state through queryMessagesLoading''',
|
||||||
'should emit new data through messagesStream and also emit loading state '
|
|
||||||
'through queryMessagesLoading',
|
|
||||||
(tester) async {
|
(tester) async {
|
||||||
const messageSearchBlocKey = Key('messageSearchBloc');
|
const messageSearchBlocKey = Key('messageSearchBloc');
|
||||||
const childKey = Key('child');
|
const childKey = Key('child');
|
||||||
@@ -171,14 +167,15 @@ void main() {
|
|||||||
find.byKey(messageSearchBlocKey),
|
find.byKey(messageSearchBlocKey),
|
||||||
);
|
);
|
||||||
|
|
||||||
final messageResponseList = _generateMessages();
|
const pagination = PaginationParams(limit: 25);
|
||||||
|
final messageResponseList = _generateMessages(count: 25);
|
||||||
|
|
||||||
when(() => mockClient.search(
|
when(() => mockClient.search(
|
||||||
testFilter,
|
testFilter,
|
||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: any(named: 'paginationParams'),
|
paginationParams: pagination,
|
||||||
)).thenAnswer(
|
)).thenAnswer(
|
||||||
(_) async => SearchMessagesResponse()
|
(_) async => SearchMessagesResponse()
|
||||||
..results = messageResponseList
|
..results = messageResponseList
|
||||||
@@ -186,7 +183,7 @@ void main() {
|
|||||||
..previous = null,
|
..previous = null,
|
||||||
);
|
);
|
||||||
|
|
||||||
messageSearchBlocState.search(filter: testFilter);
|
messageSearchBlocState.search(pagination: pagination, filter: testFilter);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
messageSearchBlocState.messagesStream,
|
messageSearchBlocState.messagesStream,
|
||||||
@@ -198,19 +195,19 @@ void main() {
|
|||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: any(named: 'paginationParams'),
|
paginationParams: pagination,
|
||||||
)).called(1);
|
)).called(1);
|
||||||
|
|
||||||
final offset = messageResponseList.length;
|
final offset = messageResponseList.length;
|
||||||
final paginatedMessageResponseList = _generateMessages(offset: offset);
|
final paginatedMessageResponseList = _generateMessages(offset: offset);
|
||||||
final pagination = PaginationParams(offset: offset);
|
final newPagination = pagination.copyWith(offset: offset);
|
||||||
|
|
||||||
when(() => mockClient.search(
|
when(() => mockClient.search(
|
||||||
testFilter,
|
testFilter,
|
||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: pagination,
|
paginationParams: newPagination,
|
||||||
)).thenAnswer(
|
)).thenAnswer(
|
||||||
(_) async => SearchMessagesResponse()
|
(_) async => SearchMessagesResponse()
|
||||||
..results = paginatedMessageResponseList
|
..results = paginatedMessageResponseList
|
||||||
@@ -244,9 +241,7 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
testWidgets(
|
testWidgets(
|
||||||
'calling messageSearchBlocState.search() again with an offset '
|
'''calling messageSearchBlocState.search() again with an offset should emit error through queryUsersLoading if client.search() throws''',
|
||||||
'should emit error through queryUsersLoading if '
|
|
||||||
'client.search() throws',
|
|
||||||
(tester) async {
|
(tester) async {
|
||||||
const messageSearchBlocKey = Key('messageSearchBloc');
|
const messageSearchBlocKey = Key('messageSearchBloc');
|
||||||
const childKey = Key('child');
|
const childKey = Key('child');
|
||||||
@@ -268,14 +263,15 @@ void main() {
|
|||||||
find.byKey(messageSearchBlocKey),
|
find.byKey(messageSearchBlocKey),
|
||||||
);
|
);
|
||||||
|
|
||||||
final messageResponseList = _generateMessages();
|
const pagination = PaginationParams(limit: 25);
|
||||||
|
final messageResponseList = _generateMessages(count: 25);
|
||||||
|
|
||||||
when(() => mockClient.search(
|
when(() => mockClient.search(
|
||||||
testFilter,
|
testFilter,
|
||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: any(named: 'paginationParams'),
|
paginationParams: pagination,
|
||||||
)).thenAnswer(
|
)).thenAnswer(
|
||||||
(_) async => SearchMessagesResponse()
|
(_) async => SearchMessagesResponse()
|
||||||
..results = messageResponseList
|
..results = messageResponseList
|
||||||
@@ -283,7 +279,7 @@ void main() {
|
|||||||
..previous = null,
|
..previous = null,
|
||||||
);
|
);
|
||||||
|
|
||||||
messageSearchBlocState.search(filter: testFilter);
|
messageSearchBlocState.search(pagination: pagination, filter: testFilter);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
messageSearchBlocState.messagesStream,
|
messageSearchBlocState.messagesStream,
|
||||||
@@ -295,11 +291,11 @@ void main() {
|
|||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: any(named: 'paginationParams'),
|
paginationParams: pagination,
|
||||||
)).called(1);
|
)).called(1);
|
||||||
|
|
||||||
final offset = messageResponseList.length;
|
final offset = messageResponseList.length;
|
||||||
final pagination = PaginationParams(offset: offset);
|
final newPagination = pagination.copyWith(offset: offset);
|
||||||
|
|
||||||
const error = 'Error! Error! Error!';
|
const error = 'Error! Error! Error!';
|
||||||
when(() => mockClient.search(
|
when(() => mockClient.search(
|
||||||
@@ -307,10 +303,13 @@ void main() {
|
|||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: pagination,
|
paginationParams: newPagination,
|
||||||
)).thenThrow(error);
|
)).thenThrow(error);
|
||||||
|
|
||||||
messageSearchBlocState.search(pagination: pagination, filter: testFilter);
|
messageSearchBlocState.search(
|
||||||
|
pagination: newPagination,
|
||||||
|
filter: testFilter,
|
||||||
|
);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
messageSearchBlocState.queryMessagesLoading,
|
messageSearchBlocState.queryMessagesLoading,
|
||||||
@@ -322,8 +321,80 @@ void main() {
|
|||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
messageFilters: any(named: 'messageFilters'),
|
messageFilters: any(named: 'messageFilters'),
|
||||||
paginationParams: pagination,
|
paginationParams: newPagination,
|
||||||
)).called(1);
|
)).called(1);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'''calling messageSearchBlocState.search() again with an offset should do nothing and return if pagination is completed''',
|
||||||
|
(tester) async {
|
||||||
|
const messageSearchBlocKey = Key('messageSearchBloc');
|
||||||
|
const childKey = Key('child');
|
||||||
|
const messageSearchBloc = MessageSearchBloc(
|
||||||
|
key: messageSearchBlocKey,
|
||||||
|
child: Offstage(key: childKey),
|
||||||
|
);
|
||||||
|
|
||||||
|
final mockClient = MockClient();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
StreamChatCore(
|
||||||
|
client: mockClient,
|
||||||
|
child: messageSearchBloc,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final messageSearchBlocState = tester.state<MessageSearchBlocState>(
|
||||||
|
find.byKey(messageSearchBlocKey),
|
||||||
|
);
|
||||||
|
|
||||||
|
const pagination = PaginationParams(limit: 25);
|
||||||
|
|
||||||
|
final messageResponseList = _generateMessages(count: 20);
|
||||||
|
|
||||||
|
when(() => mockClient.search(
|
||||||
|
testFilter,
|
||||||
|
query: any(named: 'query'),
|
||||||
|
sort: any(named: 'sort'),
|
||||||
|
messageFilters: any(named: 'messageFilters'),
|
||||||
|
paginationParams: pagination,
|
||||||
|
)).thenAnswer(
|
||||||
|
(_) async => SearchMessagesResponse()
|
||||||
|
..results = messageResponseList
|
||||||
|
..next = null
|
||||||
|
..previous = null,
|
||||||
|
);
|
||||||
|
|
||||||
|
messageSearchBlocState.search(pagination: pagination, filter: testFilter);
|
||||||
|
|
||||||
|
await expectLater(
|
||||||
|
messageSearchBlocState.messagesStream,
|
||||||
|
emits(isSameMessageResponseListAs(messageResponseList)),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(() => mockClient.search(
|
||||||
|
testFilter,
|
||||||
|
query: any(named: 'query'),
|
||||||
|
sort: any(named: 'sort'),
|
||||||
|
messageFilters: any(named: 'messageFilters'),
|
||||||
|
paginationParams: pagination,
|
||||||
|
)).called(1);
|
||||||
|
|
||||||
|
final offset = messageResponseList.length;
|
||||||
|
final newPagination = pagination.copyWith(offset: offset);
|
||||||
|
|
||||||
|
messageSearchBlocState.search(
|
||||||
|
filter: testFilter,
|
||||||
|
pagination: newPagination,
|
||||||
|
);
|
||||||
|
|
||||||
|
// should emit nothing.
|
||||||
|
await expectLater(
|
||||||
|
// skipping the initial data (behaviorSubject).
|
||||||
|
messageSearchBlocState.messagesStream.skip(1),
|
||||||
|
emitsInOrder([]),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -322,7 +322,7 @@ void main() {
|
|||||||
(tester) async {
|
(tester) async {
|
||||||
const messageSearchListCoreKey = Key('messageSearchListCore');
|
const messageSearchListCoreKey = Key('messageSearchListCore');
|
||||||
const childWidgetKey = Key('childWidget');
|
const childWidgetKey = Key('childWidget');
|
||||||
const pagination = PaginationParams();
|
const pagination = PaginationParams(limit: 25);
|
||||||
final messageSearchListCore = MessageSearchListCore(
|
final messageSearchListCore = MessageSearchListCore(
|
||||||
key: messageSearchListCoreKey,
|
key: messageSearchListCoreKey,
|
||||||
childBuilder: (List<GetMessageResponse> messages) => Container(
|
childBuilder: (List<GetMessageResponse> messages) => Container(
|
||||||
@@ -341,7 +341,7 @@ void main() {
|
|||||||
|
|
||||||
final mockClient = MockClient();
|
final mockClient = MockClient();
|
||||||
|
|
||||||
final messageResponseList = _generateMessages();
|
final messageResponseList = _generateMessages(count: 25);
|
||||||
when(() => mockClient.search(
|
when(() => mockClient.search(
|
||||||
testFilter,
|
testFilter,
|
||||||
query: any(named: 'query'),
|
query: any(named: 'query'),
|
||||||
|
|||||||
@@ -321,7 +321,7 @@ void main() {
|
|||||||
(tester) async {
|
(tester) async {
|
||||||
const userListCoreKey = Key('userListCore');
|
const userListCoreKey = Key('userListCore');
|
||||||
const listWidgetKey = Key('listWidget');
|
const listWidgetKey = Key('listWidget');
|
||||||
const pagination = PaginationParams();
|
const pagination = PaginationParams(limit: 15);
|
||||||
final userListCore = UserListCore(
|
final userListCore = UserListCore(
|
||||||
key: userListCoreKey,
|
key: userListCoreKey,
|
||||||
listBuilder: (_, items) => Container(
|
listBuilder: (_, items) => Container(
|
||||||
@@ -347,7 +347,7 @@ void main() {
|
|||||||
|
|
||||||
final mockClient = MockClient();
|
final mockClient = MockClient();
|
||||||
|
|
||||||
final users = _generateUsers();
|
final users = _generateUsers(count: 15);
|
||||||
when(() => mockClient.queryUsers(
|
when(() => mockClient.queryUsers(
|
||||||
filter: any(named: 'filter'),
|
filter: any(named: 'filter'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
|
|||||||
@@ -164,16 +164,17 @@ void main() {
|
|||||||
find.byKey(usersBlocKey),
|
find.byKey(usersBlocKey),
|
||||||
);
|
);
|
||||||
|
|
||||||
final users = _generateUsers();
|
const pagination = PaginationParams(limit: 25);
|
||||||
|
final users = _generateUsers(count: 25);
|
||||||
|
|
||||||
when(() => mockClient.queryUsers(
|
when(() => mockClient.queryUsers(
|
||||||
filter: any(named: 'filter'),
|
filter: any(named: 'filter'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
presence: any(named: 'presence'),
|
presence: any(named: 'presence'),
|
||||||
pagination: any(named: 'pagination'),
|
pagination: pagination,
|
||||||
)).thenAnswer((_) async => QueryUsersResponse()..users = users);
|
)).thenAnswer((_) async => QueryUsersResponse()..users = users);
|
||||||
|
|
||||||
usersBlocState.queryUsers();
|
usersBlocState.queryUsers(pagination: pagination);
|
||||||
|
|
||||||
await expectLater(
|
await expectLater(
|
||||||
usersBlocState.usersStream,
|
usersBlocState.usersStream,
|
||||||
@@ -184,23 +185,23 @@ void main() {
|
|||||||
filter: any(named: 'filter'),
|
filter: any(named: 'filter'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
presence: any(named: 'presence'),
|
presence: any(named: 'presence'),
|
||||||
pagination: any(named: 'pagination'),
|
pagination: pagination,
|
||||||
)).called(1);
|
)).called(1);
|
||||||
|
|
||||||
final offset = users.length;
|
final offset = users.length;
|
||||||
final paginatedUsers = _generateUsers(offset: offset);
|
final paginatedUsers = _generateUsers(offset: offset);
|
||||||
final pagination = PaginationParams(offset: offset);
|
final newPagination = pagination.copyWith(offset: offset);
|
||||||
|
|
||||||
when(() => mockClient.queryUsers(
|
when(() => mockClient.queryUsers(
|
||||||
filter: any(named: 'filter'),
|
filter: any(named: 'filter'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
presence: any(named: 'presence'),
|
presence: any(named: 'presence'),
|
||||||
pagination: pagination,
|
pagination: newPagination,
|
||||||
))
|
)).thenAnswer(
|
||||||
.thenAnswer(
|
(_) async => QueryUsersResponse()..users = paginatedUsers,
|
||||||
(_) async => QueryUsersResponse()..users = paginatedUsers);
|
);
|
||||||
|
|
||||||
usersBlocState.queryUsers(pagination: pagination);
|
usersBlocState.queryUsers(pagination: newPagination);
|
||||||
|
|
||||||
await Future.wait([
|
await Future.wait([
|
||||||
expectLater(
|
expectLater(
|
||||||
@@ -217,7 +218,7 @@ void main() {
|
|||||||
filter: any(named: 'filter'),
|
filter: any(named: 'filter'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
presence: any(named: 'presence'),
|
presence: any(named: 'presence'),
|
||||||
pagination: pagination,
|
pagination: newPagination,
|
||||||
)).called(1);
|
)).called(1);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -247,13 +248,89 @@ void main() {
|
|||||||
find.byKey(usersBlocKey),
|
find.byKey(usersBlocKey),
|
||||||
);
|
);
|
||||||
|
|
||||||
final users = _generateUsers();
|
const pagination = PaginationParams(limit: 25);
|
||||||
|
final users = _generateUsers(count: 25);
|
||||||
|
|
||||||
when(() => mockClient.queryUsers(
|
when(() => mockClient.queryUsers(
|
||||||
filter: any(named: 'filter'),
|
filter: any(named: 'filter'),
|
||||||
sort: any(named: 'sort'),
|
sort: any(named: 'sort'),
|
||||||
presence: any(named: 'presence'),
|
presence: any(named: 'presence'),
|
||||||
pagination: any(named: 'pagination'),
|
pagination: pagination,
|
||||||
|
)).thenAnswer((_) async => QueryUsersResponse()..users = users);
|
||||||
|
|
||||||
|
usersBlocState.queryUsers(pagination: pagination);
|
||||||
|
|
||||||
|
await expectLater(
|
||||||
|
usersBlocState.usersStream,
|
||||||
|
emits(isSameUserListAs(users)),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(() => mockClient.queryUsers(
|
||||||
|
filter: any(named: 'filter'),
|
||||||
|
sort: any(named: 'sort'),
|
||||||
|
presence: any(named: 'presence'),
|
||||||
|
pagination: pagination,
|
||||||
|
)).called(1);
|
||||||
|
|
||||||
|
final offset = users.length;
|
||||||
|
final newPagination = pagination.copyWith(offset: offset);
|
||||||
|
|
||||||
|
const error = 'Error! Error! Error!';
|
||||||
|
|
||||||
|
when(() => mockClient.queryUsers(
|
||||||
|
filter: any(named: 'filter'),
|
||||||
|
sort: any(named: 'sort'),
|
||||||
|
presence: any(named: 'presence'),
|
||||||
|
pagination: newPagination,
|
||||||
|
)).thenThrow(error);
|
||||||
|
|
||||||
|
usersBlocState.queryUsers(pagination: newPagination);
|
||||||
|
|
||||||
|
await expectLater(
|
||||||
|
usersBlocState.queryUsersLoading,
|
||||||
|
emitsError(error),
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(() => mockClient.queryUsers(
|
||||||
|
filter: any(named: 'filter'),
|
||||||
|
sort: any(named: 'sort'),
|
||||||
|
presence: any(named: 'presence'),
|
||||||
|
pagination: newPagination,
|
||||||
|
)).called(1);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
testWidgets(
|
||||||
|
'''calling usersBlocState.queryUsers() again with an offset should do nothing and return if pagination is completed''',
|
||||||
|
(tester) async {
|
||||||
|
const usersBlocKey = Key('usersBloc');
|
||||||
|
const childKey = Key('child');
|
||||||
|
const usersBloc = UsersBloc(
|
||||||
|
key: usersBlocKey,
|
||||||
|
child: Offstage(key: childKey),
|
||||||
|
);
|
||||||
|
|
||||||
|
final mockClient = MockClient();
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
StreamChatCore(
|
||||||
|
client: mockClient,
|
||||||
|
child: usersBloc,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final usersBlocState = tester.state<UsersBlocState>(
|
||||||
|
find.byKey(usersBlocKey),
|
||||||
|
);
|
||||||
|
|
||||||
|
const pagination = PaginationParams(limit: 30);
|
||||||
|
final users = _generateUsers(count: 25);
|
||||||
|
|
||||||
|
when(() => mockClient.queryUsers(
|
||||||
|
filter: any(named: 'filter'),
|
||||||
|
sort: any(named: 'sort'),
|
||||||
|
presence: any(named: 'presence'),
|
||||||
|
pagination: pagination,
|
||||||
)).thenAnswer((_) async => QueryUsersResponse()..users = users);
|
)).thenAnswer((_) async => QueryUsersResponse()..users = users);
|
||||||
|
|
||||||
usersBlocState.queryUsers();
|
usersBlocState.queryUsers();
|
||||||
@@ -271,30 +348,16 @@ void main() {
|
|||||||
)).called(1);
|
)).called(1);
|
||||||
|
|
||||||
final offset = users.length;
|
final offset = users.length;
|
||||||
final pagination = PaginationParams(offset: offset);
|
final newPagination = pagination.copyWith(offset: offset);
|
||||||
|
|
||||||
const error = 'Error! Error! Error!';
|
usersBlocState.queryUsers(pagination: newPagination);
|
||||||
|
|
||||||
when(() => mockClient.queryUsers(
|
|
||||||
filter: any(named: 'filter'),
|
|
||||||
sort: any(named: 'sort'),
|
|
||||||
presence: any(named: 'presence'),
|
|
||||||
pagination: pagination,
|
|
||||||
)).thenThrow(error);
|
|
||||||
|
|
||||||
usersBlocState.queryUsers(pagination: pagination);
|
|
||||||
|
|
||||||
|
// should emit nothing.
|
||||||
await expectLater(
|
await expectLater(
|
||||||
usersBlocState.queryUsersLoading,
|
// skipping the initial data (behaviorSubject).
|
||||||
emitsError(error),
|
usersBlocState.usersStream,
|
||||||
|
emitsInOrder([]),
|
||||||
);
|
);
|
||||||
|
|
||||||
verify(() => mockClient.queryUsers(
|
|
||||||
filter: any(named: 'filter'),
|
|
||||||
sort: any(named: 'sort'),
|
|
||||||
presence: any(named: 'presence'),
|
|
||||||
pagination: pagination,
|
|
||||||
)).called(1);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user