Skip to content

Commit 4f5f30a

Browse files
committed
msglist: Leave blank space for "mark as read" button so using it doesn't cause messages to shift
This commit addresses the issue of the message list shifting downwards when the "mark as read" button is pressed. The previous implementation would return an empty widget when the button was pressed and cause the message list to shift down. Now it takes a widget with a definite height, which is equal to the size of the button and won't cause the message list to shift down. Previously there used to be an empty widget below the "mark as read" button, but that has also been removed. Fixes: zulip#562
1 parent 46b4577 commit 4f5f30a

File tree

2 files changed

+11
-16
lines changed

2 files changed

+11
-16
lines changed

lib/widgets/message_list.dart

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -342,17 +342,13 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
342342
final valueKey = key as ValueKey;
343343
final index = model!.findItemWithMessageId(valueKey.value);
344344
if (index == -1) return null;
345-
return length - 1 - (index - 2);
345+
return length - 1 - (index - 1);
346346
},
347-
childCount: length + 2,
347+
childCount: length + 1,
348348
(context, i) {
349-
// To reinforce that the end of the feed has been reached:
350-
// https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/flutter.3A.20Mark-as-read/near/1680603
351-
if (i == 0) return const SizedBox(height: 36);
349+
if (i == 0) return MarkAsReadWidget(narrow: widget.narrow);
352350

353-
if (i == 1) return MarkAsReadWidget(narrow: widget.narrow);
354-
355-
final data = model!.items[length - 1 - (i - 2)];
351+
final data = model!.items[length - 1 - (i - 1)];
356352
return _buildItem(data, i);
357353
})),
358354

@@ -464,7 +460,8 @@ class MarkAsReadWidget extends StatelessWidget {
464460
return AnimatedCrossFade(
465461
duration: const Duration(milliseconds: 300),
466462
crossFadeState: (unreadCount > 0) ? CrossFadeState.showSecond : CrossFadeState.showFirst,
467-
firstChild: const SizedBox.shrink(),
463+
// The height of the firstChild is the vertical padding of the secondChild in both directions + the minimumSize height of the secondChild
464+
firstChild: const SizedBox(height: 58),
468465
secondChild: SizedBox(width: double.infinity,
469466
// Design referenced from:
470467
// https://www.figma.com/file/1JTNtYo9memgW7vV6d0ygq/Zulip-Mobile?type=design&node-id=132-9684&mode=design&t=jJwHzloKJ0TMOG4M-0

test/widgets/message_list_test.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -610,13 +610,11 @@ void main() {
610610

611611
group('MarkAsReadWidget', () {
612612
bool isMarkAsReadButtonVisible(WidgetTester tester) {
613-
// Zero height elements on the edge of a scrolling viewport
614-
// are treated as invisible for hit-testing, see
615-
// [SliverMultiBoxAdaptorElement.debugVisitOnstageChildren].
616-
// Set `skipOffstage: false` here to safely target the
617-
// [MarkAsReadWidget] even when it is inactive.
618-
return tester.getSize(
619-
find.byType(MarkAsReadWidget, skipOffstage: false)).height > 0;
613+
// The [MarkAsReadWidget] widget is an [AnimatedCrossFade] widget where
614+
// the [CrossFadeState.showSecond] state is when the "mark as read" button is visible
615+
// and the [CrossFadeState.showFirst] state is when the "mark as read" button is not visible.
616+
var animatedCrossFade = tester.widget<AnimatedCrossFade>(find.byType(AnimatedCrossFade));
617+
return animatedCrossFade.crossFadeState == CrossFadeState.showSecond;
620618
}
621619

622620
testWidgets('from read to unread', (WidgetTester tester) async {

0 commit comments

Comments
 (0)