Skip to content

Commit c448083

Browse files
committed
user [nfc]: Factor out a userDisplayName
1 parent c253f93 commit c448083

File tree

8 files changed

+41
-27
lines changed

8 files changed

+41
-27
lines changed

lib/model/user.dart

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import '../api/model/events.dart';
22
import '../api/model/initial_snapshot.dart';
33
import '../api/model/model.dart';
4+
import 'localizations.dart';
45

56
/// The portion of [PerAccountStore] describing the users in the realm.
67
mixin UserStore {
@@ -21,8 +22,17 @@ mixin UserStore {
2122
/// Code that looks up a user in this map should therefore always handle
2223
/// the possibility that the user is not found (except
2324
/// where there is a specific reason to know the user should be found).
24-
/// Consider using [ZulipLocalizations.unknownUserName].
25+
/// Consider using [userDisplayName].
2526
Map<int, User> get users;
27+
28+
/// The name to show the given user as in the UI, even for unknown users.
29+
///
30+
/// This is the user's [User.fullName] if the user is known,
31+
/// and otherwise a translation of "(unknown user)".
32+
String userDisplayName(int userId) {
33+
return users[userId]?.fullName
34+
?? GlobalLocalizations.zulipLocalizations.unknownUserName;
35+
}
2636
}
2737

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

lib/widgets/emoji_reaction.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class ReactionChip extends StatelessWidget {
162162
? userIds.map((id) {
163163
return id == store.selfUserId
164164
? zulipLocalizations.reactedEmojiSelfUser
165-
: store.users[id]?.fullName ?? zulipLocalizations.unknownUserName;
165+
: store.userDisplayName(id);
166166
}).join(', ')
167167
: userIds.length.toString();
168168

lib/widgets/inbox.dart

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -384,20 +384,16 @@ class _DmItem extends StatelessWidget {
384384
final store = PerAccountStoreWidget.of(context);
385385
final selfUser = store.users[store.selfUserId]!;
386386

387-
final zulipLocalizations = ZulipLocalizations.of(context);
388387
final designVariables = DesignVariables.of(context);
389388

390389
final title = switch (narrow.otherRecipientIds) { // TODO dedupe with [RecentDmConversationsItem]
391390
[] => selfUser.fullName,
392-
[var otherUserId] =>
393-
store.users[otherUserId]?.fullName ?? zulipLocalizations.unknownUserName,
391+
[var otherUserId] => store.userDisplayName(otherUserId),
394392

395393
// TODO(i18n): List formatting, like you can do in JavaScript:
396394
// new Intl.ListFormat('ja').format(['Chris', 'Greg', 'Alya', 'Shu'])
397395
// // 'Chris、Greg、Alya、Shu'
398-
_ => narrow.otherRecipientIds.map(
399-
(id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName
400-
).join(', '),
396+
_ => narrow.otherRecipientIds.map(store.userDisplayName).join(', '),
401397
};
402398

403399
return Material(

lib/widgets/message_list.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -417,8 +417,7 @@ class MessageListAppBarTitle extends StatelessWidget {
417417
if (otherRecipientIds.isEmpty) {
418418
return Text(zulipLocalizations.dmsWithYourselfPageTitle);
419419
} else {
420-
final names = otherRecipientIds.map(
421-
(id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName);
420+
final names = otherRecipientIds.map(store.userDisplayName);
422421
// TODO show avatars
423422
return Text(
424423
zulipLocalizations.dmsWithOthersPageTitle(names.join(', ')));
@@ -756,10 +755,10 @@ class _TypingStatusWidgetState extends State<TypingStatusWidget> with PerAccount
756755
if (typistIds.isEmpty) return const SizedBox();
757756
final text = switch (typistIds.length) {
758757
1 => localizations.onePersonTyping(
759-
store.users[typistIds.first]?.fullName ?? localizations.unknownUserName),
758+
store.userDisplayName(typistIds.first)),
760759
2 => localizations.twoPeopleTyping(
761-
store.users[typistIds.first]?.fullName ?? localizations.unknownUserName,
762-
store.users[typistIds.last]?.fullName ?? localizations.unknownUserName),
760+
store.userDisplayName(typistIds.first),
761+
store.userDisplayName(typistIds.last)),
763762
_ => localizations.manyPeopleTyping,
764763
};
765764

@@ -1159,7 +1158,7 @@ class DmRecipientHeader extends StatelessWidget {
11591158
if (message.allRecipientIds.length > 1) {
11601159
title = zulipLocalizations.messageListGroupYouAndOthers(message.allRecipientIds
11611160
.where((id) => id != store.selfUserId)
1162-
.map((id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName)
1161+
.map(store.userDisplayName)
11631162
.sorted()
11641163
.join(", "));
11651164
} else {

lib/widgets/poll.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ class _PollWidgetState extends State<PollWidget> {
8080
// new Intl.ListFormat('ja').format(['Chris', 'Greg', 'Alya', 'Zixuan'])
8181
// // 'Chris、Greg、Alya、Zixuan'
8282
final voterNames = option.voters
83-
.map((userId) =>
84-
store.users[userId]?.fullName ?? zulipLocalizations.unknownUserName)
83+
.map(store.userDisplayName)
8584
.join(', ');
8685

8786
return Row(

lib/widgets/profile.dart

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -291,19 +291,19 @@ class _UserWidget extends StatelessWidget {
291291
@override
292292
Widget build(BuildContext context) {
293293
final store = PerAccountStoreWidget.of(context);
294-
final zulipLocalizations = ZulipLocalizations.of(context);
295-
final user = store.users[userId];
296-
final fullName = user?.fullName ?? zulipLocalizations.unknownUserName;
297294
return InkWell(
298295
onTap: () => Navigator.push(context,
299296
ProfilePage.buildRoute(context: context,
300297
userId: userId)),
301298
child: Padding(
302299
padding: const EdgeInsets.all(8),
303300
child: Row(children: [
301+
// TODO(#196) render active status
304302
Avatar(userId: userId, size: 32, borderRadius: 32 / 8),
305303
const SizedBox(width: 8),
306-
Expanded(child: Text(fullName, style: _TextStyles.customProfileFieldText)), // TODO(#196) render active status
304+
Expanded(
305+
child: Text(store.userDisplayName(userId),
306+
style: _TextStyles.customProfileFieldText)),
307307
])));
308308
}
309309
}

lib/widgets/recent_dm_conversations.dart

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

3-
import '../generated/l10n/zulip_localizations.dart';
43
import '../model/narrow.dart';
54
import '../model/recent_dm_conversations.dart';
65
import '../model/unreads.dart';
@@ -82,7 +81,6 @@ class RecentDmConversationsItem extends StatelessWidget {
8281
final store = PerAccountStoreWidget.of(context);
8382
final selfUser = store.users[store.selfUserId]!;
8483

85-
final zulipLocalizations = ZulipLocalizations.of(context);
8684
final designVariables = DesignVariables.of(context);
8785

8886
final String title;
@@ -95,16 +93,14 @@ class RecentDmConversationsItem extends StatelessWidget {
9593
// TODO(#296) actually don't show this row if the user is muted?
9694
// (should we offer a "spam folder" style summary screen of recent
9795
// 1:1 DM conversations from muted users?)
98-
final otherUser = store.users[otherUserId];
99-
title = otherUser?.fullName ?? zulipLocalizations.unknownUserName;
96+
title = store.userDisplayName(otherUserId);
10097
avatar = AvatarImage(userId: otherUserId, size: _avatarSize);
10198
default:
10299
// TODO(i18n): List formatting, like you can do in JavaScript:
103100
// new Intl.ListFormat('ja').format(['Chris', 'Greg', 'Alya'])
104101
// // 'Chris、Greg、Alya'
105-
title = narrow.otherRecipientIds.map(
106-
(id) => store.users[id]?.fullName ?? zulipLocalizations.unknownUserName
107-
).join(', ');
102+
title = narrow.otherRecipientIds.map(store.userDisplayName)
103+
.join(', ');
108104
avatar = ColoredBox(color: designVariables.groupDmConversationIconBg,
109105
child: Center(
110106
child: Icon(color: designVariables.groupDmConversationIcon,

test/model/user_test.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,22 @@ import 'package:zulip/api/model/model.dart';
55

66
import '../api/model/model_checks.dart';
77
import '../example_data.dart' as eg;
8+
import 'test_store.dart';
89

910
void main() {
11+
group('userDisplayName', () {
12+
test('on a known user', () {
13+
final user = eg.user(fullName: 'Some User');
14+
final store = eg.store()..addUser(user);
15+
check(store.userDisplayName(user.userId)).equals('Some User');
16+
});
17+
18+
test('on an unknown user', () {
19+
final store = eg.store();
20+
check(store.userDisplayName(eg.user().userId)).equals('(unknown user)');
21+
});
22+
});
23+
1024
group('RealmUserUpdateEvent', () {
1125
// TODO write more tests for handling RealmUserUpdateEvent
1226

0 commit comments

Comments
 (0)