Skip to content

Commit ec0bc01

Browse files
chrisbobbegnprice
authored andcommitted
msglist [nfc]: Pull out sliver helper for our SliverStickyHeaderList
1 parent 398749f commit ec0bc01

File tree

1 file changed

+38
-35
lines changed

1 file changed

+38
-35
lines changed

lib/widgets/message_list.dart

+38-35
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,43 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
300300
Widget _buildListView(BuildContext context) {
301301
final length = model!.items.length;
302302
const centerSliverKey = ValueKey('center sliver');
303+
304+
final sliver = SliverStickyHeaderList(
305+
headerPlacement: HeaderPlacement.scrollingStart,
306+
delegate: SliverChildBuilderDelegate(
307+
// To preserve state across rebuilds for individual [MessageItem]
308+
// widgets as the size of [MessageListView.items] changes we need
309+
// to match old widgets by their key to their new position in
310+
// the list.
311+
//
312+
// The keys are of type [ValueKey] with a value of [Message.id]
313+
// and here we use a O(log n) binary search method. This could
314+
// be improved but for now it only triggers for materialized
315+
// widgets. As a simple test, flinging through Combined feed in
316+
// CZO on a Pixel 5, this only runs about 10 times per rebuild
317+
// and the timing for each call is <100 microseconds.
318+
//
319+
// Non-message items (e.g., start and end markers) that do not
320+
// have state that needs to be preserved have not been given keys
321+
// and will not trigger this callback.
322+
findChildIndexCallback: (Key key) {
323+
final valueKey = key as ValueKey<int>;
324+
final index = model!.findItemWithMessageId(valueKey.value);
325+
if (index == -1) return null;
326+
return length - 1 - (index - 2);
327+
},
328+
childCount: length + 2,
329+
(context, i) {
330+
// To reinforce that the end of the feed has been reached:
331+
// https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/flutter.3A.20Mark-as-read/near/1680603
332+
if (i == 0) return const SizedBox(height: 36);
333+
334+
if (i == 1) return MarkAsReadWidget(narrow: widget.narrow);
335+
336+
final data = model!.items[length - 1 - (i - 2)];
337+
return _buildItem(data, i);
338+
}));
339+
303340
return CustomScrollView(
304341
// TODO: Offer `ScrollViewKeyboardDismissBehavior.interactive` (or
305342
// similar) if that is ever offered:
@@ -318,41 +355,7 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
318355
center: centerSliverKey,
319356

320357
slivers: [
321-
SliverStickyHeaderList(
322-
headerPlacement: HeaderPlacement.scrollingStart,
323-
delegate: SliverChildBuilderDelegate(
324-
// To preserve state across rebuilds for individual [MessageItem]
325-
// widgets as the size of [MessageListView.items] changes we need
326-
// to match old widgets by their key to their new position in
327-
// the list.
328-
//
329-
// The keys are of type [ValueKey] with a value of [Message.id]
330-
// and here we use a O(log n) binary search method. This could
331-
// be improved but for now it only triggers for materialized
332-
// widgets. As a simple test, flinging through Combined feed in
333-
// CZO on a Pixel 5, this only runs about 10 times per rebuild
334-
// and the timing for each call is <100 microseconds.
335-
//
336-
// Non-message items (e.g., start and end markers) that do not
337-
// have state that needs to be preserved have not been given keys
338-
// and will not trigger this callback.
339-
findChildIndexCallback: (Key key) {
340-
final valueKey = key as ValueKey<int>;
341-
final index = model!.findItemWithMessageId(valueKey.value);
342-
if (index == -1) return null;
343-
return length - 1 - (index - 2);
344-
},
345-
childCount: length + 2,
346-
(context, i) {
347-
// To reinforce that the end of the feed has been reached:
348-
// https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/flutter.3A.20Mark-as-read/near/1680603
349-
if (i == 0) return const SizedBox(height: 36);
350-
351-
if (i == 1) return MarkAsReadWidget(narrow: widget.narrow);
352-
353-
final data = model!.items[length - 1 - (i - 2)];
354-
return _buildItem(data, i);
355-
})),
358+
sliver,
356359

357360
// This is a trivial placeholder that occupies no space. Its purpose is
358361
// to have the key that's passed to [ScrollView.center], and so to cause

0 commit comments

Comments
 (0)