Repository: flutter/flutter
File: packages/flutter/lib/src/widgets/routes.dart (Dart)

Code before:

  /// Whether this route can be popped.
  ///
  /// A route can be popped if there is at least one active route below it, or
  /// if [willHandlePopInternally] returns true.
  ///
  /// When this changes, if the route is visible, the route will
  /// rebuild, and any widgets that used [ModalRoute.of] will be
  /// notified.
  bool get canPop => 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;

  /// Whether this route should display a close button instead of a back button in the app bar.
  ///
  /// By default, this returns false, meaning a back button will be used when [impliesAppBarDismissal] is true.
  /// Subclasses can override this to return true when a close button (typically an X) should be shown instead.
  ///
  /// This is intended to be used by [AppBar] implementations to determine the appropriate leading widget.
  bool get shouldUseAppBarClose => false;

  // Internals

  final GlobalKey<_ModalScopeState<T>> _scopeKey = GlobalKey<_ModalScopeState<T>>();
  final GlobalKey _subtreeKey = GlobalKey();
  final PageStorageBucket _storageBucket = PageStorageBucket();

  // one of the builders
  late OverlayEntry _modalBarrier;
  Widget _buildModalBarrier(BuildContext context) {
    Widget barrier = buildModalBarrier();
    if (filter != null) {
      barrier = BackdropFilter(filter: filter!, child: barrier);
    }
    barrier = IgnorePointer(
      ignoring:
          !animation!
              .isForwardOrCompleted, // changedInternalState is called when animation.status updates
      child: barrier, // dismissed is possible when doing a manual pop gesture
    );
    if (semanticsDismissible && barrierDismissible) {
      // To be sorted after the _modalScope.
      barrier = Semantics(sortKey: const OrdinalSortKey(1.0), child: barrier);
    }
    return barrier;

Review comment (suggestion):
This feels redundant in combination with fullscreenDialog. Can we just use fullscreenDialog? `couldUseAppBarClose` feels like it is determining the behavior of the route content, while `fullscreenDialog` is declaring the route's identity and letting the content determine for itself how to behave.

Code after:

  /// Whether this route can be popped.
  ///
  /// A route can be popped if there is at least one active route below it, or
  /// if [willHandlePopInternally] returns true.
  ///
  /// When this changes, if the route is visible, the route will
  /// rebuild, and any widgets that used [ModalRoute.of] will be
  /// notified.
  bool get canPop => 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;

  /// {@macro flutter.widgets.RawDialogRoute.fullscreenDialog}
  // TODO(dkwingsmt): Rename `ModalRoute.fullscreenDialog` something semantically suitable for a modal.
  // https://github.com/flutter/flutter/issues/168949
  bool get fullscreenDialog => false;

  // Internals

  final GlobalKey<_ModalScopeState<T>> _scopeKey = GlobalKey<_ModalScopeState<T>>();
  final GlobalKey _subtreeKey = GlobalKey();
  final PageStorageBucket _storageBucket = PageStorageBucket();

  // one of the builders
  late OverlayEntry _modalBarrier;
  Widget _buildModalBarrier(BuildContext context) {
    Widget barrier = buildModalBarrier();
    if (filter != null) {
      barrier = BackdropFilter(filter: filter!, child: barrier);
    }
    barrier = IgnorePointer(
      ignoring:
          !animation!
              .isForwardOrCompleted, // changedInternalState is called when animation.status updates
      child: barrier, // dismissed is possible when doing a manual pop gesture
    );
    if (semanticsDismissible && barrierDismissible) {
      // To be sorted after the _modalScope.
      barrier = Semantics(sortKey: const OrdinalSortKey(1.0), child: barrier);
    }
    return barrier;
  }

  /// Build the barrier for this [ModalRoute], subclasses can override