@@ -517,76 +517,21 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
517517 /// focus traversal policy for a widget subtree.
518518 /// * [FocusTraversalPolicy] , a class that can be extended to describe a
519519 /// traversal policy.
520- bool get canRequestFocus => _canRequestFocus && (_focusabilityListenable? .value ?? _computeAncestorsAllowFocus ());
521- bool _computeAncestorsAllowFocus () => ancestors.every (_allowDescendantsToBeFocused);
520+ bool get canRequestFocus => _canRequestFocus && ancestors.every (_allowDescendantsToBeFocused);
522521 static bool _allowDescendantsToBeFocused (FocusNode ancestor) => ancestor.descendantsAreFocusable;
523522
524523 bool _canRequestFocus;
525524 @mustCallSuper
526525 set canRequestFocus (bool value) {
527- if (value == _canRequestFocus) {
528- return ;
529- }
530- // Have to set this first before unfocusing, since it checks this to cull
531- // unfocusable, previously-focused children.
532- _canRequestFocus = value;
533- if (hasFocus && ! value) {
534- unfocus (disposition: UnfocusDisposition .previouslyFocusedChild);
535- }
536-
537- final _FocusabilityListenable ? focusabilityListenable = _focusabilityListenable;
538- if (focusabilityListenable != null && focusabilityListenable.hasListeners) {
539- final bool ancestorsAllowFocus = focusabilityListenable._ancestorsAllowFocus = _adjustListeningNodeCountForAncestors (value ? 1 : - 1 );
540- if (ancestorsAllowFocus) {
541- focusabilityListenable.notifyListeners ();
542- }
543- }
544- _manager? ._markPropertiesChanged (this );
545- }
546-
547- // The number of descendant focus nodes whose focusability must be
548- // re-evaluated, when this node's `descentantsAreFocusable` value changes.
549- // This does not include nodes with `_canRequestFocus` set to false, even when
550- // their focusability listenable has listeners.
551- int _focusabilityListeningDescendantCount = 0 ;
552-
553- /// A [ValueListenable] that notifies registered listeners when the
554- /// focusability of this [FocusNode] changes.
555- ///
556- /// The [ValueListenable] 's `value` indicates whether this [FocusNode] can
557- /// request primary focus. It's value is always consistent with the return
558- /// value of the [canRequestFocus] getter, which only returns true when the
559- /// [FocusNode] 's [canRequestFocus] setter is set to true, and all of its
560- /// ancestors in the focus tree have [FocusNode.descendantsAreFocusable] set to
561- /// true.
562- ///
563- /// Unlike listeners added to the [FocusNode] itself, which won't be notified
564- /// until focus changes are applied in microtasks, listeners added to
565- /// [focusabilityListenable] are notified immediately as the [FocusNode] 's
566- /// focusability changes.
567- ///
568- /// This can be used to monitor, for example, whether a text field is currently
569- /// disabled, or in an inactive route, thus isn't receiving user interactions,
570- /// so that text field can unsubscribe itself from system services such as
571- /// scribble and autofill when it becomes unfocusable, and re-subscribe when it
572- /// becomes focusable again.
573- ///
574- /// This [ValueListenable] is managed by this [FocusNode] . It must not be used
575- /// after the [FocusNode] itself is disposed.
576- ValueListenable <bool > get focusabilityListenable => _focusabilityListenable ?? = _FocusabilityListenable (this );
577- _FocusabilityListenable ? _focusabilityListenable;
578-
579- // Returns whether all ancestors have `descendantsAreFocusable` set to true.
580- bool _adjustListeningNodeCountForAncestors (int delta) {
581- assert (delta != 0 );
582- for (FocusNode ? node = parent; node != null ; node = node.parent) {
583- node._focusabilityListeningDescendantCount += delta;
584- assert (node._focusabilityListeningDescendantCount >= 0 );
585- if (! node.descendantsAreFocusable) {
586- return false ;
526+ if (value != _canRequestFocus) {
527+ // Have to set this first before unfocusing, since it checks this to cull
528+ // unfocusable, previously-focused children.
529+ _canRequestFocus = value;
530+ if (hasFocus && ! value) {
531+ unfocus (disposition: UnfocusDisposition .previouslyFocusedChild);
587532 }
533+ _manager? ._markPropertiesChanged (this );
588534 }
589- return true ;
590535 }
591536
592537 /// If false, will disable focus for all of this node's descendants.
@@ -629,47 +574,9 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
629574 if (! value && hasFocus) {
630575 unfocus (disposition: UnfocusDisposition .previouslyFocusedChild);
631576 }
632- _onDescendantsAreFocusableChanged (value);
633577 _manager? ._markPropertiesChanged (this );
634578 }
635579
636- void _onDescendantsAreFocusableChanged (bool newValue) {
637- assert (_focusabilityListeningDescendantCount >= 0 );
638- final int ancestorListenerAdjustment = newValue ? _focusabilityListeningDescendantCount : - _focusabilityListeningDescendantCount;
639-
640- // If there's an ancestor that disallows focus, changing the
641- // `descendantsAreFocusable` value of this node never affects the
642- // focusability of the descendants. Notify _focusabilityListenerCount
643- // listeners only when this is not the case.
644- final bool notifyChildren = ancestorListenerAdjustment != 0
645- && _adjustListeningNodeCountForAncestors (ancestorListenerAdjustment);
646- if (notifyChildren) {
647- assert (children.isNotEmpty);
648- for (final FocusNode child in children) {
649- child._notifyFocusabilityListenersInSubtree (newValue);
650- }
651- }
652- }
653-
654- void _notifyFocusabilityListenersInSubtree (bool ancestorsAllowFocus) {
655- final _FocusabilityListenable ? focusabilityListenable = _focusabilityListenable;
656- if (_canRequestFocus && focusabilityListenable != null && focusabilityListenable.hasListeners) {
657- assert (ancestorsAllowFocus == _computeAncestorsAllowFocus ());
658- assert (ancestorsAllowFocus != focusabilityListenable._ancestorsAllowFocus);
659- focusabilityListenable._ancestorsAllowFocus = ancestorsAllowFocus;
660- focusabilityListenable.notifyListeners ();
661- }
662-
663- if (_focusabilityListeningDescendantCount > 0 && descendantsAreFocusable) {
664- // Further propagate to children whose focusability is determined by this
665- // node's ancestors.
666- assert (children.isNotEmpty);
667- for (final FocusNode child in children) {
668- child._notifyFocusabilityListenersInSubtree (ancestorsAllowFocus);
669- }
670- }
671- }
672-
673580 /// If false, tells the focus traversal policy to skip over for all of this
674581 /// node's descendants for purposes of the traversal algorithm.
675582 ///
@@ -1104,8 +1011,7 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
11041011 @mustCallSuper
11051012 void _reparent (FocusNode child) {
11061013 assert (child != this , 'Tried to make a child into a parent of itself.' );
1107- final FocusNode ? oldParent = child._parent;
1108- if (oldParent == this ) {
1014+ if (child._parent == this ) {
11091015 assert (_children.contains (child), "Found a node that says it's a child, but doesn't appear in the child list." );
11101016 // The child is already a child of this parent.
11111017 return ;
@@ -1114,30 +1020,14 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
11141020 assert (! ancestors.contains (child), 'The supplied child is already an ancestor of this node. Loops are not allowed.' );
11151021 final FocusScopeNode ? oldScope = child.enclosingScope;
11161022 final bool hadFocus = child.hasFocus;
1117-
1118- final _FocusabilityListenable ? childFocusabilityListenable = child._focusabilityListenable;
1119- final int childSubtreeListenerCount = (child.descendantsAreFocusable ? child._focusabilityListeningDescendantCount : 0 )
1120- + (child._canRequestFocus && childFocusabilityListenable != null && childFocusabilityListenable.hasListeners ? 1 : 0 );
1121- // If childSubtreeListenerCount == 0, we don't care about focusability since there are no listeners.
1122- final bool childCouldFocus = childSubtreeListenerCount > 0
1123- && child._adjustListeningNodeCountForAncestors (- childSubtreeListenerCount);
1124- oldParent? ._removeChild (child, removeScopeFocus: oldScope != nearestScope);
1125-
1023+ child._parent? ._removeChild (child, removeScopeFocus: oldScope != nearestScope);
11261024 _children.add (child);
11271025 child._parent = this ;
11281026 child._ancestors = null ;
11291027 child._updateManager (_manager);
11301028 for (final FocusNode ancestor in child.ancestors) {
11311029 ancestor._descendants = null ;
11321030 }
1133-
1134- if (childSubtreeListenerCount > 0 ) {
1135- final bool childCanFocus = child._adjustListeningNodeCountForAncestors (childSubtreeListenerCount);
1136- if (childCanFocus != childCouldFocus) {
1137- child._notifyFocusabilityListenersInSubtree (childCanFocus);
1138- }
1139- }
1140-
11411031 if (hadFocus) {
11421032 // Update the focus chain for the current focus without changing it.
11431033 _manager? .primaryFocus? ._setAsFocusedChildForScope ();
@@ -1183,8 +1073,6 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
11831073
11841074 @override
11851075 void dispose () {
1186- _focusabilityListenable? .dispose ();
1187- _focusabilityListenable = null ;
11881076 // Detaching will also unfocus and clean up the manager's data structures.
11891077 _attachment? .detach ();
11901078 super .dispose ();
@@ -1383,14 +1271,6 @@ class FocusScopeNode extends FocusNode {
13831271 this .traversalEdgeBehavior = TraversalEdgeBehavior .closedLoop,
13841272 }) : super (descendantsAreFocusable: true );
13851273
1386- @override
1387- set canRequestFocus (bool value) {
1388- if (value != _canRequestFocus) {
1389- super .canRequestFocus = value;
1390- _onDescendantsAreFocusableChanged (value);
1391- }
1392- }
1393-
13941274 @override
13951275 FocusScopeNode get nearestScope => this ;
13961276
@@ -1534,42 +1414,6 @@ class FocusScopeNode extends FocusNode {
15341414 }
15351415}
15361416
1537- class _FocusabilityListenable extends ChangeNotifier implements ValueListenable <bool > {
1538- _FocusabilityListenable (this .node);
1539-
1540- final FocusNode node;
1541-
1542- @override
1543- bool get value {
1544- assert (! hasListeners || _ancestorsAllowFocus == node._computeAncestorsAllowFocus ());
1545- return node._canRequestFocus && (hasListeners ? _ancestorsAllowFocus : node._computeAncestorsAllowFocus ());
1546- }
1547-
1548- // True if all ancestors of `node` have `descentantsAreFocusable` set to
1549- // true. The value is only maintained when there are listeners, and
1550- // `node._canRequestFocus` is true.
1551- bool _ancestorsAllowFocus = true ;
1552-
1553- @override
1554- void addListener (VoidCallback listener) {
1555- final bool hadListener = hasListeners;
1556- super .addListener (listener);
1557- assert (hasListeners);
1558- if (! hadListener && node._canRequestFocus) {
1559- _ancestorsAllowFocus = node._adjustListeningNodeCountForAncestors (1 );
1560- }
1561- }
1562-
1563- @override
1564- void removeListener (VoidCallback listener) {
1565- final bool hadListener = hasListeners;
1566- super .removeListener (listener);
1567- if (node._canRequestFocus && hadListener && ! hasListeners) {
1568- _ancestorsAllowFocus = node._adjustListeningNodeCountForAncestors (- 1 );
1569- }
1570- }
1571- }
1572-
15731417/// An enum to describe which kind of focus highlight behavior to use when
15741418/// displaying focus information.
15751419enum FocusHighlightMode {
0 commit comments