diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 436bbec594c..4ae16d68274 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -862,6 +862,7 @@ class _AppBarState extends State { final bool hasDrawer = scaffold?.hasDrawer ?? false; final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false; + final bool canPop = parentRoute?.canPop ?? false; final bool useCloseButton = parentRoute is PageRoute && parentRoute.fullscreenDialog; final double toolbarHeight = widget.toolbarHeight ?? appBarTheme.toolbarHeight ?? kToolbarHeight; @@ -947,8 +948,9 @@ class _AppBarState extends State { onPressed: _handleDrawerButton, tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip, ); - } else if (parentRoute?.impliesAppBarDismissal ?? false) { - leading = useCloseButton ? const CloseButton() : const BackButton(); + } else { + if (!hasEndDrawer && canPop) + leading = useCloseButton ? const CloseButton() : const BackButton(); } } if (leading != null) { diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index 3297793262b..6542de82dc7 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -401,7 +401,7 @@ class DrawerControllerState extends State with SingleTickerPro if (_historyEntry == null) { final ModalRoute? route = ModalRoute.of(context); if (route != null) { - _historyEntry = LocalHistoryEntry(onRemove: _handleHistoryEntryRemoved, impliesAppBarDismissal: false); + _historyEntry = LocalHistoryEntry(onRemove: _handleHistoryEntryRemoved); route.addLocalHistoryEntry(_historyEntry!); FocusScope.of(context).setFirstFocus(_focusScopeNode); } diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index 069548b7ed0..83bcdcee9ad 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -455,21 +455,13 @@ abstract class TransitionRoute extends OverlayRoute { /// An entry in the history of a [LocalHistoryRoute]. class LocalHistoryEntry { /// Creates an entry in the history of a [LocalHistoryRoute]. - /// - /// The [impliesAppBarDismissal] defaults to true if not provided. - LocalHistoryEntry({ this.onRemove, this.impliesAppBarDismissal = true }); + LocalHistoryEntry({ this.onRemove }); /// Called when this entry is removed from the history of its associated [LocalHistoryRoute]. final VoidCallback? onRemove; LocalHistoryRoute? _owner; - /// Whether an [AppBar] in the route this entry belongs to should - /// automatically add a back button or close button. - /// - /// Defaults to true. - final bool impliesAppBarDismissal; - /// Remove this entry from the history of its associated [LocalHistoryRoute]. void remove() { _owner?.removeLocalHistoryEntry(this); @@ -490,7 +482,7 @@ class LocalHistoryEntry { /// is removed from the list and its [LocalHistoryEntry.onRemove] is called. mixin LocalHistoryRoute on Route { List? _localHistory; - int _entriesImpliesAppBarDismissal = 0; + /// Adds a local history entry to this route. /// /// When asked to pop, if this route has any local history entries, this route @@ -628,12 +620,7 @@ mixin LocalHistoryRoute on Route { _localHistory ??= []; final bool wasEmpty = _localHistory!.isEmpty; _localHistory!.add(entry); - bool internalStateChanged = false; - if (entry.impliesAppBarDismissal) { - internalStateChanged = _entriesImpliesAppBarDismissal == 0; - _entriesImpliesAppBarDismissal += 1; - } - if (wasEmpty || internalStateChanged) + if (wasEmpty) changedInternalState(); } @@ -645,15 +632,10 @@ mixin LocalHistoryRoute on Route { assert(entry != null); assert(entry._owner == this); assert(_localHistory!.contains(entry)); - bool internalStateChanged = false; - if (_localHistory!.remove(entry) && entry.impliesAppBarDismissal) { - _entriesImpliesAppBarDismissal -= 1; - internalStateChanged = _entriesImpliesAppBarDismissal == 0; - } + _localHistory!.remove(entry); entry._owner = null; entry._notifyRemoved(); - if (_localHistory!.isEmpty || internalStateChanged) { - assert(_entriesImpliesAppBarDismissal == 0); + if (_localHistory!.isEmpty) { if (SchedulerBinding.instance.schedulerPhase == SchedulerPhase.persistentCallbacks) { // The local history might be removed as a result of disposing inactive // elements during finalizeTree. The state is locked at this moment, and @@ -681,12 +663,7 @@ mixin LocalHistoryRoute on Route { assert(entry._owner == this); entry._owner = null; entry._notifyRemoved(); - bool internalStateChanged = false; - if (entry.impliesAppBarDismissal) { - _entriesImpliesAppBarDismissal -= 1; - internalStateChanged = _entriesImpliesAppBarDismissal == 0; - } - if (_localHistory!.isEmpty || internalStateChanged) + if (_localHistory!.isEmpty) changedInternalState(); return false; } @@ -720,7 +697,6 @@ class _ModalScopeStatus extends InheritedWidget { const _ModalScopeStatus({ required this.isCurrent, required this.canPop, - required this.impliesAppBarDismissal, required this.route, required super.child, }) : assert(isCurrent != null), @@ -730,14 +706,12 @@ class _ModalScopeStatus extends InheritedWidget { final bool isCurrent; final bool canPop; - final bool impliesAppBarDismissal; final Route route; @override bool updateShouldNotify(_ModalScopeStatus old) { return isCurrent != old.isCurrent || canPop != old.canPop || - impliesAppBarDismissal != old.impliesAppBarDismissal || route != old.route; } @@ -746,7 +720,6 @@ class _ModalScopeStatus extends InheritedWidget { super.debugFillProperties(description); description.add(FlagProperty('isCurrent', value: isCurrent, ifTrue: 'active', ifFalse: 'inactive')); description.add(FlagProperty('canPop', value: canPop, ifTrue: 'can pop')); - description.add(FlagProperty('impliesAppBarDismissal', value: impliesAppBarDismissal, ifTrue: 'implies app bar dismissal')); } } @@ -849,7 +822,6 @@ class _ModalScopeState extends State<_ModalScope> { route: widget.route, isCurrent: widget.route.isCurrent, // _routeSetState is called if this updates canPop: widget.route.canPop, // _routeSetState is called if this updates - impliesAppBarDismissal: widget.route.impliesAppBarDismissal, child: Offstage( offstage: widget.route.offstage, // _routeSetState is called if this updates child: PageStorage( @@ -1589,14 +1561,6 @@ abstract class ModalRoute extends TransitionRoute with LocalHistoryRoute hasActiveRouteBelow || willHandlePopInternally; - /// Whether an [AppBar] in the route should automatically add a back button or - /// close button. - /// - /// This getter returns true if there is at least one active route below it, - /// or there is at least one [LocalHistoryEntry] with `impliesAppBarDismissal` - /// set to true - bool get impliesAppBarDismissal => hasActiveRouteBelow || _entriesImpliesAppBarDismissal > 0; - // Internals final GlobalKey<_ModalScopeState> _scopeKey = GlobalKey<_ModalScopeState>(); diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart index 53a653b600c..635e17c694f 100644 --- a/packages/flutter/test/material/app_bar_test.dart +++ b/packages/flutter/test/material/app_bar_test.dart @@ -3074,44 +3074,6 @@ void main() { }); }); - // Regression test for https://github.com/flutter/flutter/issues/80256 - testWidgets('The second page should have a back button even it has a end drawer', (WidgetTester tester) async { - final Page page1 = MaterialPage( - key: const ValueKey('1'), - child: Scaffold( - key: const ValueKey('1'), - appBar: AppBar(), - endDrawer: const Drawer(), - ) - ); - final Page page2 = MaterialPage( - key: const ValueKey('2'), - child: Scaffold( - key: const ValueKey('2'), - appBar: AppBar(), - endDrawer: const Drawer(), - ) - ); - final List> pages = >[ page1, page2 ]; - await tester.pumpWidget( - MaterialApp( - home: Navigator( - pages: pages, - onPopPage: (Route route, Object? result) => false, - ), - ), - ); - - // The page2 should have a back button. - expect( - find.descendant( - of: find.byKey(const ValueKey('2')), - matching: find.byType(BackButton), - ), - findsOneWidget - ); - }); - testWidgets('AppBar.preferredHeightFor', (WidgetTester tester) async { late double preferredHeight; late Size preferredSize;