attempt to remove flag
diff --git a/packages/devtools_app/lib/src/inspector/diagnostics_node.dart b/packages/devtools_app/lib/src/inspector/diagnostics_node.dart index 498966d..8f4b1ad 100644 --- a/packages/devtools_app/lib/src/inspector/diagnostics_node.dart +++ b/packages/devtools_app/lib/src/inspector/diagnostics_node.dart
@@ -65,15 +65,21 @@ final bool isProperty; - bool get isFlex => getBooleanMember('isFlex', false); + bool get isFlex => ['Row', 'Column', 'Flex'].contains(widgetRuntimeType); - int get flexFactor => json['flexFactor']; + int get flexFactor => cachedProperties + ?.firstWhere((property) => property.name == 'flex', orElse: () => null) + ?.getIntMember('value'); - Map<String, Object> get constraints => json['constraints']; + RemoteDiagnosticsNode get constraints => renderObject?.cachedProperties + ?.firstWhere((property) => property.name == 'constraints'); - Map<String, Object> get renderObject => json['renderObject']; + RemoteDiagnosticsNode _renderObject; - Map<String, Object> get size => json['size']; + RemoteDiagnosticsNode get renderObject => _renderObject; + + RemoteDiagnosticsNode get size => renderObject?.cachedProperties + ?.firstWhere((property) => property.name == 'size'); @override bool operator ==(dynamic other) { @@ -328,6 +334,10 @@ return JsonUtils.getStringMember(json, memberName); } + int getIntMember(String memberName) { + return JsonUtils.getIntMember(json, memberName); + } + bool getBooleanMember(String memberName, bool defaultValue) { if (json[memberName] == null) { return defaultValue; @@ -664,6 +674,19 @@ await (await inspectorService) ?.setSelectionInspector(valueRef, uiAlreadyUpdated); } + + Future<void> getRenderObject() async { + if (_renderObject != null) return; + final service = await inspectorService; + _renderObject = await service.renderObject(valueRef); + if (isFlex && _children != null) + for (var i = 0; i < _children.length; ++i) { + final List<dynamic> children = + _renderObject.json['children']; + _children[i]._renderObject = RemoteDiagnosticsNode( + children[i], inspectorService, true, _children[i]); + } + } } class InspectorSourceLocation {
diff --git a/packages/devtools_app/lib/src/inspector/flutter/inspector_data_models.dart b/packages/devtools_app/lib/src/inspector/flutter/inspector_data_models.dart index ac1b994..11282e9 100644 --- a/packages/devtools_app/lib/src/inspector/flutter/inspector_data_models.dart +++ b/packages/devtools_app/lib/src/inspector/flutter/inspector_data_models.dart
@@ -13,8 +13,6 @@ import '../inspector_tree.dart'; import 'story_of_your_layout/utils.dart'; -const Type boxConstraintsType = BoxConstraints; - /// Compute real widget sizes into rendered sizes to be displayed on the details tab. /// The sum of the resulting render sizes may or may not be greater than the [maxSizeAvailable] /// In the case where it is greater, we should render it with scrolling capability. @@ -95,11 +93,11 @@ // TODO(albertusangga): Move this to [RemoteDiagnosticsNode] once dart:html app is removed class LayoutProperties { LayoutProperties(this.node, {int copyLevel = 1}) - : description = node.diagnostic?.description, - size = deserializeSize(node.diagnostic?.size), - constraints = deserializeConstraints(node.diagnostic?.constraints), - isFlex = node.diagnostic?.isFlex, - flexFactor = node.diagnostic?.flexFactor, + : description = node.diagnostic.description, + size = deserializeSize(node.diagnostic.size), + constraints = deserializeConstraints(node.diagnostic.constraints), + isFlex = node.diagnostic.isFlex, + flexFactor = node.diagnostic.flexFactor, children = copyLevel == 0 ? [] : node.children @@ -154,22 +152,75 @@ return '${min.toStringAsFixed(1)}<=$axis<=${max.toStringAsFixed(1)}'; } - static BoxConstraints deserializeConstraints(Map<String, Object> json) { + /// Return the string inside the parentheses + /// example: + /// getValue('BoxConstraints(value)'); # returns 'value' + static String getValue(String description) { + return description.substring( + description.indexOf('(') + 1, description.indexOf(')')); + } + + /// This method implementation is based on [BoxConstraints].toString() implementation + static BoxConstraints deserializeConstraints( + RemoteDiagnosticsNode constraints) { // TODO(albertusangga): Support SliverConstraint - if (json == null || json['type'] != boxConstraintsType.toString()) - return null; - // TODO(albertusangga): Simplify this json (i.e: when maxWidth is null it means it is unbounded) + if (constraints == null) return null; + final value = getValue(constraints.description); + if (value.contains('unconstrained')) + return const BoxConstraints( + minWidth: 0.0, + minHeight: 0.0, + maxWidth: double.infinity, + maxHeight: double.infinity, + ); + if (value.contains('biggest')) + return const BoxConstraints( + minWidth: double.infinity, + minHeight: double.infinity, + maxWidth: double.infinity, + maxHeight: double.infinity, + ); + final widthAndHeight = value.split(', '); + final width = widthAndHeight[0]; + final height = widthAndHeight[1]; + double minWidth, maxWidth, minHeight, maxHeight; + List<double> parseRangeValue(String value) { + // '0.0<=dim<=100.0' should be split as ['0.0', 'dim', '100.0'] + final split = value.split('<='); // after the split it should conta + return [double.parse(split.first), double.parse(split.last)]; + } + + if (width.startsWith('w=')) + minWidth = maxWidth = double.parse(width.substring(2)); + else { + final rangeValue = parseRangeValue(width); + minWidth = rangeValue.first; + maxWidth = rangeValue.last; + } + if (height.startsWith('h=')) + minHeight = maxHeight = double.parse(height.substring(2)); + else { + final rangeValue = parseRangeValue(height); + minHeight = rangeValue.first; + maxHeight = rangeValue.last; + } return BoxConstraints( - minWidth: json['minWidth'], - maxWidth: json['hasBoundedWidth'] ? json['maxWidth'] : double.infinity, - minHeight: json['minHeight'], - maxHeight: json['hasBoundedHeight'] ? json['maxHeight'] : double.infinity, + minWidth: minWidth, + minHeight: minHeight, + maxWidth: maxWidth, + maxHeight: maxHeight, ); } - static Size deserializeSize(Map<String, Object> json) { - if (json == null) return null; - return Size(json['width'], json['height']); + static Size deserializeSize(RemoteDiagnosticsNode size) { + if (size == null) return null; + // size.description will look like 'Size(100.0, 50.0)' + final value = getValue(size.description); // value will be '100.0, 50.0' + final split = value.split(', '); + return Size( + double.parse(split.first), + double.parse(split.last), + ); } } @@ -192,12 +243,13 @@ // Cache the properties on an expando so that local tweaks to // FlexLayoutProperties persist across multiple lookups from an // InspectorTreeNode. + return _buildNode(node); return _flexLayoutExpando[node] ??= _buildNode(node); } static FlexLayoutProperties _buildNode(InspectorTreeNode node) { final Map<String, Object> renderObjectJson = - node.diagnostic.json['renderObject']; + node.diagnostic.renderObject.json; final List<dynamic> properties = renderObjectJson['properties']; final Map<String, Object> data = Map<String, Object>.fromIterable( properties,
diff --git a/packages/devtools_app/lib/src/inspector/flutter/inspector_screen_details_tab.dart b/packages/devtools_app/lib/src/inspector/flutter/inspector_screen_details_tab.dart index 391762e..07ac47b 100644 --- a/packages/devtools_app/lib/src/inspector/flutter/inspector_screen_details_tab.dart +++ b/packages/devtools_app/lib/src/inspector/flutter/inspector_screen_details_tab.dart
@@ -34,16 +34,13 @@ @override Widget build(BuildContext context) { - final enableExperimentalStoryOfLayout = - InspectorController.enableExperimentalStoryOfLayout; final tabs = <Tab>[ _buildTab('Details Tree'), - if (enableExperimentalStoryOfLayout) _buildTab('Layout Details'), + _buildTab('Layout Details'), ]; final tabViews = <Widget>[ detailsTree, - if (enableExperimentalStoryOfLayout) - LayoutDetailsTab(controller: controller), + LayoutDetailsTab(controller: controller), ]; final focusColor = Theme.of(context).focusColor; return Container( @@ -103,7 +100,15 @@ InspectorTreeNode get selected => controller?.selectedNode; - void onSelectionChanged() { + Future<void> loadRenderObject() async { + final nearestFlex = selected.diagnostic.isFlex + ? selected.diagnostic + : selected.parent.diagnostic; + await nearestFlex.getRenderObject(); + } + + void onSelectionChanged() async { + await loadRenderObject(); setState(() {}); } @@ -111,6 +116,7 @@ void initState() { super.initState(); controller.addSelectionListener(onSelectionChanged); + loadRenderObject(); } @override
diff --git a/packages/devtools_app/lib/src/inspector/inspector_service.dart b/packages/devtools_app/lib/src/inspector/inspector_service.dart index e21aba2..b43ef94 100644 --- a/packages/devtools_app/lib/src/inspector/inspector_service.dart +++ b/packages/devtools_app/lib/src/inspector/inspector_service.dart
@@ -954,6 +954,31 @@ args, )); } + + Future<RemoteDiagnosticsNode> renderObject(InspectorInstanceRef ref) async { + // TODO(albertusangga): Make this new Service Extension in flutter/flutter + String command = ''' + final id = '${ref.id}'; + final instance = WidgetInspectorService.instance; + final Element object = WidgetInspectorService.instance.toObject(id); + final RenderObject renderObject = object.renderObject; + return instance._safeJsonEncode( + instance._nodeToJson( + renderObject.toDiagnosticsNode(), + _SerializationDelegate( + groupName: '', + service: instance, + includeProperties: true, + ), + )); + '''; + command = '((){${command.split('\n').join()})()'; + final val = await inspectorLibrary.eval( + command, + isAlive: this, + ); + return parseDiagnosticsNodeObservatory(val); + } } enum FlutterTreeType {