diff --git a/auto_route/lib/src/router/controller/navigation_history/native_navigation_history.dart b/auto_route/lib/src/router/controller/navigation_history/native_navigation_history.dart index 226fb00a..7d91af45 100644 --- a/auto_route/lib/src/router/controller/navigation_history/native_navigation_history.dart +++ b/auto_route/lib/src/router/controller/navigation_history/native_navigation_history.dart @@ -20,6 +20,12 @@ class NavigationHistoryImpl extends NavigationHistory { void onNewUrlState(UrlState newState, {bool notify = true}) { super.onNewUrlState(newState, notify: notify); if (_currentUrl == newState.url) return; + // If the previous url is the same as the new url + // then we can infer that the screen was popped and remove the last entry + if (_previousUrl == newState.url) { + _entries.removeLast(); + return; + } _addEntry(newState); } @@ -31,6 +37,10 @@ class NavigationHistoryImpl extends NavigationHistory { String get _currentUrl => _entries.lastOrNull?.url ?? ''; + String? get _previousUrl => _entries.length > 1 + ? _entries.elementAtOrNull(_entries.length - 2)?.url + : null; + void _addEntry(UrlState urlState) { if (!urlState.hasSegments) return; final route = UrlState.toHierarchy(urlState.segments); diff --git a/auto_route/lib/src/router/controller/routing_controller.dart b/auto_route/lib/src/router/controller/routing_controller.dart index 313387b7..c5d83095 100644 --- a/auto_route/lib/src/router/controller/routing_controller.dart +++ b/auto_route/lib/src/router/controller/routing_controller.dart @@ -1018,6 +1018,24 @@ abstract class StackRouter extends RoutingController { @override RouteData get current => currentChild ?? routeData; + /// Get the top [Route] of Navigator + /// Used to assess the current route and popDisposition + Route get _navigatorTopRoute { + late Route route; + popUntil((r) { + route = r; + return true; + }); + return route; + } + + /// Get the popDisposition of the top [Route] of Navigator + RoutePopDisposition get _popDisposition => _navigatorTopRoute.popDisposition; + + /// Check if current is currently visible + bool get currentVisible => + _navigatorTopRoute.settings.name == current.route.name; + @override RouteData? get currentChild { if (_pages.isNotEmpty) { @@ -1104,12 +1122,34 @@ abstract class StackRouter extends RoutingController { } } + /// If the [RoutePopDisposition] of the top-most route is [RoutePopDisposition.doNotPop] + /// this method will call maybePop instead of .back(). + /// + /// Useful with PopScope widget. + Future maybeBack() async { + final NavigatorState? navigator = _navigatorKey.currentState; + if (navigator == null) return SynchronousFuture(false); + + if (_popDisposition == RoutePopDisposition.doNotPop) { + return await navigator.maybePop(); + } + + navigationHistory.back(); + return true; + } + @override @optionalTypeArgs Future pop([T? result]) async { final NavigatorState? navigator = _navigatorKey.currentState; if (navigator == null) return SynchronousFuture(false); - if (await navigator.maybePop(result)) { + // On the web, popping will not update the navigation history + // use maybeBack when a result does not need to be returned. + // Checks isCurrent to avoid going back when dialog is open. + if (kIsWeb && currentVisible && canNavigateBack && result == null) { + maybeBack(); + return true; + } else if (await navigator.maybePop(result)) { return true; } else if (_parent != null) { return _parent!.pop(result);