Commit 30d16e24 authored by Adam Barth's avatar Adam Barth

Separate Route and PerformanceRoute

This patch prepares us to create routes that control their performances more
closely.
parent 90d47520
...@@ -41,6 +41,15 @@ abstract class PerformanceView { ...@@ -41,6 +41,15 @@ abstract class PerformanceView {
void addStatusListener(PerformanceStatusListener listener); void addStatusListener(PerformanceStatusListener listener);
/// Stops calling the listener every time the status of the performance changes /// Stops calling the listener every time the status of the performance changes
void removeStatusListener(PerformanceStatusListener listener); 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. /// A timeline that can be reversed and used to update [Animatable]s.
...@@ -51,7 +60,7 @@ abstract class PerformanceView { ...@@ -51,7 +60,7 @@ abstract class PerformanceView {
/// may also take direct control of the timeline by manipulating [progress], or /// may also take direct control of the timeline by manipulating [progress], or
/// [fling] the timeline causing a physics-based simulation to take over the /// [fling] the timeline causing a physics-based simulation to take over the
/// progression. /// progression.
class Performance implements PerformanceView { class Performance extends PerformanceView {
Performance({ this.duration, double progress }) { Performance({ this.duration, double progress }) {
_timeline = new SimulationStepper(_tick); _timeline = new SimulationStepper(_tick);
if (progress != null) if (progress != null)
...@@ -94,16 +103,9 @@ class Performance implements PerformanceView { ...@@ -94,16 +103,9 @@ class Performance implements PerformanceView {
return timing != null ? timing.transform(progress, _curveDirection) : progress; 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 /// Whether this animation is currently animating in either the forward or reverse direction
bool get isAnimating => _timeline.isAnimating; bool get isAnimating => _timeline.isAnimating;
/// The current status of this animation
PerformanceStatus get status { PerformanceStatus get status {
if (!isAnimating && progress == 1.0) if (!isAnimating && progress == 1.0)
return PerformanceStatus.completed; return PerformanceStatus.completed;
......
...@@ -131,7 +131,7 @@ class Dialog extends StatelessComponent { ...@@ -131,7 +131,7 @@ class Dialog extends StatelessComponent {
} }
} }
class _DialogRoute extends Route { class _DialogRoute extends PerformanceRoute {
_DialogRoute({ this.completer, this.builder }); _DialogRoute({ this.completer, this.builder });
final Completer completer; final Completer completer;
......
...@@ -256,7 +256,6 @@ class DragRoute extends Route { ...@@ -256,7 +256,6 @@ class DragRoute extends Route {
bool get ephemeral => true; bool get ephemeral => true;
bool get modal => false; bool get modal => false;
bool get opaque => false; bool get opaque => false;
Duration get transitionDuration => const Duration();
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) { Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance) {
return new Positioned( return new Positioned(
......
...@@ -71,13 +71,6 @@ class NavigatorState extends State<Navigator> { ...@@ -71,13 +71,6 @@ class NavigatorState extends State<Navigator> {
push(new PageRoute(builder)); push(new PageRoute(builder));
} }
void _insertRoute(Route route) {
_history.insert(_currentPosition, route);
route._onDismissed = _handleRouteDismissed;
route._onRemoveRoute = _handleRemoveRoute;
route.didPush();
}
void push(Route route) { void push(Route route) {
assert(!_debugCurrentlyHaveRoute(route)); assert(!_debugCurrentlyHaveRoute(route));
setState(() { setState(() {
...@@ -119,13 +112,18 @@ class NavigatorState extends State<Navigator> { ...@@ -119,13 +112,18 @@ class NavigatorState extends State<Navigator> {
return index >= 0 && index <= _currentPosition; return index >= 0 && index <= _currentPosition;
} }
void _handleRouteDismissed(Route route) { void _didDismissRoute(Route route) {
assert(_history.contains(route)); assert(_history.contains(route));
if (_history.lastIndexOf(route) <= _currentPosition) if (_history.lastIndexOf(route) <= _currentPosition)
popRoute(route); 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)); assert(_history.contains(route));
setState(() { setState(() {
_history.remove(route); _history.remove(route);
...@@ -165,33 +163,7 @@ class NavigatorState extends State<Navigator> { ...@@ -165,33 +163,7 @@ class NavigatorState extends State<Navigator> {
} }
abstract class Route { 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 true, then the route represents some on-screen state.
/// ///
/// If hasContent is false, then no performance will be created, and the values of /// If hasContent is false, then no performance will be created, and the values of
...@@ -242,32 +214,69 @@ abstract class Route { ...@@ -242,32 +214,69 @@ abstract class Route {
/// cover the entire application surface or are in any way semi-transparent. /// cover the entire application surface or are in any way semi-transparent.
bool get opaque => false; bool get opaque => false;
/// If this is set to a non-zero [Duration], then an [Performance] PerformanceView get performance => null;
/// object, available via the performance field, will be created when the bool get isActuallyOpaque => (performance == null || performance.isCompleted) && opaque;
/// route is first built, using the duration described here.
Duration get transitionDuration => Duration.ZERO; Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance);
NavigatorState _navigator;
void didPush(NavigatorState navigator) {
assert(_navigator == null);
_navigator = navigator;
assert(_navigator != null);
performance?.addStatusListener(_handlePerformanceStatusChanged);
}
void didPop([dynamic result]) {
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; bool get isActuallyOpaque => (performance == null || _performance.isCompleted) && opaque;
Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance); Widget build(NavigatorState navigator, PerformanceView nextRoutePerformance);
void didPush() { void didPush(NavigatorState navigator) {
_performance = createPerformance();
super.didPush(navigator);
_performance?.forward(); _performance?.forward();
} }
void didPop([dynamic result]) { void didPop([dynamic result]) {
_performance?.reverse(); _performance?.reverse();
if (performance == null && _onRemoveRoute != null) super.didPop(result);
_onRemoveRoute(this);
} }
String toString() => '$runtimeType()';
} }
const Duration _kTransitionDuration = const Duration(milliseconds: 150); const Duration _kTransitionDuration = const Duration(milliseconds: 150);
const Point _kTransitionStartPoint = const Point(0.0, 75.0); const Point _kTransitionStartPoint = const Point(0.0, 75.0);
class PageRoute extends Route { class PageRoute extends PerformanceRoute {
PageRoute(this.builder); PageRoute(this.builder);
final RouteBuilder builder; final RouteBuilder builder;
......
...@@ -117,7 +117,7 @@ class MenuPosition { ...@@ -117,7 +117,7 @@ class MenuPosition {
final double left; final double left;
} }
class _MenuRoute extends Route { class _MenuRoute extends PerformanceRoute {
_MenuRoute({ this.completer, this.position, this.builder, this.level }); _MenuRoute({ this.completer, this.position, this.builder, this.level });
final Completer completer; final Completer completer;
......
...@@ -97,7 +97,7 @@ class SnackBar extends StatelessComponent { ...@@ -97,7 +97,7 @@ class SnackBar extends StatelessComponent {
} }
} }
class _SnackBarRoute extends Route { class _SnackBarRoute extends PerformanceRoute {
_SnackBarRoute({ this.content, this.actions }); _SnackBarRoute({ this.content, this.actions });
final Widget content; final Widget content;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment