fixup! refactor chatview to have two sliver lists

This commit is contained in:
Henry Hiles 2026-09-24 20:22:30 -04:00
commit 856072e0b0
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 31 additions and 45 deletions

View file

@ -11,9 +11,6 @@ final class ChatScroll<T>({
required final ListController historyListController,
required final ListController liveListController,
required final ScrollController scrollController,
required final bool hasMore,
required final bool isLoadingOlder,
required final Future<void> Function() loadOlder,
required final Future<void> Function(String id) jumpToId,
}) {
static ChatScroll<T> use<T>({
@ -28,8 +25,6 @@ final class ChatScroll<T>({
final centerKey = useMemoized(GlobalKey.new);
final anchorId = useState<String?>(null);
final hasMore = useState(true);
final isLoadingOlder = useState(false);
final anchorIdValue = anchorId.value;
@ -65,17 +60,40 @@ final class ChatScroll<T>({
}, [controllerData, anchorIdValue]);
Future<void> loadOlderItems() async {
if (!hasMore.value || isLoadingOlder.value) return;
if (controllerData.isLoading) return;
isLoadingOlder.value = true;
await loadOlder();
}
try {
hasMore.value = await loadOlder();
} finally {
isLoadingOlder.value = false;
useEffect(() {
const loadThreshold = 500.0;
const bottomThreshold = 50.0;
void checkPosition() {
if (!scrollController.hasClients) return;
final position = scrollController.position;
if (position.extentAfter <= loadThreshold) {
loadOlderItems();
}
if (position.extentBefore <= bottomThreshold) {
onReachedBottom();
}
}
scrollController.addListener(checkPosition);
WidgetsBinding.instance.addPostFrameCallback((_) {
checkPosition();
});
return () {
scrollController.removeListener(checkPosition);
};
}, [scrollController, controllerData, loadOlder, onReachedBottom]);
Future<void> jumpToId(String itemId) async {
if (!scrollController.hasClients) return;
@ -108,35 +126,6 @@ final class ChatScroll<T>({
}
}
useEffect(() {
const loadThreshold = 500.0;
const bottomThreshold = 50.0;
void checkPosition() {
if (!scrollController.hasClients) {
return;
}
final position = scrollController.position;
if (position.extentAfter <= loadThreshold) {
if (hasMore.value && !isLoadingOlder.value) {
loadOlderItems();
}
}
if (position.extentBefore <= bottomThreshold) {
onReachedBottom();
}
}
scrollController.addListener(checkPosition);
WidgetsBinding.instance.addPostFrameCallback((_) => checkPosition());
return () => scrollController.removeListener(checkPosition);
}, [scrollController, onReachedBottom]);
return .new(
historyItems: split.history,
liveItems: split.live,
@ -144,9 +133,6 @@ final class ChatScroll<T>({
historyListController: historyListController.value,
liveListController: liveListController.value,
scrollController: scrollController,
hasMore: hasMore.value,
isLoadingOlder: isLoadingOlder.value,
loadOlder: loadOlderItems,
jumpToId: jumpToId,
);
}

View file

@ -68,7 +68,7 @@ class const ChatTimeline({
itemCount: scroll.historyItems.length,
itemBuilder: (_, index) => eventRow(
scroll.historyItems[index],
scroll.historyItems.getOrNull(index),
scroll.historyItems.getOrNull(index + 1),
jumpToId: jumpToId,
getEventOptions: getEventOptions,
highlightedEvent: highlightedEvent,