Skip to content

Commit 04a9ea4

Browse files
chrisbobbegnprice
authored andcommitted
unreads: In @-mentions count, exclude messages in muted DM conversations
Fixes #2026.
1 parent 93edff3 commit 04a9ea4

File tree

3 files changed

+81
-2
lines changed

3 files changed

+81
-2
lines changed

lib/model/message_list.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,9 @@ class MessageListView with ChangeNotifier, _MessageSequence {
691691
return true;
692692

693693
case MentionsNarrow():
694+
// If changing this, consider whether [Unreads.countInMentionsNarrow]
695+
// should be changed correspondingly, so the message-list view matches
696+
// the unread-count badge.
694697
case StarredMessagesNarrow():
695698
case KeywordSearchNarrow():
696699
if (message.conversation case DmConversation(:final allRecipientIds)) {

lib/model/unreads.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,30 @@ class Unreads extends PerAccountStoreBase with ChangeNotifier {
220220

221221
int countInDmNarrow(DmNarrow narrow) => dms[narrow]?.length ?? 0;
222222

223-
int countInMentionsNarrow() => mentions.length;
223+
/// The unread count for the mentions narrow.
224+
///
225+
/// This excludes DM messages in conversations that are considered muted,
226+
/// by [UserStore.shouldMuteDmConversation].
227+
// If changing which messages to exclude, consider whether the @-mentions
228+
// view should change its "is-message-visible" code correspondingly,
229+
// so the unread-count badge matches what you see in that view.
230+
// TODO: deduplicate "is-message-visible" code
231+
// between [Unreads] and [MessageListView]?
232+
// TODO(#370): maintain this count incrementally, rather than recomputing from scratch
233+
int countInMentionsNarrow() {
234+
int c = 0;
235+
for (final messageId in mentions) {
236+
final narrow = locatorMap[messageId];
237+
if (narrow == null) continue; // TODO(log)
238+
switch (narrow) {
239+
case DmNarrow():
240+
if (channelStore.shouldMuteDmConversation(narrow)) continue;
241+
case TopicNarrow():
242+
}
243+
c++;
244+
}
245+
return c;
246+
}
224247

225248
// TODO: Implement unreads handling.
226249
int countInStarredMessagesNarrow() => 0;

test/model/unreads_test.dart

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,13 +254,66 @@ void main() {
254254
test('smoke', () async {
255255
final stream = eg.stream();
256256
prepare();
257+
await store.addUser(eg.otherUser);
257258
await store.addStream(stream);
258259
fillWithMessages([
259260
eg.streamMessage(stream: stream, flags: []),
260261
eg.streamMessage(stream: stream, flags: [MessageFlag.mentioned]),
261262
eg.streamMessage(stream: stream, flags: [MessageFlag.wildcardMentioned]),
263+
eg.dmMessage(from: eg.otherUser, to: [eg.selfUser], flags: [MessageFlag.mentioned]),
264+
eg.dmMessage(from: eg.otherUser, to: [eg.selfUser], flags: [MessageFlag.wildcardMentioned]),
262265
]);
263-
check(model.countInMentionsNarrow()).equals(2);
266+
check(model.countInMentionsNarrow()).equals(4);
267+
});
268+
269+
test('excludes unreads in muted DM conversations', () async {
270+
// Regression test for https://github.com/zulip/zulip-flutter/issues/2026
271+
prepare();
272+
await store.addUser(eg.otherUser);
273+
await store.setMutedUsers([eg.otherUser.userId]);
274+
275+
fillWithMessages([
276+
eg.dmMessage(from: eg.otherUser, to: [eg.selfUser], flags: [MessageFlag.mentioned]),
277+
]);
278+
check(model.countInMentionsNarrow()).equals(0);
279+
});
280+
281+
test('not affected by DM sender being unknown', () async {
282+
prepare();
283+
final unknownUser = eg.user();
284+
check(store.getUser(unknownUser.userId)).isNull();
285+
286+
fillWithMessages([
287+
eg.dmMessage(from: unknownUser, to: [eg.selfUser], flags: [MessageFlag.mentioned]),
288+
]);
289+
check(model.countInMentionsNarrow()).equals(1);
290+
});
291+
292+
test('not affected by channel being unknown/unsubscribed/muted, nor topic being muted', () async {
293+
prepare();
294+
295+
final channel1 = eg.stream(); // unknown
296+
297+
final channel2 = eg.stream(); // unsubscribed
298+
await store.addStream(channel2);
299+
check(store.subscriptions[channel2.streamId]).isNull();
300+
301+
final channel3 = eg.stream(); // muted
302+
await store.addStream(channel3);
303+
await store.addSubscription(eg.subscription(channel3, isMuted: true));
304+
305+
final channel4 = eg.stream(); // unmuted, containing muted topic
306+
await store.addStream(channel4);
307+
await store.addSubscription(eg.subscription(channel4, isMuted: false));
308+
await store.setUserTopic(channel4, 'a', UserTopicVisibilityPolicy.muted);
309+
310+
fillWithMessages([
311+
eg.streamMessage(stream: channel1, flags: [MessageFlag.mentioned]),
312+
eg.streamMessage(stream: channel2, flags: [MessageFlag.mentioned]),
313+
eg.streamMessage(stream: channel3, flags: [MessageFlag.mentioned]),
314+
eg.streamMessage(stream: channel4, topic: 'a', flags: [MessageFlag.mentioned]),
315+
]);
316+
check(model.countInMentionsNarrow()).equals(4);
264317
});
265318
});
266319

0 commit comments

Comments
 (0)