Skip to content

Commit 9857b65

Browse files
Notify Flutter inspector when navigating widget tree with keyboard (#9810)
* Notify Flutter inspector when navigating widget tree with keyboard * Add inspector tree left/right keyboard navigation coverage Updates inspector tree tests to cover left and right arrow navigation, including expand, next-row selection, and parent selection behavior. Also ensures left navigation to a parent notifies Flutter Inspector consistently with other keyboard selection changes. * Fix inspector widget tree visibility issues during keyboard navigation Resolves two regressions surfaced when navigating the inspector widget tree with the arrow-left key. 1. Clicking a still-visible row used to call `expandPath` on the clicked node, which re-expanded the clicked node itself and undid any subtree collapses the user had just performed via the arrow-left key. Removed the call from `onSelectNode`; programmatic selection flows (search, on-device pick) continue to call `expandPath` via `syncTreeSelection`, so external selection still works correctly. 2. Collapsing all the way to the root via the arrow-left key shrank the visible rows down to a single row, which the inspector treated as a "still loading" state and replaced with a spinner — hiding the user's `[root]` row. Gated that branch on `!firstInspectorTreeLoadCompleted` so the spinner only shows during the initial load; afterwards a one-row tree renders as the legitimate single-row state. Adds regression tests covering both behaviors. * docs: add release notes for inspector keyboard navigation fixes (#9810) * test: update inspector tree selection test for collapsed nodes
1 parent a14ede6 commit 9857b65

3 files changed

Lines changed: 461 additions & 7 deletions

File tree

packages/devtools_app/lib/src/screens/inspector/inspector_tree_controller.dart

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,10 @@ class InspectorTreeController extends DisposableController
357357
return true;
358358
}
359359
if (selectionLocal.parent != null) {
360-
return setSelectedNode(selectionLocal.parent);
360+
return setSelectedNode(
361+
selectionLocal.parent,
362+
notifyFlutterInspector: true,
363+
);
361364
}
362365
return false;
363366
},
@@ -399,8 +402,7 @@ class InspectorTreeController extends DisposableController
399402
_numRows - 1,
400403
),
401404
)?.node;
402-
setSelectedNode(nodeToSelect);
403-
return true;
405+
return setSelectedNode(nodeToSelect, notifyFlutterInspector: true);
404406
},
405407
);
406408
}
@@ -573,7 +575,12 @@ class InspectorTreeController extends DisposableController
573575
if (diagnostic != null && diagnostic.groupIsHidden) {
574576
diagnostic.hideableGroupLeader?.toggleHiddenGroup();
575577
}
576-
expandPath(node);
578+
// Intentionally do NOT call expandPath(node) here. User clicks happen on
579+
// already-visible rows, so ancestors are already expanded; calling
580+
// expandPath would also re-expand the clicked node itself, undoing any
581+
// collapse the user just performed via the left arrow key. Programmatic
582+
// selection paths (search, on-device pick) call expandPath themselves via
583+
// [InspectorController.syncTreeSelection].
577584
}
578585

579586
Rect getBoundingBox(InspectorTreeRow row) {
@@ -1142,8 +1149,12 @@ class _InspectorTreeState extends State<InspectorTree>
11421149
valueListenable: treeControllerLocal.rowsInTree,
11431150
builder: (context, rows, _) {
11441151
// Note: The inspector rows contain only the fake root node when the
1145-
// inspector tree is shutdown.
1146-
if (rows.length <= 1) {
1152+
// inspector tree is shutdown. Only show the loading indicator on the
1153+
// initial tree load (before [firstInspectorTreeLoadCompleted] is set);
1154+
// after that, a one-row tree is the legitimate result of the user
1155+
// collapsing all the way to the root via the keyboard, and we should
1156+
// render the tree (with its single row) rather than a spinner.
1157+
if (rows.length <= 1 && !controller.firstInspectorTreeLoadCompleted) {
11471158
// This works around a bug when Scrollbars are present on a short lived
11481159
// widget.
11491160
return const SizedBox(child: CenteredCircularProgressIndicator());

packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ TODO: Remove this section if there are not any updates.
2121

2222
- Deleted the option to use the legacy inspector.
2323
[#9782](https://github.com/flutter/devtools/pull/9782)
24+
- Fixed an issue where navigating the Inspector widget tree with the keyboard arrow keys did not update the selected widget in the connected Flutter app. [#9810](https://github.com/flutter/devtools/pull/9810)
25+
- Fixed an issue where clicking a widget row after collapsing a subtree with the left arrow key unexpectedly re-expanded the subtree. [#9810](https://github.com/flutter/devtools/pull/9810)
26+
- Fixed an issue where collapsing the Inspector widget tree to a single row with the left arrow key caused a loading spinner to appear instead of showing the root node. [#9810](https://github.com/flutter/devtools/pull/9810)
2427

2528
## Performance updates
2629

0 commit comments

Comments
 (0)