fix: let the chats align to the top

This commit is contained in:
Freek van de Ven 2025-02-18 22:27:43 +01:00
parent 7b3ddc5118
commit 02e668dd6f

View file

@ -249,6 +249,7 @@ class _ChatBody extends HookWidget {
var isLoadingOlder = useState(false); var isLoadingOlder = useState(false);
var isLoadingNewer = useState(false); var isLoadingNewer = useState(false);
var autoScrollEnabled = useState(true);
var messagesStream = useMemoized( var messagesStream = useMemoized(
() => service.getMessages(chatId: chatId), () => service.getMessages(chatId: chatId),
@ -317,14 +318,21 @@ class _ChatBody extends HookWidget {
var offset = scrollController.offset; var offset = scrollController.offset;
var maxScroll = scrollController.position.maxScrollExtent; var maxScroll = scrollController.position.maxScrollExtent;
var threshold = options.paginationControls.scrollOffset;
if ((maxScroll - offset) <= options.paginationControls.scrollOffset && var distanceFromBottom = maxScroll - offset;
!isLoadingOlder.value) {
if (distanceFromBottom > 50) {
autoScrollEnabled.value = false;
} else {
autoScrollEnabled.value = true;
}
if (offset <= threshold && !isLoadingOlder.value) {
unawaited(loadOlderMessages()); unawaited(loadOlderMessages());
} }
if (offset <= options.paginationControls.scrollOffset && if (distanceFromBottom <= threshold && !isLoadingNewer.value) {
!isLoadingNewer.value) {
unawaited(loadNewerMessages()); unawaited(loadNewerMessages());
} }
} }
@ -338,6 +346,34 @@ class _ChatBody extends HookWidget {
chat, chat,
]); ]);
useEffect(
() {
var disposed = false;
/// Continuously scroll to the bottom of the chat
Future<void> scrollLoop() async {
while (!disposed && autoScrollEnabled.value) {
await Future.delayed(const Duration(milliseconds: 500));
if (disposed || !autoScrollEnabled.value) break;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (disposed || !autoScrollEnabled.value) return;
if (scrollController.hasClients) {
scrollController.jumpTo(
scrollController.position.maxScrollExtent,
);
}
});
}
}
unawaited(scrollLoop());
return () => disposed = true;
},
[autoScrollEnabled.value],
);
if (chat == null) { if (chat == null) {
if (!options.enableLoadingIndicator) return const SizedBox.shrink(); if (!options.enableLoadingIndicator) return const SizedBox.shrink();
return options.builders.loadingWidgetBuilder.call(context); return options.builders.loadingWidgetBuilder.call(context);
@ -358,17 +394,13 @@ class _ChatBody extends HookWidget {
? options.builders.loadingChatMessageBuilder.call(context) ? options.builders.loadingChatMessageBuilder.call(context)
: const SizedBox.shrink(); : const SizedBox.shrink();
var reversedMessages = messages.reversed.toList();
var bubbleChildren = <Widget>[]; var bubbleChildren = <Widget>[];
if (reversedMessages.isEmpty) { if (messages.isEmpty) {
bubbleChildren bubbleChildren
.add(ChatNoMessages(isGroupChat: chat?.isGroupChat ?? false)); .add(ChatNoMessages(isGroupChat: chat?.isGroupChat ?? false));
} else { } else {
for (var (index, msg) in reversedMessages.indexed) { for (var (index, msg) in messages.indexed) {
var nextIndex = index + 1; var prevMsg = index > 0 ? messages[index - 1] : null;
var prevMsg = nextIndex < reversedMessages.length
? reversedMessages[nextIndex]
: null;
bubbleChildren.add( bubbleChildren.add(
ChatBubble( ChatBubble(
@ -390,15 +422,13 @@ class _ChatBody extends HookWidget {
return Column( return Column(
children: [ children: [
Expanded( Expanded(
child: Align( child: ListView.builder(
alignment: options.chatAlignment ?? Alignment.bottomCenter, reverse: false,
child: ListView(
reverse: true,
controller: scrollController, controller: scrollController,
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
padding: const EdgeInsets.only(top: 24), padding: const EdgeInsets.only(top: 24),
children: listViewChildren, itemCount: listViewChildren.length,
), itemBuilder: (context, index) => listViewChildren[index],
), ),
), ),
ChatBottomInputSection( ChatBottomInputSection(