Unverified Commit 37f86c31 authored by Greg Spencer's avatar Greg Spencer Committed by GitHub

Clean up some things I noticed while doing another change (#45658)

This fixes some minor things I noticed while doing another change.

- Uncomments an old test that wants to be run, but can't be, and marked it as "skipped", so that the code won't rot anymore.
- Added the focus state to the short string version of a FocusNode
- Added a missing piece of information to findAncestorWidgetOfExactType
parent 2a5e528a
......@@ -911,7 +911,12 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
@override
String toStringShort() {
return '${describeIdentity(this)}${debugLabel != null && debugLabel.isNotEmpty ? '($debugLabel)' : ''}';
final bool hasDebugLabel = debugLabel != null && debugLabel.isNotEmpty;
final String extraData = '${hasDebugLabel ? debugLabel : ''}'
'${hasFocus && hasDebugLabel ? ' ' : ''}'
'${hasFocus && !hasPrimaryFocus ? '[IN FOCUS PATH]' : ''}'
'${hasPrimaryFocus ? '[PRIMARY FOCUS]' : ''}';
return '${describeIdentity(this)}${extraData.isNotEmpty ? '($extraData)' : ''}';
}
}
......
......@@ -2044,15 +2044,15 @@ abstract class BuildContext {
/// Returns the nearest ancestor widget of the given type [T], which must be the
/// type of a concrete [Widget] subclass.
///
/// In general, [dependOnInheritedWidgetOfExactType] is more useful, since inherited
/// widgets will trigger consumers to rebuild when they change. This method is
/// appropriate when used in interaction event handlers (e.g. gesture
/// callbacks) or for performing one-off tasks such as asserting that you have
/// or don't have a widget of a specific type as an ancestor. The return value
/// of a Widget's build method should not depend on the value returned by this
/// method, because the build context will not rebuild if the return value of
/// this method changes. This could lead to a situation where data used in the
/// build method changes, but the widget is not rebuilt.
/// In general, [dependOnInheritedWidgetOfExactType] is more useful, since
/// inherited widgets will trigger consumers to rebuild when they change. This
/// method is appropriate when used in interaction event handlers (e.g.
/// gesture callbacks) or for performing one-off tasks such as asserting that
/// you have or don't have a widget of a specific type as an ancestor. The
/// return value of a Widget's build method should not depend on the value
/// returned by this method, because the build context will not rebuild if the
/// return value of this method changes. This could lead to a situation where
/// data used in the build method changes, but the widget is not rebuilt.
///
/// Calling this method is relatively expensive (O(N) in the depth of the
/// tree). Only call this method if the distance from this widget to the
......@@ -2062,6 +2062,9 @@ abstract class BuildContext {
/// because the widget tree is no longer stable at that time. To refer to
/// an ancestor from one of those methods, save a reference to the ancestor
/// by calling [findAncestorWidgetOfExactType] in [State.didChangeDependencies].
///
/// Returns null if a widget of the requested type does not appear in the
/// ancestors of this context.
T findAncestorWidgetOfExactType<T extends Widget>();
/// Returns the [State] object of the nearest ancestor [StatefulWidget] widget
......
......@@ -664,12 +664,12 @@ void main() {
description,
equalsIgnoringHashCodes(
'FocusManager#00000\n'
' │ primaryFocus: FocusNode#00000(Child 4)\n'
' │ primaryFocus: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' │ primaryFocusCreator: Container-[GlobalKey#00000] ← [root]\n'
' │\n'
' └─rootScope: FocusScopeNode#00000(Root Focus Scope)\n'
' └─rootScope: FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n'
' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusScopeNode#00000\n'
' │ focusedChildren: FocusScopeNode#00000([IN FOCUS PATH])\n'
' │\n'
' ├─Child 1: FocusScopeNode#00000(Scope 1)\n'
' │ │ context: Container-[GlobalKey#00000]\n'
......@@ -683,19 +683,19 @@ void main() {
' │ └─Child 2: FocusNode#00000\n'
' │ context: Container-[GlobalKey#00000]\n'
' │\n'
' └─Child 2: FocusScopeNode#00000\n'
' └─Child 2: FocusScopeNode#00000([IN FOCUS PATH])\n'
' │ context: Container-[GlobalKey#00000]\n'
' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusNode#00000(Child 4)\n'
' │ focusedChildren: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' │\n'
' └─Child 1: FocusNode#00000(Parent 2)\n'
' └─Child 1: FocusNode#00000(Parent 2 [IN FOCUS PATH])\n'
' │ context: Container-[GlobalKey#00000]\n'
' │ IN FOCUS PATH\n'
' │\n'
' ├─Child 1: FocusNode#00000(Child 3)\n'
' │ context: Container-[GlobalKey#00000]\n'
' │\n'
' └─Child 2: FocusNode#00000(Child 4)\n'
' └─Child 2: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' context: Container-[GlobalKey#00000]\n'
' PRIMARY FOCUS\n'
));
......
......@@ -227,12 +227,12 @@ void main() {
expect(parentFocusScope, hasAGoodToStringDeep);
expect(
parentFocusScope.toStringDeep(),
equalsIgnoringHashCodes('FocusScopeNode#00000(Parent Scope Node)\n'
equalsIgnoringHashCodes('FocusScopeNode#00000(Parent Scope Node [IN FOCUS PATH])\n'
' │ context: FocusScope\n'
' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusNode#00000(Child)\n'
' │ focusedChildren: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' │\n'
' └─Child 1: FocusNode#00000(Child)\n'
' └─Child 1: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' context: Focus\n'
' PRIMARY FOCUS\n'),
);
......@@ -240,16 +240,17 @@ void main() {
expect(FocusManager.instance.rootScope, hasAGoodToStringDeep);
expect(
FocusManager.instance.rootScope.toStringDeep(minLevel: DiagnosticLevel.info),
equalsIgnoringHashCodes('FocusScopeNode#00000(Root Focus Scope)\n'
equalsIgnoringHashCodes('FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n'
' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusScopeNode#00000(Parent Scope Node)\n'
' │ focusedChildren: FocusScopeNode#00000(Parent Scope Node [IN FOCUS\n'
' │ PATH])\n'
' │\n'
' └─Child 1: FocusScopeNode#00000(Parent Scope Node)\n'
' └─Child 1: FocusScopeNode#00000(Parent Scope Node [IN FOCUS PATH])\n'
' │ context: FocusScope\n'
' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusNode#00000(Child)\n'
' │ focusedChildren: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' │\n'
' └─Child 1: FocusNode#00000(Child)\n'
' └─Child 1: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' context: Focus\n'
' PRIMARY FOCUS\n'),
);
......
......@@ -255,42 +255,42 @@ void main() {
expect(log, equals(<String>['left']));
});
// This test doesn't work because the testing framework uses a fake version of
// the pointer event dispatch loop.
//
// TODO(abarth): Test more of the real code and enable this test.
// See https://github.com/flutter/flutter/issues/4771.
//
// testWidgets('Pending gestures are rejected', (WidgetTester tester) async {
// List<String> log = <String>[];
// final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
// '/': (BuildContext context) {
// return new Row(
// children: <Widget>[
// new GestureDetector(
// onTap: () {
// log.add('left');
// Navigator.pushNamed(context, '/second');
// },
// child: new Text('left')
// ),
// new GestureDetector(
// onTap: () { log.add('right'); },
// child: new Text('right')
// ),
// ]
// );
// },
// '/second': (BuildContext context) => new Container(),
// };
// await tester.pumpWidget(new MaterialApp(routes: routes));
// TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('right')), pointer: 23);
// expect(log, isEmpty);
// await tester.tap(find.text('left'));
// expect(log, equals(<String>['left']));
// await gesture.up();
// expect(log, equals(<String>['left']));
// });
testWidgets('Pending gestures are rejected', (WidgetTester tester) async {
final List<String> log = <String>[];
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) {
return Row(
children: <Widget>[
GestureDetector(
onTap: () {
log.add('left');
Navigator.pushNamed(context, '/second');
},
child: const Text('left')
),
GestureDetector(
onTap: () { log.add('right'); },
child: const Text('right'),
),
]
);
},
'/second': (BuildContext context) => Container(),
};
await tester.pumpWidget(MaterialApp(routes: routes));
final TestGesture gesture = await tester.startGesture(tester.getCenter(find.text('right')), pointer: 23);
expect(log, isEmpty);
await tester.tap(find.text('left'));
expect(log, equals(<String>['left']));
await gesture.up();
expect(log, equals(<String>['left']));
// This test doesn't work because it relies on part of the pointer event
// dispatching mechanism that is mocked out in testing. We should use the real
// mechanism even during testing and enable this test.
// TODO(abarth): Test more of the real code and enable this test.
// See https://github.com/flutter/flutter/issues/4771.
}, skip: true);
testWidgets('popAndPushNamed', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
......
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