Skip to content

Decrease whitespace at end of message feed #1628

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions lib/model/message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ sealed class MessageListMessageBaseItem extends MessageListItem {
ZulipMessageContent get content;
bool showSender;
bool isLastInBlock;
bool isLastInFeed;

MessageListMessageBaseItem({
required this.showSender,
required this.isLastInBlock,
required this.isLastInFeed,
});
}

Expand All @@ -63,6 +65,7 @@ class MessageListMessageItem extends MessageListMessageBaseItem {
this.content, {
required super.showSender,
required super.isLastInBlock,
required super.isLastInFeed,
});
}

Expand All @@ -77,6 +80,7 @@ class MessageListOutboxMessageItem extends MessageListMessageBaseItem {
this.message, {
required super.showSender,
required super.isLastInBlock,
required super.isLastInFeed,
}) : content = ZulipContent(nodes: [
ParagraphNode(links: null, nodes: [TextNode(message.contentMarkdown)]),
]);
Expand Down Expand Up @@ -435,27 +439,37 @@ mixin _MessageSequence {
required MessageListMessageBaseItem Function(bool canShareSender) buildItem,
}) {
final bool canShareSender;
if (prevMessage == null || !haveSameRecipient(prevMessage, message)) {
if (prevMessage == null) {
items.add(MessageListRecipientHeaderItem(message));
canShareSender = false;
} else {
assert(items.last is MessageListMessageBaseItem);
final prevMessageItem = items.last as MessageListMessageBaseItem;
assert(identical(prevMessageItem.message, prevMessage));
assert(prevMessageItem.isLastInBlock);
prevMessageItem.isLastInBlock = false;
assert(prevMessageItem.isLastInFeed);

if (!messagesSameDay(prevMessageItem.message, message)) {
items.add(MessageListDateSeparatorItem(message));
prevMessageItem.isLastInFeed = false;

if (!haveSameRecipient(prevMessage, message)) {
items.add(MessageListRecipientHeaderItem(message));
canShareSender = false;
} else {
canShareSender = prevMessageItem.message.senderId == message.senderId;
prevMessageItem.isLastInBlock = false;

if (!messagesSameDay(prevMessageItem.message, message)) {
items.add(MessageListDateSeparatorItem(message));
canShareSender = false;
} else {
canShareSender = prevMessageItem.message.senderId == message.senderId;
}
}
}
final item = buildItem(canShareSender);
assert(identical(item.message, message));
assert(item.showSender == !canShareSender);
assert(item.isLastInBlock);
assert(item.isLastInFeed);
if (shouldSetMiddleItem) {
middleItem = items.length;
}
Expand All @@ -476,7 +490,7 @@ mixin _MessageSequence {
shouldSetMiddleItem: index == middleMessage,
prevMessage: prevMessage,
buildItem: (bool canShareSender) => MessageListMessageItem(
message, content, showSender: !canShareSender, isLastInBlock: true));
message, content, showSender: !canShareSender, isLastInBlock: true, isLastInFeed: true));
}

/// Append to [items] based on the index-th message in [outboxMessages].
Expand All @@ -494,7 +508,7 @@ mixin _MessageSequence {
shouldSetMiddleItem: index == 0 && middleMessage == messages.length,
prevMessage: prevMessage,
buildItem: (bool canShareSender) => MessageListOutboxMessageItem(
message, showSender: !canShareSender, isLastInBlock: true));
message, showSender: !canShareSender, isLastInBlock: true, isLastInFeed: true));
}

/// Remove items associated with [outboxMessages] from [items].
Expand All @@ -513,6 +527,7 @@ mixin _MessageSequence {
if (items.isNotEmpty) {
final lastItem = items.last as MessageListMessageItem;
lastItem.isLastInBlock = true;
lastItem.isLastInFeed = true;
}
if (middleMessage == messages.length) middleItem = items.length;
}
Expand Down
8 changes: 3 additions & 5 deletions lib/widgets/message_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -963,8 +963,8 @@ class _MessageListState extends State<MessageList> with PerAccountStoreAwareStat
// TODO perhaps offer mark-as-read even when not done fetching?
MarkAsReadWidget(narrow: widget.narrow),
// To reinforce that the end of the feed has been reached:
// https://chat.zulip.org/#narrow/stream/243-mobile-team/topic/flutter.3A.20Mark-as-read/near/1680603
const SizedBox(height: 36),
// https://chat.zulip.org/#narrow/channel/48-mobile/topic/space.20at.20end.20of.20thread/near/2203391
const SizedBox(height: 12),
]);
} else if (model.busyFetchingMore) {
// See [_buildStartCap] for why this condition shows a loading indicator.
Expand Down Expand Up @@ -1334,9 +1334,7 @@ class MessageItem extends StatelessWidget {
MessageListMessageItem() => MessageWithPossibleSender(item: item),
MessageListOutboxMessageItem() => OutboxMessageWithPossibleSender(item: item),
},
// TODO refine this padding; discussion:
// https://github.com/zulip/zulip-flutter/pull/1453#discussion_r2106526985
if (item.isLastInBlock) const SizedBox(height: 11),
if (item.isLastInBlock && !item.isLastInFeed) const SizedBox(height: 11),
]));
if (item case MessageListMessageItem(:final message)) {
child = _UnreadMarker(
Expand Down
4 changes: 3 additions & 1 deletion test/model/message_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3037,7 +3037,8 @@ void checkInvariants(MessageListView model) {
|| MessageListOutboxMessageItem()
|| MessageListDateSeparatorItem() => false,
MessageListRecipientHeaderItem() => true,
});
})
..isLastInFeed.equals(i == model.items.length);
}
check(model.items).length.equals(i);

Expand Down Expand Up @@ -3082,6 +3083,7 @@ extension MessageListMessageBaseItemChecks on Subject<MessageListMessageBaseItem
Subject<ZulipMessageContent> get content => has((x) => x.content, 'content');
Subject<bool> get showSender => has((x) => x.showSender, 'showSender');
Subject<bool> get isLastInBlock => has((x) => x.isLastInBlock, 'isLastInBlock');
Subject<bool> get isLastInFeed => has((x) => x.isLastInFeed, 'isLastInFeed');
}

extension MessageListMessageItemChecks on Subject<MessageListMessageItem> {
Expand Down