Commit 5c4c1b8d authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Cleaning up minor issues (#5779)

I did a pass through some of the code cleaning minor things up.
parent 411db2d5
......@@ -28,6 +28,8 @@ class DragDownDetails {
}
/// Signature for when a pointer has contacted the screen and might begin to move.
///
/// See [DragGestureRecognizer.onDown].
typedef void GestureDragDownCallback(DragDownDetails details);
/// Details for [GestureDragStartCallback].
......@@ -44,6 +46,8 @@ class DragStartDetails {
}
/// Signature for when a pointer has contacted the screen and has begun to move.
///
/// See [DragGestureRecognizer.onStart].
typedef void GestureDragStartCallback(DragStartDetails details);
/// Details for [GestureDragUpdateCallback].
......@@ -87,6 +91,8 @@ class DragUpdateDetails {
/// Signature for when a pointer that is in contact with the screen and moving
/// has moved again.
///
/// See [DragGestureRecognizer.onUpdate].
typedef void GestureDragUpdateCallback(DragUpdateDetails details);
/// Details for [GestureDragEndCallback].
......@@ -107,10 +113,14 @@ class DragEndDetails {
///
/// The velocity at which the pointer was moving when it stopped contacting
/// the screen is available in the `details`.
///
/// See [DragGestureRecognizer.onEnd].
typedef void GestureDragEndCallback(DragEndDetails details);
/// Signature for when the pointer that previously triggered a
/// [GestureDragDownCallback] did not complete.
///
/// See [DragGestureRecognizer.onCancel].
typedef void GestureDragCancelCallback();
bool _isFlingGesture(Velocity velocity) {
......
......@@ -950,6 +950,18 @@ class PipelineOwner {
}
}
/// The object that is managing semantics for this pipeline owner, if any.
///
/// An owner is created by [addSemanticsListener] the first time a listener is
/// added.
///
/// The owner is valid for as long as there are listeners. Once the last
/// listener is removed (by calling [SemanticsOwner.removeListener] on the
/// [semanticsOwner]), the [semanticsOwner] field will revert to null, and the
/// previous owner will be disposed.
///
/// When [semanticsOwner] is null, the [PipelineOwner] skips all steps
/// relating to semantics.
SemanticsOwner get semanticsOwner => _semanticsOwner;
SemanticsOwner _semanticsOwner;
bool _debugDoingSemantics = false;
......
......@@ -33,7 +33,7 @@ enum CrossFadeState {
/// animation crops overflowing children during the animation by aligning their
/// top edge, which means that the bottom will be clipped.
class AnimatedCrossFade extends StatefulWidget {
/// Creates a cross fade animation widget.
/// Creates a cross-fade animation widget.
///
/// The [duration] of the animation is the same for all components (fade in,
/// fade out, and size), and you can pass [Interval]s instead of [Curve]s in
......@@ -54,17 +54,14 @@ class AnimatedCrossFade extends StatefulWidget {
}
/// The child that is visible when [crossFadeState] is [showFirst]. It fades
/// out when transitioning from [showFirst] to [showSecond] and fades in
/// otherwise.
/// out when transitioning from [showFirst] to [showSecond] and vice versa.
final Widget firstChild;
/// The child that is visible when [crossFadeState] is [showSecond]. It fades
/// in when transitioning from [showFirst] to [showSecond] and fades out
/// otherwise.
/// in when transitioning from [showFirst] to [showSecond] and vice versa.
final Widget secondChild;
/// This field identifies the child that will be shown when the animation has
/// completed.
/// The child that will be shown when the animation has completed.
final CrossFadeState crossFadeState;
/// The duration of the whole orchestrated animation.
......@@ -90,6 +87,16 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> {
Animation<double> _firstAnimation;
Animation<double> _secondAnimation;
@override
void initState() {
super.initState();
_controller = new AnimationController(duration: config.duration);
if (config.crossFadeState == CrossFadeState.showSecond)
_controller.value = 1.0;
_firstAnimation = _initAnimation(config.firstCurve, true);
_secondAnimation = _initAnimation(config.secondCurve, false);
}
Animation<double> _initAnimation(Curve curve, bool inverted) {
final CurvedAnimation animation = new CurvedAnimation(
parent: _controller,
......@@ -102,16 +109,6 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> {
).animate(animation) : animation;
}
@override
void initState() {
super.initState();
_controller = new AnimationController(duration: config.duration);
if (config.crossFadeState == CrossFadeState.showSecond)
_controller.value = 1.0;
_firstAnimation = _initAnimation(config.firstCurve, true);
_secondAnimation = _initAnimation(config.secondCurve, false);
}
@override
void dispose() {
_controller.dispose();
......@@ -121,7 +118,12 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> {
@override
void didUpdateConfig(AnimatedCrossFade oldConfig) {
super.didUpdateConfig(oldConfig);
if (config.duration != oldConfig.duration)
_controller.duration = config.duration;
if (config.firstCurve != oldConfig.firstCurve)
_firstAnimation = _initAnimation(config.firstCurve, true);
if (config.secondCurve != oldConfig.secondCurve)
_secondAnimation = _initAnimation(config.secondCurve, false);
if (config.crossFadeState != oldConfig.crossFadeState) {
switch (config.crossFadeState) {
case CrossFadeState.showFirst:
......@@ -132,15 +134,6 @@ class _AnimatedCrossFadeState extends State<AnimatedCrossFade> {
break;
}
}
if (config.duration != oldConfig.duration)
_controller.duration = config.duration;
if (config.firstCurve != oldConfig.firstCurve) {
_firstAnimation = _initAnimation(config.firstCurve, true);
}
if (config.secondCurve != oldConfig.secondCurve) {
_secondAnimation = _initAnimation(config.secondCurve, false);
}
}
@override
......
......@@ -134,8 +134,8 @@ class _DismissableState extends State<Dismissable> {
@override
void dispose() {
_moveController?.stop();
_resizeController?.stop();
_moveController.dispose();
_resizeController?.dispose();
super.dispose();
}
......
......@@ -2508,7 +2508,7 @@ class StatefulElement extends ComponentElement {
"inheritFromWidgetOfExactType($targetType) was called before ${_state.runtimeType}.initState() completed.\n"
"When an inherited widget changes, for example if the value of Theme.of() changes, "
"its dependent widgets are rebuilt. If the dependent widget's reference to "
"the inherited widget is in an constructor or an initState() method, "
"the inherited widget is in a constructor or an initState() method, "
"then the rebuilt dependent widget will not reflect the changes in the "
"inherited widget.\n"
"Typically references to to inherited widgets should occur in widget build() methods.\n"
......
......@@ -156,7 +156,6 @@ class Image extends StatefulWidget {
/// Whether to continue showing the old image (true), or briefly show nothing
/// (false), when the image provider changes.
// TODO(ianh): Find a better name.
final bool gaplessPlayback;
@override
......
......@@ -156,7 +156,7 @@ abstract class AnimatedWidgetBaseState<T extends ImplicitlyAnimatedWidget> exten
@override
void dispose() {
_controller.stop();
_controller.dispose();
super.dispose();
}
......
......@@ -52,83 +52,6 @@ class LayoutBuilder extends RenderObjectWidget {
// updateRenderObject is redundant with the logic in the LayoutBuilderElement below.
}
class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
_RenderLayoutBuilder({
LayoutCallback callback,
}) : _callback = callback;
LayoutCallback get callback => _callback;
LayoutCallback _callback;
set callback(LayoutCallback value) {
if (value == _callback)
return;
_callback = value;
markNeedsLayout();
}
bool _debugThrowIfNotCheckingIntrinsics() {
assert(() {
if (!RenderObject.debugCheckingIntrinsics) {
throw new FlutterError(
'LayoutBuilder does not support returning intrinsic dimensions.\n'
'Calculating the intrinsic dimensions would require running the layout callback speculatively, '
'which might mutate the live render object tree.'
);
}
return true;
});
return true;
}
@override
double computeMinIntrinsicWidth(double height) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
double computeMaxIntrinsicWidth(double height) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
double computeMinIntrinsicHeight(double width) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
double computeMaxIntrinsicHeight(double width) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
void performLayout() {
assert(callback != null);
invokeLayoutCallback(callback);
if (child != null) {
child.layout(constraints, parentUsesSize: true);
size = constraints.constrain(child.size);
} else {
size = constraints.biggest;
}
}
@override
bool hitTestChildren(HitTestResult result, { Point position }) {
return child?.hitTest(result, position: position) ?? false;
}
@override
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset);
}
}
// TODO(ianh): move this class up to just below its widget.
class _LayoutBuilderElement extends RenderObjectElement {
_LayoutBuilderElement(LayoutBuilder widget) : super(widget);
......@@ -220,6 +143,82 @@ class _LayoutBuilderElement extends RenderObjectElement {
}
}
class _RenderLayoutBuilder extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
_RenderLayoutBuilder({
LayoutCallback callback,
}) : _callback = callback;
LayoutCallback get callback => _callback;
LayoutCallback _callback;
set callback(LayoutCallback value) {
if (value == _callback)
return;
_callback = value;
markNeedsLayout();
}
bool _debugThrowIfNotCheckingIntrinsics() {
assert(() {
if (!RenderObject.debugCheckingIntrinsics) {
throw new FlutterError(
'LayoutBuilder does not support returning intrinsic dimensions.\n'
'Calculating the intrinsic dimensions would require running the layout callback speculatively, '
'which might mutate the live render object tree.'
);
}
return true;
});
return true;
}
@override
double computeMinIntrinsicWidth(double height) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
double computeMaxIntrinsicWidth(double height) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
double computeMinIntrinsicHeight(double width) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
double computeMaxIntrinsicHeight(double width) {
assert(_debugThrowIfNotCheckingIntrinsics());
return 0.0;
}
@override
void performLayout() {
assert(callback != null);
invokeLayoutCallback(callback);
if (child != null) {
child.layout(constraints, parentUsesSize: true);
size = constraints.constrain(child.size);
} else {
size = constraints.biggest;
}
}
@override
bool hitTestChildren(HitTestResult result, { Point position }) {
return child?.hitTest(result, position: position) ?? false;
}
@override
void paint(PaintingContext context, Offset offset) {
if (child != null)
context.paintChild(child, offset);
}
}
void _debugReportException(String context, dynamic exception, StackTrace stack) {
FlutterError.reportError(new FlutterErrorDetails(
exception: exception,
......
......@@ -83,7 +83,7 @@ class MimicOverlayEntry {
void dispose() {
_targetKey = null;
_curve = null;
_controller?.stop();
_controller?.dispose();
_controller = null;
_handle.stopMimic();
_handle = null;
......
......@@ -80,9 +80,10 @@ abstract class Route<T> {
/// is replaced, or if the navigator itself is disposed).
void dispose() { }
// If the route's transition can be popped via a user gesture (e.g. the iOS
// back gesture), this should return a controller object that can be used
// to control the transition animation's progress.
/// If the route's transition can be popped via a user gesture (e.g. the iOS
/// back gesture), this should return a controller object that can be used to
/// control the transition animation's progress. Otherwise, it should return
/// null.
NavigationGestureController startPopGesture(NavigatorState navigator) {
return null;
}
......@@ -158,15 +159,28 @@ class NavigatorObserver {
void didStopUserGesture() { }
}
// An interface to be implemented by the Route, allowing its transition
// animation to be controlled by a drag.
/// Interface describing an object returned by the [Route.startPopGesture]
/// method, allowing the route's transition animations to be controlled by a
/// drag or other user gesture.
abstract class NavigationGestureController {
/// Configures the NavigationGestureController and tells the given [Navigator] that
/// a gesture has started.
NavigationGestureController(this._navigator) {
// Disable Hero transitions until the gesture is complete.
_navigator.didStartUserGesture();
}
// Must be called when the gesture is done.
/// The navigator that this object is controlling.
@protected
NavigatorState get navigator => _navigator;
NavigatorState _navigator;
/// Release the resources used by this object. The object is no longer usable
/// after this method is called.
///
/// Must be called when the gesture is done.
///
/// Calling this method notifies the navigator that the gesture has completed.
void dispose() {
_navigator.didStopUserGesture();
_navigator = null;
......@@ -179,10 +193,6 @@ abstract class NavigationGestureController {
// The drag gesture has ended with a horizontal motion of
// [fractionalVelocity] as a fraction of screen width per second.
void dragEnd(double fractionalVelocity);
@protected
NavigatorState get navigator => _navigator;
NavigatorState _navigator;
}
/// Signature for the [Navigator.popUntil] predicate argument.
......@@ -363,6 +373,8 @@ class NavigatorState extends State<Navigator> {
bool _debugLocked = false; // used to prevent re-entrant calls to push, pop, and friends
/// Looks up the route with the given name using [Navigator.onGenerateRoute],
/// and then [push]es that route.
void pushNamed(String name) {
assert(!_debugLocked);
assert(name != null);
......@@ -376,6 +388,15 @@ class NavigatorState extends State<Navigator> {
push(route);
}
/// Adds the given route to the navigator's history, and transitions to it.
///
/// The new route and the previous route (if any) are notified (see
/// [Route.didPush] and [Route.didChangeNext]). If the [Navigator] has an
/// [Navigator.observer], it will be notified as well (see
/// [NavigatorObserver.didPush]).
///
/// Ongoing gestures within the current route are canceled when a new route is
/// pushed.
void push(Route<dynamic> route) {
assert(!_debugLocked);
assert(() { _debugLocked = true; return true; });
......@@ -396,6 +417,14 @@ class NavigatorState extends State<Navigator> {
_cancelActivePointers();
}
/// Replaces a route that is not currently visible with a new route.
///
/// The new route and the route below the new route (if any) are notified
/// (see [Route.didReplace] and [Route.didChangeNext]). The navigator observer
/// is not notified. The old route is disposed (see [Route.dispose]).
///
/// This can be useful in combination with [removeRouteBelow] when building a
/// non-linear user experience.
void replace({ Route<dynamic> oldRoute, Route<dynamic> newRoute }) {
assert(!_debugLocked);
assert(oldRoute != null);
......@@ -425,17 +454,29 @@ class NavigatorState extends State<Navigator> {
oldRoute._navigator = null;
});
assert(() { _debugLocked = false; return true; });
_cancelActivePointers();
}
void replaceRouteBefore({ Route<dynamic> anchorRoute, Route<dynamic> newRoute }) {
/// Replaces a route that is not currently visible with a new route.
///
/// The route to be removed is the one below the given `anchorRoute`. That
/// route must not be the first route in the history.
///
/// In every other way, this acts the same as [replace].
void replaceRouteBelow({ Route<dynamic> anchorRoute, Route<dynamic> newRoute }) {
assert(anchorRoute != null);
assert(anchorRoute._navigator == this);
assert(_history.indexOf(anchorRoute) > 0);
replace(oldRoute: _history[_history.indexOf(anchorRoute)-1], newRoute: newRoute);
}
void removeRouteBefore(Route<dynamic> anchorRoute) {
/// Removes the route below the given `anchorRoute`. The route to be removed
/// must not currently be visible. The `anchorRoute` must not be the first
/// route in the history.
///
/// The removed route is disposed (see [Route.dispose]). The route prior to
/// the removed route, if any, is notified (see [Route.didChangeNext]). The
/// navigator observer is not notified.
void removeRouteBelow(Route<dynamic> anchorRoute) {
assert(!_debugLocked);
assert(() { _debugLocked = true; return true; });
assert(anchorRoute._navigator == this);
......@@ -453,9 +494,21 @@ class NavigatorState extends State<Navigator> {
targetRoute._navigator = null;
});
assert(() { _debugLocked = false; return true; });
_cancelActivePointers();
}
/// Removes the top route in the [Navigator]'s history.
///
/// If an argument is provided, that argument will be the return value of the
/// route (see [Route.didPop]).
///
/// If there are any routes left on the history, the top remaining route is
/// notified (see [Route.didPopNext]), and the method returns true. In that
/// case, if the [Navigator] has an [Navigator.observer], it will be notified
/// as well (see [NavigatorObserver.didPop]). Otherwise, if the popped route
/// was the last route, the method returns false.
///
/// Ongoing gestures within the current route are canceled when a route is
/// popped.
bool pop([dynamic result]) {
assert(!_debugLocked);
assert(() { _debugLocked = true; return true; });
......@@ -487,6 +540,7 @@ class NavigatorState extends State<Navigator> {
return true;
}
/// Repeatedly calls [pop] until the given `predicate` returns true.
void popUntil(RoutePredicate predicate) {
while (!predicate(_history.last))
pop();
......@@ -533,8 +587,7 @@ class NavigatorState extends State<Navigator> {
}
void _cancelActivePointers() {
// This mechanism is far from perfect. See the issue below for more details:
// https://github.com/flutter/flutter/issues/4770
// TODO(abarth): This mechanism is far from perfect. See https://github.com/flutter/flutter/issues/4770
RenderAbsorbPointer absorber = _overlayKey.currentContext?.ancestorRenderObjectOfType(const TypeMatcher<RenderAbsorbPointer>());
setState(() {
absorber?.absorbing = true;
......
......@@ -109,6 +109,9 @@ abstract class TransitionRoute<T> extends OverlayRoute<T> {
Animation<double> get animation => _animation;
Animation<double> _animation;
/// The animation controller that the route uses to drive the transitions.
///
/// The animation itself is exposed by the [animation] property.
@protected
AnimationController get controller => _controller;
AnimationController _controller;
......
......@@ -780,9 +780,21 @@ class ScrollNotification extends Notification {
/// The scrollable that scrolled.
final ScrollableState scrollable;
/// The details from the underlying [DragGestureRecognizer] gesture, if the
/// notification ultimately came from a [DragGestureRecognizer.onStart]
/// handler; otherwise null.
DragStartDetails get dragStartDetails => kind == ScrollNotificationKind.started ? _details : null;
/// The details from the underlying [DragGestureRecognizer] gesture, if the
/// notification ultimately came from a [DragGestureRecognizer.onUpdate]
/// handler; otherwise null.
DragUpdateDetails get dragUpdateDetails => kind == ScrollNotificationKind.updated ? _details : null;
/// The details from the underlying [DragGestureRecognizer] gesture, if the
/// notification ultimately came from a [DragGestureRecognizer.onEnd]
/// handler; otherwise null.
DragEndDetails get dragEndDetails => kind == ScrollNotificationKind.ended ? _details : null;
final dynamic _details;
/// The number of scrollable widgets that have already received this
......
......@@ -334,6 +334,11 @@ class PositionedTransition extends AnimatedWidget {
///
/// * [PositionedTransition]
class RelativePositionedTransition extends AnimatedWidget {
/// Create an animated version of [Positioned].
///
/// Each frame, the [Positioned] widget will be configured to represent the
/// current value of the [rect] argument assuming that the stack has the given
/// [size]. Both [rect] and [size] must be non-null.
RelativePositionedTransition({
Key key,
@required Animation<Rect> rect,
......@@ -342,6 +347,8 @@ class RelativePositionedTransition extends AnimatedWidget {
}) : super(key: key, animation: rect);
/// The animation that controls the child's size and position.
///
/// See also [size].
Animation<Rect> get rect => animation;
/// The [Positioned] widget's offsets are relative to a box of this
......
......@@ -210,7 +210,7 @@ void main() {
await runNavigatorTest(
tester,
host,
() { host.removeRouteBefore(second); },
() { host.removeRouteBelow(second); },
<String>[
'first: dispose',
]
......@@ -251,7 +251,7 @@ void main() {
await runNavigatorTest(
tester,
host,
() { host.removeRouteBefore(four); },
() { host.removeRouteBelow(four); },
<String>[
'second: didChangeNext four',
'three: dispose',
......@@ -317,7 +317,7 @@ void main() {
await runNavigatorTest(
tester,
host,
() { host.replaceRouteBefore(anchorRoute: routeC, newRoute: routeB = new TestRoute('b')); },
() { host.replaceRouteBelow(anchorRoute: routeC, newRoute: routeB = new TestRoute('b')); },
<String>[
'b: install',
'b: didReplace B',
......
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