diff --git a/packages/flutter/lib/src/animation/performance.dart b/packages/flutter/lib/src/animation/performance.dart index 92c77f8b59..3a4125d8fa 100644 --- a/packages/flutter/lib/src/animation/performance.dart +++ b/packages/flutter/lib/src/animation/performance.dart @@ -41,6 +41,15 @@ abstract class PerformanceView { void addStatusListener(PerformanceStatusListener listener); /// Stops calling the listener every time the status of the performance changes void removeStatusListener(PerformanceStatusListener listener); + + /// The current status of this animation + PerformanceStatus get status; + + /// Whether this animation is stopped at the beginning + bool get isDismissed => status == PerformanceStatus.dismissed; + + /// Whether this animation is stopped at the end + bool get isCompleted => status == PerformanceStatus.completed; } /// A timeline that can be reversed and used to update [Animatable]s. @@ -51,7 +60,7 @@ abstract class PerformanceView { /// may also take direct control of the timeline by manipulating [progress], or /// [fling] the timeline causing a physics-based simulation to take over the /// progression. -class Performance implements PerformanceView { +class Performance extends PerformanceView { Performance({ this.duration, double progress }) { _timeline = new SimulationStepper(_tick); if (progress != null) @@ -94,16 +103,9 @@ class Performance implements PerformanceView { return timing != null ? timing.transform(progress, _curveDirection) : progress; } - /// Whether this animation is stopped at the beginning - bool get isDismissed => status == PerformanceStatus.dismissed; - - /// Whether this animation is stopped at the end - bool get isCompleted => status == PerformanceStatus.completed; - /// Whether this animation is currently animating in either the forward or reverse direction bool get isAnimating => _timeline.isAnimating; - /// The current status of this animation PerformanceStatus get status { if (!isAnimating && progress == 1.0) return PerformanceStatus.completed; diff --git a/packages/flutter/lib/src/widgets/dialog.dart b/packages/flutter/lib/src/widgets/dialog.dart index 688f0f9174..88b44ade59 100644 --- a/packages/flutter/lib/src/widgets/dialog.dart +++ b/packages/flutter/lib/src/widgets/dialog.dart @@ -131,7 +131,7 @@ class Dialog extends StatelessComponent { } } -class _DialogRoute extends Route { +class _DialogRoute extends PerformanceRoute { _DialogRoute({ this.completer, this.builder }); final Completer completer; diff --git a/packages/flutter/lib/src/widgets/drag_target.dart b/packages/flutter/lib/src/widgets/drag_target.dart index 5d1533c270..679c2fa1d4 100644 --- a/packages/flutter/lib/src/widgets/drag_target.dart +++ b/packages/flutter/lib/src/widgets/drag_target.dart @@ -256,7 +256,6 @@ class DragRoute extends Route { bool get ephemeral => true; bool get modal => false; bool get opaque => false; - Duration get transitionDuration => const Duration(); Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) { return new Positioned( diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart index 112bf87808..909d11bbe7 100644 --- a/packages/flutter/lib/src/widgets/navigator.dart +++ b/packages/flutter/lib/src/widgets/navigator.dart @@ -71,13 +71,6 @@ class NavigatorState extends State { push(new PageRoute(builder)); } - void _insertRoute(Route route) { - _history.insert(_currentPosition, route); - route._onDismissed = _handleRouteDismissed; - route._onRemoveRoute = _handleRemoveRoute; - route.didPush(); - } - void push(Route route) { assert(!_debugCurrentlyHaveRoute(route)); setState(() { @@ -119,13 +112,18 @@ class NavigatorState extends State { return index >= 0 && index <= _currentPosition; } - void _handleRouteDismissed(Route route) { + void _didDismissRoute(Route route) { assert(_history.contains(route)); if (_history.lastIndexOf(route) <= _currentPosition) popRoute(route); } - void _handleRemoveRoute(Route route) { + void _insertRoute(Route route) { + _history.insert(_currentPosition, route); + route.didPush(this); + } + + void _removeRoute(Route route) { assert(_history.contains(route)); setState(() { _history.remove(route); @@ -165,33 +163,7 @@ class NavigatorState extends State { } - abstract class Route { - Route() { - _performance = createPerformance(); - } - - PerformanceView get performance => _performance?.view; - Performance _performance; - _RouteCallback _onDismissed; - _RouteCallback _onRemoveRoute; - - Performance createPerformance() { - Duration duration = transitionDuration; - if (duration > Duration.ZERO) { - return new Performance(duration: duration) - ..addStatusListener((PerformanceStatus status) { - if (status == PerformanceStatus.dismissed) { - if (_onDismissed != null) - _onDismissed(this); - if (_onRemoveRoute != null) - _onRemoveRoute(this); - } - }); - } - return null; - } - /// If hasContent is true, then the route represents some on-screen state. /// /// If hasContent is false, then no performance will be created, and the values of @@ -242,32 +214,69 @@ abstract class Route { /// cover the entire application surface or are in any way semi-transparent. bool get opaque => false; - /// If this is set to a non-zero [Duration], then an [Performance] - /// object, available via the performance field, will be created when the - /// route is first built, using the duration described here. - Duration get transitionDuration => Duration.ZERO; - - bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque; + PerformanceView get performance => null; + bool get isActuallyOpaque => (performance == null || performance.isCompleted) && opaque; Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance); - void didPush() { - _performance?.forward(); + NavigatorState _navigator; + + void didPush(NavigatorState navigator) { + assert(_navigator == null); + _navigator = navigator; + assert(_navigator != null); + performance?.addStatusListener(_handlePerformanceStatusChanged); } void didPop([dynamic result]) { - _performance?.reverse(); - if (performance == null && _onRemoveRoute != null) - _onRemoveRoute(this); + assert(_navigator != null); + if (performance == null) + _navigator._removeRoute(this); + } + + void _handlePerformanceStatusChanged(PerformanceStatus status) { + if (status == PerformanceStatus.dismissed) { + _navigator._didDismissRoute(this); + _navigator._removeRoute(this); + _navigator = null; + } } String toString() => '$runtimeType()'; } +abstract class PerformanceRoute extends Route { + PerformanceView get performance => _performance?.view; + Performance _performance; + + Performance createPerformance() { + Duration duration = transitionDuration; + assert(duration >= Duration.ZERO); + return new Performance(duration: duration); + } + + Duration get transitionDuration; + + bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque; + + Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance); + + void didPush(NavigatorState navigator) { + _performance = createPerformance(); + super.didPush(navigator); + _performance?.forward(); + } + + void didPop([dynamic result]) { + _performance?.reverse(); + super.didPop(result); + } +} + const Duration _kTransitionDuration = const Duration(milliseconds: 150); const Point _kTransitionStartPoint = const Point(0.0, 75.0); -class PageRoute extends Route { +class PageRoute extends PerformanceRoute { PageRoute(this.builder); final RouteBuilder builder; diff --git a/packages/flutter/lib/src/widgets/popup_menu.dart b/packages/flutter/lib/src/widgets/popup_menu.dart index e3cd1059ce..518d921a95 100644 --- a/packages/flutter/lib/src/widgets/popup_menu.dart +++ b/packages/flutter/lib/src/widgets/popup_menu.dart @@ -117,7 +117,7 @@ class MenuPosition { final double left; } -class _MenuRoute extends Route { +class _MenuRoute extends PerformanceRoute { _MenuRoute({ this.completer, this.position, this.builder, this.level }); final Completer completer; diff --git a/packages/flutter/lib/src/widgets/snack_bar.dart b/packages/flutter/lib/src/widgets/snack_bar.dart index 3db720df0f..85454960b4 100644 --- a/packages/flutter/lib/src/widgets/snack_bar.dart +++ b/packages/flutter/lib/src/widgets/snack_bar.dart @@ -97,7 +97,7 @@ class SnackBar extends StatelessComponent { } } -class _SnackBarRoute extends Route { +class _SnackBarRoute extends PerformanceRoute { _SnackBarRoute({ this.content, this.actions }); final Widget content;