Skip to content

Commit a24dbde

Browse files
committed
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. This commit also removes the retry logic for an in-progress query computation as there is no longer the cause that would necessitate such a retry.
1 parent ca3e002 commit a24dbde

File tree

2 files changed

+21
-50
lines changed

2 files changed

+21
-50
lines changed

lib/model/autocomplete.dart

+21-17
Original file line numberDiff line numberDiff line change
@@ -164,17 +164,31 @@ class AutocompleteViewManager {
164164
/// * When the object will no longer be used, call [dispose] to free
165165
/// resources on the [PerAccountStore].
166166
class MentionAutocompleteView extends ChangeNotifier {
167-
MentionAutocompleteView._({required this.store, required this.narrow});
167+
MentionAutocompleteView._({
168+
required this.store,
169+
required this.narrow,
170+
required this.sortedUsers,
171+
});
168172

169173
factory MentionAutocompleteView.init({
170174
required PerAccountStore store,
171175
required Narrow narrow,
172176
}) {
173-
final view = MentionAutocompleteView._(store: store, narrow: narrow);
177+
final users = store.users.values.toList();
178+
final sortedUsers = sortByRelevance(users: users);
179+
final view = MentionAutocompleteView._(
180+
store: store,
181+
narrow: narrow,
182+
sortedUsers: sortedUsers,
183+
);
174184
store.autocompleteViewManager.registerMentionAutocomplete(view);
175185
return view;
176186
}
177187

188+
static List<User> sortByRelevance({required List<User> users}) {
189+
return users; // TODO(#228) sort for most relevant first
190+
}
191+
178192
@override
179193
void dispose() {
180194
store.autocompleteViewManager.unregisterMentionAutocomplete(this);
@@ -186,6 +200,7 @@ class MentionAutocompleteView extends ChangeNotifier {
186200

187201
final PerAccountStore store;
188202
final Narrow narrow;
203+
final List<User> sortedUsers;
189204

190205
MentionAutocompleteQuery? get query => _query;
191206
MentionAutocompleteQuery? _query;
@@ -209,17 +224,7 @@ class MentionAutocompleteView extends ChangeNotifier {
209224
List<MentionAutocompleteResult> _results = [];
210225

211226
Future<void> _startSearch(MentionAutocompleteQuery query) async {
212-
List<MentionAutocompleteResult>? newResults;
213-
214-
while (true) {
215-
try {
216-
newResults = await _computeResults(query);
217-
break;
218-
} on ConcurrentModificationError {
219-
// Retry
220-
// TODO backoff?
221-
}
222-
}
227+
final newResults = await _computeResults(query);
223228

224229
if (newResults == null) {
225230
// Query was old; new search is in progress. Or, no listeners to notify.
@@ -232,9 +237,8 @@ class MentionAutocompleteView extends ChangeNotifier {
232237

233238
Future<List<MentionAutocompleteResult>?> _computeResults(MentionAutocompleteQuery query) async {
234239
final List<MentionAutocompleteResult> results = [];
235-
final Iterable<User> users = store.users.values;
236240

237-
final iterator = users.iterator;
241+
final iterator = sortedUsers.iterator;
238242
bool isDone = false;
239243
while (!isDone) {
240244
// CPU perf: End this task; enqueue a new one for resuming this work
@@ -245,7 +249,7 @@ class MentionAutocompleteView extends ChangeNotifier {
245249
}
246250

247251
for (int i = 0; i < 1000; i++) {
248-
if (!iterator.moveNext()) { // Can throw ConcurrentModificationError
252+
if (!iterator.moveNext()) {
249253
isDone = true;
250254
break;
251255
}
@@ -256,7 +260,7 @@ class MentionAutocompleteView extends ChangeNotifier {
256260
}
257261
}
258262
}
259-
return results; // TODO(#228) sort for most relevant first
263+
return results;
260264
}
261265
}
262266

test/model/autocomplete_test.dart

-33
Original file line numberDiff line numberDiff line change
@@ -274,39 +274,6 @@ void main() {
274274
}
275275
});
276276

277-
test('MentionAutocompleteView mutating store.users while in progress causes retry', () async {
278-
const narrow = CombinedFeedNarrow();
279-
final store = eg.store();
280-
for (int i = 0; i < 1500; i++) {
281-
await store.addUser(eg.user(userId: i, email: 'user$i@example.com', fullName: 'User $i'));
282-
}
283-
final view = MentionAutocompleteView.init(store: store, narrow: narrow);
284-
285-
bool done = false;
286-
view.addListener(() { done = true; });
287-
view.query = MentionAutocompleteQuery('User 10000');
288-
289-
await Future(() {});
290-
check(done).isFalse();
291-
await store.addUser(eg.user(userId: 10000, email: '[email protected]', fullName: 'User 10000'));
292-
check(done).isFalse();
293-
await Future(() {});
294-
await Future(() {});
295-
check(done).isFalse();
296-
await Future(() {});
297-
check(done).isTrue();
298-
check(view.results).single
299-
.isA<UserMentionAutocompleteResult>()
300-
.userId.equals(10000);
301-
// new result sticks; no "zombie" result from `store.users` pre-mutation
302-
for (int i = 0; i < 10; i++) { // for good measure
303-
await Future(() {});
304-
check(view.results).single
305-
.isA<UserMentionAutocompleteResult>()
306-
.userId.equals(10000);
307-
}
308-
});
309-
310277
group('MentionAutocompleteQuery.testUser', () {
311278
doCheck(String rawQuery, User user, bool expected) {
312279
final result = MentionAutocompleteQuery(rawQuery)

0 commit comments

Comments
 (0)