@@ -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 ({
@@ -820,6 +824,12 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
820824 return null ;
821825 }
822826
827+ bool _matchEmail (User user, AutocompleteDataCache cache) {
828+ final lowercaseEmail = cache.normalizedEmailForUser (user);
829+ if (lowercaseEmail == null ) return false ; // Email not known
830+ return lowercaseEmail.startsWith (_lowercase);
831+ }
832+
823833 /// A measure of a wildcard result's quality in the context of the query,
824834 /// from 0 (best) to one less than [_numResultRanks] .
825835 ///
@@ -829,18 +839,29 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
829839 /// A measure of a user result's quality in the context of the query,
830840 /// from 0 (best) to one less than [_numResultRanks] .
831841 ///
842+ /// When [nameMatchQuality] is non-null (the name matches),
843+ /// callers should skip computing [matchesEmail] and pass null for that.
844+ ///
832845 /// See also [_rankWildcardResult] .
833- static int _rankUserResult (User user, {required NameMatchQuality nameMatchQuality}) {
834- return switch (nameMatchQuality) {
835- NameMatchQuality .exact => 1 ,
836- NameMatchQuality .totalPrefix => 2 ,
837- NameMatchQuality .wordPrefixes => 3 ,
838- };
846+ static int _rankUserResult (User user, {
847+ required NameMatchQuality ? nameMatchQuality,
848+ required bool ? matchesEmail,
849+ }) {
850+ if (nameMatchQuality != null ) {
851+ assert (matchesEmail == null );
852+ return switch (nameMatchQuality) {
853+ NameMatchQuality .exact => 1 ,
854+ NameMatchQuality .totalPrefix => 2 ,
855+ NameMatchQuality .wordPrefixes => 3 ,
856+ };
857+ }
858+ assert (matchesEmail == true );
859+ return 4 ;
839860 }
840861
841862 /// The number of possible values returned by
842863 /// [_rankWildcardResult] and [_rankUserResult] .
843- static const _numResultRanks = 4 ;
864+ static const _numResultRanks = 5 ;
844865
845866 @override
846867 String toString () {
@@ -888,9 +909,17 @@ class AutocompleteDataCache {
888909 ?? = normalizedNameForUser (user).split (' ' );
889910 }
890911
912+ final Map <int , String ?> _normalizedEmailsByUser = {};
913+
914+ /// The normalized `deliveryEmail` of [user] , or null if that's null.
915+ String ? normalizedEmailForUser (User user) {
916+ return _normalizedEmailsByUser[user.userId] ?? = user.deliveryEmail? .toLowerCase ();
917+ }
918+
891919 void invalidateUser (int userId) {
892920 _normalizedNamesByUser.remove (userId);
893921 _normalizedNameWordsByUser.remove (userId);
922+ _normalizedEmailsByUser.remove (userId);
894923 }
895924}
896925
@@ -953,6 +982,12 @@ sealed class MentionAutocompleteResult extends ComposeAutocompleteResult {
953982 // special rank when the whole query appears contiguously
954983 // right after a word-boundary character.
955984 // Our [NameMatchQuality.wordPrefixes] seems smarter.
985+ // - An "exact" match quality on emails: probably not worth its complexity.
986+ // Emails are much more uniform in their endings than users' names are,
987+ // so a prefix match should be adequate. (If I've typed "[email protected] ", 988+ // that'll probably be the only result. There might be an "[email protected] ", 989+ // and an "exact" match would downrank that, but still that's just two items
990+ // to scan through.)
956991 // - A "word-boundary" match quality on user emails:
957992 // "words" is a wrong abstraction when matching on emails.
958993 // - Ranking some case-sensitive matches differently from case-insensitive
0 commit comments