@@ -455,13 +455,21 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
455
455
/// An entry in the history of a [LocalHistoryRoute] .
456
456
class LocalHistoryEntry {
457
457
/// Creates an entry in the history of a [LocalHistoryRoute] .
458
- LocalHistoryEntry ({ this .onRemove });
458
+ ///
459
+ /// The [impliesAppBarDismissal] defaults to true if not provided.
460
+ LocalHistoryEntry ({ this .onRemove, this .impliesAppBarDismissal = true });
459
461
460
462
/// Called when this entry is removed from the history of its associated [LocalHistoryRoute] .
461
463
final VoidCallback ? onRemove;
462
464
463
465
LocalHistoryRoute <dynamic >? _owner;
464
466
467
+ /// Whether an [AppBar] in the route this entry belongs to should
468
+ /// automatically add a back button or close button.
469
+ ///
470
+ /// Defaults to true.
471
+ final bool impliesAppBarDismissal;
472
+
465
473
/// Remove this entry from the history of its associated [LocalHistoryRoute] .
466
474
void remove () {
467
475
_owner? .removeLocalHistoryEntry (this );
@@ -482,7 +490,7 @@ class LocalHistoryEntry {
482
490
/// is removed from the list and its [LocalHistoryEntry.onRemove] is called.
483
491
mixin LocalHistoryRoute <T > on Route <T > {
484
492
List <LocalHistoryEntry >? _localHistory;
485
-
493
+ int _entriesImpliesAppBarDismissal = 0 ;
486
494
/// Adds a local history entry to this route.
487
495
///
488
496
/// When asked to pop, if this route has any local history entries, this route
@@ -620,7 +628,12 @@ mixin LocalHistoryRoute<T> on Route<T> {
620
628
_localHistory ?? = < LocalHistoryEntry > [];
621
629
final bool wasEmpty = _localHistory! .isEmpty;
622
630
_localHistory! .add (entry);
623
- if (wasEmpty)
631
+ bool internalStateChanged = false ;
632
+ if (entry.impliesAppBarDismissal) {
633
+ internalStateChanged = _entriesImpliesAppBarDismissal == 0 ;
634
+ _entriesImpliesAppBarDismissal += 1 ;
635
+ }
636
+ if (wasEmpty || internalStateChanged)
624
637
changedInternalState ();
625
638
}
626
639
@@ -632,10 +645,15 @@ mixin LocalHistoryRoute<T> on Route<T> {
632
645
assert (entry != null );
633
646
assert (entry._owner == this );
634
647
assert (_localHistory! .contains (entry));
635
- _localHistory! .remove (entry);
648
+ bool internalStateChanged = false ;
649
+ if (_localHistory! .remove (entry) && entry.impliesAppBarDismissal) {
650
+ _entriesImpliesAppBarDismissal -= 1 ;
651
+ internalStateChanged = _entriesImpliesAppBarDismissal == 0 ;
652
+ }
636
653
entry._owner = null ;
637
654
entry._notifyRemoved ();
638
- if (_localHistory! .isEmpty) {
655
+ if (_localHistory! .isEmpty || internalStateChanged) {
656
+ assert (_entriesImpliesAppBarDismissal == 0 );
639
657
if (SchedulerBinding .instance.schedulerPhase == SchedulerPhase .persistentCallbacks) {
640
658
// The local history might be removed as a result of disposing inactive
641
659
// elements during finalizeTree. The state is locked at this moment, and
@@ -663,7 +681,12 @@ mixin LocalHistoryRoute<T> on Route<T> {
663
681
assert (entry._owner == this );
664
682
entry._owner = null ;
665
683
entry._notifyRemoved ();
666
- if (_localHistory! .isEmpty)
684
+ bool internalStateChanged = false ;
685
+ if (entry.impliesAppBarDismissal) {
686
+ _entriesImpliesAppBarDismissal -= 1 ;
687
+ internalStateChanged = _entriesImpliesAppBarDismissal == 0 ;
688
+ }
689
+ if (_localHistory! .isEmpty || internalStateChanged)
667
690
changedInternalState ();
668
691
return false ;
669
692
}
@@ -697,6 +720,7 @@ class _ModalScopeStatus extends InheritedWidget {
697
720
const _ModalScopeStatus ({
698
721
required this .isCurrent,
699
722
required this .canPop,
723
+ required this .impliesAppBarDismissal,
700
724
required this .route,
701
725
required super .child,
702
726
}) : assert (isCurrent != null ),
@@ -706,12 +730,14 @@ class _ModalScopeStatus extends InheritedWidget {
706
730
707
731
final bool isCurrent;
708
732
final bool canPop;
733
+ final bool impliesAppBarDismissal;
709
734
final Route <dynamic > route;
710
735
711
736
@override
712
737
bool updateShouldNotify (_ModalScopeStatus old) {
713
738
return isCurrent != old.isCurrent ||
714
739
canPop != old.canPop ||
740
+ impliesAppBarDismissal != old.impliesAppBarDismissal ||
715
741
route != old.route;
716
742
}
717
743
@@ -720,6 +746,7 @@ class _ModalScopeStatus extends InheritedWidget {
720
746
super .debugFillProperties (description);
721
747
description.add (FlagProperty ('isCurrent' , value: isCurrent, ifTrue: 'active' , ifFalse: 'inactive' ));
722
748
description.add (FlagProperty ('canPop' , value: canPop, ifTrue: 'can pop' ));
749
+ description.add (FlagProperty ('impliesAppBarDismissal' , value: impliesAppBarDismissal, ifTrue: 'implies app bar dismissal' ));
723
750
}
724
751
}
725
752
@@ -822,6 +849,7 @@ class _ModalScopeState<T> extends State<_ModalScope<T>> {
822
849
route: widget.route,
823
850
isCurrent: widget.route.isCurrent, // _routeSetState is called if this updates
824
851
canPop: widget.route.canPop, // _routeSetState is called if this updates
852
+ impliesAppBarDismissal: widget.route.impliesAppBarDismissal,
825
853
child: Offstage (
826
854
offstage: widget.route.offstage, // _routeSetState is called if this updates
827
855
child: PageStorage (
@@ -1561,6 +1589,14 @@ abstract class ModalRoute<T> extends TransitionRoute<T> with LocalHistoryRoute<T
1561
1589
/// notified.
1562
1590
bool get canPop => hasActiveRouteBelow || willHandlePopInternally;
1563
1591
1592
+ /// Whether an [AppBar] in the route should automatically add a back button or
1593
+ /// close button.
1594
+ ///
1595
+ /// This getter returns true if there is at least one active route below it,
1596
+ /// or there is at least one [LocalHistoryEntry] with `impliesAppBarDismissal`
1597
+ /// set to true
1598
+ bool get impliesAppBarDismissal => hasActiveRouteBelow || _entriesImpliesAppBarDismissal > 0 ;
1599
+
1564
1600
// Internals
1565
1601
1566
1602
final GlobalKey <_ModalScopeState <T >> _scopeKey = GlobalKey <_ModalScopeState <T >>();
0 commit comments