Unverified Commit f98b4863 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Make debugCheckHasMaterial more useful (#14101)

Fixes https://github.com/flutter/flutter/issues/2877
parent b1248de5
...@@ -22,20 +22,45 @@ import 'material.dart'; ...@@ -22,20 +22,45 @@ import 'material.dart';
bool debugCheckHasMaterial(BuildContext context) { bool debugCheckHasMaterial(BuildContext context) {
assert(() { assert(() {
if (context.widget is! Material && context.ancestorWidgetOfExactType(Material) == null) { if (context.widget is! Material && context.ancestorWidgetOfExactType(Material) == null) {
final Element element = context; final StringBuffer message = new StringBuffer();
throw new FlutterError( message.writeln('No Material widget found.');
'No Material widget found.\n' message.writeln(
'${context.widget.runtimeType} widgets require a Material widget ancestor.\n' '${context.widget.runtimeType} widgets require a Material '
'In material design, most widgets are conceptually "printed" on a sheet of material. In Flutter\'s material library, ' 'widget ancestor.'
'that material is represented by the Material widget. It is the Material widget that renders ink splashes, for instance. '
'Because of this, many material library widgets require that there be a Material widget in the tree above them.\n'
'To introduce a Material widget, you can either directly include one, or use a widget that contains Material itself, '
'such as a Card, Dialog, Drawer, or Scaffold.\n'
'The specific widget that could not find a Material ancestor was:\n'
' ${context.widget}\n'
'The ownership chain for the affected widget is:\n'
' ${element.debugGetCreatorChain(10)}'
); );
message.writeln(
'In material design, most widgets are conceptually "printed" on '
'a sheet of material. In Flutter\'s material library, that '
'material is represented by the Material widget. It is the '
'Material widget that renders ink splashes, for instance. '
'Because of this, many material library widgets require that '
'there be a Material widget in the tree above them.'
);
message.writeln(
'To introduce a Material widget, you can either directly '
'include one, or use a widget that contains Material itself, '
'such as a Card, Dialog, Drawer, or Scaffold.'
);
message.writeln(
'The specific widget that could not find a Material ancestor was:'
);
message.writeln(' ${context.widget}');
final List<Widget> ancestors = <Widget>[];
context.visitAncestorElements((Element element) {
ancestors.add(element.widget);
return true;
});
if (ancestors.isNotEmpty) {
message.write('The ancestors of this widget were:');
for (Widget ancestor in ancestors)
message.write('\n $ancestor');
} else {
message.writeln(
'This widget is the root of the tree, so it has no '
'ancestors, let alone a "Material" ancestor.'
);
}
throw new FlutterError(message.toString());
} }
return true; return true;
}()); }());
......
...@@ -11,6 +11,8 @@ void main() { ...@@ -11,6 +11,8 @@ void main() {
onPressed: null, onPressed: null,
child: const Text('Go'), child: const Text('Go'),
)); ));
expect(tester.takeException(), isFlutterError); final dynamic exception = tester.takeException();
expect(exception, isFlutterError);
expect(exception.toString(), endsWith(':\n FlatButton(disabled)\n [root]'));
}); });
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment