loadConversationMessages method
Future<void>
loadConversationMessages(
{ - bool reset = false,
})
Implementation
Future<void> loadConversationMessages({bool reset = false}) async {
if (isLoadingConversationPage || isConversationLastPage) {
return;
}
double? previousMaxExtent;
double? previousPixels;
if (!reset && chatScrollController.hasClients) {
previousMaxExtent =
chatScrollController.positions.lastOrNull?.maxScrollExtent;
previousPixels = chatScrollController.positions.lastOrNull?.pixels;
}
isLoadingConversationPage = true;
String url = ApiUrls.queriesUrl(
assistantId,
conversation.value?.id ?? "",
page: conversationPage,
isMarketplace: isMarketplace,
);
try {
await ApiService.call(
url,
RequestType.get,
onSuccess: (response) {
List<dynamic> items = response.data['items'] ?? [];
if (items.isNotEmpty) {
List<PupauMessage> queryList = messagesFromLoadedChat(
jsonEncode(items),
);
for (PupauMessage message in queryList) {
PupauMessage userMessage = MessageService.getUserLoadedMessage(
message,
);
if (isFirstMessageInGroup(message.groupId)) {
messages.insert(0, userMessage);
}
PupauMessage assistantMessage =
MessageService.getAssistantLoadedMessage(message);
messages.insert(0, assistantMessage);
}
}
int total = response.data['total'] ?? 0;
conversationItemsLoaded += items.length;
if (total > 0) {
isConversationLastPage = conversationItemsLoaded >= total;
} else {
isConversationLastPage = items.length < 20;
}
conversationPage++;
messages.refresh();
update();
},
onError: (error) {
update();
},
);
} finally {
isLoadingConversationPage = false;
update();
}
if (!reset &&
previousPixels != null &&
previousMaxExtent != null &&
chatScrollController.hasClients) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!chatScrollController.hasClients) return;
final position = chatScrollController.positions.lastOrNull;
if (position == null) return;
double newMax = position.maxScrollExtent;
double minExtent = position.minScrollExtent;
double offsetDiff = newMax - previousMaxExtent!;
double targetOffset = previousPixels! + offsetDiff;
// Clamp targetOffset to valid bounds first, then apply safety margin to prevent bounce
// Use a small safety margin (0.5px) to prevent floating point precision issues
final safetyMargin = 0.5;
targetOffset = targetOffset.clamp(minExtent, newMax);
// Apply safety margin to prevent overshoot that causes bounce
if (targetOffset >= newMax - safetyMargin) {
targetOffset = newMax - safetyMargin;
}
// Use position.jumpTo() which respects physics constraints better
position.jumpTo(targetOffset);
});
}
}