callPlaygroundFunction method
This function is used as playground for testing.
Returns a list of visual errors in the Flutter application. Each error contains:
- nodeId: The ID of the DiagnosticsNode with the error
- description: Description of the error
- errorType: Type of the error (e.g., "Layout Overflow", "Render Issue")
Implementation
Future<RPCResponse> callPlaygroundFunction(
final Map<String, dynamic> params,
) async {
final serviceManager = devtoolsService.serviceManager;
if (!serviceManager.connectedState.value.connected) {
return RPCResponse.error('Not connected to VM service');
}
final vmService = serviceManager.service;
if (vmService == null) {
return RPCResponse.error('VM service not available');
}
final objectGroupManager = initObjectGroup(debugName: 'playground');
// final objectRef = await vmService.getObject(
// isolateId,
// 'RenderFlex#${errors.first.renderFlexId}', // The ID from RenderFlex#f8f6b
// );
final group = objectGroupManager.next;
final response = await devtoolsService.callServiceExtensionRaw(
'ext.flutter.inspector.'
'${WidgetInspectorServiceExtensions.widgetLocationIdMap.name}',
args: {
'groupName': group.groupName,
'isSummaryTree': 'false',
'withPreviews': 'true',
'fullDetails': 'true',
},
);
final objectGroupApi = inspector_service.ObjectGroup(
'visual-errors',
inspector_service.InspectorService(
dartVmDevtoolsService: devtoolsService,
),
);
final rootNodes = RemoteDiagnosticsNode(
response.json!['result'] as Map<String, Object?>,
objectGroupApi,
false,
null,
);
// one of children contains in description correct renderFlexId.
// so we need to find it and use it as rootNode.
Future<RemoteDiagnosticsNode?> findNodeWithId(
final RemoteDiagnosticsNode node,
final String id,
) async {
if (node.toString(minLevel: DiagnosticLevel.debug).contains(id)) {
return node;
}
if (!node.hasChildren) return null;
final children = await node.children ?? [];
for (final child in children) {
final found = await findNodeWithId(child, id);
if (found != null) return found;
}
return null;
}
// final rootNode = await findNodeWithId(rootNodes, errors.first.renderFlexId);
// print(jsonEncode(rootNode?.json));
// return RPCResponse.successMap({'errors': errors});
try {
// Get a new object group for this operation
final group = objectGroupManager.next;
try {
// Get the root widget tree with full details to analyze for errors
final response = await vmService.callServiceExtension(
'ext.flutter.inspector.getRootWidgetTree',
// isolateId: isolateId,
args: {
'groupName': group.groupName,
'isSummaryTree': 'true',
'withPreviews': 'true',
'fullDetails': 'false',
},
);
if (response.json == null || response.json!['result'] == null) {
await objectGroupManager.cancelNext();
return RPCResponse.error('Root widget tree not available');
}
// Parse the root node
final rootNode = RemoteDiagnosticsNode(
response.json!['result'] as Map<String, Object?>,
null, // objectGroupApi not needed for error detection
false, // not a property
null, // no parent
);
print(jsonEncode(rootNode.json));
// Find all errors in the tree
// final errors = await _findErrors(rootNode);
// Promote the group after successful operation
await objectGroupManager.promoteNext();
return RPCResponse.successMap({'errors': []});
} catch (e) {
// Cancel the group on error
await objectGroupManager.cancelNext();
rethrow;
}
} catch (e, stackTrace) {
return RPCResponse.error('Error getting visual errors: $e', stackTrace);
}
}