Don't reverse the CustomScrollView #34

Manually merged
Henry-Hiles merged 4 commits from non-reversed-scroll-view into main 2026-06-02 21:10:02 -04:00
2 changed files with 30 additions and 6 deletions
Showing only changes of commit 1215be0b21 - Show all commits

attempt to remember position when loading history

Henry Hiles 2026-06-02 20:42:04 -04:00
Signed by: Henry-Hiles
SSH key fingerprint: SHA256:VKQUdS31Q90KvX7EkKMHMBpUspcmItAh86a+v7PGiIs

View file

@ -39,7 +39,9 @@ class RoomChatController extends AsyncNotifier<IList<Event>> {
} }
return room.timeline return room.timeline
.toValueIList(sort: true, compare: (a, b) => (a ?? 0).compareTo(b ?? 0)) .toEntryIList(compare: (a, b) => (a?.key ?? 0).compareTo(b?.key ?? 0))
.map((element) => element.value)
.toIList()
.addAll(room.sticky) .addAll(room.sticky)
.map((entry) { .map((entry) {
final foundEvent = entry == null ? null : room.events[entry]; final foundEvent = entry == null ? null : room.events[entry];

View file

@ -79,6 +79,13 @@ class RoomChat extends HookConsumerWidget {
final scrollController = useScrollController(); final scrollController = useScrollController();
final controllerData = ref.watch(controllerProvider); final controllerData = ref.watch(controllerProvider);
final heightBeforeLoad = useState<double?>(null);
Future<void> loadOlder() async {
heightBeforeLoad.value = scrollController.position.maxScrollExtent;
await notifier.loadOlder();
}
useEffect(() { useEffect(() {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (scrollController.hasClients) { if (scrollController.hasClients) {
@ -90,8 +97,19 @@ class RoomChat extends HookConsumerWidget {
}, [scrollController.hasClients]); }, [scrollController.hasClients]);
useEffect(() { useEffect(() {
if (scrollController.hasClients && if (!scrollController.hasClients || controllerData is! AsyncData) return;
scrollController.position.atEdge &&
if (heightBeforeLoad.value != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (scrollController.hasClients) {
scrollController.jumpTo(
scrollController.position.maxScrollExtent -
heightBeforeLoad.value!,
);
}
heightBeforeLoad.value = null;
});
} else if (scrollController.position.atEdge &&
scrollController.position.pixels != 0) { scrollController.position.pixels != 0) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
if (scrollController.hasClients) { if (scrollController.hasClients) {
@ -104,7 +122,9 @@ class RoomChat extends HookConsumerWidget {
useEffect(() { useEffect(() {
Future<void> listener() async { Future<void> listener() async {
if (!scrollController.position.atEdge) return; if (!scrollController.hasClients || !scrollController.position.atEdge) {
return;
}
final room = ref.watch( final room = ref.watch(
RoomsController.provider.select((value) => value[roomId]), RoomsController.provider.select((value) => value[roomId]),
@ -112,7 +132,9 @@ class RoomChat extends HookConsumerWidget {
if (room == null) return; if (room == null) return;
if (scrollController.position.pixels == 0) { if (scrollController.position.pixels == 0) {
if (room.hasMore) await notifier.loadOlder(); if (room.hasMore) {
await loadOlder();
}
} else { } else {
await client.markRead(room); await client.markRead(room);
} }
@ -369,7 +391,7 @@ class RoomChat extends HookConsumerWidget {
child: Center( child: Center(
child: ElevatedButton( child: ElevatedButton(
onPressed: controllerData is AsyncData onPressed: controllerData is AsyncData
? notifier.loadOlder ? loadOlder
: null, : null,
child: Text("Load More"), child: Text("Load More"),
), ),