@@ -790,15 +790,19 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
790
790
if (store.isUserMuted (user.userId)) return null ;
791
791
792
792
final cache = store.autocompleteViewManager.autocompleteDataCache;
793
- // TODO(#236) test email too, not just name
794
793
final nameMatchQuality = _matchName (
795
794
normalizedName: cache.normalizedNameForUser (user),
796
795
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
+ }
798
801
799
802
return UserMentionAutocompleteResult (
800
803
userId: user.userId,
801
- rank: _rankUserResult (user, nameMatchQuality: nameMatchQuality));
804
+ rank: _rankUserResult (user,
805
+ nameMatchQuality: nameMatchQuality, matchesEmail: matchesEmail));
802
806
}
803
807
804
808
NameMatchQuality ? _matchName ({
@@ -820,6 +824,12 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
820
824
return null ;
821
825
}
822
826
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
+
823
833
/// A measure of a wildcard result's quality in the context of the query,
824
834
/// from 0 (best) to one less than [_numResultRanks] .
825
835
///
@@ -829,18 +839,29 @@ class MentionAutocompleteQuery extends ComposeAutocompleteQuery {
829
839
/// A measure of a user result's quality in the context of the query,
830
840
/// from 0 (best) to one less than [_numResultRanks] .
831
841
///
842
+ /// When [nameMatchQuality] is non-null (the name matches),
843
+ /// callers should skip computing [matchesEmail] and pass null for that.
844
+ ///
832
845
/// 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 ;
839
860
}
840
861
841
862
/// The number of possible values returned by
842
863
/// [_rankWildcardResult] and [_rankUserResult] .
843
- static const _numResultRanks = 4 ;
864
+ static const _numResultRanks = 5 ;
844
865
845
866
@override
846
867
String toString () {
@@ -888,9 +909,17 @@ class AutocompleteDataCache {
888
909
?? = normalizedNameForUser (user).split (' ' );
889
910
}
890
911
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
+
891
919
void invalidateUser (int userId) {
892
920
_normalizedNamesByUser.remove (userId);
893
921
_normalizedNameWordsByUser.remove (userId);
922
+ _normalizedEmailsByUser.remove (userId);
894
923
}
895
924
}
896
925
@@ -953,6 +982,12 @@ sealed class MentionAutocompleteResult extends ComposeAutocompleteResult {
953
982
// special rank when the whole query appears contiguously
954
983
// right after a word-boundary character.
955
984
// 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.)
956
991
// - A "word-boundary" match quality on user emails:
957
992
// "words" is a wrong abstraction when matching on emails.
958
993
// - Ranking some case-sensitive matches differently from case-insensitive
0 commit comments