Skip to content

Commit 8af150c

Browse files
chrisbobbesm-sayedi
andcommitted
recent-dms: Exclude DM conversations where all other recipients are muted
Co-authored-by: Sayed Mahmood Sayedi <[email protected]>
1 parent f99e6d8 commit 8af150c

File tree

4 files changed

+44
-12
lines changed

4 files changed

+44
-12
lines changed

lib/model/user.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import '../api/model/events.dart';
22
import '../api/model/initial_snapshot.dart';
33
import '../api/model/model.dart';
44
import 'localizations.dart';
5+
import 'narrow.dart';
56
import 'store.dart';
67

78
/// The portion of [PerAccountStore] describing the users in the realm.
@@ -85,6 +86,17 @@ mixin UserStore on PerAccountStoreBase {
8586
/// Looks for [userId] in a private [Set],
8687
/// or in [event.mutedUsers] instead if event is non-null.
8788
bool isUserMuted(int userId, {MutedUsersEvent? event});
89+
90+
/// Whether the self-user has muted everyone in [narrow].
91+
///
92+
/// Returns false for the self-DM.
93+
///
94+
/// Calls [isUserMuted] for each participant, passing along [event].
95+
bool shouldMuteDmConversation(DmNarrow narrow, {MutedUsersEvent? event}) {
96+
if (narrow.otherRecipientIds.isEmpty) return false;
97+
return narrow.otherRecipientIds.every(
98+
(userId) => isUserMuted(userId, event: event));
99+
}
88100
}
89101

90102
/// The implementation of [UserStore] that does the work.

lib/widgets/recent_dm_conversations.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class _RecentDmConversationsPageBodyState extends State<RecentDmConversationsPag
5252

5353
@override
5454
Widget build(BuildContext context) {
55+
final store = PerAccountStoreWidget.of(context);
5556
final zulipLocalizations = ZulipLocalizations.of(context);
5657
final sorted = model!.sorted;
5758

@@ -71,6 +72,12 @@ class _RecentDmConversationsPageBodyState extends State<RecentDmConversationsPag
7172
itemCount: sorted.length,
7273
itemBuilder: (context, index) {
7374
final narrow = sorted[index];
75+
if (store.shouldMuteDmConversation(narrow)) {
76+
// Filter out conversations where everyone is muted.
77+
// TODO should we offer a "spam folder"-style summary screen
78+
// for these conversations we're filtering out?
79+
return SizedBox.shrink();
80+
}
7481
return RecentDmConversationsItem(
7582
narrow: narrow,
7683
unreadCount: unreadsModel!.countInDmNarrow(narrow));
@@ -106,9 +113,6 @@ class RecentDmConversationsItem extends StatelessWidget {
106113
title = store.selfUser.fullName;
107114
avatar = AvatarImage(userId: store.selfUserId, size: _avatarSize);
108115
case [var otherUserId]:
109-
// TODO(#296) actually don't show this row if the user is muted?
110-
// (should we offer a "spam folder" style summary screen of recent
111-
// 1:1 DM conversations from muted users?)
112116
title = store.userDisplayName(otherUserId);
113117
avatar = AvatarImage(userId: otherUserId, size: _avatarSize);
114118
default:

test/model/user_test.dart

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import 'package:checks/checks.dart';
22
import 'package:flutter_test/flutter_test.dart';
33
import 'package:zulip/api/model/events.dart';
44
import 'package:zulip/api/model/model.dart';
5+
import 'package:zulip/model/narrow.dart';
6+
import 'package:zulip/model/store.dart';
57

68
import '../api/model/model_checks.dart';
79
import '../example_data.dart' as eg;
@@ -81,25 +83,39 @@ void main() {
8183
});
8284

8385
testWidgets('MutedUsersEvent', (tester) async {
86+
late PerAccountStore store;
87+
88+
void checkDmConversationMuted(List<int> otherUserIds, bool expected) {
89+
final narrow = DmNarrow.withOtherUsers(otherUserIds, selfUserId: store.selfUserId);
90+
check(store.shouldMuteDmConversation(narrow)).equals(expected);
91+
}
92+
8493
final user1 = eg.user(userId: 1);
8594
final user2 = eg.user(userId: 2);
8695
final user3 = eg.user(userId: 3);
8796

88-
final store = eg.store(initialSnapshot: eg.initialSnapshot(
97+
store = eg.store(initialSnapshot: eg.initialSnapshot(
8998
realmUsers: [user1, user2, user3],
9099
mutedUsers: [MutedUserItem(id: 2), MutedUserItem(id: 1)]));
91100
check(store.isUserMuted(1)).isTrue();
92101
check(store.isUserMuted(2)).isTrue();
93102
check(store.isUserMuted(3)).isFalse();
103+
checkDmConversationMuted([1], true);
104+
checkDmConversationMuted([1, 2], true);
105+
checkDmConversationMuted([2, 3], false);
106+
checkDmConversationMuted([1, 2, 3], false);
94107

95108
await store.handleEvent(eg.mutedUsersEvent([2, 1, 3]));
96109
check(store.isUserMuted(1)).isTrue();
97110
check(store.isUserMuted(2)).isTrue();
98111
check(store.isUserMuted(3)).isTrue();
112+
checkDmConversationMuted([1, 2, 3], true);
99113

100114
await store.handleEvent(eg.mutedUsersEvent([2, 3]));
101115
check(store.isUserMuted(1)).isFalse();
102116
check(store.isUserMuted(2)).isTrue();
103117
check(store.isUserMuted(3)).isTrue();
118+
checkDmConversationMuted([1], false);
119+
checkDmConversationMuted([], false);
104120
});
105121
}

test/widgets/recent_dm_conversations_test.dart

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,11 @@ Future<void> setupPage(WidgetTester tester, {
6969
void main() {
7070
TestZulipBinding.ensureInitialized();
7171

72-
group('RecentDmConversationsPage', () {
73-
Finder findConversationItem(Narrow narrow) => find.byWidgetPredicate(
74-
(widget) => widget is RecentDmConversationsItem && widget.narrow == narrow,
75-
);
72+
Finder findConversationItem(Narrow narrow) => find.byWidgetPredicate(
73+
(widget) => widget is RecentDmConversationsItem && widget.narrow == narrow,
74+
);
7675

76+
group('RecentDmConversationsPage', () {
7777
testWidgets('appearance when empty', (tester) async {
7878
await setupPage(tester, users: [], dmMessages: []);
7979
check(find.text('You have no direct messages yet! Why not start the conversation?'))
@@ -260,8 +260,8 @@ void main() {
260260
mutedUserIds: [user.userId],
261261
dmMessages: [message]);
262262

263-
checkAvatar(tester, DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId));
264-
checkTitle(tester, 'Muted user');
263+
final narrow = DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId);
264+
check(findConversationItem(narrow)).findsNothing();
265265
});
266266
});
267267

@@ -346,8 +346,8 @@ void main() {
346346
mutedUserIds: [user0.userId, user1.userId],
347347
dmMessages: [message]);
348348

349-
checkAvatar(tester, DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId));
350-
checkTitle(tester, 'Muted user, Muted user');
349+
final narrow = DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId);
350+
check(findConversationItem(narrow)).findsNothing();
351351
});
352352
});
353353

0 commit comments

Comments
 (0)