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 { ...@@ -911,7 +911,12 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
@override @override
String toStringShort() { 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 { ...@@ -2044,15 +2044,15 @@ abstract class BuildContext {
/// Returns the nearest ancestor widget of the given type [T], which must be the /// Returns the nearest ancestor widget of the given type [T], which must be the
/// type of a concrete [Widget] subclass. /// type of a concrete [Widget] subclass.
/// ///
/// In general, [dependOnInheritedWidgetOfExactType] is more useful, since inherited /// In general, [dependOnInheritedWidgetOfExactType] is more useful, since
/// widgets will trigger consumers to rebuild when they change. This method is /// inherited widgets will trigger consumers to rebuild when they change. This
/// appropriate when used in interaction event handlers (e.g. gesture /// method is appropriate when used in interaction event handlers (e.g.
/// callbacks) or for performing one-off tasks such as asserting that you have /// gesture callbacks) or for performing one-off tasks such as asserting that
/// or don't have a widget of a specific type as an ancestor. The return value /// you have or don't have a widget of a specific type as an ancestor. The
/// of a Widget's build method should not depend on the value returned by this /// return value of a Widget's build method should not depend on the value
/// method, because the build context will not rebuild if the return value of /// returned by this method, because the build context will not rebuild if the
/// this method changes. This could lead to a situation where data used in the /// return value of this method changes. This could lead to a situation where
/// build method changes, but the widget is not rebuilt. /// 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 /// 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 /// tree). Only call this method if the distance from this widget to the
...@@ -2062,6 +2062,9 @@ abstract class BuildContext { ...@@ -2062,6 +2062,9 @@ abstract class BuildContext {
/// because the widget tree is no longer stable at that time. To refer to /// 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 /// an ancestor from one of those methods, save a reference to the ancestor
/// by calling [findAncestorWidgetOfExactType] in [State.didChangeDependencies]. /// 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>(); T findAncestorWidgetOfExactType<T extends Widget>();
/// Returns the [State] object of the nearest ancestor [StatefulWidget] widget /// Returns the [State] object of the nearest ancestor [StatefulWidget] widget
......
...@@ -664,12 +664,12 @@ void main() { ...@@ -664,12 +664,12 @@ void main() {
description, description,
equalsIgnoringHashCodes( equalsIgnoringHashCodes(
'FocusManager#00000\n' 'FocusManager#00000\n'
' │ primaryFocus: FocusNode#00000(Child 4)\n' ' │ primaryFocus: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' │ primaryFocusCreator: Container-[GlobalKey#00000] ← [root]\n' ' │ primaryFocusCreator: Container-[GlobalKey#00000] ← [root]\n'
' │\n' ' │\n'
' └─rootScope: FocusScopeNode#00000(Root Focus Scope)\n' ' └─rootScope: FocusScopeNode#00000(Root Focus Scope [IN FOCUS PATH])\n'
' │ IN FOCUS PATH\n' ' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusScopeNode#00000\n' ' │ focusedChildren: FocusScopeNode#00000([IN FOCUS PATH])\n'
' │\n' ' │\n'
' ├─Child 1: FocusScopeNode#00000(Scope 1)\n' ' ├─Child 1: FocusScopeNode#00000(Scope 1)\n'
' │ │ context: Container-[GlobalKey#00000]\n' ' │ │ context: Container-[GlobalKey#00000]\n'
...@@ -683,19 +683,19 @@ void main() { ...@@ -683,19 +683,19 @@ void main() {
' │ └─Child 2: FocusNode#00000\n' ' │ └─Child 2: FocusNode#00000\n'
' │ context: Container-[GlobalKey#00000]\n' ' │ context: Container-[GlobalKey#00000]\n'
' │\n' ' │\n'
' └─Child 2: FocusScopeNode#00000\n' ' └─Child 2: FocusScopeNode#00000([IN FOCUS PATH])\n'
' │ context: Container-[GlobalKey#00000]\n' ' │ context: Container-[GlobalKey#00000]\n'
' │ IN FOCUS PATH\n' ' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusNode#00000(Child 4)\n' ' │ focusedChildren: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' │\n' ' │\n'
' └─Child 1: FocusNode#00000(Parent 2)\n' ' └─Child 1: FocusNode#00000(Parent 2 [IN FOCUS PATH])\n'
' │ context: Container-[GlobalKey#00000]\n' ' │ context: Container-[GlobalKey#00000]\n'
' │ IN FOCUS PATH\n' ' │ IN FOCUS PATH\n'
' │\n' ' │\n'
' ├─Child 1: FocusNode#00000(Child 3)\n' ' ├─Child 1: FocusNode#00000(Child 3)\n'
' │ context: Container-[GlobalKey#00000]\n' ' │ context: Container-[GlobalKey#00000]\n'
' │\n' ' │\n'
' └─Child 2: FocusNode#00000(Child 4)\n' ' └─Child 2: FocusNode#00000(Child 4 [PRIMARY FOCUS])\n'
' context: Container-[GlobalKey#00000]\n' ' context: Container-[GlobalKey#00000]\n'
' PRIMARY FOCUS\n' ' PRIMARY FOCUS\n'
)); ));
......
...@@ -227,12 +227,12 @@ void main() { ...@@ -227,12 +227,12 @@ void main() {
expect(parentFocusScope, hasAGoodToStringDeep); expect(parentFocusScope, hasAGoodToStringDeep);
expect( expect(
parentFocusScope.toStringDeep(), parentFocusScope.toStringDeep(),
equalsIgnoringHashCodes('FocusScopeNode#00000(Parent Scope Node)\n' equalsIgnoringHashCodes('FocusScopeNode#00000(Parent Scope Node [IN FOCUS PATH])\n'
' │ context: FocusScope\n' ' │ context: FocusScope\n'
' │ IN FOCUS PATH\n' ' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusNode#00000(Child)\n' ' │ focusedChildren: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' │\n' ' │\n'
' └─Child 1: FocusNode#00000(Child)\n' ' └─Child 1: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' context: Focus\n' ' context: Focus\n'
' PRIMARY FOCUS\n'), ' PRIMARY FOCUS\n'),
); );
...@@ -240,16 +240,17 @@ void main() { ...@@ -240,16 +240,17 @@ void main() {
expect(FocusManager.instance.rootScope, hasAGoodToStringDeep); expect(FocusManager.instance.rootScope, hasAGoodToStringDeep);
expect( expect(
FocusManager.instance.rootScope.toStringDeep(minLevel: DiagnosticLevel.info), 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' ' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusScopeNode#00000(Parent Scope Node)\n' ' │ focusedChildren: FocusScopeNode#00000(Parent Scope Node [IN FOCUS\n'
' │ PATH])\n'
' │\n' ' │\n'
' └─Child 1: FocusScopeNode#00000(Parent Scope Node)\n' ' └─Child 1: FocusScopeNode#00000(Parent Scope Node [IN FOCUS PATH])\n'
' │ context: FocusScope\n' ' │ context: FocusScope\n'
' │ IN FOCUS PATH\n' ' │ IN FOCUS PATH\n'
' │ focusedChildren: FocusNode#00000(Child)\n' ' │ focusedChildren: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' │\n' ' │\n'
' └─Child 1: FocusNode#00000(Child)\n' ' └─Child 1: FocusNode#00000(Child [PRIMARY FOCUS])\n'
' context: Focus\n' ' context: Focus\n'
' PRIMARY FOCUS\n'), ' PRIMARY FOCUS\n'),
); );
......
...@@ -255,42 +255,42 @@ void main() { ...@@ -255,42 +255,42 @@ void main() {
expect(log, equals(<String>['left'])); expect(log, equals(<String>['left']));
}); });
// This test doesn't work because the testing framework uses a fake version of testWidgets('Pending gestures are rejected', (WidgetTester tester) async {
// the pointer event dispatch loop. 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. // TODO(abarth): Test more of the real code and enable this test.
// See https://github.com/flutter/flutter/issues/4771. // See https://github.com/flutter/flutter/issues/4771.
// }, skip: true);
// 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('popAndPushNamed', (WidgetTester tester) async { testWidgets('popAndPushNamed', (WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{ 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