@@ -183,6 +183,7 @@ class MentionAutocompleteView extends ChangeNotifier {
183
183
@override
184
184
void dispose () {
185
185
store.autocompleteViewManager.unregisterMentionAutocomplete (this );
186
+ _sortedUsers = null ;
186
187
// We cancel in-progress computations by checking [hasListeners] between tasks.
187
188
// After [super.dispose] is called, [hasListeners] returns false.
188
189
// TODO test that logic (may involve detecting an unhandled Future rejection; how?)
@@ -206,6 +207,7 @@ class MentionAutocompleteView extends ChangeNotifier {
206
207
/// Called in particular when we get a [RealmUserEvent] .
207
208
void refreshStaleUserResults () {
208
209
if (_query != null ) {
210
+ _sortedUsers = null ;
209
211
_startSearch (_query! );
210
212
}
211
213
}
@@ -244,11 +246,89 @@ class MentionAutocompleteView extends ChangeNotifier {
244
246
notifyListeners ();
245
247
}
246
248
249
+ List <User >? _sortedUsers;
250
+
251
+ int compareByRelevance ({
252
+ required User userA,
253
+ required User userB,
254
+ required int ? streamId,
255
+ required String ? topic,
256
+ }) {
257
+ // TODO(#234): give preference to "all", "everyone" or "stream".
258
+
259
+ // TODO(#618): give preference to subscribed users first.
260
+
261
+ if (streamId != null ) {
262
+ final conversationPrecedence = store.recentSenders.compareByRecency (
263
+ userA: userA,
264
+ userB: userB,
265
+ streamId: streamId,
266
+ topic: topic);
267
+ if (conversationPrecedence != 0 ) {
268
+ return conversationPrecedence;
269
+ }
270
+ }
271
+
272
+ final dmPrecedence = store.recentDmConversationsView.compareByDms (userA, userB);
273
+ if (dmPrecedence != 0 ) {
274
+ return dmPrecedence;
275
+ }
276
+
277
+ if (! userA.isBot && userB.isBot) {
278
+ return - 1 ;
279
+ } else if (userA.isBot && ! userB.isBot) {
280
+ return 1 ;
281
+ }
282
+
283
+ final userAName = store.autocompleteViewManager.autocompleteDataCache
284
+ .lowercasedNameForUserName (userA.fullName);
285
+ final userBName = store.autocompleteViewManager.autocompleteDataCache
286
+ .lowercasedNameForUserName (userB.fullName);
287
+ return userAName.compareTo (userBName);
288
+ }
289
+
290
+ List <User > sortByRelevance ({
291
+ required List <User > users,
292
+ required Narrow narrow,
293
+ }) {
294
+ switch (narrow) {
295
+ case StreamNarrow ():
296
+ users.sort ((userA, userB) => compareByRelevance (
297
+ userA: userA,
298
+ userB: userB,
299
+ streamId: narrow.streamId,
300
+ topic: null ));
301
+ case TopicNarrow ():
302
+ users.sort ((userA, userB) => compareByRelevance (
303
+ userA: userA,
304
+ userB: userB,
305
+ streamId: narrow.streamId,
306
+ topic: narrow.topic));
307
+ case DmNarrow ():
308
+ users.sort ((userA, userB) => compareByRelevance (
309
+ userA: userA,
310
+ userB: userB,
311
+ streamId: null ,
312
+ topic: null ));
313
+ case AllMessagesNarrow ():
314
+ // do nothing in this case for now
315
+ }
316
+ return users;
317
+ }
318
+
319
+ void _sortUsers () {
320
+ final users = store.users.values.toList ();
321
+ _sortedUsers = sortByRelevance (users: users, narrow: narrow);
322
+ }
323
+
247
324
Future <List <MentionAutocompleteResult >?> _computeResults (MentionAutocompleteQuery query) async {
248
325
final List <MentionAutocompleteResult > results = [];
249
- final Iterable <User > users = store.users.values;
250
326
251
- final iterator = users.iterator;
327
+ if (_sortedUsers == null ) {
328
+ _sortUsers ();
329
+ }
330
+
331
+ final iterator = _sortedUsers! .iterator;
252
332
bool isDone = false ;
253
333
while (! isDone) {
254
334
// CPU perf: End this task; enqueue a new one for resuming this work
@@ -270,7 +350,7 @@ class MentionAutocompleteView extends ChangeNotifier {
270
350
}
271
351
}
272
352
}
273
- return results; // TODO(#228) sort for most relevant first
353
+ return results;
274
354
}
275
355
}
276
356
@@ -339,6 +419,12 @@ class AutocompleteDataCache {
339
419
void invalidateUser (int userId) {
340
420
_nameWordsByUser.remove (userId);
341
421
}
422
+
423
+ final Map <String , String > _lowercasedNamesByUserName = {};
424
+
425
+ String lowercasedNameForUserName (String name) {
426
+ return _lowercasedNamesByUserName[name] ?? = name.toLowerCase ();
427
+ }
342
428
}
343
429
344
430
sealed class MentionAutocompleteResult {}
0 commit comments