Skip to content

Commit

Permalink
autocomplete: Add user avatars to user-mention autocompletes
Browse files Browse the repository at this point in the history
Fixes: #227
  • Loading branch information
sm-sayedi authored and gnprice committed Mar 27, 2024
1 parent 4ab1a82 commit 919cf12
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 16 deletions.
13 changes: 10 additions & 3 deletions lib/widgets/autocomplete.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';

import 'content.dart';
import 'store.dart';
import '../model/autocomplete.dart';
import '../model/compose.dart';
Expand Down Expand Up @@ -119,19 +120,25 @@ class _ComposeAutocompleteState extends State<ComposeAutocomplete> with PerAccou

Widget _buildItem(BuildContext _, int index) {
final option = _resultsToDisplay[index];
Widget avatar;
String label;
switch (option) {
case UserMentionAutocompleteResult(:var userId):
// TODO(#227) avatar
avatar = Avatar(userId: userId, size: 32, borderRadius: 3);
label = PerAccountStoreWidget.of(context).users[userId]!.fullName;
}
return InkWell(
onTap: () {
_onTapOption(option);
},
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(label)));
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Row(
children: [
avatar,
const SizedBox(width: 8),
Text(label),
])));
}

@override
Expand Down
54 changes: 41 additions & 13 deletions test/widgets/autocomplete_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,25 @@ import 'package:zulip/api/model/model.dart';
import 'package:zulip/api/route/messages.dart';
import 'package:zulip/model/compose.dart';
import 'package:zulip/model/narrow.dart';
import 'package:zulip/model/store.dart';
import 'package:zulip/widgets/message_list.dart';
import 'package:zulip/widgets/store.dart';

import '../api/fake_api.dart';
import '../example_data.dart' as eg;
import '../model/binding.dart';
import '../model/test_store.dart';
import 'content_test.dart';

/// Simulates loading a [MessageListPage] and tapping to focus the compose input.
///
/// Also adds [users] to the [PerAccountStore],
/// so they can show up in autocomplete.
///
/// Also sets [debugNetworkImageHttpClientProvider] to return a constant image.
///
/// The caller must set [debugNetworkImageHttpClientProvider] back to null
/// before the end of the test.
Future<Finder> setupToComposeInput(WidgetTester tester, {
required List<User> users,
}) async {
Expand All @@ -39,6 +46,8 @@ Future<Finder> setupToComposeInput(WidgetTester tester, {
messages: [message],
).toJson());

prepareBoringImageHttpClient();

await tester.pumpWidget(
MaterialApp(
localizationsDelegates: ZulipLocalizations.localizationsDelegates,
Expand All @@ -65,10 +74,26 @@ void main() {
TestZulipBinding.ensureInitialized();

group('ComposeAutocomplete', () {

Finder findNetworkImage(String url) {
return find.byWidgetPredicate((widget) => switch(widget) {
Image(image: NetworkImage(url: var imageUrl)) when imageUrl == url
=> true,
_ => false,
});
}

void checkUserShown(User user, PerAccountStore store, {required bool expected}) {
check(find.text(user.fullName).evaluate().length).equals(expected ? 1 : 0);
final avatarFinder =
findNetworkImage(store.tryResolveUrl(user.avatarUrl!).toString());
check(avatarFinder.evaluate().length).equals(expected ? 1 : 0);
}

testWidgets('options appear, disappear, and change correctly', (WidgetTester tester) async {
final user1 = eg.user(userId: 1, fullName: 'User One');
final user2 = eg.user(userId: 2, fullName: 'User Two');
final user3 = eg.user(userId: 3, fullName: 'User Three');
final user1 = eg.user(userId: 1, fullName: 'User One', avatarUrl: 'user1.png');
final user2 = eg.user(userId: 2, fullName: 'User Two', avatarUrl: 'user2.png');
final user3 = eg.user(userId: 3, fullName: 'User Three', avatarUrl: 'user3.png');
final composeInputFinder = await setupToComposeInput(tester, users: [user1, user2, user3]);
final store = await testBinding.globalStore.perAccount(eg.selfAccount.id);

Expand All @@ -77,34 +102,37 @@ void main() {
await tester.enterText(composeInputFinder, 'hello @user ');
await tester.enterText(composeInputFinder, 'hello @user t');
await tester.pumpAndSettle(); // async computation; options appear

// "User Two" and "User Three" appear, but not "User One"
check(tester.widgetList(find.text('User One'))).isEmpty();
tester.widget(find.text('User Two'));
tester.widget(find.text('User Three'));
checkUserShown(user1, store, expected: false);
checkUserShown(user2, store, expected: true);
checkUserShown(user3, store, expected: true);

// Finishing autocomplete updates compose box; causes options to disappear
await tester.tap(find.text('User Three'));
await tester.pump();
check(tester.widget<TextField>(composeInputFinder).controller!.text)
.contains(mention(user3, users: store.users));
check(tester.widgetList(find.text('User One'))).isEmpty();
check(tester.widgetList(find.text('User Two'))).isEmpty();
check(tester.widgetList(find.text('User Three'))).isEmpty();
checkUserShown(user1, store, expected: false);
checkUserShown(user2, store, expected: false);
checkUserShown(user3, store, expected: false);

// Then a new autocomplete intent brings up options again
// TODO(#226): Remove this extra edit when this bug is fixed.
await tester.enterText(composeInputFinder, 'hello @user tw');
await tester.enterText(composeInputFinder, 'hello @user two');
await tester.pumpAndSettle(); // async computation; options appear
tester.widget(find.text('User Two'));
checkUserShown(user2, store, expected: true);

// Removing autocomplete intent causes options to disappear
// TODO(#226): Remove one of these edits when this bug is fixed.
await tester.enterText(composeInputFinder, '');
await tester.enterText(composeInputFinder, ' ');
check(tester.widgetList(find.text('User One'))).isEmpty();
check(tester.widgetList(find.text('User Two'))).isEmpty();
check(tester.widgetList(find.text('User Three'))).isEmpty();
checkUserShown(user1, store, expected: false);
checkUserShown(user2, store, expected: false);
checkUserShown(user3, store, expected: false);

debugNetworkImageHttpClientProvider = null;
});
});
}

0 comments on commit 919cf12

Please sign in to comment.