Skip to content

Commit 77ce192

Browse files
committed
msglist: Show sender only when needed
Fixes: zulip#175
1 parent b3f7aff commit 77ce192

File tree

3 files changed

+51
-6
lines changed

3 files changed

+51
-6
lines changed

lib/model/message_list.dart

+7-2
Original file line numberDiff line numberDiff line change
@@ -180,16 +180,20 @@ mixin _MessageSequence {
180180
// and date separators #173.
181181
final message = messages[index];
182182
final content = contents[index];
183+
bool canShareSender;
183184
if (index > 0 && canShareRecipientHeader(messages[index - 1], message)) {
184185
assert(items.last is MessageListMessageItem);
185186
final prevMessageItem = items.last as MessageListMessageItem;
186187
assert(identical(prevMessageItem.message, messages[index - 1]));
187188
assert(prevMessageItem.isLastInBlock);
188189
prevMessageItem.isLastInBlock = false;
190+
canShareSender = (prevMessageItem.message.senderId == message.senderId);
189191
} else {
190192
items.add(MessageListRecipientHeaderItem(message));
193+
canShareSender = false;
191194
}
192-
items.add(MessageListMessageItem(message, content, showSender: true, isLastInBlock: true));
195+
items.add(MessageListMessageItem(message, content,
196+
showSender: !canShareSender, isLastInBlock: true));
193197
}
194198

195199
/// Update [items] to include markers at start and end as appropriate.
@@ -403,7 +407,8 @@ class MessageListView with ChangeNotifier, _MessageSequence {
403407
/// were changed, and ignores any changes to its stream or topic.
404408
///
405409
/// TODO(#150): Handle message moves.
406-
// NB that when handling message moves (#150), recipient headers may need updating.
410+
// NB that when handling message moves (#150), recipient headers
411+
// may need updating, and consequently showSender too.
407412
void maybeUpdateMessage(UpdateMessageEvent event) {
408413
final idx = _findMessageWithId(event.messageId);
409414
if (idx == -1) {

test/model/message_list_test.dart

+41-1
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,43 @@ void main() async {
549549
checkNotifiedOnce();
550550
});
551551

552+
test('showSender is maintained correctly', () async {
553+
// TODO(#150): This will get more complicated with message moves.
554+
// Until then, we always compute this sequentially from oldest to newest.
555+
// So we just need to exercise the different cases of the logic for
556+
// whether the sender should be shown, but the difference between
557+
// fetchInitial and maybeAddMessage etc. doesn't matter.
558+
559+
const timestamp = 1693602618;
560+
final stream = eg.stream();
561+
Message streamMessage(int id, User sender) =>
562+
eg.streamMessage(id: id, sender: sender,
563+
stream: stream, topic: 'foo', timestamp: timestamp);
564+
Message dmMessage(int id, User sender) =>
565+
eg.dmMessage(id: id, from: sender, timestamp: timestamp,
566+
to: [sender.userId == eg.selfUser.userId ? eg.otherUser : eg.selfUser]);
567+
568+
prepare();
569+
await prepareMessages(foundOldest: true, messages: [
570+
streamMessage(1, eg.selfUser), // first message, so show sender
571+
streamMessage(2, eg.selfUser), // hide sender
572+
streamMessage(3, eg.otherUser), // no recipient header, but new sender
573+
dmMessage(4, eg.otherUser), // same sender, but recipient header
574+
]);
575+
576+
// We check showSender has the right values in [checkInvariants],
577+
// but to make this test explicit:
578+
check(model.items).deepEquals([
579+
it()..isA<MessageListHistoryStartItem>(),
580+
it()..isA<MessageListRecipientHeaderItem>(),
581+
it()..isA<MessageListMessageItem>().showSender.isTrue(),
582+
it()..isA<MessageListMessageItem>().showSender.isFalse(),
583+
it()..isA<MessageListMessageItem>().showSender.isTrue(),
584+
it()..isA<MessageListRecipientHeaderItem>(),
585+
it()..isA<MessageListMessageItem>().showSender.isTrue(),
586+
]);
587+
});
588+
552589
group('canShareRecipientHeader', () {
553590
test('stream messages vs DMs, no share', () {
554591
final dmMessage = eg.dmMessage(from: eg.selfUser, to: [eg.otherUser]);
@@ -669,15 +706,18 @@ void checkInvariants(MessageListView model) {
669706
check(model.items[i++]).isA<MessageListLoadingItem>();
670707
}
671708
for (int j = 0; j < model.messages.length; j++) {
709+
bool isFirstInBlock = false;
672710
if (j == 0
673711
|| !canShareRecipientHeader(model.messages[j-1], model.messages[j])) {
674712
check(model.items[i++]).isA<MessageListRecipientHeaderItem>()
675713
.message.identicalTo(model.messages[j]);
714+
isFirstInBlock = true;
676715
}
677716
check(model.items[i++]).isA<MessageListMessageItem>()
678717
..message.identicalTo(model.messages[j])
679718
..content.identicalTo(model.contents[j])
680-
..showSender.isTrue()
719+
..showSender.equals(
720+
isFirstInBlock || model.messages[j].senderId != model.messages[j-1].senderId)
681721
..isLastInBlock.equals(
682722
i == model.items.length || model.items[i] is! MessageListMessageItem);
683723
}

test/widgets/message_list_test.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ void main() {
6969

7070
testWidgets('basic', (tester) async {
7171
await setupMessageListPage(tester, foundOldest: false,
72-
messages: List.generate(100, (i) => eg.streamMessage(id: 950 + i, sender: eg.selfUser)));
73-
check(itemCount(tester)).equals(101);
72+
messages: List.generate(200, (i) => eg.streamMessage(id: 950 + i, sender: eg.selfUser)));
73+
check(itemCount(tester)).equals(201);
7474

7575
// Fling-scroll upward...
7676
await tester.fling(find.byType(MessageListPage), const Offset(0, 300), 8000);
@@ -83,7 +83,7 @@ void main() {
8383
await tester.pump(Duration.zero); // Allow a frame for the response to arrive.
8484

8585
// Now we have more messages.
86-
check(itemCount(tester)).equals(201);
86+
check(itemCount(tester)).equals(301);
8787
});
8888

8989
testWidgets('observe double-fetch glitch', (tester) async {

0 commit comments

Comments
 (0)