| // Copyright 2019 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import 'package:flutter_test/flutter_test.dart'; |
| import 'package:flutter/material.dart'; |
| import 'package:flutter/widgets.dart'; |
| |
| void main() { |
| group(WidgetOrderFocusTraversalPolicy, () { |
| testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async { |
| final GlobalKey key1 = GlobalKey(debugLabel: '1'); |
| final GlobalKey key2 = GlobalKey(debugLabel: '2'); |
| final GlobalKey key3 = GlobalKey(debugLabel: '3'); |
| final GlobalKey key4 = GlobalKey(debugLabel: '4'); |
| final GlobalKey key5 = GlobalKey(debugLabel: '5'); |
| await tester.pumpWidget(DefaultFocusTraversal( |
| policy: WidgetOrderFocusTraversalPolicy(), |
| child: FocusScope( |
| key: key1, |
| child: Column( |
| children: <Widget>[ |
| Focus( |
| key: key2, |
| child: Container(key: key3, width: 100, height: 100), |
| ), |
| Focus( |
| key: key4, |
| child: Container(key: key5, width: 100, height: 100), |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Element firstChild = tester.element(find.byKey(key3)); |
| final Element secondChild = tester.element(find.byKey(key5)); |
| final FocusNode firstFocusNode = Focus.of(firstChild); |
| final FocusNode secondFocusNode = Focus.of(secondChild); |
| final FocusNode scope = Focus.of(firstChild).enclosingScope; |
| secondFocusNode.nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| }); |
| testWidgets('Move focus to next node.', (WidgetTester tester) async { |
| final GlobalKey key1 = GlobalKey(debugLabel: '1'); |
| final GlobalKey key2 = GlobalKey(debugLabel: '2'); |
| final GlobalKey key3 = GlobalKey(debugLabel: '3'); |
| final GlobalKey key4 = GlobalKey(debugLabel: '4'); |
| final GlobalKey key5 = GlobalKey(debugLabel: '5'); |
| final GlobalKey key6 = GlobalKey(debugLabel: '6'); |
| bool focus1; |
| bool focus2; |
| bool focus3; |
| bool focus5; |
| await tester.pumpWidget( |
| DefaultFocusTraversal( |
| policy: WidgetOrderFocusTraversalPolicy(), |
| child: FocusScope( |
| debugLabel: 'key1', |
| key: key1, |
| onFocusChange: (bool focus) => focus1 = focus, |
| child: Column( |
| children: <Widget>[ |
| FocusScope( |
| debugLabel: 'key2', |
| key: key2, |
| onFocusChange: (bool focus) => focus2 = focus, |
| child: Column( |
| children: <Widget>[ |
| Focus( |
| debugLabel: 'key3', |
| key: key3, |
| onFocusChange: (bool focus) => focus3 = focus, |
| child: Container(key: key4), |
| ), |
| Focus( |
| debugLabel: 'key5', |
| key: key5, |
| onFocusChange: (bool focus) => focus5 = focus, |
| child: Container(key: key6), |
| ), |
| ], |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final Element firstChild = tester.element(find.byKey(key4)); |
| final Element secondChild = tester.element(find.byKey(key6)); |
| final FocusNode firstFocusNode = Focus.of(firstChild); |
| final FocusNode secondFocusNode = Focus.of(secondChild); |
| final FocusNode scope = Focus.of(firstChild).enclosingScope; |
| firstFocusNode.requestFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isTrue); |
| expect(focus2, isTrue); |
| expect(focus3, isTrue); |
| expect(focus5, isNull); |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| |
| focus1 = null; |
| focus2 = null; |
| focus3 = null; |
| focus5 = null; |
| |
| Focus.of(firstChild).nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isNull); |
| expect(focus2, isNull); |
| expect(focus3, isFalse); |
| expect(focus5, isTrue); |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| |
| focus1 = null; |
| focus2 = null; |
| focus3 = null; |
| focus5 = null; |
| |
| Focus.of(firstChild).nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isNull); |
| expect(focus2, isNull); |
| expect(focus3, isTrue); |
| expect(focus5, isFalse); |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| |
| focus1 = null; |
| focus2 = null; |
| focus3 = null; |
| focus5 = null; |
| |
| // Tests that can still move back to original node. |
| Focus.of(firstChild).previousFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isNull); |
| expect(focus2, isNull); |
| expect(focus3, isFalse); |
| expect(focus5, isTrue); |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| }); |
| testWidgets('Move focus to previous node.', (WidgetTester tester) async { |
| final GlobalKey key1 = GlobalKey(debugLabel: '1'); |
| final GlobalKey key2 = GlobalKey(debugLabel: '2'); |
| final GlobalKey key3 = GlobalKey(debugLabel: '3'); |
| final GlobalKey key4 = GlobalKey(debugLabel: '4'); |
| final GlobalKey key5 = GlobalKey(debugLabel: '5'); |
| final GlobalKey key6 = GlobalKey(debugLabel: '6'); |
| await tester.pumpWidget( |
| DefaultFocusTraversal( |
| policy: WidgetOrderFocusTraversalPolicy(), |
| child: FocusScope( |
| key: key1, |
| child: Column( |
| children: <Widget>[ |
| FocusScope( |
| key: key2, |
| child: Column( |
| children: <Widget>[ |
| Focus( |
| key: key3, |
| child: Container(key: key4), |
| ), |
| Focus( |
| key: key5, |
| child: Container(key: key6), |
| ), |
| ], |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final Element firstChild = tester.element(find.byKey(key4)); |
| final Element secondChild = tester.element(find.byKey(key6)); |
| final FocusNode firstFocusNode = Focus.of(firstChild); |
| final FocusNode secondFocusNode = Focus.of(secondChild); |
| final FocusNode scope = Focus.of(firstChild).enclosingScope; |
| secondFocusNode.requestFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| |
| Focus.of(firstChild).previousFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| |
| Focus.of(firstChild).previousFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| |
| // Tests that can still move back to original node. |
| Focus.of(firstChild).nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| }); |
| }); |
| group(ReadingOrderTraversalPolicy, () { |
| testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async { |
| final GlobalKey key1 = GlobalKey(debugLabel: '1'); |
| final GlobalKey key2 = GlobalKey(debugLabel: '2'); |
| final GlobalKey key3 = GlobalKey(debugLabel: '3'); |
| final GlobalKey key4 = GlobalKey(debugLabel: '4'); |
| final GlobalKey key5 = GlobalKey(debugLabel: '5'); |
| await tester.pumpWidget(DefaultFocusTraversal( |
| policy: ReadingOrderTraversalPolicy(), |
| child: FocusScope( |
| key: key1, |
| child: Column( |
| children: <Widget>[ |
| Focus( |
| key: key2, |
| child: Container(key: key3, width: 100, height: 100), |
| ), |
| Focus( |
| key: key4, |
| child: Container(key: key5, width: 100, height: 100), |
| ), |
| ], |
| ), |
| ), |
| )); |
| |
| final Element firstChild = tester.element(find.byKey(key3)); |
| final Element secondChild = tester.element(find.byKey(key5)); |
| final FocusNode firstFocusNode = Focus.of(firstChild); |
| final FocusNode secondFocusNode = Focus.of(secondChild); |
| final FocusNode scope = Focus.of(firstChild).enclosingScope; |
| secondFocusNode.nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| }); |
| testWidgets('Move reading focus to next node.', (WidgetTester tester) async { |
| final GlobalKey key1 = GlobalKey(debugLabel: '1'); |
| final GlobalKey key2 = GlobalKey(debugLabel: '2'); |
| final GlobalKey key3 = GlobalKey(debugLabel: '3'); |
| final GlobalKey key4 = GlobalKey(debugLabel: '4'); |
| final GlobalKey key5 = GlobalKey(debugLabel: '5'); |
| final GlobalKey key6 = GlobalKey(debugLabel: '6'); |
| bool focus1; |
| bool focus2; |
| bool focus3; |
| bool focus5; |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: DefaultFocusTraversal( |
| policy: ReadingOrderTraversalPolicy(), |
| child: FocusScope( |
| debugLabel: 'key1', |
| key: key1, |
| onFocusChange: (bool focus) => focus1 = focus, |
| child: Column( |
| children: <Widget>[ |
| FocusScope( |
| debugLabel: 'key2', |
| key: key2, |
| onFocusChange: (bool focus) => focus2 = focus, |
| child: Row( |
| children: <Widget>[ |
| Focus( |
| debugLabel: 'key3', |
| key: key3, |
| onFocusChange: (bool focus) => focus3 = focus, |
| child: Container(key: key4), |
| ), |
| Focus( |
| debugLabel: 'key5', |
| key: key5, |
| onFocusChange: (bool focus) => focus5 = focus, |
| child: Container(key: key6), |
| ), |
| ], |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| void clear() { |
| focus1 = null; |
| focus2 = null; |
| focus3 = null; |
| focus5 = null; |
| } |
| |
| final Element firstChild = tester.element(find.byKey(key4)); |
| final Element secondChild = tester.element(find.byKey(key6)); |
| final FocusNode firstFocusNode = Focus.of(firstChild); |
| final FocusNode secondFocusNode = Focus.of(secondChild); |
| final FocusNode scope = Focus.of(firstChild).enclosingScope; |
| firstFocusNode.requestFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isTrue); |
| expect(focus2, isTrue); |
| expect(focus3, isTrue); |
| expect(focus5, isNull); |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| Focus.of(firstChild).nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isNull); |
| expect(focus2, isNull); |
| expect(focus3, isFalse); |
| expect(focus5, isTrue); |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| Focus.of(firstChild).nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isNull); |
| expect(focus2, isNull); |
| expect(focus3, isTrue); |
| expect(focus5, isFalse); |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| // Tests that can still move back to original node. |
| Focus.of(firstChild).previousFocus(); |
| |
| await tester.pump(); |
| |
| expect(focus1, isNull); |
| expect(focus2, isNull); |
| expect(focus3, isFalse); |
| expect(focus5, isTrue); |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| }); |
| testWidgets('Move reading focus to previous node.', (WidgetTester tester) async { |
| final GlobalKey key1 = GlobalKey(debugLabel: '1'); |
| final GlobalKey key2 = GlobalKey(debugLabel: '2'); |
| final GlobalKey key3 = GlobalKey(debugLabel: '3'); |
| final GlobalKey key4 = GlobalKey(debugLabel: '4'); |
| final GlobalKey key5 = GlobalKey(debugLabel: '5'); |
| final GlobalKey key6 = GlobalKey(debugLabel: '6'); |
| await tester.pumpWidget( |
| DefaultFocusTraversal( |
| policy: ReadingOrderTraversalPolicy(), |
| child: FocusScope( |
| key: key1, |
| child: Column( |
| children: <Widget>[ |
| FocusScope( |
| key: key2, |
| child: Column( |
| children: <Widget>[ |
| Focus( |
| key: key3, |
| child: Container(key: key4), |
| ), |
| Focus( |
| key: key5, |
| child: Container(key: key6), |
| ), |
| ], |
| ), |
| ), |
| ], |
| ), |
| ), |
| ), |
| ); |
| |
| final Element firstChild = tester.element(find.byKey(key4)); |
| final Element secondChild = tester.element(find.byKey(key6)); |
| final FocusNode firstFocusNode = Focus.of(firstChild); |
| final FocusNode secondFocusNode = Focus.of(secondChild); |
| final FocusNode scope = Focus.of(firstChild).enclosingScope; |
| secondFocusNode.requestFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| |
| Focus.of(firstChild).previousFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| |
| Focus.of(firstChild).previousFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isFalse); |
| expect(secondFocusNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| |
| // Tests that can still move back to original node. |
| Focus.of(firstChild).nextFocus(); |
| |
| await tester.pump(); |
| |
| expect(firstFocusNode.hasFocus, isTrue); |
| expect(secondFocusNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| }); |
| }); |
| group(DirectionalFocusTraversalPolicyMixin, () { |
| testWidgets('Move focus in all directions.', (WidgetTester tester) async { |
| final GlobalKey upperLeftKey = GlobalKey(debugLabel: 'upperLeftKey'); |
| final GlobalKey upperRightKey = GlobalKey(debugLabel: 'upperRightKey'); |
| final GlobalKey lowerLeftKey = GlobalKey(debugLabel: 'lowerLeftKey'); |
| final GlobalKey lowerRightKey = GlobalKey(debugLabel: 'lowerRightKey'); |
| bool focusUpperLeft; |
| bool focusUpperRight; |
| bool focusLowerLeft; |
| bool focusLowerRight; |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: DefaultFocusTraversal( |
| policy: WidgetOrderFocusTraversalPolicy(), |
| child: FocusScope( |
| debugLabel: 'Scope', |
| child: Column( |
| children: <Widget>[ |
| Row( |
| children: <Widget>[ |
| Focus( |
| debugLabel: 'upperLeft', |
| onFocusChange: (bool focus) => focusUpperLeft = focus, |
| child: Container(width: 100, height: 100, key: upperLeftKey), |
| ), |
| Focus( |
| debugLabel: 'upperRight', |
| onFocusChange: (bool focus) => focusUpperRight = focus, |
| child: Container(width: 100, height: 100, key: upperRightKey), |
| ), |
| ], |
| ), |
| Row( |
| children: <Widget>[ |
| Focus( |
| debugLabel: 'lowerLeft', |
| onFocusChange: (bool focus) => focusLowerLeft = focus, |
| child: Container(width: 100, height: 100, key: lowerLeftKey), |
| ), |
| Focus( |
| debugLabel: 'lowerRight', |
| onFocusChange: (bool focus) => focusLowerRight = focus, |
| child: Container(width: 100, height: 100, key: lowerRightKey), |
| ), |
| ], |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| void clear() { |
| focusUpperLeft = null; |
| focusUpperRight = null; |
| focusLowerLeft = null; |
| focusLowerRight = null; |
| } |
| |
| final FocusNode upperLeftNode = Focus.of(tester.element(find.byKey(upperLeftKey))); |
| final FocusNode upperRightNode = Focus.of(tester.element(find.byKey(upperRightKey))); |
| final FocusNode lowerLeftNode = Focus.of(tester.element(find.byKey(lowerLeftKey))); |
| final FocusNode lowerRightNode = Focus.of(tester.element(find.byKey(lowerRightKey))); |
| final FocusNode scope = upperLeftNode.enclosingScope; |
| upperLeftNode.requestFocus(); |
| |
| await tester.pump(); |
| |
| expect(focusUpperLeft, isTrue); |
| expect(focusUpperRight, isNull); |
| expect(focusLowerLeft, isNull); |
| expect(focusLowerRight, isNull); |
| expect(upperLeftNode.hasFocus, isTrue); |
| expect(upperRightNode.hasFocus, isFalse); |
| expect(lowerLeftNode.hasFocus, isFalse); |
| expect(lowerRightNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.right), isTrue); |
| |
| await tester.pump(); |
| |
| expect(focusUpperLeft, isFalse); |
| expect(focusUpperRight, isTrue); |
| expect(focusLowerLeft, isNull); |
| expect(focusLowerRight, isNull); |
| expect(upperLeftNode.hasFocus, isFalse); |
| expect(upperRightNode.hasFocus, isTrue); |
| expect(lowerLeftNode.hasFocus, isFalse); |
| expect(lowerRightNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.down), isTrue); |
| |
| await tester.pump(); |
| |
| expect(focusUpperLeft, isNull); |
| expect(focusUpperRight, isFalse); |
| expect(focusLowerLeft, isNull); |
| expect(focusLowerRight, isTrue); |
| expect(upperLeftNode.hasFocus, isFalse); |
| expect(upperRightNode.hasFocus, isFalse); |
| expect(lowerLeftNode.hasFocus, isFalse); |
| expect(lowerRightNode.hasFocus, isTrue); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.left), isTrue); |
| |
| await tester.pump(); |
| |
| expect(focusUpperLeft, isNull); |
| expect(focusUpperRight, isNull); |
| expect(focusLowerLeft, isTrue); |
| expect(focusLowerRight, isFalse); |
| expect(upperLeftNode.hasFocus, isFalse); |
| expect(upperRightNode.hasFocus, isFalse); |
| expect(lowerLeftNode.hasFocus, isTrue); |
| expect(lowerRightNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.up), isTrue); |
| |
| await tester.pump(); |
| |
| expect(focusUpperLeft, isTrue); |
| expect(focusUpperRight, isNull); |
| expect(focusLowerLeft, isFalse); |
| expect(focusLowerRight, isNull); |
| expect(upperLeftNode.hasFocus, isTrue); |
| expect(upperRightNode.hasFocus, isFalse); |
| expect(lowerLeftNode.hasFocus, isFalse); |
| expect(lowerRightNode.hasFocus, isFalse); |
| expect(scope.hasFocus, isTrue); |
| }); |
| testWidgets('Directional focus avoids hysterisis.', (WidgetTester tester) async { |
| final List<GlobalKey> keys = <GlobalKey>[ |
| GlobalKey(debugLabel: 'row 1:1'), |
| GlobalKey(debugLabel: 'row 2:1'), |
| GlobalKey(debugLabel: 'row 2:2'), |
| GlobalKey(debugLabel: 'row 3:1'), |
| GlobalKey(debugLabel: 'row 3:2'), |
| GlobalKey(debugLabel: 'row 3:3'), |
| ]; |
| List<bool> focus = List<bool>.generate(keys.length, (int _) => null); |
| Focus makeFocus(int index) { |
| return Focus( |
| debugLabel: keys[index].toString(), |
| onFocusChange: (bool isFocused) => focus[index] = isFocused, |
| child: Container(width: 100, height: 100, key: keys[index]), |
| ); |
| } |
| |
| /// Layout is: |
| /// keys[0] |
| /// keys[1] keys[2] |
| /// keys[3] keys[4] keys[5] |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: DefaultFocusTraversal( |
| policy: WidgetOrderFocusTraversalPolicy(), |
| child: FocusScope( |
| debugLabel: 'Scope', |
| child: Column( |
| crossAxisAlignment: CrossAxisAlignment.center, |
| children: <Widget>[ |
| Row( |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| makeFocus(0), |
| ], |
| ), |
| Row( |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| makeFocus(1), |
| makeFocus(2), |
| ], |
| ), |
| Row( |
| mainAxisAlignment: MainAxisAlignment.center, |
| children: <Widget>[ |
| makeFocus(3), |
| makeFocus(4), |
| makeFocus(5), |
| ], |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| void clear() { |
| focus = List<bool>.generate(keys.length, (int _) => null); |
| } |
| |
| final List<FocusNode> nodes = keys.map<FocusNode>((GlobalKey key) => Focus.of(tester.element(find.byKey(key)))).toList(); |
| final FocusNode scope = nodes[0].enclosingScope; |
| nodes[4].requestFocus(); |
| |
| void expectState(List<bool> states) { |
| for (int index = 0; index < states.length; ++index) { |
| expect(focus[index], states[index] == null ? isNull : (states[index] ? isTrue : isFalse)); |
| if (states[index] == null) { |
| expect(nodes[index].hasFocus, isFalse); |
| } else { |
| expect(nodes[index].hasFocus, states[index]); |
| } |
| expect(scope.hasFocus, isTrue); |
| } |
| } |
| |
| // Test to make sure that we follow the same path backwards and forwards. |
| await tester.pump(); |
| expectState(<bool>[null, null, null, null, true, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.up), isTrue); |
| await tester.pump(); |
| |
| expectState(<bool>[null, null, true, null, false, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.up), isTrue); |
| await tester.pump(); |
| |
| expectState(<bool>[true, null, false, null, null, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.down), isTrue); |
| await tester.pump(); |
| |
| expectState(<bool>[false, null, true, null, null, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.down), isTrue); |
| await tester.pump(); |
| expectState(<bool>[null, null, false, null, true, null]); |
| clear(); |
| |
| // Make sure that moving in a different axis clears the history. |
| expect(scope.focusInDirection(TraversalDirection.left), isTrue); |
| await tester.pump(); |
| expectState(<bool>[null, null, null, true, false, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.up), isTrue); |
| await tester.pump(); |
| |
| expectState(<bool>[null, true, null, false, null, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.up), isTrue); |
| await tester.pump(); |
| |
| expectState(<bool>[true, false, null, null, null, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.down), isTrue); |
| await tester.pump(); |
| |
| expectState(<bool>[false, true, null, null, null, null]); |
| clear(); |
| |
| expect(scope.focusInDirection(TraversalDirection.down), isTrue); |
| await tester.pump(); |
| expectState(<bool>[null, false, null, true, null, null]); |
| clear(); |
| }); |
| testWidgets('Can find first focus in all directions.', (WidgetTester tester) async { |
| final GlobalKey upperLeftKey = GlobalKey(debugLabel: 'upperLeftKey'); |
| final GlobalKey upperRightKey = GlobalKey(debugLabel: 'upperRightKey'); |
| final GlobalKey lowerLeftKey = GlobalKey(debugLabel: 'lowerLeftKey'); |
| |
| await tester.pumpWidget( |
| Directionality( |
| textDirection: TextDirection.ltr, |
| child: DefaultFocusTraversal( |
| policy: WidgetOrderFocusTraversalPolicy(), |
| child: FocusScope( |
| debugLabel: 'scope', |
| child: Column( |
| children: <Widget>[ |
| Row( |
| children: <Widget>[ |
| Focus( |
| debugLabel: 'upperLeft', |
| child: Container(width: 100, height: 100, key: upperLeftKey), |
| ), |
| Focus( |
| debugLabel: 'upperRight', |
| child: Container(width: 100, height: 100, key: upperRightKey), |
| ), |
| ], |
| ), |
| Row( |
| children: <Widget>[ |
| Focus( |
| debugLabel: 'lowerLeft', |
| child: Container(width: 100, height: 100, key: lowerLeftKey), |
| ), |
| Focus( |
| debugLabel: 'lowerRight', |
| child: Container(width: 100, height: 100), |
| ), |
| ], |
| ), |
| ], |
| ), |
| ), |
| ), |
| ), |
| ); |
| |
| final FocusNode upperLeftNode = Focus.of(tester.element(find.byKey(upperLeftKey))); |
| final FocusNode upperRightNode = Focus.of(tester.element(find.byKey(upperRightKey))); |
| final FocusNode lowerLeftNode = Focus.of(tester.element(find.byKey(lowerLeftKey))); |
| final FocusNode scope = upperLeftNode.enclosingScope; |
| |
| await tester.pump(); |
| |
| final FocusTraversalPolicy policy = DefaultFocusTraversal.of(upperLeftKey.currentContext); |
| |
| expect(policy.findFirstFocusInDirection(scope, TraversalDirection.up), equals(lowerLeftNode)); |
| expect(policy.findFirstFocusInDirection(scope, TraversalDirection.down), equals(upperLeftNode)); |
| expect(policy.findFirstFocusInDirection(scope, TraversalDirection.left), equals(upperRightNode)); |
| expect(policy.findFirstFocusInDirection(scope, TraversalDirection.right), equals(upperLeftNode)); |
| }); |
| }); |
| } |