From 896cd9146c026e636e048a0b8be460e6cc267d04 Mon Sep 17 00:00:00 2001 From: "Ahmed R." <103958012+ahmedrasar@users.noreply.github.com> Date: Tue, 8 Apr 2025 09:07:39 +0200 Subject: [PATCH] Fix `DropdownMenu` keyboard navigation on filtered entries (#165868) Fix `DropdownMenu` keyboard navigation when `enableFilter` is set to true. Nothing major here, just a simple bugfix. ## Related Issues - Fixes #165867 ## Tests Added 1 test. ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md --- .../lib/src/material/dropdown_menu.dart | 3 +- .../test/material/dropdown_menu_test.dart | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/material/dropdown_menu.dart b/packages/flutter/lib/src/material/dropdown_menu.dart index 0fb5730f3ce..6e2fb035a99 100644 --- a/packages/flutter/lib/src/material/dropdown_menu.dart +++ b/packages/flutter/lib/src/material/dropdown_menu.dart @@ -884,6 +884,7 @@ class _DropdownMenuState extends State> { currentHighlight = null; controller.close(); } else { + filteredEntries = widget.dropdownMenuEntries; // close to open if (_localTextEditingController!.text.isNotEmpty) { _enableFilter = false; @@ -934,8 +935,6 @@ class _DropdownMenuState extends State> { filteredEntries = widget.filterCallback?.call(filteredEntries, _localTextEditingController!.text) ?? filter(widget.dropdownMenuEntries, _localTextEditingController!); - } else { - filteredEntries = widget.dropdownMenuEntries; } _menuHasEnabledItem = filteredEntries.any((DropdownMenuEntry entry) => entry.enabled); diff --git a/packages/flutter/test/material/dropdown_menu_test.dart b/packages/flutter/test/material/dropdown_menu_test.dart index 6ed4036fcfe..11804862ba5 100644 --- a/packages/flutter/test/material/dropdown_menu_test.dart +++ b/packages/flutter/test/material/dropdown_menu_test.dart @@ -1701,6 +1701,55 @@ void main() { expect(tester.takeException(), isNull); }); + // Regression test for https://github.com/flutter/flutter/issues/165867. + testWidgets('Keyboard navigation only traverses filtered entries', (WidgetTester tester) async { + final TextEditingController controller = TextEditingController(); + addTearDown(controller.dispose); + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: DropdownMenu( + requestFocusOnTap: true, + enableFilter: true, + controller: controller, + dropdownMenuEntries: const >[ + DropdownMenuEntry(value: TestMenu.mainMenu0, label: 'Good Match 1'), + DropdownMenuEntry(value: TestMenu.mainMenu1, label: 'Bad Match 1'), + DropdownMenuEntry(value: TestMenu.mainMenu2, label: 'Good Match 2'), + DropdownMenuEntry(value: TestMenu.mainMenu3, label: 'Bad Match 2'), + DropdownMenuEntry(value: TestMenu.mainMenu4, label: 'Good Match 3'), + DropdownMenuEntry(value: TestMenu.mainMenu5, label: 'Bad Match 3'), + ], + ), + ), + ), + ); + + // Open the menu. + await tester.tap(find.byType(DropdownMenu)); + await tester.pump(); + + // Filter the entries to only show the ones with 'Good Match'. + await tester.enterText(find.byType(TextField), 'Good Match'); + await tester.pump(); + + // Since the first entry is already highlighted, navigate to the second item. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); + await tester.pump(); + expect(controller.text, 'Good Match 2'); + + // Navigate to the third item. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); + await tester.pump(); + expect(controller.text, 'Good Match 3'); + + // Navigate back to the first item. + await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown); + await tester.pump(); + expect(controller.text, 'Good Match 1'); + }); + // Regression test for https://github.com/flutter/flutter/issues/147253. testWidgets('Default search prioritises the current highlight', (WidgetTester tester) async { final ThemeData themeData = ThemeData();