feat: 2 way pagination

Signed-off-by: Sahil Kumar <[email protected]>
This commit is contained in:
Sahil Kumar
2020-12-02 19:30:24 +05:30
parent ac0fc427ae
commit 390062f1c2
5 changed files with 219 additions and 141 deletions
+13 -6
View File
@@ -480,8 +480,8 @@ class _MessageListViewState extends State<MessageListView> {
} else {
streamChannel.getReplies(widget.parentMessage.id);
}
_topWasVisible = !topIsVisible;
}
_topWasVisible = topIsVisible;
},
);
}
@@ -515,14 +515,21 @@ class _MessageListViewState extends State<MessageListView> {
key: ValueKey<String>('BOTTOM-MESSAGE'),
onVisibilityChanged: (visibility) {
final isVisible = visibility.visibleBounds != Rect.zero;
if (isVisible &&
!_bottomWasVisible &&
streamChannel.channel.config?.readEvents == true) {
if (streamChannel.channel.state.unreadCount > 0) {
if (isVisible && !_bottomWasVisible) {
if (widget.parentMessage == null) {
streamChannel.queryMessages(direction: QueryDirection.bottom);
} else {
streamChannel.getReplies(
widget.parentMessage.id,
direction: QueryDirection.bottom,
);
}
if (streamChannel.channel.config?.readEvents == true &&
streamChannel.channel.state.unreadCount > 0) {
streamChannel.channel.markRead();
}
_bottomWasVisible = !isVisible;
}
_bottomWasVisible = isVisible;
if (mounted) {
setState(() {
_showScrollToBottom = !isVisible;
+74 -24
View File
@@ -4,6 +4,8 @@ import 'package:flutter/material.dart';
import 'package:rxdart/rxdart.dart';
import 'package:stream_chat/stream_chat.dart';
enum QueryDirection { top, bottom }
/// Widget used to provide information about the channel to the widget tree
///
/// Use [StreamChannel.of] to get the current [StreamChannelState] instance.
@@ -52,34 +54,57 @@ class StreamChannelState extends State<StreamChannel> {
/// The stream notifying the state of queryMessage call
Stream<bool> get queryMessage => _queryMessageController.stream;
bool _paginationEnded = false;
bool _topPaginationEnded = false;
bool _bottomPaginationEnded = false;
/// Calls [channel.query] updating [queryMessage] stream
void queryMessages() {
if (_queryMessageController.value == true || _paginationEnded) {
void queryMessages({QueryDirection direction = QueryDirection.top}) {
if (_queryMessageController.value == true ||
(_topPaginationEnded && _bottomPaginationEnded)) {
return;
}
_queryMessageController.add(true);
String firstId;
if (channel.state.messages.isNotEmpty) {
firstId = channel.state.messages.first.id;
}
String id;
PaginationParams params;
final messageLimit = 50;
final messageLimit = 25;
if (channel.state.messages.isNotEmpty) {
switch (direction) {
case QueryDirection.top:
id = channel.state.messages.first.id;
params = PaginationParams(
lessThan: id,
limit: messageLimit,
);
break;
case QueryDirection.bottom:
id = channel.state.messages.last.id;
params = PaginationParams(
greaterThan: id,
limit: messageLimit,
);
break;
}
}
widget.channel
.query(
messagesPagination: PaginationParams(
lessThan: firstId,
limit: messageLimit,
),
messagesPagination: params,
preferOffline: true,
)
.then((res) {
if (res.messages.isEmpty || res.messages.length < messageLimit) {
_paginationEnded = true;
switch (direction) {
case QueryDirection.top:
_topPaginationEnded = true;
break;
case QueryDirection.bottom:
_bottomPaginationEnded = true;
break;
}
}
_queryMessageController.add(false);
}).catchError((e, stack) {
@@ -90,35 +115,60 @@ class StreamChannelState extends State<StreamChannel> {
}
/// Calls [channel.getReplies] updating [queryMessage] stream
Future<void> getReplies(String parentId) async {
if (_queryMessageController.value == true || _paginationEnded) {
Future<void> getReplies(
String parentId, {
QueryDirection direction = QueryDirection.top,
}) async {
if (_queryMessageController.value == true ||
(_topPaginationEnded && _bottomPaginationEnded)) {
return;
}
_queryMessageController.add(true);
String firstId;
String id;
PaginationParams params;
final messageLimit = 50;
if (widget.channel.state.threads.containsKey(parentId)) {
final thread = widget.channel.state.threads[parentId];
if (thread != null && thread.isNotEmpty) {
firstId = thread?.first?.id;
switch (direction) {
case QueryDirection.top:
id = thread?.first?.id;
params = PaginationParams(
lessThan: id,
limit: messageLimit,
);
break;
case QueryDirection.bottom:
id = thread?.last?.id;
params = PaginationParams(
greaterThan: id,
limit: messageLimit,
);
break;
}
}
}
final messageLimit = 50;
return widget.channel
.getReplies(
parentId,
PaginationParams(
lessThan: firstId,
limit: messageLimit,
),
params,
preferOffline: true,
)
.then((res) {
if (res.messages.isEmpty || res.messages.length < messageLimit) {
_paginationEnded = true;
switch (direction) {
case QueryDirection.top:
_topPaginationEnded = true;
break;
case QueryDirection.bottom:
_bottomPaginationEnded = true;
break;
}
}
_queryMessageController.add(false);
}).catchError((e, stack) {