Skip to content

Commit

Permalink
Fix DropdownMenu keyboard navigation (#147294)
Browse files Browse the repository at this point in the history
Fix #147253
Fix #147516

Resubmitted #147285 because I accidentally added reviewer as contributor in a commit by using Github "add suggestion to batch". Which causing CLA check to fail and I cannot revert it.

I use exact match of label instead of contains to minimise possible change in actual user search.
I added the new test after the original keyboard navigation test to avoid merge conflict with another incoming PR.
Let me know if I need to make any changes.

Sorry for the inconvenience, I am new to the process.
  • Loading branch information
PurplePolyhedron committed May 10, 2024
1 parent da9712f commit fdfc408
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 0 deletions.
3 changes: 3 additions & 0 deletions packages/flutter/lib/src/material/dropdown_menu.dart
Expand Up @@ -550,6 +550,9 @@ class _DropdownMenuState<T> extends State<DropdownMenu<T>> {
if (searchText.isEmpty) {
return null;
}
if (currentHighlight != null && entries[currentHighlight!].label.toLowerCase().contains(searchText)) {
return currentHighlight;
}
final int index = entries.indexWhere((DropdownMenuEntry<T> entry) => entry.label.toLowerCase().contains(searchText));

return index != -1 ? index : null;
Expand Down
110 changes: 110 additions & 0 deletions packages/flutter/test/material/dropdown_menu_test.dart
Expand Up @@ -764,6 +764,116 @@ void main() {
expect(item5material.color, Colors.transparent); // the previous item should not be highlighted.
}, variant: TargetPlatformVariant.desktop());

// Regression test for https://github.com/flutter/flutter/issues/147253.
testWidgets('Down key and up key can navigate on desktop platforms '
'when a label text contains another label text', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
home: const Scaffold(
body: DropdownMenu<int>(
dropdownMenuEntries: <DropdownMenuEntry<int>>[
DropdownMenuEntry<int>(
value: 0,
label: 'ABC'
),
DropdownMenuEntry<int>(
value: 1,
label: 'AB'
),
DropdownMenuEntry<int>(
value: 2,
label: 'ABCD'
),
],
),
),
));

await tester.tap(find.byType(DropdownMenu<int>));
await tester.pump();

final Finder button0Material = find.descendant(
of: find.widgetWithText(MenuItemButton, 'ABC').last,
matching: find.byType(Material),
);
final Finder button1Material = find.descendant(
of: find.widgetWithText(MenuItemButton, 'AB').last,
matching: find.byType(Material),
);
final Finder button2Material = find.descendant(
of: find.widgetWithText(MenuItemButton, 'ABCD').last,
matching: find.byType(Material),
);

// Press down key three times, the highlight should move to the next item each time.
await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.pumpAndSettle();
Material item0Material = tester.widget<Material>(button0Material);
expect(item0Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));

await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.pumpAndSettle();
Material item1Material = tester.widget<Material>(button1Material);
expect(item1Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));

await tester.sendKeyEvent(LogicalKeyboardKey.arrowDown);
await tester.pumpAndSettle();
final Material item2Material = tester.widget<Material>(button2Material);
expect(item2Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));

// Press up key two times, the highlight should up each time.
await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp);
await tester.pumpAndSettle();
item1Material = tester.widget<Material>(button1Material);
expect(item1Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));

await tester.sendKeyEvent(LogicalKeyboardKey.arrowUp);
await tester.pumpAndSettle();
item0Material = tester.widget<Material>(button0Material);
expect(item0Material.color, themeData.colorScheme.onSurface.withOpacity(0.12));

}, variant: TargetPlatformVariant.desktop());

// Regression test for https://github.com/flutter/flutter/issues/147253.
testWidgets('Default search prioritises the current highlight on desktop platforms',
(WidgetTester tester) async {
final ThemeData themeData = ThemeData();
await tester.pumpWidget(MaterialApp(
theme: themeData,
home: Scaffold(
body: DropdownMenu<TestMenu>(
dropdownMenuEntries: menuChildren,
),
),
));

const String itemLabel = 'Item 2';
// Open the menu
await tester.tap(find.byType(DropdownMenu<TestMenu>));
await tester.pumpAndSettle();
// Highlight the third item by exact search.
await tester.enterText(find.byType(TextField).first, itemLabel);
await tester.pumpAndSettle();
Finder button2Material = find.descendant(
of: find.widgetWithText(MenuItemButton, itemLabel).last,
matching: find.byType(Material),
);
Material item2material = tester.widget<Material>(button2Material);
expect(item2material.color, themeData.colorScheme.onSurface.withOpacity(0.12));

// Search something that matches multiple items.
await tester.enterText(find.byType(TextField).first, 'Item');
await tester.pumpAndSettle();
// The third item should still be highlighted.
button2Material = find.descendant(
of: find.widgetWithText(MenuItemButton, itemLabel).last,
matching: find.byType(Material),
);
item2material = tester.widget<Material>(button2Material);
expect(item2material.color, themeData.colorScheme.onSurface.withOpacity(0.12));
}, variant: TargetPlatformVariant.desktop());

testWidgets('The text input should match the label of the menu item '
'while pressing down key on desktop platforms', (WidgetTester tester) async {
final ThemeData themeData = ThemeData();
Expand Down

0 comments on commit fdfc408

Please sign in to comment.