Conversation
There was a problem hiding this comment.
Code Review
This pull request refactors the flex layout explorer by introducing FlexLayoutExplorerScope, an InheritedWidget used to share properties and callbacks down the widget tree. This successfully removes the need to pass the state object directly to child widgets. The review feedback recommends adding defensive null checks for the nullable objectGroup in FlexChildVisualizer to avoid potential runtime crashes from using the null-assertion operator.
Replace passing FlexLayoutExplorerWidgetState to VisualizeFlexChildren and FlexChildVisualizer with _FlexLayoutExplorerScope, an InheritedWidget providing rootProperties, animation controllers, and mutation/selection callbacks. Fixes flutter#2701
0e24e2e to
bff9f44
Compare
|
Hi @hannah-hyj , I added you as a reviewer as I think this is a pure "flutter best practices" PR with nothing to do with DevTools business logic. I'd love your input. |
kenzieschmoll
left a comment
There was a problem hiding this comment.
Why an InheritedWidget here? A few reasons I'd avoid it:
- The drilling is one hop.
VisualizeFlexChildrenis the only widget betweenFlexLayoutExplorerWidgetStateandFlexChildVisualizer, and it already forwards five other params. - No rebuild-scoping benefit.
_buildLayoutruns insideAnimatedBuilder(animation: changeController)→LayoutBuilder, so every consumer is rebuilt top-down anyway.updateShouldNotifycan't trigger a rebuild that isn't already happening. - Compile-time guarantee becomes runtime.
required this.statewas enforced by the compiler;_of(context)is anassert+!. It also meansFlexChildVisualizercan't be built or widget-tested without a scope wrapper. Note this replaces theTODO(polina-c, jacob314): consider refactoring to remove !with a new!.
#2701 is about what we pass, not how. onTap, onDoubleTap, markAsDirty, and properties are app logic that shouldn't be on a State — that's the root cause. These belong on InspectorController, or on a layout-explorer sub-controller that InspectorController owns and disposes. InspectorController already holds _layoutGroups for this feature and LayoutExplorerWidgetState already has widget.inspectorController, so children can reach it without any new plumbing. That removes the state-passing and makes the logic unit-testable — neither of which the scope gets us. It also drops the markAsDirty threading this PR adds through _buildContent → the two dropdown builders → _onChangeFlexFactor/_onChangeFlexFit.
Replaces passing
FlexLayoutExplorerWidgetStatedown toVisualizeFlexChildrenandFlexChildVisualizerwithFlexLayoutExplorerScope, anInheritedWidget.FlexLayoutExplorerScopeprovides descendants with scoped access torootProperties, the entrance animation (entranceControllerandentranceCurve), and the necessary interaction callbacks (markAsDirty,onTap, andonDoubleTap). This eliminates passing mutableStateobjects down the widget tree while avoiding prop drilling and preserving all existing layout visualizer behaviors.Fixes #2701