Unverified Commit 6ab2445e authored by Michael Goderbauer's avatar Michael Goderbauer Committed by GitHub

Fix Textfields in Semantics Debugger (#37158)

parent d82bca2a
......@@ -194,7 +194,42 @@ class _SemanticsClient extends ChangeNotifier {
}
}
String _getMessage(SemanticsNode node) {
class _SemanticsDebuggerPainter extends CustomPainter {
const _SemanticsDebuggerPainter(this.owner, this.generation, this.pointerPosition, this.devicePixelRatio);
final PipelineOwner owner;
final int generation;
final Offset pointerPosition; // in physical pixels
final double devicePixelRatio;
SemanticsNode get _rootSemanticsNode {
return owner.semanticsOwner?.rootSemanticsNode;
}
@override
void paint(Canvas canvas, Size size) {
final SemanticsNode rootNode = _rootSemanticsNode;
canvas.save();
canvas.scale(1.0 / devicePixelRatio, 1.0 / devicePixelRatio);
if (rootNode != null)
_paint(canvas, rootNode, _findDepth(rootNode));
if (pointerPosition != null) {
final Paint paint = Paint();
paint.color = const Color(0x7F0090FF);
canvas.drawCircle(pointerPosition, 10.0 * devicePixelRatio, paint);
}
canvas.restore();
}
@override
bool shouldRepaint(_SemanticsDebuggerPainter oldDelegate) {
return owner != oldDelegate.owner
|| generation != oldDelegate.generation
|| pointerPosition != oldDelegate.pointerPosition;
}
@visibleForTesting
String getMessage(SemanticsNode node) {
final SemanticsData data = node.getSemanticsData();
final List<String> annotations = <String>[];
......@@ -203,6 +238,10 @@ String _getMessage(SemanticsNode node) {
annotations.add(data.hasFlag(SemanticsFlag.isChecked) ? 'checked' : 'unchecked');
wantsTap = true;
}
if (data.hasFlag(SemanticsFlag.isTextField)) {
annotations.add('textfield');
wantsTap = true;
}
if (data.hasAction(SemanticsAction.tap)) {
if (!wantsTap)
......@@ -256,16 +295,10 @@ String _getMessage(SemanticsNode node) {
}
return message.trim();
}
const TextStyle _messageStyle = TextStyle(
color: Color(0xFF000000),
fontSize: 10.0,
height: 0.8,
);
}
void _paintMessage(Canvas canvas, SemanticsNode node) {
final String message = _getMessage(node);
void _paintMessage(Canvas canvas, SemanticsNode node) {
final String message = getMessage(node);
if (message.isEmpty)
return;
final Rect rect = node.rect;
......@@ -273,7 +306,11 @@ void _paintMessage(Canvas canvas, SemanticsNode node) {
canvas.clipRect(rect);
final TextPainter textPainter = TextPainter()
..text = TextSpan(
style: _messageStyle,
style: const TextStyle(
color: Color(0xFF000000),
fontSize: 10.0,
height: 0.8,
),
text: message,
)
..textDirection = TextDirection.ltr // _getMessage always returns LTR text, even if node.label is RTL
......@@ -282,9 +319,9 @@ void _paintMessage(Canvas canvas, SemanticsNode node) {
textPainter.paint(canvas, Alignment.center.inscribe(textPainter.size, rect).topLeft);
canvas.restore();
}
}
int _findDepth(SemanticsNode node) {
int _findDepth(SemanticsNode node) {
if (!node.hasChildren || node.mergeAllDescendantsIntoThisNode)
return 1;
int childrenDepth = 0;
......@@ -293,9 +330,9 @@ int _findDepth(SemanticsNode node) {
return true;
});
return childrenDepth + 1;
}
}
void _paint(Canvas canvas, SemanticsNode node, int rank) {
void _paint(Canvas canvas, SemanticsNode node, int rank) {
canvas.save();
if (node.transform != null)
canvas.transform(node.transform.storage);
......@@ -329,39 +366,5 @@ void _paint(Canvas canvas, SemanticsNode node, int rank) {
});
}
canvas.restore();
}
class _SemanticsDebuggerPainter extends CustomPainter {
const _SemanticsDebuggerPainter(this.owner, this.generation, this.pointerPosition, this.devicePixelRatio);
final PipelineOwner owner;
final int generation;
final Offset pointerPosition; // in physical pixels
final double devicePixelRatio;
SemanticsNode get _rootSemanticsNode {
return owner.semanticsOwner?.rootSemanticsNode;
}
@override
void paint(Canvas canvas, Size size) {
final SemanticsNode rootNode = _rootSemanticsNode;
canvas.save();
canvas.scale(1.0 / devicePixelRatio, 1.0 / devicePixelRatio);
if (rootNode != null)
_paint(canvas, rootNode, _findDepth(rootNode));
if (pointerPosition != null) {
final Paint paint = Paint();
paint.color = const Color(0x7F0090FF);
canvas.drawCircle(pointerPosition, 10.0 * devicePixelRatio, paint);
}
canvas.restore();
}
@override
bool shouldRepaint(_SemanticsDebuggerPainter oldDelegate) {
return owner != oldDelegate.owner
|| generation != oldDelegate.generation
|| pointerPosition != oldDelegate.pointerPosition;
}
}
......@@ -362,4 +362,113 @@ void main() {
expect(valueTop, isFalse);
expect(valueTop, isFalse);
});
testWidgets('SemanticsDebugger checkbox message', (WidgetTester tester) async {
final Key checkbox = UniqueKey();
final Key checkboxUnchecked = UniqueKey();
final Key checkboxDisabled = UniqueKey();
final Key checkboxDisabledUnchecked = UniqueKey();
final Key debugger = UniqueKey();
await tester.pumpWidget(
Directionality(
textDirection: TextDirection.ltr,
child: SemanticsDebugger(
key: debugger,
child: Material(
child: ListView(
children: <Widget>[
Semantics(
container: true,
key: checkbox,
child: Checkbox(
value: true,
onChanged: (bool _) { },
),
),
Semantics(
container: true,
key: checkboxUnchecked,
child: Checkbox(
value: false,
onChanged: (bool _) { },
),
),
Semantics(
container: true,
key: checkboxDisabled,
child: const Checkbox(
value: true,
onChanged: null,
),
),
Semantics(
container: true,
key: checkboxDisabledUnchecked,
child: const Checkbox(
value: false,
onChanged: null,
),
),
],
),
),
),
),
);
expect(
_getMessageShownInSemanticsDebugger(widgetKey: checkbox, debuggerKey: debugger, tester: tester),
'checked',
);
expect(
_getMessageShownInSemanticsDebugger(widgetKey: checkboxUnchecked, debuggerKey: debugger, tester: tester),
'unchecked',
);
expect(
_getMessageShownInSemanticsDebugger(widgetKey: checkboxDisabled, debuggerKey: debugger, tester: tester),
'checked; disabled',
);
expect(
_getMessageShownInSemanticsDebugger(widgetKey: checkboxDisabledUnchecked, debuggerKey: debugger, tester: tester),
'unchecked; disabled',
);
});
testWidgets('SemanticsDebugger textfield', (WidgetTester tester) async {
final UniqueKey textField = UniqueKey();
final UniqueKey debugger = UniqueKey();
await tester.pumpWidget(
MaterialApp(
home: SemanticsDebugger(
key: debugger,
child: Material(
child: TextField(
key: textField,
),
),
),
),
);
expect(
_getMessageShownInSemanticsDebugger(widgetKey: textField, debuggerKey: debugger, tester: tester),
'textfield',
);
});
}
String _getMessageShownInSemanticsDebugger({
@required Key widgetKey,
@required Key debuggerKey,
@required WidgetTester tester,
}) {
final CustomPaint customPaint = tester.widgetList(find.descendant(
of: find.byKey(debuggerKey),
matching: find.byType(CustomPaint),
)).first;
final dynamic semanticsDebuggerPainter = customPaint.foregroundPainter;
expect(semanticsDebuggerPainter.runtimeType.toString(), '_SemanticsDebuggerPainter');
return semanticsDebuggerPainter.getMessage(tester.renderObject(find.byKey(widgetKey)).debugSemantics);
}
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