don't depend on SuperSliverList for scrolls

This commit is contained in:
Henry Hiles 2026-09-26 13:58:30 -04:00
commit 3217c17ea0
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs
2 changed files with 13 additions and 40 deletions

View file

@ -7,15 +7,12 @@ import "package:material_ui/material_ui.dart";
import "package:nexus/models/direction.dart";
import "package:nexus/models/event.dart";
import "package:nexus/models/room_chat.dart";
import "package:super_sliver_list/super_sliver_list.dart";
final class ChatScroll({
required final IList<Event> historyItems,
required final IList<Event> liveItems,
required final GlobalKey centerKey,
required final GlobalKey anchorItemKey,
required final ListController historyListController,
required final ListController liveListController,
required final ScrollController scrollController,
required final bool atBottom,
required final Future<void> Function(String id) jumpToId,
@ -31,8 +28,6 @@ final class ChatScroll({
final anchorItemKey = useMemoized(GlobalKey.new, [anchorId.value]);
final historyListController = useMemoized(ListController.new);
final liveListController = useMemoized(ListController.new);
final scrollController = useScrollController();
final centerKey = useMemoized(GlobalKey.new);
@ -156,47 +151,29 @@ final class ChatScroll({
],
);
double? resolveOffset(String itemId) {
final historyIndex = split.history.indexWhere(
(item) => item.eventId == itemId,
);
if (historyIndex != -1) {
// TODO: Replace SuperSliverView because of the bug that requires this: #94
// ignore: invalid_use_of_visible_for_testing_member
return historyListController.getOffsetToReveal(historyIndex, 0.5);
}
final liveIndex = split.live.indexWhere((item) => item.eventId == itemId);
if (liveIndex != -1) {
// ignore: invalid_use_of_visible_for_testing_member
return liveListController.getOffsetToReveal(liveIndex, 0.5);
}
return null;
}
Future<void> jumpToId(String itemId) async {
if (!scrollController.hasClients) return;
final offset = resolveOffset(itemId);
if (offset != null) {
await scrollController.animateTo(
offset,
duration: const .new(milliseconds: 700),
curve: Curves.easeInOut,
);
return;
}
if (anchorId.value != itemId) {
final completer = Completer<BuildContext>();
anchorMountedCompleter.value = completer;
pendingAnchorTarget.value = itemId;
contextualEvent.value = itemId;
final context = await completer.future;
if (!context.mounted) return;
if (context.mounted) {
await Scrollable.ensureVisible(
context,
alignment: 0.5,
duration: const .new(milliseconds: 700),
curve: Curves.easeInOut,
);
return;
}
final context = anchorItemKey.currentContext;
if (context != null && context.mounted) {
await Scrollable.ensureVisible(
context,
alignment: 0.5,
@ -226,8 +203,6 @@ final class ChatScroll({
liveItems: split.live,
centerKey: centerKey,
anchorItemKey: anchorItemKey,
historyListController: historyListController,
liveListController: liveListController,
scrollController: scrollController,
atBottom: atBottom.value,
jumpToId: jumpToId,

View file

@ -50,7 +50,6 @@ class const ChatTimeline({
SliverToBoxAdapter(child: SizedBox(height: composerHeight)),
SuperSliverList.builder(
listController: scroll.liveListController,
itemCount: scroll.liveItems.length,
itemBuilder: (_, index) => eventRow(
scroll.liveItems[index],
@ -68,7 +67,6 @@ class const ChatTimeline({
SuperSliverList.builder(
key: scroll.centerKey,
listController: scroll.historyListController,
itemCount: scroll.historyItems.length,
itemBuilder: (_, index) => eventRow(
scroll.historyItems[index],