Skip to content

Commit 0a476e1

Browse files
committed
recent-dms: Distinguish muted users in recent DMs page
1 parent e78fb98 commit 0a476e1

File tree

2 files changed

+62
-24
lines changed

2 files changed

+62
-24
lines changed

lib/widgets/recent_dm_conversations.dart

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22

3+
import '../generated/l10n/zulip_localizations.dart';
34
import '../model/narrow.dart';
45
import '../model/recent_dm_conversations.dart';
56
import '../model/unreads.dart';
@@ -79,6 +80,7 @@ class RecentDmConversationsItem extends StatelessWidget {
7980
@override
8081
Widget build(BuildContext context) {
8182
final store = PerAccountStoreWidget.of(context);
83+
final localizations = ZulipLocalizations.of(context);
8284
final designVariables = DesignVariables.of(context);
8385

8486
final String title;
@@ -88,16 +90,26 @@ class RecentDmConversationsItem extends StatelessWidget {
8890
title = store.selfUser.fullName;
8991
avatar = AvatarImage(userId: store.selfUserId, size: _avatarSize);
9092
case [var otherUserId]:
91-
// TODO(#296) actually don't show this row if the user is muted?
92-
// (should we offer a "spam folder" style summary screen of recent
93-
// 1:1 DM conversations from muted users?)
94-
title = store.userDisplayName(otherUserId);
95-
avatar = AvatarImage(userId: otherUserId, size: _avatarSize);
93+
// Although we currently don't display a DM conversation with a muted
94+
// user; in the future we will have the "Search by location" feature
95+
// similar to Web where a DM conversation with a muted user is displayed
96+
// if searched for explicitly; for example using: "dm:Chris Bobbe".
97+
// https://zulip.com/help/search-for-messages#search-by-location
98+
final isUserMuted = store.isUserMuted(otherUserId);
99+
title = isUserMuted
100+
? localizations.mutedUser
101+
: store.userDisplayName(otherUserId);
102+
avatar = isUserMuted
103+
? AvatarPlaceholder(size: _avatarSize)
104+
: AvatarImage(userId: otherUserId, size: _avatarSize);
96105
default:
97106
// TODO(i18n): List formatting, like you can do in JavaScript:
98107
// new Intl.ListFormat('ja').format(['Chris', 'Greg', 'Alya'])
99108
// // 'Chris、Greg、Alya'
100-
title = narrow.otherRecipientIds.map(store.userDisplayName)
109+
title = narrow.otherRecipientIds.map((id) =>
110+
store.isUserMuted(id)
111+
? localizations.mutedUser
112+
: store.userDisplayName(id))
101113
.join(', ');
102114
avatar = ColoredBox(color: designVariables.groupDmConversationIconBg,
103115
child: Center(

test/widgets/recent_dm_conversations_test.dart

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,14 @@ import '../model/test_store.dart';
1919
import '../test_navigation.dart';
2020
import 'content_checks.dart';
2121
import 'message_list_checks.dart';
22+
import 'message_list_test.dart';
2223
import 'page_checks.dart';
2324
import 'test_app.dart';
2425

2526
Future<void> setupPage(WidgetTester tester, {
2627
required List<DmMessage> dmMessages,
2728
required List<User> users,
29+
List<int>? mutedUserIds,
2830
NavigatorObserver? navigatorObserver,
2931
String? newNameForSelfUser,
3032
}) async {
@@ -37,6 +39,7 @@ Future<void> setupPage(WidgetTester tester, {
3739
for (final user in users) {
3840
await store.addUser(user);
3941
}
42+
await store.muteUsers(mutedUserIds ?? []);
4043

4144
await store.addMessages(dmMessages);
4245

@@ -110,7 +113,7 @@ void main() {
110113

111114
group('RecentDmConversationsItem', () {
112115
group('content/appearance', () {
113-
void checkAvatar(WidgetTester tester, DmNarrow narrow) {
116+
void checkAvatar(WidgetTester tester, DmNarrow narrow, {bool isMuted = false}) {
114117
final shape = tester.widget<AvatarShape>(
115118
find.descendant(
116119
of: find.byType(RecentDmConversationsItem),
@@ -124,7 +127,9 @@ void main() {
124127
case []: // self-1:1
125128
check(shape).child.isA<AvatarImage>().userId.equals(eg.selfUser.userId);
126129
case [var otherUserId]: // 1:1
127-
check(shape).child.isA<AvatarImage>().userId.equals(otherUserId);
130+
isMuted
131+
? check(shape).child.isA<AvatarPlaceholder>()
132+
: check(shape).child.isA<AvatarImage>().userId.equals(otherUserId);
128133
default: // group
129134
// TODO(#232): syntax like `check(find(…), findsOneWidget)`
130135
tester.widget(find.descendant(
@@ -204,13 +209,23 @@ void main() {
204209
});
205210

206211
group('1:1', () {
207-
testWidgets('has right title/avatar', (tester) async {
208-
final user = eg.user(userId: 1);
209-
final message = eg.dmMessage(from: eg.selfUser, to: [user]);
210-
await setupPage(tester, users: [user], dmMessages: [message]);
211-
212-
checkAvatar(tester, DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId));
213-
checkTitle(tester, user.fullName);
212+
group('has right title/avatar', () {
213+
for (final isUserMuted in [false, true]) {
214+
testWidgets(isUserMuted ? 'muted user' : 'normal user', (tester) async {
215+
final user = eg.user(userId: 1);
216+
final message = eg.dmMessage(from: eg.selfUser, to: [user]);
217+
await setupPage(tester,
218+
users: [user],
219+
mutedUserIds: isUserMuted ? [user.userId] : [],
220+
dmMessages: [message],
221+
);
222+
223+
checkAvatar(tester,
224+
DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId),
225+
isMuted: isUserMuted);
226+
checkTitle(tester, isUserMuted ? localizations.mutedUser : user.fullName);
227+
});
228+
}
214229
});
215230

216231
testWidgets('no error when user somehow missing from user store', (tester) async {
@@ -258,15 +273,26 @@ void main() {
258273
return result;
259274
}
260275

261-
testWidgets('has right title/avatar', (tester) async {
262-
final users = usersList(2);
263-
final user0 = users[0];
264-
final user1 = users[1];
265-
final message = eg.dmMessage(from: eg.selfUser, to: [user0, user1]);
266-
await setupPage(tester, users: users, dmMessages: [message]);
267-
268-
checkAvatar(tester, DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId));
269-
checkTitle(tester, '${user0.fullName}, ${user1.fullName}');
276+
group('has right title/avatar', () {
277+
for (final areUsersMuted in [false, true]) {
278+
testWidgets(areUsersMuted ? 'muted users' : 'normal users', (tester) async {
279+
final users = usersList(2);
280+
final user0 = users[0];
281+
final user1 = users[1];
282+
final message = eg.dmMessage(from: eg.selfUser, to: [user0, user1]);
283+
await setupPage(
284+
tester,
285+
users: users,
286+
mutedUserIds: areUsersMuted ? [user0.userId, user1.userId] : [],
287+
dmMessages: [message],
288+
);
289+
290+
checkAvatar(tester, DmNarrow.ofMessage(message, selfUserId: eg.selfUser.userId));
291+
checkTitle(tester, areUsersMuted
292+
? '${localizations.mutedUser}, ${localizations.mutedUser}'
293+
: '${user0.fullName}, ${user1.fullName}');
294+
});
295+
}
270296
});
271297

272298
testWidgets('no error when one user somehow missing from user store', (tester) async {

0 commit comments

Comments
 (0)