Skip to content

Commit

Permalink
fix: suggestions callback being called even when closed
Browse files Browse the repository at this point in the history
  • Loading branch information
clragon committed Feb 3, 2024
1 parent 8fba3ee commit b0ad50f
Show file tree
Hide file tree
Showing 6 changed files with 52 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
### Added
- force refreshing suggestions with `SuggestionsController.refresh`

### Fixed
- suggestionsCallback getting called even when closed

## 5.1.0 - 2024-01-27
### Added
- Returning null from `suggestionsCallback` hides the box
Expand Down
33 changes: 23 additions & 10 deletions lib/src/common/base/suggestions_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,19 @@ class SuggestionsController<T> extends ChangeNotifier {

List<T>? _suggestions;

/// A stream of events that occur when the suggestions list should be refreshed.
///
/// For internal use only.
Stream<void> get $refreshes => _refreshesController.stream;
final StreamController<void> _refreshesController =
StreamController<void>.broadcast();

/// Resets the suggestions so that they are requested again.
void refresh() => suggestions = null;
void refresh() {
ChangeNotifier.debugAssertNotDisposed(this);
_suggestions = null;
_refreshesController.add(null);
}

/// Whether the suggestions box is loading.
bool get isLoading => _isLoading;
Expand Down Expand Up @@ -132,10 +143,18 @@ class SuggestionsController<T> extends ChangeNotifier {
/// A stream of events that occur when the suggestions box should be resized.
///
/// For internal use only.
Stream<void> get resizes => _resizesController.stream;
Stream<void> get $resizes => _resizesController.stream;
final StreamController<void> _resizesController =
StreamController<void>.broadcast();

/// Resizes the suggestions box.
///
/// You usually don't need to call this method manually.
void resize() {
ChangeNotifier.debugAssertNotDisposed(this);
_resizesController.add(null);
}

/// A stream of selected suggestions.
Stream<T> get selections => _selectionsController.stream;
final StreamController<T> _selectionsController =
Expand All @@ -146,14 +165,6 @@ class SuggestionsController<T> extends ChangeNotifier {
/// This notifies potential listeners of the selection.
void select(T suggestion) => _selectionsController.add(suggestion);

/// Resizes the suggestions box.
///
/// You usually don't need to call this method manually.
void resize() {
ChangeNotifier.debugAssertNotDisposed(this);
_resizesController.add(null);
}

/// Focuses the suggestions box.
void focusBox() {
if (_focusState == SuggestionsFocusState.box) return;
Expand Down Expand Up @@ -204,7 +215,9 @@ class SuggestionsController<T> extends ChangeNotifier {
@override
void dispose() {
close();
_refreshesController.close();
_resizesController.close();
_selectionsController.close();
super.dispose();
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/common/field/suggestions_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ class _SuggestionsFieldState<T> extends State<SuggestionsField<T>> {
link: link,
child: ConnectorWidget(
value: controller,
connect: (value) => value.resizes.listen((_) => onResize()),
connect: (value) => value.$resizes.listen((_) => onResize()),
disconnect: (value, key) => key?.cancel(),
child: SuggestionsFieldFocusConnector<T>(
controller: controller,
Expand Down
31 changes: 17 additions & 14 deletions lib/src/common/search/suggestions_search.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,20 +65,14 @@ class SuggestionsSearch<T> extends StatefulWidget {

class _SuggestionsSearchState<T> extends State<SuggestionsSearch<T>> {
bool isQueued = false;
late String search;
late bool wasOpen;
late bool hadSuggestions;
late String search = widget.textEditingController.text;
late bool wasOpen = widget.controller.isOpen;
late bool hadSuggestions = widget.controller.suggestions != null;

@override
void initState() {
super.initState();
search = widget.textEditingController.text;
wasOpen = widget.controller.isOpen;
hadSuggestions = widget.controller.suggestions != null;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted) return;
if (wasOpen) load();
});
WidgetsBinding.instance.addPostFrameCallback((_) => load());
}

void onChange() {
Expand All @@ -91,14 +85,14 @@ class _SuggestionsSearchState<T> extends State<SuggestionsSearch<T>> {
bool isOpen = widget.controller.isOpen;
if (wasOpen == isOpen) return;
wasOpen = isOpen;
if (isOpen) load();
load();
}

void onSuggestionsChange() {
bool hasSuggestions = widget.controller.suggestions != null;
if (hadSuggestions == hasSuggestions) return;
hadSuggestions = hasSuggestions;
if (!hasSuggestions) load();
load();
}

/// Loads suggestions if not already loaded.
Expand All @@ -110,6 +104,7 @@ class _SuggestionsSearchState<T> extends State<SuggestionsSearch<T>> {
/// Loads suggestions. Discards any previously loaded suggestions.
Future<void> reload() async {
if (!mounted) return;
if (!wasOpen) return;

if (widget.controller.isLoading) {
isQueued = true;
Expand Down Expand Up @@ -151,13 +146,21 @@ class _SuggestionsSearchState<T> extends State<SuggestionsSearch<T>> {
debounceDuration: widget.debounceDuration,
onChanged: (value) {
search = value;
reload();
widget.controller.refresh();
},
child: ConnectorWidget(
value: widget.controller,
connect: (value) => value.addListener(onChange),
disconnect: (value, key) => value.removeListener(onChange),
child: widget.child,
child: ConnectorWidget(
value: widget.controller,
connect: (value) => value.$refreshes.listen((_) {
hadSuggestions = false; // prevents double load
reload();
}),
disconnect: (value, key) => key?.cancel(),
child: widget.child,
),
),
),
);
Expand Down
8 changes: 6 additions & 2 deletions test/common/base/suggestions_controller_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ void main() {
expect(controller.suggestions, equals(['a', 'b', 'c']));
});

test('refreshes the suggestions', () {
test('refreshes the suggestions', () async {
expect(controller.suggestions, isNull);
controller.suggestions = ['a', 'b', 'c'];
bool called = false;
controller.$refreshes.listen((_) => called = true);
controller.refresh();
await Future<void>.value();
expect(controller.suggestions, null);
expect(called, isTrue);
});

test('sets loading state', () {
Expand Down Expand Up @@ -88,7 +92,7 @@ void main() {

test('sends resize event', () async {
bool called = false;
controller.resizes.listen((_) => called = true);
controller.$resizes.listen((_) => called = true);
controller.resize();
await Future<void>.value();
expect(called, isTrue);
Expand Down
2 changes: 2 additions & 0 deletions test/common/search/suggestions_search_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ void main() {
});

testWidgets('loads when queued up', (WidgetTester tester) async {
controller.open();

await tester.pumpWidget(
MaterialApp(
home: Material(
Expand Down

0 comments on commit b0ad50f

Please sign in to comment.