@@ -790,15 +790,19 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
790790 if (store.isUserMuted (user.userId)) return null ;
791791
792792 final cache = store.autocompleteViewManager.autocompleteDataCache;
793- // TODO(#236) test email too, not just name
794793 final nameMatchQuality = _matchName (
795794 normalizedName: cache.normalizedNameForUser (user),
796795 normalizedNameWords: cache.normalizedNameWordsForUser (user));
797- if (nameMatchQuality == null ) return null ;
796+ bool ? matchesEmail;
797+ if (nameMatchQuality == null ) {
798+ matchesEmail = _matchEmail (user, cache);
799+ if (! matchesEmail) return null ;
800+ }
798801
799802 return UserMentionAutocompleteResult (
800803 userId: user.userId,
801- rank: _rankUserResult (user, nameMatchQuality: nameMatchQuality));
804+ rank: _rankUserResult (user,
805+ nameMatchQuality: nameMatchQuality, matchesEmail: matchesEmail));
802806 }
803807
804808 NameMatchQuality ? _matchName ({
@@ -826,6 +830,12 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
826830 return null ;
827831 }
828832
833+ bool _matchEmail (User user, AutocompleteDataCache cache) {
834+ final lowercaseEmail = cache.normalizedEmailForUser (user);
835+ if (lowercaseEmail == null ) return false ; // Email not known
836+ return lowercaseEmail.startsWith (_lowercase);
837+ }
838+
829839 /// A measure of a wildcard result's quality in the context of the query,
830840 /// from 0 (best) to one less than [_numResultRanks] .
831841 ///
@@ -835,18 +845,29 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
835845 /// A measure of a user result's quality in the context of the query,
836846 /// from 0 (best) to one less than [_numResultRanks] .
837847 ///
848+ /// When [nameMatchQuality] is non-null (the name matches),
849+ /// callers should skip computing [matchesEmail] and pass null for that.
850+ ///
838851 /// See also [_rankWildcardResult] .
839- static int _rankUserResult (User user, {required NameMatchQuality nameMatchQuality}) {
840- return switch (nameMatchQuality) {
841- NameMatchQuality .exact => 1 ,
842- NameMatchQuality .totalPrefix => 2 ,
843- NameMatchQuality .wordPrefixes => 3 ,
844- };
852+ static int _rankUserResult (User user, {
853+ required NameMatchQuality ? nameMatchQuality,
854+ required bool ? matchesEmail,
855+ }) {
856+ if (nameMatchQuality != null ) {
857+ assert (matchesEmail == null );
858+ return switch (nameMatchQuality) {
859+ NameMatchQuality .exact => 1 ,
860+ NameMatchQuality .totalPrefix => 2 ,
861+ NameMatchQuality .wordPrefixes => 3 ,
862+ };
863+ }
864+ assert (matchesEmail == true );
865+ return 4 ;
845866 }
846867
847868 /// The number of possible values returned by
848869 /// [_rankWildcardResult] and [_rankUserResult] .
849- static const _numResultRanks = 4 ;
870+ static const _numResultRanks = 5 ;
850871
851872 @override
852873 String toString () {
@@ -894,9 +915,17 @@ class AutocompleteDataCache {
894915 ?? = normalizedNameForUser (user).split (' ' );
895916 }
896917
918+ final Map <int , String ?> _normalizedEmailsByUser = {};
919+
920+ /// The normalized `deliveryEmail` of [user] , or null if that's null.
921+ String ? normalizedEmailForUser (User user) {
922+ return _normalizedEmailsByUser[user.userId] ?? = user.deliveryEmail? .toLowerCase ();
923+ }
924+
897925 void invalidateUser (int userId) {
898926 _normalizedNamesByUser.remove (userId);
899927 _normalizedNameWordsByUser.remove (userId);
928+ _normalizedEmailsByUser.remove (userId);
900929 }
901930}
902931
@@ -959,6 +988,12 @@ sealed class MentionAutocompleteResult extends ComposeAutocompleteResult {
959988 // special rank when the whole query appears contiguously
960989 // right after a word-boundary character.
961990 // Our [NameMatchQuality.wordPrefixes] seems smarter.
991+ // - An "exact" match quality on emails: probably not worth its complexity.
992+ // Emails are much more uniform in their endings than users' names are,
993+ // so a prefix match should be adequate. (If I've typed "[email protected] ", 994+ // that'll probably be the only result. There might be an "[email protected] ", 995+ // and an "exact" match would downrank that, but still that's just two items
996+ // to scan through.)
962997 // - A "word-boundary" match quality on user emails:
963998 // "words" is a wrong abstraction when matching on emails.
964999 // - Ranking some case-sensitive matches differently from case-insensitive
0 commit comments