Skip to content

Commit 846261a

Browse files
committed
autocomplete: Show user status emoji in user-mention autocomplete
1 parent 646f9d9 commit 846261a

File tree

2 files changed

+53
-4
lines changed

2 files changed

+53
-4
lines changed

lib/widgets/autocomplete.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,11 @@ class _MentionAutocompleteItem extends StatelessWidget {
314314
mainAxisSize: MainAxisSize.min,
315315
crossAxisAlignment: CrossAxisAlignment.start,
316316
children: [
317-
labelWidget,
317+
Row(children: [
318+
Flexible(child: labelWidget),
319+
if (option case UserMentionAutocompleteResult(:var userId))
320+
UserStatusEmoji(userId: userId, size: 18,
321+
padding: const EdgeInsetsDirectional.only(start: 5.0))]),
318322
if (sublabelWidget != null) sublabelWidget,
319323
])),
320324
]));

test/widgets/autocomplete_test.dart

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import 'package:zulip/api/model/model.dart';
77
import 'package:zulip/api/route/messages.dart';
88
import 'package:zulip/api/route/channels.dart';
99
import 'package:zulip/api/route/realm.dart';
10+
import 'package:zulip/basic.dart';
1011
import 'package:zulip/model/compose.dart';
1112
import 'package:zulip/model/emoji.dart';
1213
import 'package:zulip/model/localizations.dart';
@@ -15,6 +16,7 @@ import 'package:zulip/model/store.dart';
1516
import 'package:zulip/model/typing_status.dart';
1617
import 'package:zulip/widgets/compose_box.dart';
1718
import 'package:zulip/widgets/content.dart';
19+
import 'package:zulip/widgets/emoji.dart';
1820
import 'package:zulip/widgets/message_list.dart';
1921

2022
import '../api/fake_api.dart';
@@ -23,6 +25,7 @@ import '../flutter_checks.dart';
2325
import '../model/binding.dart';
2426
import '../model/test_store.dart';
2527
import '../test_images.dart';
28+
import 'message_list_test.dart';
2629
import 'test_app.dart';
2730

2831
/// Simulates loading a [MessageListPage] and tapping to focus the compose input.
@@ -36,6 +39,7 @@ import 'test_app.dart';
3639
/// before the end of the test.
3740
Future<Finder> setupToComposeInput(WidgetTester tester, {
3841
List<User> users = const [],
42+
List<(int userId, UserStatusChange change)>? userStatuses,
3943
Narrow? narrow,
4044
}) async {
4145
assert(narrow is ChannelNarrow? || narrow is SendableNarrow?);
@@ -47,6 +51,7 @@ Future<Finder> setupToComposeInput(WidgetTester tester, {
4751
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);
4852
await store.addUsers([eg.selfUser, eg.otherUser]);
4953
await store.addUsers(users);
54+
await store.changeUserStatuses(userStatuses ?? []);
5055
final connection = store.connection as FakeApiConnection;
5156

5257
narrow ??= DmNarrow(
@@ -152,9 +157,24 @@ void main() {
152157
Finder findAvatarImage(int userId) =>
153158
find.byWidgetPredicate((widget) => widget is AvatarImage && widget.userId == userId);
154159

155-
void checkUserShown(User user, {required bool expected}) {
156-
check(find.text(user.fullName)).findsExactly(expected ? 1 : 0);
157-
check(findAvatarImage(user.userId)).findsExactly(expected ? 1 : 0);
160+
void checkUserShown(User user, {required bool expected, bool withStatusEmoji = false}) {
161+
assert(expected || !withStatusEmoji);
162+
163+
final nameFinder = find.text(user.fullName);
164+
check(nameFinder).findsExactly(expected ? 1 : 0);
165+
166+
final avatarFinder = findAvatarImage(user.userId);
167+
check(avatarFinder).findsExactly(expected ? 1 : 0);
168+
169+
final statusEmojiFinder = findStatusEmoji(UnicodeEmojiWidget);
170+
if (withStatusEmoji) {
171+
checkUserStatusEmoji(statusEmojiFinder, isAnimated: false);
172+
}
173+
final rowFinder = find.ancestor(of: nameFinder,
174+
matching: find.ancestor(of: avatarFinder,
175+
matching: find.ancestor(of: statusEmojiFinder,
176+
matching: find.byType(Row))));
177+
check(rowFinder).findsExactly(expected && withStatusEmoji ? 1 : 0);
158178
}
159179

160180
testWidgets('user options appear, disappear, and change correctly', (tester) async {
@@ -202,6 +222,31 @@ void main() {
202222
debugNetworkImageHttpClientProvider = null;
203223
});
204224

225+
testWidgets('status emoji is set -> emoji is displayed', (tester) async {
226+
final user1 = eg.user(userId: 1, fullName: 'User One', avatarUrl: 'user1.png');
227+
final user2 = eg.user(userId: 2, fullName: 'User Two', avatarUrl: 'user2.png');
228+
final composeInputFinder = await setupToComposeInput(tester,
229+
users: [user1, user2], userStatuses: [
230+
(
231+
user1.userId,
232+
UserStatusChange(
233+
text: OptionSome('Busy'),
234+
emoji: OptionSome(StatusEmoji(emojiName: 'working_on_it',
235+
emojiCode: '1f6e0', reactionType: ReactionType.unicodeEmoji)))
236+
),
237+
]);
238+
239+
// // TODO(#226): Remove this extra edit when this bug is fixed.
240+
await tester.enterText(composeInputFinder, 'hello @u');
241+
await tester.enterText(composeInputFinder, 'hello @');
242+
await tester.pumpAndSettle(); // async computation; options appear
243+
244+
checkUserShown(user1, expected: true, withStatusEmoji: true);
245+
checkUserShown(user2, expected: true, withStatusEmoji: false);
246+
247+
debugNetworkImageHttpClientProvider = null;
248+
});
249+
205250
void checkWildcardShown(WildcardMentionOption wildcard, {required bool expected}) {
206251
check(find.text(wildcard.canonicalString)).findsExactly(expected ? 1 : 0);
207252
}

0 commit comments

Comments
 (0)