Skip to content

Commit 7b8c8d4

Browse files
sm-sayedignprice
andcommitted
autocomplete: Introduce a field for sorted users
This field will be used to maintain a list of sorted users based on the most relevant autocomplete criteria in the upcoming commits. Co-authored-by: Greg Price <[email protected]>
1 parent 7354ce7 commit 7b8c8d4

File tree

2 files changed

+35
-15
lines changed

2 files changed

+35
-15
lines changed

lib/model/autocomplete.dart

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,10 @@ class AutocompleteViewManager {
148148
autocompleteDataCache.invalidateUser(event.userId);
149149
}
150150

151+
void handleMessageEvent(MessageEvent event) {
152+
_refreshStaleUserResults();
153+
}
154+
151155
/// Called when the app is reassembled during debugging, e.g. for hot reload.
152156
///
153157
/// Calls [MentionAutocompleteView.reassemble] for all that are registered.
@@ -193,6 +197,7 @@ class MentionAutocompleteView extends ChangeNotifier {
193197
@override
194198
void dispose() {
195199
store.autocompleteViewManager.unregisterMentionAutocomplete(this);
200+
_sortedUsers = null;
196201
// We cancel in-progress computations by checking [hasListeners] between tasks.
197202
// After [super.dispose] is called, [hasListeners] returns false.
198203
// TODO test that logic (may involve detecting an unhandled Future rejection; how?)
@@ -213,9 +218,11 @@ class MentionAutocompleteView extends ChangeNotifier {
213218

214219
/// Recompute user results for the current query, if any.
215220
///
216-
/// Called in particular when we get a [RealmUserEvent].
221+
/// Called in particular when we get a [RealmUserEvent], a [MessageEvent], or
222+
/// [MessageListView.fetchOlder] is called.
217223
void refreshStaleUserResults() {
218224
if (_query != null) {
225+
_sortedUsers = null;
219226
_startSearch(_query!);
220227
}
221228
}
@@ -225,6 +232,7 @@ class MentionAutocompleteView extends ChangeNotifier {
225232
/// This will redo the search from scratch for the current query, if any.
226233
void reassemble() {
227234
if (_query != null) {
235+
_sortedUsers = null;
228236
_startSearch(_query!);
229237
}
230238
}
@@ -251,22 +259,43 @@ class MentionAutocompleteView extends ChangeNotifier {
251259
notifyListeners();
252260
}
253261

262+
List<User>? _sortedUsers;
263+
264+
List<User> sortByRelevance({required List<User> users}) {
265+
return users; // TODO(#228) sort for most relevant first
266+
}
267+
268+
void _sortUsers() {
269+
final users = store.users.values.toList();
270+
_sortedUsers = sortByRelevance(users: users);
271+
}
272+
254273
Future<List<MentionAutocompleteResult>?> _computeResults(MentionAutocompleteQuery query) async {
255274
final List<MentionAutocompleteResult> results = [];
256-
final Iterable<User> users = store.users.values;
257275

258-
final iterator = users.iterator;
276+
if (_sortedUsers == null) {
277+
_sortUsers();
278+
}
279+
280+
final sortedUsers = _sortedUsers!;
281+
final iterator = sortedUsers.iterator;
259282
bool isDone = false;
260283
while (!isDone) {
261284
// CPU perf: End this task; enqueue a new one for resuming this work
262285
await Future(() {});
263286

287+
if (_sortedUsers != sortedUsers) {
288+
// The list of users this loop has been working from has become stale.
289+
// Abort so _startSearch can retry with the new list.
290+
throw ConcurrentModificationError();
291+
}
292+
264293
if (query != _query || !hasListeners) { // false if [dispose] has been called.
265294
return null;
266295
}
267296

268297
for (int i = 0; i < 1000; i++) {
269-
if (!iterator.moveNext()) { // Can throw ConcurrentModificationError
298+
if (!iterator.moveNext()) {
270299
isDone = true;
271300
break;
272301
}
@@ -277,7 +306,7 @@ class MentionAutocompleteView extends ChangeNotifier {
277306
}
278307
}
279308
}
280-
return results; // TODO(#228) sort for most relevant first
309+
return results;
281310
}
282311
}
283312

lib/model/store.dart

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -448,16 +448,6 @@ class PerAccountStore extends ChangeNotifier with StreamStore {
448448
user.profileData = null;
449449
}
450450
}
451-
// The following two lines will eventually not change [users], but are here to
452-
// trigger a modification to the collection as only changing the properties
453-
// of [user] does not signal a modification of [users] where needed.
454-
//
455-
// One example of this is [MentionAutocompleteView._computeResults] which
456-
// throws a `ConcurrentModificationError` when there is a modification done
457-
// to [users].
458-
users[-1] = user;
459-
users.remove(-1);
460-
461451
autocompleteViewManager.handleRealmUserUpdateEvent(event);
462452
notifyListeners();
463453
} else if (event is StreamEvent) {
@@ -475,6 +465,7 @@ class PerAccountStore extends ChangeNotifier with StreamStore {
475465
} else if (event is MessageEvent) {
476466
assert(debugLog("server event: message ${jsonEncode(event.message.toJson())}"));
477467
recentDmConversationsView.handleMessageEvent(event);
468+
autocompleteViewManager.handleMessageEvent(event);
478469
for (final view in _messageListViews) {
479470
view.maybeAddMessage(event.message);
480471
}

0 commit comments

Comments
 (0)