diff --git a/lib/controllers/room_chat.dart b/lib/controllers/room_chat.dart index fd6c12a..773f30d 100644 --- a/lib/controllers/room_chat.dart +++ b/lib/controllers/room_chat.dart @@ -3,7 +3,6 @@ import "dart:math"; import "package:collection/collection.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart"; -import "package:flutter/foundation.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:fluttertagger/fluttertagger.dart"; import "package:nexus/controllers/attachment.dart"; @@ -84,14 +83,6 @@ class RoomChatController(final ChatParams info) .where((rowId) => room.events[rowId]?.threadRoot == null) .toIList(); - // TODO: remove, debugging replies not showing - debugPrint( - "[timeline] build ${info.roomId}: " - "syncedTail=${room.timeline.entries.sortedBy((entry) => entry.key).reversed.take(5).map((entry) => "${entry.key}:${entry.value}").toList()} " - "clientSticky=${room.clientSticky.toList()} " - "chatTail=${timeline.reversed.take(5).toList()}", - ); - if (info.contextualEvent == null || timeline.contains(info.contextualEvent)) { ref.watch( @@ -465,11 +456,6 @@ class RoomChatController(final ChatParams info) /// Shows [event], which was just sent, until it comes down sync. void addSent(Event? event) { - // TODO: remove, debugging replies not showing - debugPrint( - "[timeline] addSent: rowId=${event?.rowId} eventId=${event?.eventId} " - "alreadySynced=${ref.read(RoomsController.provider)[info.roomId]?.timeline.values.contains(event?.rowId)}", - ); if (event case final event?) { ref .read(RoomsController.provider.notifier) diff --git a/lib/helpers/hooks/chat_scroll.dart b/lib/helpers/hooks/chat_scroll.dart index 9e8f8de..84b4043 100644 --- a/lib/helpers/hooks/chat_scroll.dart +++ b/lib/helpers/hooks/chat_scroll.dart @@ -9,14 +9,6 @@ import "package:nexus/models/room_chat.dart"; typedef JumpToEvent = Future Function(int rowId); -/// Identifies the row for the event with [rowId], so it can be found to -/// scroll to it, and keeps its element when rows are added before it. -final class EventRowKey extends GlobalKey { - EventRowKey(this.rowId) : super.constructor(); - - final int rowId; -} - final class ChatScroll({ required final IList historyRows, required final IList liveRows, @@ -28,7 +20,7 @@ final class ChatScroll({ required final JumpToEvent jumpToEvent, required final Future Function() jumpToBottom, - required final EventRowKey Function(int eventRowId) keyFor, + required final GlobalKey Function(int eventRowId) keyFor, }) { factory use({ required AsyncValue controllerData, @@ -50,9 +42,9 @@ final class ChatScroll({ final scrollController = useScrollController(); final centerKey = useMemoized(GlobalKey.new); - final itemKeys = useMemoized(() => {}, []); - EventRowKey keyFor(int eventRowId) => - itemKeys.putIfAbsent(eventRowId, () => EventRowKey(eventRowId)); + final itemKeys = useMemoized(() => {}, []); + GlobalKey keyFor(int eventRowId) => + itemKeys.putIfAbsent(eventRowId, GlobalKey.new); useEffect(() { if (anchorId.value == null) { @@ -109,13 +101,6 @@ final class ChatScroll({ final anchorIndex = items.indexOf(anchor); final historyLength = anchorIndex == -1 ? items.length : anchorIndex + 1; - // TODO: remove, debugging replies not showing - debugPrint( - "[timeline] split: anchor=$anchor anchorIndex=$anchorIndex " - "length=${items.length} " - "historyTail=${items.take(historyLength).toList().reversed.take(3).toList()} " - "live=${items.skip(historyLength).toList()}", - ); return ( history: items.take(historyLength).toIList().reversed.toIList(), live: items.skip(historyLength).toIList(), @@ -128,27 +113,13 @@ final class ChatScroll({ void updateAtBottom() { if (!hookContext.mounted || !scrollController.hasClients) return; - final position = scrollController.position; - final isAtBottom = position.extentBefore <= 0; - if (isAtBottom != atBottom.value) { - // TODO: remove, debugging replies not showing - debugPrint( - "[timeline] atBottom: $isAtBottom pixels=${position.pixels} " - "min=${position.minScrollExtent} anchor=${anchorId.value} " - "live=${split.live.length}", - ); - atBottom.value = isAtBottom; - } + final isAtBottom = scrollController.position.extentBefore <= 0; + if (isAtBottom != atBottom.value) atBottom.value = isAtBottom; } useEffect(() { final previous = previousLastRowId.value; previousLastRowId.value = lastRowId; - // TODO: remove, debugging replies not showing - debugPrint( - "[timeline] lastRowId: previous=$previous last=$lastRowId " - "atBottom=${atBottom.value} contextualEvent=${contextualEvent.value}", - ); if (previous == null || lastRowId == null || previous == lastRowId) { return null; @@ -156,11 +127,6 @@ final class ChatScroll({ if (!atBottom.value || contextualEvent.value != null) return null; WidgetsBinding.instance.addPostFrameCallback((_) { - // TODO: remove, debugging replies not showing - debugPrint( - "[timeline] re-anchoring to $lastRowId " - "hasClients=${scrollController.hasClients}", - ); if (!scrollController.hasClients) return; anchorId.value = lastRowId; diff --git a/lib/widgets/room_chat/chat_timeline.dart b/lib/widgets/room_chat/chat_timeline.dart index 5a69b49..57388b9 100644 --- a/lib/widgets/room_chat/chat_timeline.dart +++ b/lib/widgets/room_chat/chat_timeline.dart @@ -25,31 +25,25 @@ class const ChatTimeline({ int? previousEventRowId, { required Key key, }) => HighlightWrapper( - EventRenderer( - eventRowId, - previousEventRowId: previousEventRowId, - roomId: chat.roomId, - jumpToEvent: jumpToEvent, - onOpenThread: onOpenThread, - getEventOptions: getEventOptions, - onSwipe: onSwipe == null ? null : () => onSwipe!(eventRowId), - readReceiptsChat: chat, - threadRoot: chat.threadRoot, + // To work around an AWFUL SuperSliverList bug + ConstrainedBox( + constraints: const BoxConstraints(minHeight: 0.01), + child: EventRenderer( + eventRowId, + previousEventRowId: previousEventRowId, + roomId: chat.roomId, + jumpToEvent: jumpToEvent, + onOpenThread: onOpenThread, + getEventOptions: getEventOptions, + onSwipe: onSwipe == null ? null : () => onSwipe!(eventRowId), + readReceiptsChat: chat, + threadRoot: chat.threadRoot, + ), ), key: key, isHighlighted: scroll.highlightedEvent == eventRowId, ); - /// Where the row with [key] now is in [rows], so its element moves with it - /// when rows are added before it, rather than being rebuilt by index. - int? indexOf(IList rows, Key key) => switch (key) { - EventRowKey(:final rowId) => switch (rows.indexOf(rowId)) { - -1 => null, - final index => index, - }, - _ => null, - }; - @override Widget build(BuildContext context) => LayoutBuilder( builder: (context, constraints) => TweenAnimationBuilder( @@ -76,7 +70,6 @@ class const ChatTimeline({ SuperSliverList.builder( itemCount: scroll.liveRows.length, - findChildIndexCallback: (key) => indexOf(scroll.liveRows, key), itemBuilder: (_, index) => eventRow( scroll.liveRows[index], index > 0 @@ -89,8 +82,6 @@ class const ChatTimeline({ SuperSliverList.builder( key: scroll.centerKey, itemCount: scroll.historyRows.length, - findChildIndexCallback: (key) => - indexOf(scroll.historyRows, key), itemBuilder: (_, index) => eventRow( scroll.historyRows[index], scroll.historyRows.getOrNull(index + 1),