Skip to content

Commit fdb8fc2

Browse files
committed
msglist [nfc]: Let ScrollView count forward, and sliver handle reverse
This means that the overall scroll view has AxisDirection.down as the scroll direction, rather than AxisDirection.up, and the SliverStickyHeader is passed GrowthDirection.reverse instead of GrowthDirection.forward in order to get the same effect. This makes the scrolling a little easier to think about when focused on MessageList's code, because for example (as seen in this diff) `scrollMetrics.extentBefore` now refers to the messages that are older than the ones on screen, rather than those that are newer. This also brings us closer to the setup we'll want for #80 and #82, opening the message list at an anchor other than the end: the empty placeholder sliver at the bottom will become the list of messages after the starting anchor, while the sliver at the top will remain the list of messages above the anchor.
1 parent 037fc72 commit fdb8fc2

File tree

1 file changed

+10
-10
lines changed

1 file changed

+10
-10
lines changed

Diff for: lib/widgets/message_list.dart

+10-10
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
218218
_scrollToBottomVisibleValue.value = true;
219219
}
220220

221-
if (scrollMetrics.extentAfter < kFetchMessagesBufferPixels) {
221+
if (scrollMetrics.extentBefore < kFetchMessagesBufferPixels) {
222222
// TODO: This ends up firing a second time shortly after we fetch a batch.
223223
// The result is that each time we decide to fetch a batch, we end up
224224
// fetching two batches in quick succession. This is basically harmless
@@ -278,6 +278,7 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
278278

279279
Widget _buildListView(context) {
280280
final length = model!.items.length;
281+
const centerSliverKey = ValueKey('center sliver');
281282
return CustomScrollView(
282283
// TODO: Offer `ScrollViewKeyboardDismissBehavior.interactive` (or
283284
// similar) if that is ever offered:
@@ -291,18 +292,12 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
291292
},
292293

293294
controller: scrollController,
294-
295-
// Setting reverse: true means the scroll starts at the bottom.
296-
// Flipping the indexes (in the SliverChildBuilderDelegate callback)
297-
// means the start/bottom has the latest messages.
298-
// This works great when we want to start from the latest.
299-
// TODO handle scroll starting at first unread, or link anchor
300-
// TODO on new message when scrolled up, anchor scroll to what's in view
301-
reverse: true,
295+
anchor: 1.0,
296+
center: centerSliverKey,
302297

303298
slivers: [
304299
SliverStickyHeaderList(
305-
headerPlacement: HeaderPlacement.scrollingEnd,
300+
headerPlacement: HeaderPlacement.scrollingStart,
306301
delegate: SliverChildBuilderDelegate(
307302
// To preserve state across rebuilds for individual [MessageItem]
308303
// widgets as the size of [MessageListView.items] changes we need
@@ -336,6 +331,11 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
336331
final data = model!.items[length - 1 - (i - 2)];
337332
return _buildItem(data, i);
338333
})),
334+
335+
// This is a trivial placeholder that occupies no space. Its purpose is
336+
// to have the key that's passed to [ScrollView.center], and so to cause
337+
// the above [SliverStickyHeaderList] to run from bottom to top.
338+
const SliverToBoxAdapter(key: centerSliverKey),
339339
]);
340340
}
341341

0 commit comments

Comments
 (0)