Merge NNBD branch into master (#270)

This commit is contained in:
Michael Goderbauer
2021-01-27 12:55:35 -08:00
committed by GitHub
parent 1c7d23bdbe
commit f3e92fded0
23 changed files with 449 additions and 732 deletions

View File

@ -7,6 +7,9 @@ task:
upgrade_script: upgrade_script:
- flutter channel master - flutter channel master
- flutter upgrade - flutter upgrade
# TODO(goderbauer): Remove next two lines when https://github.com/flutter/flutter/issues/74772 is resolved.
- rm -rf /home/cirrus/sdks/flutter/bin/cache
- flutter doctor
- git fetch origin master - git fetch origin master
activate_script: pub global activate flutter_plugin_tools activate_script: pub global activate flutter_plugin_tools
matrix: matrix:

View File

@ -2,6 +2,10 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [2.0.0-nullsafety.0] - November 16, 2020
* Migrates to null safety.
## [1.1.2] - July 28, 2020 ## [1.1.2] - July 28, 2020
* Fixes for upcoming changes to the flutter framework. * Fixes for upcoming changes to the flutter framework.

View File

@ -50,7 +50,7 @@ class _OpenContainerTransformDemoState
extends State<OpenContainerTransformDemo> { extends State<OpenContainerTransformDemo> {
ContainerTransitionType _transitionType = ContainerTransitionType.fade; ContainerTransitionType _transitionType = ContainerTransitionType.fade;
void _showMarkedAsDoneSnackbar(bool isMarkedAsDone) { void _showMarkedAsDoneSnackbar(bool? isMarkedAsDone) {
if (isMarkedAsDone ?? false) if (isMarkedAsDone ?? false)
ScaffoldMessenger.of(context).showSnackBar(const SnackBar( ScaffoldMessenger.of(context).showSnackBar(const SnackBar(
content: Text('Marked as done!'), content: Text('Marked as done!'),
@ -271,14 +271,14 @@ class _OpenContainerTransformDemoState
class _OpenContainerWrapper extends StatelessWidget { class _OpenContainerWrapper extends StatelessWidget {
const _OpenContainerWrapper({ const _OpenContainerWrapper({
this.closedBuilder, required this.closedBuilder,
this.transitionType, required this.transitionType,
this.onClosed, required this.onClosed,
}); });
final OpenContainerBuilder closedBuilder; final CloseContainerBuilder closedBuilder;
final ContainerTransitionType transitionType; final ContainerTransitionType transitionType;
final ClosedCallback<bool> onClosed; final ClosedCallback<bool?> onClosed;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -295,7 +295,7 @@ class _OpenContainerWrapper extends StatelessWidget {
} }
class _ExampleCard extends StatelessWidget { class _ExampleCard extends StatelessWidget {
const _ExampleCard({this.openContainer}); const _ExampleCard({required this.openContainer});
final VoidCallback openContainer; final VoidCallback openContainer;
@ -333,7 +333,7 @@ class _ExampleCard extends StatelessWidget {
'adipiscing elit, sed do eiusmod tempor.', 'adipiscing elit, sed do eiusmod tempor.',
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodyText2 .bodyText2!
.copyWith(color: Colors.black54), .copyWith(color: Colors.black54),
), ),
), ),
@ -345,8 +345,8 @@ class _ExampleCard extends StatelessWidget {
class _SmallerCard extends StatelessWidget { class _SmallerCard extends StatelessWidget {
const _SmallerCard({ const _SmallerCard({
this.openContainer, required this.openContainer,
this.subtitle, required this.subtitle,
}); });
final VoidCallback openContainer; final VoidCallback openContainer;
@ -397,7 +397,7 @@ class _SmallerCard extends StatelessWidget {
} }
class _ExampleSingleTile extends StatelessWidget { class _ExampleSingleTile extends StatelessWidget {
const _ExampleSingleTile({this.openContainer}); const _ExampleSingleTile({required this.openContainer});
final VoidCallback openContainer; final VoidCallback openContainer;
@ -454,10 +454,10 @@ class _InkWellOverlay extends StatelessWidget {
this.child, this.child,
}); });
final VoidCallback openContainer; final VoidCallback? openContainer;
final double width; final double? width;
final double height; final double? height;
final Widget child; final Widget? child;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -510,7 +510,7 @@ class _DetailsPage extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Text( Text(
'Title', 'Title',
style: Theme.of(context).textTheme.headline5.copyWith( style: Theme.of(context).textTheme.headline5!.copyWith(
color: Colors.black54, color: Colors.black54,
fontSize: 30.0, fontSize: 30.0,
), ),
@ -518,7 +518,7 @@ class _DetailsPage extends StatelessWidget {
const SizedBox(height: 10), const SizedBox(height: 10),
Text( Text(
_loremIpsumParagraph, _loremIpsumParagraph,
style: Theme.of(context).textTheme.bodyText2.copyWith( style: Theme.of(context).textTheme.bodyText2!.copyWith(
color: Colors.black54, color: Colors.black54,
height: 1.5, height: 1.5,
fontSize: 16.0, fontSize: 16.0,

View File

@ -14,7 +14,7 @@ class FadeScaleTransitionDemo extends StatefulWidget {
class _FadeScaleTransitionDemoState extends State<FadeScaleTransitionDemo> class _FadeScaleTransitionDemoState extends State<FadeScaleTransitionDemo>
with SingleTickerProviderStateMixin { with SingleTickerProviderStateMixin {
AnimationController _controller; late AnimationController _controller;
@override @override
void initState() { void initState() {
@ -48,8 +48,6 @@ class _FadeScaleTransitionDemoState extends State<FadeScaleTransitionDemo>
case AnimationStatus.dismissed: case AnimationStatus.dismissed:
return false; return false;
} }
assert(false);
return null;
} }
@override @override
@ -58,7 +56,7 @@ class _FadeScaleTransitionDemoState extends State<FadeScaleTransitionDemo>
appBar: AppBar(title: const Text('Fade')), appBar: AppBar(title: const Text('Fade')),
floatingActionButton: AnimatedBuilder( floatingActionButton: AnimatedBuilder(
animation: _controller, animation: _controller,
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
return FadeScaleTransition( return FadeScaleTransition(
animation: _controller, animation: _controller,
child: child, child: child,

View File

@ -126,11 +126,11 @@ class _TransitionsHomePageState extends State<_TransitionsHomePage> {
class _TransitionListTile extends StatelessWidget { class _TransitionListTile extends StatelessWidget {
const _TransitionListTile({ const _TransitionListTile({
this.onTap, this.onTap,
this.title, required this.title,
this.subtitle, required this.subtitle,
}); });
final GestureTapCallback onTap; final GestureTapCallback? onTap;
final String title; final String title;
final String subtitle; final String subtitle;

View File

@ -14,11 +14,11 @@ class SharedAxisTransitionDemo extends StatefulWidget {
} }
class _SharedAxisTransitionDemoState extends State<SharedAxisTransitionDemo> { class _SharedAxisTransitionDemoState extends State<SharedAxisTransitionDemo> {
SharedAxisTransitionType _transitionType = SharedAxisTransitionType? _transitionType =
SharedAxisTransitionType.horizontal; SharedAxisTransitionType.horizontal;
bool _isLoggedIn = false; bool _isLoggedIn = false;
void _updateTransitionType(SharedAxisTransitionType newType) { void _updateTransitionType(SharedAxisTransitionType? newType) {
setState(() { setState(() {
_transitionType = newType; _transitionType = newType;
}); });
@ -51,7 +51,7 @@ class _SharedAxisTransitionDemoState extends State<SharedAxisTransitionDemo> {
child: child, child: child,
animation: animation, animation: animation,
secondaryAnimation: secondaryAnimation, secondaryAnimation: secondaryAnimation,
transitionType: _transitionType, transitionType: _transitionType!,
); );
}, },
child: _isLoggedIn ? _CoursePage() : _SignInPage(), child: _isLoggedIn ? _CoursePage() : _SignInPage(),
@ -80,7 +80,7 @@ class _SharedAxisTransitionDemoState extends State<SharedAxisTransitionDemo> {
Radio<SharedAxisTransitionType>( Radio<SharedAxisTransitionType>(
value: SharedAxisTransitionType.horizontal, value: SharedAxisTransitionType.horizontal,
groupValue: _transitionType, groupValue: _transitionType,
onChanged: (SharedAxisTransitionType newValue) { onChanged: (SharedAxisTransitionType? newValue) {
_updateTransitionType(newValue); _updateTransitionType(newValue);
}, },
), ),
@ -88,7 +88,7 @@ class _SharedAxisTransitionDemoState extends State<SharedAxisTransitionDemo> {
Radio<SharedAxisTransitionType>( Radio<SharedAxisTransitionType>(
value: SharedAxisTransitionType.vertical, value: SharedAxisTransitionType.vertical,
groupValue: _transitionType, groupValue: _transitionType,
onChanged: (SharedAxisTransitionType newValue) { onChanged: (SharedAxisTransitionType? newValue) {
_updateTransitionType(newValue); _updateTransitionType(newValue);
}, },
), ),
@ -96,7 +96,7 @@ class _SharedAxisTransitionDemoState extends State<SharedAxisTransitionDemo> {
Radio<SharedAxisTransitionType>( Radio<SharedAxisTransitionType>(
value: SharedAxisTransitionType.scaled, value: SharedAxisTransitionType.scaled,
groupValue: _transitionType, groupValue: _transitionType,
onChanged: (SharedAxisTransitionType newValue) { onChanged: (SharedAxisTransitionType? newValue) {
_updateTransitionType(newValue); _updateTransitionType(newValue);
}, },
), ),
@ -146,7 +146,7 @@ class _CoursePage extends StatelessWidget {
class _CourseSwitch extends StatefulWidget { class _CourseSwitch extends StatefulWidget {
const _CourseSwitch({ const _CourseSwitch({
this.course, required this.course,
}); });
final String course; final String course;

View File

@ -6,7 +6,7 @@ publish_to: none
version: 0.0.1 version: 0.0.1
environment: environment:
sdk: ">=2.3.0 <3.0.0" sdk: ">=2.12.0-0 <3.0.0"
dependencies: dependencies:
animations: animations:

View File

@ -1,203 +0,0 @@
// Copyright 2020 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO(shihaohong): Remove DualTransitionBuilder once flutter/flutter's `stable`
// branch contains DualTransitionBuilder.
import 'package:flutter/widgets.dart';
/// Builder callback used by [DualTransitionBuilder].
///
/// The builder is expected to return a transition powered by the provided
/// `animation` and wrapping the provided `child`.
///
/// The `animation` provided to the builder always runs forward from 0.0 to 1.0.
typedef TransitionBuilder = Widget Function(
BuildContext context,
Animation<double> animation,
Widget child,
);
/// A transition builder that animates its [child] based on the
/// [AnimationStatus] of the provided [animation].
///
/// This widget can be used to specify different enter and exit transitions for
/// a [child].
///
/// While the [animation] runs forward, the [child] is animated according to
/// [forwardBuilder] and while the [animation] is running in reverse, it is
/// animated according to [reverseBuilder].
///
/// Using this builder allows the widget tree to maintain its shape by nesting
/// the enter and exit transitions. This ensures that no state information of
/// any descendant widget is lost when the transition starts or completes.
class DualTransitionBuilder extends StatefulWidget {
/// Creates a [DualTransitionBuilder].
///
/// The [animation], [forwardBuilder], and [reverseBuilder] arguments are
/// required and must not be null.
const DualTransitionBuilder({
Key key,
@required this.animation,
@required this.forwardBuilder,
@required this.reverseBuilder,
this.child,
}) : assert(animation != null),
assert(forwardBuilder != null),
assert(reverseBuilder != null),
super(key: key);
/// The animation that drives the [child]'s transition.
///
/// When this animation runs forward, the [child] transitions as specified by
/// [forwardBuilder]. When it runs in reverse, the child transitions according
/// to [reverseBuilder].
final Animation<double> animation;
/// A builder for the transition that makes [child] appear on screen.
///
/// The [child] should be fully visible when the provided `animation` reaches
/// 1.0.
///
/// The `animation` provided to this builder is running forward from 0.0 to
/// 1.0 when [animation] runs _forward_. When [animation] runs in reverse,
/// the given `animation` is set to [kAlwaysCompleteAnimation].
///
/// See also:
///
/// * [reverseBuilder], which builds the transition for making the [child]
/// disappear from the screen.
final TransitionBuilder forwardBuilder;
/// A builder for a transition that makes [child] disappear from the screen.
///
/// The [child] should be fully invisible when the provided `animation`
/// reaches 1.0.
///
/// The `animation` provided to this builder is running forward from 0.0 to
/// 1.0 when [animation] runs in _reverse_. When [animation] runs forward,
/// the given `animation` is set to [kAlwaysDismissedAnimation].
///
/// See also:
///
/// * [forwardBuilder], which builds the transition for making the [child]
/// appear on screen.
final TransitionBuilder reverseBuilder;
/// The widget below this [DualTransitionBuilder] in the tree.
///
/// This child widget will be wrapped by the transitions built by
/// [forwardBuilder] and [reverseBuilder].
final Widget child;
@override
State<DualTransitionBuilder> createState() => _DualTransitionBuilderState();
}
class _DualTransitionBuilderState extends State<DualTransitionBuilder> {
AnimationStatus _effectiveAnimationStatus;
final ProxyAnimation _forwardAnimation = ProxyAnimation();
final ProxyAnimation _reverseAnimation = ProxyAnimation();
@override
void initState() {
super.initState();
_effectiveAnimationStatus = widget.animation.status;
widget.animation.addStatusListener(_animationListener);
_updateAnimations();
}
void _animationListener(AnimationStatus animationStatus) {
final AnimationStatus oldEffective = _effectiveAnimationStatus;
_effectiveAnimationStatus = _calculateEffectiveAnimationStatus(
lastEffective: _effectiveAnimationStatus,
current: animationStatus,
);
if (oldEffective != _effectiveAnimationStatus) {
_updateAnimations();
}
}
@override
void didUpdateWidget(DualTransitionBuilder oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.animation != widget.animation) {
oldWidget.animation.removeStatusListener(_animationListener);
widget.animation.addStatusListener(_animationListener);
_animationListener(widget.animation.status);
}
}
// When a transition is interrupted midway we just want to play the ongoing
// animation in reverse. Switching to the actual reverse transition would
// yield a disjoint experience since the forward and reverse transitions are
// very different.
AnimationStatus _calculateEffectiveAnimationStatus({
@required AnimationStatus lastEffective,
@required AnimationStatus current,
}) {
assert(current != null);
assert(lastEffective != null);
switch (current) {
case AnimationStatus.dismissed:
case AnimationStatus.completed:
return current;
case AnimationStatus.forward:
switch (lastEffective) {
case AnimationStatus.dismissed:
case AnimationStatus.completed:
case AnimationStatus.forward:
return current;
case AnimationStatus.reverse:
return lastEffective;
}
break;
case AnimationStatus.reverse:
switch (lastEffective) {
case AnimationStatus.dismissed:
case AnimationStatus.completed:
case AnimationStatus.reverse:
return current;
case AnimationStatus.forward:
return lastEffective;
}
break;
}
return null; // unreachable
}
void _updateAnimations() {
switch (_effectiveAnimationStatus) {
case AnimationStatus.dismissed:
case AnimationStatus.forward:
_forwardAnimation.parent = widget.animation;
_reverseAnimation.parent = kAlwaysDismissedAnimation;
break;
case AnimationStatus.reverse:
case AnimationStatus.completed:
_forwardAnimation.parent = kAlwaysCompleteAnimation;
_reverseAnimation.parent = ReverseAnimation(widget.animation);
break;
}
}
@override
void dispose() {
widget.animation.removeStatusListener(_animationListener);
super.dispose();
}
@override
Widget build(BuildContext context) {
return widget.forwardBuilder(
context,
_forwardAnimation,
widget.reverseBuilder(
context,
_reverseAnimation,
widget.child,
),
);
}
}

View File

@ -2,14 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/material.dart' import 'package:flutter/material.dart';
hide decelerateEasing; // ignore: undefined_hidden_name import 'package:flutter/widgets.dart';
// TODO(goderbauer): Remove implementation import when material properly exports the file.
import 'package:flutter/src/material/curves.dart'; // ignore: implementation_imports
// TODO(shihaohong): Remove DualTransitionBuilder once flutter/flutter's `stable`
// branch contains DualTransitionBuilder.
import 'dual_transition_builder.dart' as dual_transition_builder;
import 'modal.dart'; import 'modal.dart';
/// The modal transition configuration for a Material fade transition. /// The modal transition configuration for a Material fade transition.
@ -121,11 +116,10 @@ class FadeScaleTransition extends StatelessWidget {
/// [animation] is typically an [AnimationController] that drives the transition /// [animation] is typically an [AnimationController] that drives the transition
/// animation. [animation] cannot be null. /// animation. [animation] cannot be null.
const FadeScaleTransition({ const FadeScaleTransition({
Key key, Key? key,
@required this.animation, required this.animation,
this.child, this.child,
}) : assert(animation != null), }) : super(key: key);
super(key: key);
/// The animation that drives the [child]'s entrance and exit. /// The animation that drives the [child]'s entrance and exit.
/// ///
@ -139,7 +133,7 @@ class FadeScaleTransition extends StatelessWidget {
/// ///
/// This widget will transition in and out as driven by [animation] and /// This widget will transition in and out as driven by [animation] and
/// [secondaryAnimation]. /// [secondaryAnimation].
final Widget child; final Widget? child;
static final Animatable<double> _fadeInTransition = CurveTween( static final Animatable<double> _fadeInTransition = CurveTween(
curve: const Interval(0.0, 0.3), curve: const Interval(0.0, 0.3),
@ -155,12 +149,12 @@ class FadeScaleTransition extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return dual_transition_builder.DualTransitionBuilder( return DualTransitionBuilder(
animation: animation, animation: animation,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return FadeTransition( return FadeTransition(
opacity: _fadeInTransition.animate(animation), opacity: _fadeInTransition.animate(animation),
@ -173,7 +167,7 @@ class FadeScaleTransition extends StatelessWidget {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return FadeTransition( return FadeTransition(
opacity: _fadeOutTransition.animate(animation), opacity: _fadeOutTransition.animate(animation),

View File

@ -3,10 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
// TODO(shihaohong): Remove DualTransitionBuilder once flutter/flutter's `stable`
// branch contains DualTransitionBuilder.
import 'dual_transition_builder.dart' as dual_transition_builder;
/// Used by [PageTransitionsTheme] to define a page route transition animation /// Used by [PageTransitionsTheme] to define a page route transition animation
/// in which the outgoing page fades out, then the incoming page fades in and /// in which the outgoing page fades out, then the incoming page fades in and
@ -69,12 +66,12 @@ class FadeThroughPageTransitionsBuilder extends PageTransitionsBuilder {
/// The color to use for the background color during the transition. /// The color to use for the background color during the transition.
/// ///
/// This defaults to the [Theme]'s [ThemeData.canvasColor]. /// This defaults to the [Theme]'s [ThemeData.canvasColor].
final Color fillColor; final Color? fillColor;
@override @override
Widget buildTransitions<T>( Widget buildTransitions<T>(
PageRoute<T> route, PageRoute<T>? route,
BuildContext context, BuildContext? context,
Animation<double> animation, Animation<double> animation,
Animation<double> secondaryAnimation, Animation<double> secondaryAnimation,
Widget child, Widget child,
@ -166,12 +163,11 @@ class FadeThroughTransition extends StatelessWidget {
/// The [animation] and [secondaryAnimation] argument are required and must /// The [animation] and [secondaryAnimation] argument are required and must
/// not be null. /// not be null.
const FadeThroughTransition({ const FadeThroughTransition({
@required this.animation, required this.animation,
@required this.secondaryAnimation, required this.secondaryAnimation,
this.fillColor, this.fillColor,
this.child, this.child,
}) : assert(animation != null), });
assert(secondaryAnimation != null);
/// The animation that drives the [child]'s entrance and exit. /// The animation that drives the [child]'s entrance and exit.
/// ///
@ -193,13 +189,13 @@ class FadeThroughTransition extends StatelessWidget {
/// The color to use for the background color during the transition. /// The color to use for the background color during the transition.
/// ///
/// This defaults to the [Theme]'s [ThemeData.canvasColor]. /// This defaults to the [Theme]'s [ThemeData.canvasColor].
final Color fillColor; final Color? fillColor;
/// The widget below this widget in the tree. /// The widget below this widget in the tree.
/// ///
/// This widget will transition in and out as driven by [animation] and /// This widget will transition in and out as driven by [animation] and
/// [secondaryAnimation]. /// [secondaryAnimation].
final Widget child; final Widget? child;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -217,20 +213,20 @@ class FadeThroughTransition extends StatelessWidget {
} }
class _ZoomedFadeInFadeOut extends StatelessWidget { class _ZoomedFadeInFadeOut extends StatelessWidget {
const _ZoomedFadeInFadeOut({Key key, this.animation, this.child}) const _ZoomedFadeInFadeOut({Key? key, required this.animation, this.child})
: super(key: key); : super(key: key);
final Animation<double> animation; final Animation<double> animation;
final Widget child; final Widget? child;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return dual_transition_builder.DualTransitionBuilder( return DualTransitionBuilder(
animation: animation, animation: animation,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return _ZoomedFadeIn( return _ZoomedFadeIn(
animation: animation, animation: animation,
@ -240,7 +236,7 @@ class _ZoomedFadeInFadeOut extends StatelessWidget {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return _FadeOut( return _FadeOut(
child: child, child: child,
@ -255,10 +251,10 @@ class _ZoomedFadeInFadeOut extends StatelessWidget {
class _ZoomedFadeIn extends StatelessWidget { class _ZoomedFadeIn extends StatelessWidget {
const _ZoomedFadeIn({ const _ZoomedFadeIn({
this.child, this.child,
this.animation, required this.animation,
}); });
final Widget child; final Widget? child;
final Animation<double> animation; final Animation<double> animation;
static final CurveTween _inCurve = CurveTween( static final CurveTween _inCurve = CurveTween(
@ -304,10 +300,10 @@ class _ZoomedFadeIn extends StatelessWidget {
class _FadeOut extends StatelessWidget { class _FadeOut extends StatelessWidget {
const _FadeOut({ const _FadeOut({
this.child, this.child,
this.animation, required this.animation,
}); });
final Widget child; final Widget? child;
final Animation<double> animation; final Animation<double> animation;
static final CurveTween _outCurve = CurveTween( static final CurveTween _outCurve = CurveTween(

View File

@ -46,15 +46,13 @@ typedef _ModalTransitionBuilder = Widget Function(
/// ///
/// * [ModalConfiguration], which is the configuration object used to define /// * [ModalConfiguration], which is the configuration object used to define
/// the modal's characteristics. /// the modal's characteristics.
Future<T> showModal<T>({ Future<T?> showModal<T>({
@required BuildContext context, required BuildContext context,
ModalConfiguration configuration = const FadeScaleTransitionConfiguration(), ModalConfiguration configuration = const FadeScaleTransitionConfiguration(),
bool useRootNavigator = true, bool useRootNavigator = true,
WidgetBuilder builder, required WidgetBuilder builder,
}) { }) {
assert(configuration != null); String? barrierLabel = configuration.barrierLabel;
assert(useRootNavigator != null);
String barrierLabel = configuration.barrierLabel;
// Avoid looking up [MaterialLocalizations.of(context).modalBarrierDismissLabel] // Avoid looking up [MaterialLocalizations.of(context).modalBarrierDismissLabel]
// if there is no dismissible barrier. // if there is no dismissible barrier.
if (configuration.barrierDismissible && configuration.barrierLabel == null) { if (configuration.barrierDismissible && configuration.barrierLabel == null) {
@ -89,22 +87,21 @@ class _ModalRoute<T> extends PopupRoute<T> {
this.barrierColor, this.barrierColor,
this.barrierDismissible = true, this.barrierDismissible = true,
this.barrierLabel, this.barrierLabel,
this.transitionDuration, required this.transitionDuration,
this.reverseTransitionDuration, required this.reverseTransitionDuration,
_ModalTransitionBuilder transitionBuilder, required _ModalTransitionBuilder transitionBuilder,
@required this.builder, required this.builder,
}) : assert(barrierDismissible != null), }) : assert(!barrierDismissible || barrierLabel != null),
assert(!barrierDismissible || barrierLabel != null),
_transitionBuilder = transitionBuilder; _transitionBuilder = transitionBuilder;
@override @override
final Color barrierColor; final Color? barrierColor;
@override @override
final bool barrierDismissible; final bool barrierDismissible;
@override @override
final String barrierLabel; final String? barrierLabel;
@override @override
final Duration transitionDuration; final Duration transitionDuration;
@ -129,7 +126,7 @@ class _ModalRoute<T> extends PopupRoute<T> {
child: Builder( child: Builder(
builder: (BuildContext context) { builder: (BuildContext context) {
final Widget child = Builder(builder: builder); final Widget child = Builder(builder: builder);
return theme != null ? Theme(data: theme, child: child) : child; return Theme(data: theme, child: child);
}, },
), ),
), ),
@ -178,16 +175,12 @@ abstract class ModalConfiguration {
/// application. [transitionDuration] and [reverseTransitionDuration] /// application. [transitionDuration] and [reverseTransitionDuration]
/// cannot be null. /// cannot be null.
const ModalConfiguration({ const ModalConfiguration({
@required this.barrierColor, required this.barrierColor,
@required this.barrierDismissible, required this.barrierDismissible,
this.barrierLabel, this.barrierLabel,
@required this.transitionDuration, required this.transitionDuration,
@required this.reverseTransitionDuration, required this.reverseTransitionDuration,
}) : assert(barrierColor != null), }) : assert(!barrierDismissible || barrierLabel != null);
assert(barrierDismissible != null),
assert(!barrierDismissible || barrierLabel != null),
assert(transitionDuration != null),
assert(reverseTransitionDuration != null);
/// The color to use for the modal barrier. If this is null, the barrier will /// The color to use for the modal barrier. If this is null, the barrier will
/// be transparent. /// be transparent.
@ -197,7 +190,7 @@ abstract class ModalConfiguration {
final bool barrierDismissible; final bool barrierDismissible;
/// The semantic label used for a dismissible barrier. /// The semantic label used for a dismissible barrier.
final String barrierLabel; final String? barrierLabel;
/// The duration of the transition running forwards. /// The duration of the transition running forwards.
final Duration transitionDuration; final Duration transitionDuration;

View File

@ -9,7 +9,7 @@ import 'package:flutter/scheduler.dart';
/// ///
/// Parameter `returnValue` is the value which will be provided to [OpenContainer.onClosed] /// Parameter `returnValue` is the value which will be provided to [OpenContainer.onClosed]
/// when `action` is called. /// when `action` is called.
typedef CloseContainerActionCallback<S> = void Function({S returnValue}); typedef CloseContainerActionCallback<S> = void Function({S? returnValue});
/// Signature for a function that creates a [Widget] in open state within an /// Signature for a function that creates a [Widget] in open state within an
/// [OpenContainer]. /// [OpenContainer].
@ -74,13 +74,13 @@ typedef ClosedCallback<S> = void Function(S data);
/// * [Transitions with animated containers](https://material.io/design/motion/choreography.html#transformation) /// * [Transitions with animated containers](https://material.io/design/motion/choreography.html#transformation)
/// in the Material spec. /// in the Material spec.
@optionalTypeArgs @optionalTypeArgs
class OpenContainer<T extends Object> extends StatefulWidget { class OpenContainer<T extends Object?> extends StatefulWidget {
/// Creates an [OpenContainer]. /// Creates an [OpenContainer].
/// ///
/// All arguments except for [key] must not be null. The arguments /// All arguments except for [key] must not be null. The arguments
/// [openBuilder] and [closedBuilder] are required. /// [openBuilder] and [closedBuilder] are required.
const OpenContainer({ const OpenContainer({
Key key, Key? key,
this.closedColor = Colors.white, this.closedColor = Colors.white,
this.openColor = Colors.white, this.openColor = Colors.white,
this.middleColor, this.middleColor,
@ -91,25 +91,14 @@ class OpenContainer<T extends Object> extends StatefulWidget {
), ),
this.openShape = const RoundedRectangleBorder(), this.openShape = const RoundedRectangleBorder(),
this.onClosed, this.onClosed,
@required this.closedBuilder, required this.closedBuilder,
@required this.openBuilder, required this.openBuilder,
this.tappable = true, this.tappable = true,
this.transitionDuration = const Duration(milliseconds: 300), this.transitionDuration = const Duration(milliseconds: 300),
this.transitionType = ContainerTransitionType.fade, this.transitionType = ContainerTransitionType.fade,
this.useRootNavigator = false, this.useRootNavigator = false,
this.routeSettings, this.routeSettings,
}) : assert(closedColor != null), }) : super(key: key);
assert(openColor != null),
assert(closedElevation != null),
assert(openElevation != null),
assert(closedShape != null),
assert(openShape != null),
assert(closedBuilder != null),
assert(openBuilder != null),
assert(tappable != null),
assert(transitionType != null),
assert(useRootNavigator != null),
super(key: key);
/// Background color of the container while it is closed. /// Background color of the container while it is closed.
/// ///
@ -147,7 +136,7 @@ class OpenContainer<T extends Object> extends StatefulWidget {
/// See also: /// See also:
/// ///
/// * [Material.color], which is used to implement this property. /// * [Material.color], which is used to implement this property.
final Color middleColor; final Color? middleColor;
/// Elevation of the container while it is closed. /// Elevation of the container while it is closed.
/// ///
@ -208,7 +197,7 @@ class OpenContainer<T extends Object> extends StatefulWidget {
/// ///
/// If no value is returned via [Navigator.pop] or [OpenContainer.openBuilder.action], /// If no value is returned via [Navigator.pop] or [OpenContainer.openBuilder.action],
/// `null` will be returned by default. /// `null` will be returned by default.
final ClosedCallback<T> onClosed; final ClosedCallback<T?>? onClosed;
/// Called to obtain the child for the container in the closed state. /// Called to obtain the child for the container in the closed state.
/// ///
@ -259,13 +248,13 @@ class OpenContainer<T extends Object> extends StatefulWidget {
final bool useRootNavigator; final bool useRootNavigator;
/// Provides additional data to the [openBuilder] route pushed by the Navigator. /// Provides additional data to the [openBuilder] route pushed by the Navigator.
final RouteSettings routeSettings; final RouteSettings? routeSettings;
@override @override
_OpenContainerState<T> createState() => _OpenContainerState<T>(); _OpenContainerState<T> createState() => _OpenContainerState<T>();
} }
class _OpenContainerState<T> extends State<OpenContainer<T>> { class _OpenContainerState<T> extends State<OpenContainer<T?>> {
// Key used in [_OpenContainerRoute] to hide the widget returned by // Key used in [_OpenContainerRoute] to hide the widget returned by
// [OpenContainer.openBuilder] in the source route while the container is // [OpenContainer.openBuilder] in the source route while the container is
// opening/open. A copy of that widget is included in the // opening/open. A copy of that widget is included in the
@ -281,7 +270,7 @@ class _OpenContainerState<T> extends State<OpenContainer<T>> {
Future<void> openContainer() async { Future<void> openContainer() async {
final Color middleColor = final Color middleColor =
widget.middleColor ?? Theme.of(context).canvasColor; widget.middleColor ?? Theme.of(context).canvasColor;
final T data = await Navigator.of( final T? data = await Navigator.of(
context, context,
rootNavigator: widget.useRootNavigator, rootNavigator: widget.useRootNavigator,
).push(_OpenContainerRoute<T>( ).push(_OpenContainerRoute<T>(
@ -302,7 +291,7 @@ class _OpenContainerState<T> extends State<OpenContainer<T>> {
routeSettings: widget.routeSettings, routeSettings: widget.routeSettings,
)); ));
if (widget.onClosed != null) { if (widget.onClosed != null) {
widget.onClosed(data); widget.onClosed!(data);
} }
} }
@ -342,11 +331,11 @@ class _OpenContainerState<T> extends State<OpenContainer<T>> {
/// `isVisible` is ignored). /// `isVisible` is ignored).
class _Hideable extends StatefulWidget { class _Hideable extends StatefulWidget {
const _Hideable({ const _Hideable({
Key key, Key? key,
this.child, this.child,
}) : super(key: key); }) : super(key: key);
final Widget child; final Widget? child;
@override @override
State<_Hideable> createState() => _HideableState(); State<_Hideable> createState() => _HideableState();
@ -354,9 +343,9 @@ class _Hideable extends StatefulWidget {
class _HideableState extends State<_Hideable> { class _HideableState extends State<_Hideable> {
/// When non-null the child is replaced by a [SizedBox] of the set size. /// When non-null the child is replaced by a [SizedBox] of the set size.
Size get placeholderSize => _placeholderSize; Size? get placeholderSize => _placeholderSize;
Size _placeholderSize; Size? _placeholderSize;
set placeholderSize(Size value) { set placeholderSize(Size? value) {
if (_placeholderSize == value) { if (_placeholderSize == value) {
return; return;
} }
@ -372,7 +361,6 @@ class _HideableState extends State<_Hideable> {
bool get isVisible => _visible; bool get isVisible => _visible;
bool _visible = true; bool _visible = true;
set isVisible(bool value) { set isVisible(bool value) {
assert(value != null);
if (_visible == value) { if (_visible == value) {
return; return;
} }
@ -400,33 +388,22 @@ class _HideableState extends State<_Hideable> {
class _OpenContainerRoute<T> extends ModalRoute<T> { class _OpenContainerRoute<T> extends ModalRoute<T> {
_OpenContainerRoute({ _OpenContainerRoute({
@required this.closedColor, required this.closedColor,
@required this.openColor, required this.openColor,
@required this.middleColor, required this.middleColor,
@required double closedElevation, required double closedElevation,
@required this.openElevation, required this.openElevation,
@required ShapeBorder closedShape, required ShapeBorder closedShape,
@required this.openShape, required this.openShape,
@required this.closedBuilder, required this.closedBuilder,
@required this.openBuilder, required this.openBuilder,
@required this.hideableKey, required this.hideableKey,
@required this.closedBuilderKey, required this.closedBuilderKey,
@required this.transitionDuration, required this.transitionDuration,
@required this.transitionType, required this.transitionType,
@required this.useRootNavigator, required this.useRootNavigator,
@required RouteSettings routeSettings, required RouteSettings? routeSettings,
}) : assert(closedColor != null), }) : _elevationTween = Tween<double>(
assert(openColor != null),
assert(closedElevation != null),
assert(openElevation != null),
assert(closedShape != null),
assert(openBuilder != null),
assert(closedBuilder != null),
assert(hideableKey != null),
assert(closedBuilderKey != null),
assert(transitionType != null),
assert(useRootNavigator != null),
_elevationTween = Tween<double>(
begin: closedElevation, begin: closedElevation,
end: openElevation, end: openElevation,
), ),
@ -444,21 +421,21 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
_openOpacityTween = _getOpenOpacityTween(transitionType), _openOpacityTween = _getOpenOpacityTween(transitionType),
super(settings: routeSettings); super(settings: routeSettings);
static _FlippableTweenSequence<Color> _getColorTween({ static _FlippableTweenSequence<Color?> _getColorTween({
@required ContainerTransitionType transitionType, required ContainerTransitionType transitionType,
@required Color closedColor, required Color closedColor,
@required Color openColor, required Color openColor,
@required Color middleColor, required Color middleColor,
}) { }) {
switch (transitionType) { switch (transitionType) {
case ContainerTransitionType.fade: case ContainerTransitionType.fade:
return _FlippableTweenSequence<Color>( return _FlippableTweenSequence<Color?>(
<TweenSequenceItem<Color>>[ <TweenSequenceItem<Color?>>[
TweenSequenceItem<Color>( TweenSequenceItem<Color>(
tween: ConstantTween<Color>(closedColor), tween: ConstantTween<Color>(closedColor),
weight: 1 / 5, weight: 1 / 5,
), ),
TweenSequenceItem<Color>( TweenSequenceItem<Color?>(
tween: ColorTween(begin: closedColor, end: openColor), tween: ColorTween(begin: closedColor, end: openColor),
weight: 1 / 5, weight: 1 / 5,
), ),
@ -469,20 +446,19 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
], ],
); );
case ContainerTransitionType.fadeThrough: case ContainerTransitionType.fadeThrough:
return _FlippableTweenSequence<Color>( return _FlippableTweenSequence<Color?>(
<TweenSequenceItem<Color>>[ <TweenSequenceItem<Color?>>[
TweenSequenceItem<Color>( TweenSequenceItem<Color?>(
tween: ColorTween(begin: closedColor, end: middleColor), tween: ColorTween(begin: closedColor, end: middleColor),
weight: 1 / 5, weight: 1 / 5,
), ),
TweenSequenceItem<Color>( TweenSequenceItem<Color?>(
tween: ColorTween(begin: middleColor, end: openColor), tween: ColorTween(begin: middleColor, end: openColor),
weight: 4 / 5, weight: 4 / 5,
), ),
], ],
); );
} }
return null; // unreachable
} }
static _FlippableTweenSequence<double> _getClosedOpacityTween( static _FlippableTweenSequence<double> _getClosedOpacityTween(
@ -497,7 +473,6 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
), ),
], ],
); );
break;
case ContainerTransitionType.fadeThrough: case ContainerTransitionType.fadeThrough:
return _FlippableTweenSequence<double>( return _FlippableTweenSequence<double>(
<TweenSequenceItem<double>>[ <TweenSequenceItem<double>>[
@ -511,9 +486,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
), ),
], ],
); );
break;
} }
return null; // unreachable
} }
static _FlippableTweenSequence<double> _getOpenOpacityTween( static _FlippableTweenSequence<double> _getOpenOpacityTween(
@ -536,7 +509,6 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
), ),
], ],
); );
break;
case ContainerTransitionType.fadeThrough: case ContainerTransitionType.fadeThrough:
return _FlippableTweenSequence<double>( return _FlippableTweenSequence<double>(
<TweenSequenceItem<double>>[ <TweenSequenceItem<double>>[
@ -550,9 +522,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
), ),
], ],
); );
break;
} }
return null; // unreachable
} }
final Color closedColor; final Color closedColor;
@ -579,11 +549,11 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
final ShapeBorderTween _shapeTween; final ShapeBorderTween _shapeTween;
final _FlippableTweenSequence<double> _closedOpacityTween; final _FlippableTweenSequence<double> _closedOpacityTween;
final _FlippableTweenSequence<double> _openOpacityTween; final _FlippableTweenSequence<double> _openOpacityTween;
final _FlippableTweenSequence<Color> _colorTween; final _FlippableTweenSequence<Color?> _colorTween;
static final TweenSequence<Color> _scrimFadeInTween = TweenSequence<Color>( static final TweenSequence<Color?> _scrimFadeInTween = TweenSequence<Color?>(
<TweenSequenceItem<Color>>[ <TweenSequenceItem<Color?>>[
TweenSequenceItem<Color>( TweenSequenceItem<Color?>(
tween: ColorTween(begin: Colors.transparent, end: Colors.black54), tween: ColorTween(begin: Colors.transparent, end: Colors.black54),
weight: 1 / 5, weight: 1 / 5,
), ),
@ -593,7 +563,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
), ),
], ],
); );
static final Tween<Color> _scrimFadeOutTween = ColorTween( static final Tween<Color?> _scrimFadeOutTween = ColorTween(
begin: Colors.transparent, begin: Colors.transparent,
end: Colors.black54, end: Colors.black54,
); );
@ -608,14 +578,14 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
// the bounds of the enclosing [Navigator]. // the bounds of the enclosing [Navigator].
final RectTween _rectTween = RectTween(); final RectTween _rectTween = RectTween();
AnimationStatus _lastAnimationStatus; AnimationStatus? _lastAnimationStatus;
AnimationStatus _currentAnimationStatus; AnimationStatus? _currentAnimationStatus;
@override @override
TickerFuture didPush() { TickerFuture didPush() {
_takeMeasurements(navigatorContext: hideableKey.currentContext); _takeMeasurements(navigatorContext: hideableKey.currentContext!);
animation.addStatusListener((AnimationStatus status) { animation!.addStatusListener((AnimationStatus status) {
_lastAnimationStatus = _currentAnimationStatus; _lastAnimationStatus = _currentAnimationStatus;
_currentAnimationStatus = status; _currentAnimationStatus = status;
switch (status) { switch (status) {
@ -635,9 +605,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
} }
@override @override
bool didPop(T result) { bool didPop(T? result) {
_takeMeasurements( _takeMeasurements(
navigatorContext: subtreeContext, navigatorContext: subtreeContext!,
delayForSourceRoute: true, delayForSourceRoute: true,
); );
return super.didPop(result); return super.didPop(result);
@ -645,44 +615,44 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
@override @override
void dispose() { void dispose() {
if (hideableKey?.currentState?.isVisible == false) { if (hideableKey.currentState?.isVisible == false) {
// This route may be disposed without dismissing its animation if it is // This route may be disposed without dismissing its animation if it is
// removed by the navigator. // removed by the navigator.
SchedulerBinding.instance SchedulerBinding.instance!
.addPostFrameCallback((Duration d) => _toggleHideable(hide: false)); .addPostFrameCallback((Duration d) => _toggleHideable(hide: false));
} }
super.dispose(); super.dispose();
} }
void _toggleHideable({bool hide}) { void _toggleHideable({required bool hide}) {
if (hideableKey?.currentState != null) { if (hideableKey.currentState != null) {
hideableKey.currentState hideableKey.currentState!
..placeholderSize = null ..placeholderSize = null
..isVisible = !hide; ..isVisible = !hide;
} }
} }
void _takeMeasurements({ void _takeMeasurements({
BuildContext navigatorContext, required BuildContext navigatorContext,
bool delayForSourceRoute = false, bool delayForSourceRoute = false,
}) { }) {
final RenderBox navigator = Navigator.of( final RenderBox navigator = Navigator.of(
navigatorContext, navigatorContext,
rootNavigator: useRootNavigator, rootNavigator: useRootNavigator,
).context.findRenderObject(); ).context.findRenderObject() as RenderBox;
final Size navSize = _getSize(navigator); final Size navSize = _getSize(navigator);
_rectTween.end = Offset.zero & navSize; _rectTween.end = Offset.zero & navSize;
void takeMeasurementsInSourceRoute([Duration _]) { void takeMeasurementsInSourceRoute([Duration? _]) {
if (!navigator.attached || hideableKey.currentContext == null) { if (!navigator.attached || hideableKey.currentContext == null) {
return; return;
} }
_rectTween.begin = _getRect(hideableKey, navigator); _rectTween.begin = _getRect(hideableKey, navigator);
hideableKey.currentState.placeholderSize = _rectTween.begin.size; hideableKey.currentState!.placeholderSize = _rectTween.begin!.size;
} }
if (delayForSourceRoute) { if (delayForSourceRoute) {
SchedulerBinding.instance SchedulerBinding.instance!
.addPostFrameCallback(takeMeasurementsInSourceRoute); .addPostFrameCallback(takeMeasurementsInSourceRoute);
} else { } else {
takeMeasurementsInSourceRoute(); takeMeasurementsInSourceRoute();
@ -690,7 +660,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
} }
Size _getSize(RenderBox render) { Size _getSize(RenderBox render) {
assert(render != null && render.hasSize); assert(render.hasSize);
return render.size; return render.size;
} }
@ -698,9 +668,10 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
// coordinate system of `ancestor`. // coordinate system of `ancestor`.
Rect _getRect(GlobalKey key, RenderBox ancestor) { Rect _getRect(GlobalKey key, RenderBox ancestor) {
assert(key.currentContext != null); assert(key.currentContext != null);
assert(ancestor != null && ancestor.hasSize); assert(ancestor.hasSize);
final RenderBox render = key.currentContext.findRenderObject(); final RenderBox render =
assert(render != null && render.hasSize); key.currentContext!.findRenderObject() as RenderBox;
assert(render.hasSize);
return MatrixUtils.transformRect( return MatrixUtils.transformRect(
render.getTransformTo(ancestor), render.getTransformTo(ancestor),
Offset.zero & render.size, Offset.zero & render.size,
@ -720,6 +691,8 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
case AnimationStatus.reverse: case AnimationStatus.reverse:
isInProgress = true; isInProgress = true;
break; break;
case null:
break;
} }
switch (_lastAnimationStatus) { switch (_lastAnimationStatus) {
case AnimationStatus.completed: case AnimationStatus.completed:
@ -730,12 +703,14 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
case AnimationStatus.reverse: case AnimationStatus.reverse:
wasInProgress = true; wasInProgress = true;
break; break;
case null:
break;
} }
return wasInProgress && isInProgress; return wasInProgress && isInProgress;
} }
void closeContainer({T returnValue}) { void closeContainer({T? returnValue}) {
Navigator.of(subtreeContext).pop(returnValue); Navigator.of(subtreeContext!).pop(returnValue);
} }
@override @override
@ -748,7 +723,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
if (animation.isCompleted) { if (animation.isCompleted) {
return SizedBox.expand( return SizedBox.expand(
child: Material( child: Material(
@ -771,9 +746,9 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
reverseCurve: reverseCurve:
_transitionWasInterrupted ? null : Curves.fastOutSlowIn.flipped, _transitionWasInterrupted ? null : Curves.fastOutSlowIn.flipped,
); );
TweenSequence<Color> colorTween; TweenSequence<Color?>? colorTween;
TweenSequence<double> closedOpacityTween, openOpacityTween; TweenSequence<double>? closedOpacityTween, openOpacityTween;
Animatable<Color> scrimTween; Animatable<Color?>? scrimTween;
switch (animation.status) { switch (animation.status) {
case AnimationStatus.dismissed: case AnimationStatus.dismissed:
case AnimationStatus.forward: case AnimationStatus.forward:
@ -804,10 +779,10 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
assert(openOpacityTween != null); assert(openOpacityTween != null);
assert(scrimTween != null); assert(scrimTween != null);
final Rect rect = _rectTween.evaluate(curvedAnimation); final Rect rect = _rectTween.evaluate(curvedAnimation)!;
return SizedBox.expand( return SizedBox.expand(
child: Container( child: Container(
color: scrimTween.evaluate(curvedAnimation), color: scrimTween!.evaluate(curvedAnimation),
child: Align( child: Align(
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: Transform.translate( child: Transform.translate(
@ -818,7 +793,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
child: Material( child: Material(
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
animationDuration: Duration.zero, animationDuration: Duration.zero,
color: colorTween.evaluate(animation), color: colorTween!.evaluate(animation),
shape: _shapeTween.evaluate(curvedAnimation), shape: _shapeTween.evaluate(curvedAnimation),
elevation: _elevationTween.evaluate(curvedAnimation), elevation: _elevationTween.evaluate(curvedAnimation),
child: Stack( child: Stack(
@ -829,13 +804,13 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
fit: BoxFit.fitWidth, fit: BoxFit.fitWidth,
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: SizedBox( child: SizedBox(
width: _rectTween.begin.width, width: _rectTween.begin!.width,
height: _rectTween.begin.height, height: _rectTween.begin!.height,
child: (hideableKey.currentState?.isInTree ?? child: (hideableKey.currentState?.isInTree ??
false) false)
? null ? null
: Opacity( : Opacity(
opacity: closedOpacityTween opacity: closedOpacityTween!
.evaluate(animation), .evaluate(animation),
child: Builder( child: Builder(
key: closedBuilderKey, key: closedBuilderKey,
@ -854,10 +829,10 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
fit: BoxFit.fitWidth, fit: BoxFit.fitWidth,
alignment: Alignment.topLeft, alignment: Alignment.topLeft,
child: SizedBox( child: SizedBox(
width: _rectTween.end.width, width: _rectTween.end!.width,
height: _rectTween.end.height, height: _rectTween.end!.height,
child: Opacity( child: Opacity(
opacity: openOpacityTween.evaluate(animation), opacity: openOpacityTween!.evaluate(animation),
child: Builder( child: Builder(
key: _openBuilderKey, key: _openBuilderKey,
builder: (BuildContext context) { builder: (BuildContext context) {
@ -884,7 +859,7 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
bool get maintainState => true; bool get maintainState => true;
@override @override
Color get barrierColor => null; Color? get barrierColor => null;
@override @override
bool get opaque => true; bool get opaque => true;
@ -893,16 +868,16 @@ class _OpenContainerRoute<T> extends ModalRoute<T> {
bool get barrierDismissible => false; bool get barrierDismissible => false;
@override @override
String get barrierLabel => null; String? get barrierLabel => null;
} }
class _FlippableTweenSequence<T> extends TweenSequence<T> { class _FlippableTweenSequence<T> extends TweenSequence<T> {
_FlippableTweenSequence(this._items) : super(_items); _FlippableTweenSequence(this._items) : super(_items);
final List<TweenSequenceItem<T>> _items; final List<TweenSequenceItem<T>> _items;
_FlippableTweenSequence<T> _flipped; _FlippableTweenSequence<T>? _flipped;
_FlippableTweenSequence<T> get flipped { _FlippableTweenSequence<T>? get flipped {
if (_flipped == null) { if (_flipped == null) {
final List<TweenSequenceItem<T>> newItems = <TweenSequenceItem<T>>[]; final List<TweenSequenceItem<T>> newItems = <TweenSequenceItem<T>>[];
for (int i = 0; i < _items.length; i++) { for (int i = 0; i < _items.length; i++) {

View File

@ -18,14 +18,11 @@ class _ChildEntry {
/// The [primaryController], [secondaryController], [transition] and /// The [primaryController], [secondaryController], [transition] and
/// [widgetChild] parameters must not be null. /// [widgetChild] parameters must not be null.
_ChildEntry({ _ChildEntry({
@required this.primaryController, required this.primaryController,
@required this.secondaryController, required this.secondaryController,
@required this.transition, required this.transition,
@required this.widgetChild, required this.widgetChild,
}) : assert(primaryController != null), });
assert(secondaryController != null),
assert(widgetChild != null),
assert(transition != null);
/// The animation controller for the child's transition. /// The animation controller for the child's transition.
final AnimationController primaryController; final AnimationController primaryController;
@ -172,17 +169,13 @@ class PageTransitionSwitcher extends StatefulWidget {
/// The [duration], [reverse], and [transitionBuilder] parameters /// The [duration], [reverse], and [transitionBuilder] parameters
/// must not be null. /// must not be null.
const PageTransitionSwitcher({ const PageTransitionSwitcher({
Key key, Key? key,
this.duration = const Duration(milliseconds: 300), this.duration = const Duration(milliseconds: 300),
this.reverse = false, this.reverse = false,
@required this.transitionBuilder, required this.transitionBuilder,
this.layoutBuilder = defaultLayoutBuilder, this.layoutBuilder = defaultLayoutBuilder,
this.child, this.child,
}) : assert(duration != null), }) : super(key: key);
assert(reverse != null),
assert(transitionBuilder != null),
assert(layoutBuilder != null),
super(key: key);
/// The current child widget to display. /// The current child widget to display.
/// ///
@ -195,7 +188,7 @@ class PageTransitionSwitcher extends StatefulWidget {
/// ///
/// The child is considered to be "new" if it has a different type or [Key] /// The child is considered to be "new" if it has a different type or [Key]
/// (see [Widget.canUpdate]). /// (see [Widget.canUpdate]).
final Widget child; final Widget? child;
/// The duration of the transition from the old [child] value to the new one. /// The duration of the transition from the old [child] value to the new one.
/// ///
@ -285,7 +278,7 @@ class PageTransitionSwitcher extends StatefulWidget {
class _PageTransitionSwitcherState extends State<PageTransitionSwitcher> class _PageTransitionSwitcherState extends State<PageTransitionSwitcher>
with TickerProviderStateMixin { with TickerProviderStateMixin {
final List<_ChildEntry> _activeEntries = <_ChildEntry>[]; final List<_ChildEntry> _activeEntries = <_ChildEntry>[];
_ChildEntry _currentEntry; _ChildEntry? _currentEntry;
int _childNumber = 0; int _childNumber = 0;
@override @override
@ -308,30 +301,30 @@ class _PageTransitionSwitcherState extends State<PageTransitionSwitcher>
final bool hasOldChild = _currentEntry != null; final bool hasOldChild = _currentEntry != null;
if (hasNewChild != hasOldChild || if (hasNewChild != hasOldChild ||
hasNewChild && hasNewChild &&
!Widget.canUpdate(widget.child, _currentEntry.widgetChild)) { !Widget.canUpdate(widget.child!, _currentEntry!.widgetChild)) {
// Child has changed, fade current entry out and add new entry. // Child has changed, fade current entry out and add new entry.
_childNumber += 1; _childNumber += 1;
_addEntryForNewChild(shouldAnimate: true); _addEntryForNewChild(shouldAnimate: true);
} else if (_currentEntry != null) { } else if (_currentEntry != null) {
assert(hasOldChild && hasNewChild); assert(hasOldChild && hasNewChild);
assert(Widget.canUpdate(widget.child, _currentEntry.widgetChild)); assert(Widget.canUpdate(widget.child!, _currentEntry!.widgetChild));
// Child has been updated. Make sure we update the child widget and // Child has been updated. Make sure we update the child widget and
// transition in _currentEntry even though we're not going to start a new // transition in _currentEntry even though we're not going to start a new
// animation, but keep the key from the old transition so that we // animation, but keep the key from the old transition so that we
// update the transition instead of replacing it. // update the transition instead of replacing it.
_currentEntry.widgetChild = widget.child; _currentEntry!.widgetChild = widget.child!;
_updateTransitionForEntry(_currentEntry); // uses entry.widgetChild _updateTransitionForEntry(_currentEntry!); // uses entry.widgetChild
} }
} }
void _addEntryForNewChild({@required bool shouldAnimate}) { void _addEntryForNewChild({required bool shouldAnimate}) {
assert(shouldAnimate || _currentEntry == null); assert(shouldAnimate || _currentEntry == null);
if (_currentEntry != null) { if (_currentEntry != null) {
assert(shouldAnimate); assert(shouldAnimate);
if (widget.reverse) { if (widget.reverse) {
_currentEntry.primaryController.reverse(); _currentEntry!.primaryController.reverse();
} else { } else {
_currentEntry.secondaryController.forward(); _currentEntry!.secondaryController.forward();
} }
_currentEntry = null; _currentEntry = null;
} }
@ -359,35 +352,31 @@ class _PageTransitionSwitcherState extends State<PageTransitionSwitcher>
primaryController.value = 1.0; primaryController.value = 1.0;
} }
_currentEntry = _newEntry( _currentEntry = _newEntry(
child: widget.child, child: widget.child!,
primaryController: primaryController, primaryController: primaryController,
secondaryController: secondaryController, secondaryController: secondaryController,
builder: widget.transitionBuilder, builder: widget.transitionBuilder,
); );
if (widget.reverse && _activeEntries.isNotEmpty) { if (widget.reverse && _activeEntries.isNotEmpty) {
// Add below old child. // Add below old child.
_activeEntries.insert(_activeEntries.length - 1, _currentEntry); _activeEntries.insert(_activeEntries.length - 1, _currentEntry!);
} else { } else {
// Add on top of old child. // Add on top of old child.
_activeEntries.add(_currentEntry); _activeEntries.add(_currentEntry!);
} }
} }
_ChildEntry _newEntry({ _ChildEntry _newEntry({
@required Widget child, required Widget child,
@required PageTransitionSwitcherTransitionBuilder builder, required PageTransitionSwitcherTransitionBuilder builder,
@required AnimationController primaryController, required AnimationController primaryController,
@required AnimationController secondaryController, required AnimationController secondaryController,
}) { }) {
final Widget transition = builder( final Widget transition = builder(
child, child,
primaryController, primaryController,
secondaryController, secondaryController,
); );
assert(
transition != null,
'PageTransitionSwitcher.builder must not return null.',
);
final _ChildEntry entry = _ChildEntry( final _ChildEntry entry = _ChildEntry(
widgetChild: child, widgetChild: child,
transition: KeyedSubtree.wrap( transition: KeyedSubtree.wrap(
@ -426,10 +415,6 @@ class _PageTransitionSwitcherState extends State<PageTransitionSwitcher>
entry.primaryController, entry.primaryController,
entry.secondaryController, entry.secondaryController,
); );
assert(
transition != null,
'PageTransitionSwitcher.builder must not return null.',
);
entry.transition = KeyedSubtree( entry.transition = KeyedSubtree(
key: entry.transition.key, key: entry.transition.key,
child: transition, child: transition,

View File

@ -4,19 +4,9 @@
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart' import 'package:flutter/material.dart';
hide
decelerateEasing, // ignore: undefined_hidden_name
standardEasing, // ignore: undefined_hidden_name
accelerateEasing; // ignore: undefined_hidden_name
// TODO(goderbauer): Remove implementation import when material properly exports the file.
import 'package:flutter/src/material/curves.dart'; // ignore: implementation_imports
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
// TODO(shihaohong): Remove DualTransitionBuilder once flutter/flutter's `stable`
// branch contains DualTransitionBuilder.
import 'dual_transition_builder.dart' as dual_transition_builder;
/// Determines which type of shared axis transition is used. /// Determines which type of shared axis transition is used.
enum SharedAxisTransitionType { enum SharedAxisTransitionType {
/// Creates a shared axis vertical (y-axis) page transition. /// Creates a shared axis vertical (y-axis) page transition.
@ -87,9 +77,9 @@ enum SharedAxisTransitionType {
class SharedAxisPageTransitionsBuilder extends PageTransitionsBuilder { class SharedAxisPageTransitionsBuilder extends PageTransitionsBuilder {
/// Construct a [SharedAxisPageTransitionsBuilder]. /// Construct a [SharedAxisPageTransitionsBuilder].
const SharedAxisPageTransitionsBuilder({ const SharedAxisPageTransitionsBuilder({
@required this.transitionType, required this.transitionType,
this.fillColor, this.fillColor,
}) : assert(transitionType != null); });
/// Determines which [SharedAxisTransitionType] to build. /// Determines which [SharedAxisTransitionType] to build.
final SharedAxisTransitionType transitionType; final SharedAxisTransitionType transitionType;
@ -97,12 +87,12 @@ class SharedAxisPageTransitionsBuilder extends PageTransitionsBuilder {
/// The color to use for the background color during the transition. /// The color to use for the background color during the transition.
/// ///
/// This defaults to the [Theme]'s [ThemeData.canvasColor]. /// This defaults to the [Theme]'s [ThemeData.canvasColor].
final Color fillColor; final Color? fillColor;
@override @override
Widget buildTransitions<T>( Widget buildTransitions<T>(
PageRoute<T> route, PageRoute<T>? route,
BuildContext context, BuildContext? context,
Animation<double> animation, Animation<double> animation,
Animation<double> secondaryAnimation, Animation<double> secondaryAnimation,
Widget child, Widget child,
@ -197,14 +187,13 @@ class SharedAxisTransition extends StatelessWidget {
/// The [animation] and [secondaryAnimation] argument are required and must /// The [animation] and [secondaryAnimation] argument are required and must
/// not be null. /// not be null.
const SharedAxisTransition({ const SharedAxisTransition({
Key key, Key? key,
@required this.animation, required this.animation,
@required this.secondaryAnimation, required this.secondaryAnimation,
@required this.transitionType, required this.transitionType,
this.fillColor, this.fillColor,
this.child, this.child,
}) : assert(transitionType != null), }) : super(key: key);
super(key: key);
/// The animation that drives the [child]'s entrance and exit. /// The animation that drives the [child]'s entrance and exit.
/// ///
@ -234,23 +223,23 @@ class SharedAxisTransition extends StatelessWidget {
/// The color to use for the background color during the transition. /// The color to use for the background color during the transition.
/// ///
/// This defaults to the [Theme]'s [ThemeData.canvasColor]. /// This defaults to the [Theme]'s [ThemeData.canvasColor].
final Color fillColor; final Color? fillColor;
/// The widget below this widget in the tree. /// The widget below this widget in the tree.
/// ///
/// This widget will transition in and out as driven by [animation] and /// This widget will transition in and out as driven by [animation] and
/// [secondaryAnimation]. /// [secondaryAnimation].
final Widget child; final Widget? child;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Color color = fillColor ?? Theme.of(context).canvasColor; final Color color = fillColor ?? Theme.of(context).canvasColor;
return dual_transition_builder.DualTransitionBuilder( return DualTransitionBuilder(
animation: animation, animation: animation,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return _EnterTransition( return _EnterTransition(
animation: animation, animation: animation,
@ -261,7 +250,7 @@ class SharedAxisTransition extends StatelessWidget {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return _ExitTransition( return _ExitTransition(
animation: animation, animation: animation,
@ -271,12 +260,12 @@ class SharedAxisTransition extends StatelessWidget {
child: child, child: child,
); );
}, },
child: dual_transition_builder.DualTransitionBuilder( child: DualTransitionBuilder(
animation: ReverseAnimation(secondaryAnimation), animation: ReverseAnimation(secondaryAnimation),
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return _EnterTransition( return _EnterTransition(
animation: animation, animation: animation,
@ -288,7 +277,7 @@ class SharedAxisTransition extends StatelessWidget {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return _ExitTransition( return _ExitTransition(
animation: animation, animation: animation,
@ -305,15 +294,15 @@ class SharedAxisTransition extends StatelessWidget {
class _EnterTransition extends StatelessWidget { class _EnterTransition extends StatelessWidget {
const _EnterTransition({ const _EnterTransition({
this.animation, required this.animation,
this.transitionType, required this.transitionType,
this.reverse = false, this.reverse = false,
this.child, this.child,
}); });
final Animation<double> animation; final Animation<double> animation;
final SharedAxisTransitionType transitionType; final SharedAxisTransitionType transitionType;
final Widget child; final Widget? child;
final bool reverse; final bool reverse;
static final Animatable<double> _fadeInTransition = CurveTween( static final Animatable<double> _fadeInTransition = CurveTween(
@ -343,7 +332,7 @@ class _EnterTransition extends StatelessWidget {
opacity: _fadeInTransition.animate(animation), opacity: _fadeInTransition.animate(animation),
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
return Transform.translate( return Transform.translate(
offset: slideInTransition.evaluate(animation), offset: slideInTransition.evaluate(animation),
child: child, child: child,
@ -352,7 +341,6 @@ class _EnterTransition extends StatelessWidget {
child: child, child: child,
), ),
); );
break;
case SharedAxisTransitionType.vertical: case SharedAxisTransitionType.vertical:
final Animatable<Offset> slideInTransition = Tween<Offset>( final Animatable<Offset> slideInTransition = Tween<Offset>(
begin: Offset(0.0, !reverse ? 30.0 : -30.0), begin: Offset(0.0, !reverse ? 30.0 : -30.0),
@ -363,7 +351,7 @@ class _EnterTransition extends StatelessWidget {
opacity: _fadeInTransition.animate(animation), opacity: _fadeInTransition.animate(animation),
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
return Transform.translate( return Transform.translate(
offset: slideInTransition.evaluate(animation), offset: slideInTransition.evaluate(animation),
child: child, child: child,
@ -372,7 +360,6 @@ class _EnterTransition extends StatelessWidget {
child: child, child: child,
), ),
); );
break;
case SharedAxisTransitionType.scaled: case SharedAxisTransitionType.scaled:
return FadeTransition( return FadeTransition(
opacity: _fadeInTransition.animate(animation), opacity: _fadeInTransition.animate(animation),
@ -382,18 +369,16 @@ class _EnterTransition extends StatelessWidget {
child: child, child: child,
), ),
); );
break;
} }
return null; // unreachable
} }
} }
class _ExitTransition extends StatelessWidget { class _ExitTransition extends StatelessWidget {
const _ExitTransition({ const _ExitTransition({
this.animation, required this.animation,
this.transitionType, required this.transitionType,
this.reverse = false, this.reverse = false,
@required this.fillColor, required this.fillColor,
this.child, this.child,
}); });
@ -401,7 +386,7 @@ class _ExitTransition extends StatelessWidget {
final SharedAxisTransitionType transitionType; final SharedAxisTransitionType transitionType;
final bool reverse; final bool reverse;
final Color fillColor; final Color fillColor;
final Widget child; final Widget? child;
static final Animatable<double> _fadeOutTransition = _FlippedCurveTween( static final Animatable<double> _fadeOutTransition = _FlippedCurveTween(
curve: accelerateEasing, curve: accelerateEasing,
@ -432,7 +417,7 @@ class _ExitTransition extends StatelessWidget {
color: fillColor, color: fillColor,
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
return Transform.translate( return Transform.translate(
offset: slideOutTransition.evaluate(animation), offset: slideOutTransition.evaluate(animation),
child: child, child: child,
@ -442,7 +427,6 @@ class _ExitTransition extends StatelessWidget {
), ),
), ),
); );
break;
case SharedAxisTransitionType.vertical: case SharedAxisTransitionType.vertical:
final Animatable<Offset> slideOutTransition = Tween<Offset>( final Animatable<Offset> slideOutTransition = Tween<Offset>(
begin: Offset.zero, begin: Offset.zero,
@ -455,7 +439,7 @@ class _ExitTransition extends StatelessWidget {
color: fillColor, color: fillColor,
child: AnimatedBuilder( child: AnimatedBuilder(
animation: animation, animation: animation,
builder: (BuildContext context, Widget child) { builder: (BuildContext context, Widget? child) {
return Transform.translate( return Transform.translate(
offset: slideOutTransition.evaluate(animation), offset: slideOutTransition.evaluate(animation),
child: child, child: child,
@ -465,7 +449,6 @@ class _ExitTransition extends StatelessWidget {
), ),
), ),
); );
break;
case SharedAxisTransitionType.scaled: case SharedAxisTransitionType.scaled:
return FadeTransition( return FadeTransition(
opacity: _fadeOutTransition.animate(animation), opacity: _fadeOutTransition.animate(animation),
@ -478,9 +461,7 @@ class _ExitTransition extends StatelessWidget {
), ),
), ),
); );
break;
} }
return null; // unreachable
} }
} }
@ -494,9 +475,8 @@ class _ExitTransition extends StatelessWidget {
class _FlippedCurveTween extends CurveTween { class _FlippedCurveTween extends CurveTween {
/// Creates a vertically flipped [CurveTween]. /// Creates a vertically flipped [CurveTween].
_FlippedCurveTween({ _FlippedCurveTween({
@required Curve curve, required Curve curve,
}) : assert(curve != null), }) : super(curve: curve);
super(curve: curve);
@override @override
double transform(double t) => 1.0 - super.transform(t); double transform(double t) => 1.0 - super.transform(t);

View File

@ -1,10 +1,10 @@
name: animations name: animations
description: Fancy pre-built animations that can easily be integrated into any Flutter application. description: Fancy pre-built animations that can easily be integrated into any Flutter application.
version: 1.1.2 version: 2.0.0-nullsafety.0
homepage: https://github.com/flutter/packages/tree/master/packages/animations homepage: https://github.com/flutter/packages/tree/master/packages/animations
environment: environment:
sdk: ">=2.2.2 <3.0.0" sdk: '>=2.12.0-0 <3.0.0'
dependencies: dependencies:
flutter: flutter:
@ -13,4 +13,4 @@ dependencies:
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
vector_math: ^2.0.8 vector_math: ">=2.1.0-nullsafety.5 <3.0.0"

View File

@ -2,10 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// TODO(shihaohong): Remove DualTransitionBuilder once flutter/flutter's `stable`
// branch contains DualTransitionBuilder.
import 'package:animations/src/dual_transition_builder.dart'
as dual_transition_builder;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
@ -18,12 +14,12 @@ void main() {
); );
await tester.pumpWidget(Center( await tester.pumpWidget(Center(
child: dual_transition_builder.DualTransitionBuilder( child: DualTransitionBuilder(
animation: controller, animation: controller,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return ScaleTransition( return ScaleTransition(
scale: animation, scale: animation,
@ -33,7 +29,7 @@ void main() {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return FadeTransition( return FadeTransition(
opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation), opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation),
@ -88,12 +84,12 @@ void main() {
await tester.pumpWidget(Directionality( await tester.pumpWidget(Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: Center( child: Center(
child: dual_transition_builder.DualTransitionBuilder( child: DualTransitionBuilder(
animation: controller, animation: controller,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return ScaleTransition( return ScaleTransition(
scale: animation, scale: animation,
@ -103,7 +99,7 @@ void main() {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return FadeTransition( return FadeTransition(
opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation), opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation),
@ -150,12 +146,12 @@ void main() {
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
); );
await tester.pumpWidget(Center( await tester.pumpWidget(Center(
child: dual_transition_builder.DualTransitionBuilder( child: DualTransitionBuilder(
animation: controller, animation: controller,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return ScaleTransition( return ScaleTransition(
scale: animation, scale: animation,
@ -165,7 +161,7 @@ void main() {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return FadeTransition( return FadeTransition(
opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation), opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation),
@ -216,12 +212,12 @@ void main() {
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
); );
await tester.pumpWidget(Center( await tester.pumpWidget(Center(
child: dual_transition_builder.DualTransitionBuilder( child: DualTransitionBuilder(
animation: controller, animation: controller,
forwardBuilder: ( forwardBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return ScaleTransition( return ScaleTransition(
scale: animation, scale: animation,
@ -231,7 +227,7 @@ void main() {
reverseBuilder: ( reverseBuilder: (
BuildContext context, BuildContext context,
Animation<double> animation, Animation<double> animation,
Widget child, Widget? child,
) { ) {
return FadeTransition( return FadeTransition(
opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation), opacity: Tween<double>(begin: 1.0, end: 0.0).animate(animation),
@ -286,7 +282,7 @@ double _getOpacity(WidgetTester tester) {
} }
class _StatefulTestWidget extends StatefulWidget { class _StatefulTestWidget extends StatefulWidget {
const _StatefulTestWidget({Key key, this.name}) : super(key: key); const _StatefulTestWidget({Key? key, required this.name}) : super(key: key);
final String name; final String name;

View File

@ -455,7 +455,7 @@ double _getOpacity(GlobalKey key, WidgetTester tester) {
matching: find.byType(FadeTransition), matching: find.byType(FadeTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final FadeTransition transition = widget; final FadeTransition transition = widget as FadeTransition;
return a * transition.opacity.value; return a * transition.opacity.value;
}); });
} }
@ -466,18 +466,18 @@ double _getScale(GlobalKey key, WidgetTester tester) {
matching: find.byType(ScaleTransition), matching: find.byType(ScaleTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final ScaleTransition transition = widget; final ScaleTransition transition = widget as ScaleTransition;
return a * transition.scale.value; return a * transition.scale.value;
}); });
} }
class _FlutterLogoModal extends StatefulWidget { class _FlutterLogoModal extends StatefulWidget {
const _FlutterLogoModal({ const _FlutterLogoModal({
Key key, Key? key,
this.name, this.name,
}) : super(key: key); }) : super(key: key);
final String name; final String? name;
@override @override
_FlutterLogoModalState createState() => _FlutterLogoModalState(); _FlutterLogoModalState createState() => _FlutterLogoModalState();

View File

@ -47,7 +47,7 @@ void main() {
expect(_getOpacity(bottomRoute, tester), 1.0); expect(_getOpacity(bottomRoute, tester), 1.0);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
@ -127,7 +127,7 @@ void main() {
navigatorKey: navigator, navigatorKey: navigator,
), ),
); );
navigator.currentState.pushNamed('/a'); navigator.currentState!.pushNamed('/a');
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
@ -135,7 +135,7 @@ void main() {
expect(_getOpacity(topRoute, tester), 1.0); expect(_getOpacity(topRoute, tester), 1.0);
expect(find.text(bottomRoute), findsNothing); expect(find.text(bottomRoute), findsNothing);
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Top route is full size and fully visible. // Top route is full size and fully visible.
@ -223,7 +223,7 @@ void main() {
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
// Jump to halfway point of transition. // Jump to halfway point of transition.
@ -242,7 +242,7 @@ void main() {
expect(topOpacity, lessThan(1.0)); expect(topOpacity, lessThan(1.0));
// Interrupt the transition with a pop. // Interrupt the transition with a pop.
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Noting changed. // Noting changed.
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
@ -288,7 +288,7 @@ void main() {
navigatorKey: navigator, navigatorKey: navigator,
contentBuilder: (RouteSettings settings) { contentBuilder: (RouteSettings settings) {
return _StatefulTestWidget( return _StatefulTestWidget(
key: ValueKey<String>(settings.name), key: ValueKey<String?>(settings.name),
name: settings.name, name: settings.name,
); );
}, },
@ -296,73 +296,73 @@ void main() {
); );
final _StatefulTestWidgetState bottomState = final _StatefulTestWidgetState bottomState =
tester.state(find.byKey(const ValueKey<String>(bottomRoute))); tester.state(find.byKey(const ValueKey<String?>(bottomRoute)));
expect(bottomState.widget.name, bottomRoute); expect(bottomState.widget.name, bottomRoute);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
final _StatefulTestWidgetState topState = tester.state( final _StatefulTestWidgetState topState = tester.state(
find.byKey(const ValueKey<String>(topRoute)), find.byKey(const ValueKey<String?>(topRoute)),
); );
expect(topState.widget.name, topRoute); expect(topState.widget.name, topRoute);
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey( tester.state(find.byKey(
const ValueKey<String>(bottomRoute), const ValueKey<String?>(bottomRoute),
skipOffstage: false, skipOffstage: false,
)), )),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect(find.byKey(const ValueKey<String>(topRoute)), findsNothing); expect(find.byKey(const ValueKey<String?>(topRoute)), findsNothing);
}); });
testWidgets('should keep state', (WidgetTester tester) async { testWidgets('should keep state', (WidgetTester tester) async {
@ -433,22 +433,22 @@ void main() {
double _getOpacity(String key, WidgetTester tester) { double _getOpacity(String key, WidgetTester tester) {
final Finder finder = find.ancestor( final Finder finder = find.ancestor(
of: find.byKey(ValueKey<String>(key)), of: find.byKey(ValueKey<String?>(key)),
matching: find.byType(FadeTransition), matching: find.byType(FadeTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final FadeTransition transition = widget; final FadeTransition transition = widget as FadeTransition;
return a * transition.opacity.value; return a * transition.opacity.value;
}); });
} }
double _getScale(String key, WidgetTester tester) { double _getScale(String key, WidgetTester tester) {
final Finder finder = find.ancestor( final Finder finder = find.ancestor(
of: find.byKey(ValueKey<String>(key)), of: find.byKey(ValueKey<String?>(key)),
matching: find.byType(ScaleTransition), matching: find.byType(ScaleTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final ScaleTransition transition = widget; final ScaleTransition transition = widget as ScaleTransition;
return a * transition.scale.value; return a * transition.scale.value;
}); });
} }
@ -456,13 +456,13 @@ double _getScale(String key, WidgetTester tester) {
class _TestWidget extends StatelessWidget { class _TestWidget extends StatelessWidget {
const _TestWidget({this.navigatorKey, this.contentBuilder}); const _TestWidget({this.navigatorKey, this.contentBuilder});
final Key navigatorKey; final Key? navigatorKey;
final _ContentBuilder contentBuilder; final _ContentBuilder? contentBuilder;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
navigatorKey: navigatorKey, navigatorKey: navigatorKey as GlobalKey<NavigatorState>?,
theme: ThemeData( theme: ThemeData(
platform: TargetPlatform.android, platform: TargetPlatform.android,
pageTransitionsTheme: const PageTransitionsTheme( pageTransitionsTheme: const PageTransitionsTheme(
@ -476,11 +476,11 @@ class _TestWidget extends StatelessWidget {
settings: settings, settings: settings,
builder: (BuildContext context) { builder: (BuildContext context) {
return contentBuilder != null return contentBuilder != null
? contentBuilder(settings) ? contentBuilder!(settings)
: Container( : Container(
child: Center( child: Center(
key: ValueKey<String>(settings.name), key: ValueKey<String?>(settings.name),
child: Text(settings.name), child: Text(settings.name!),
), ),
); );
}, },
@ -491,9 +491,9 @@ class _TestWidget extends StatelessWidget {
} }
class _StatefulTestWidget extends StatefulWidget { class _StatefulTestWidget extends StatefulWidget {
const _StatefulTestWidget({Key key, this.name}) : super(key: key); const _StatefulTestWidget({Key? key, this.name}) : super(key: key);
final String name; final String? name;
@override @override
State<_StatefulTestWidget> createState() => _StatefulTestWidgetState(); State<_StatefulTestWidget> createState() => _StatefulTestWidgetState();
@ -502,7 +502,7 @@ class _StatefulTestWidget extends StatefulWidget {
class _StatefulTestWidgetState extends State<_StatefulTestWidget> { class _StatefulTestWidgetState extends State<_StatefulTestWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Text(widget.name); return Text(widget.name!);
} }
} }

View File

@ -464,7 +464,7 @@ double _getOpacity(GlobalKey key, WidgetTester tester) {
matching: find.byType(FadeTransition), matching: find.byType(FadeTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final FadeTransition transition = widget; final FadeTransition transition = widget as FadeTransition;
return a * transition.opacity.value; return a * transition.opacity.value;
}); });
} }
@ -475,18 +475,18 @@ double _getScale(GlobalKey key, WidgetTester tester) {
matching: find.byType(ScaleTransition), matching: find.byType(ScaleTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final ScaleTransition transition = widget; final ScaleTransition transition = widget as ScaleTransition;
return a * transition.scale.value; return a * transition.scale.value;
}); });
} }
class _FlutterLogoModal extends StatefulWidget { class _FlutterLogoModal extends StatefulWidget {
const _FlutterLogoModal({ const _FlutterLogoModal({
Key key, Key? key,
this.name, this.name,
}) : super(key: key); }) : super(key: key);
final String name; final String? name;
@override @override
_FlutterLogoModalState createState() => _FlutterLogoModalState(); _FlutterLogoModalState createState() => _FlutterLogoModalState();
@ -516,8 +516,7 @@ class _TestModalConfiguration extends ModalConfiguration {
String barrierLabel = 'customLabel', String barrierLabel = 'customLabel',
Duration transitionDuration = const Duration(milliseconds: 300), Duration transitionDuration = const Duration(milliseconds: 300),
Duration reverseTransitionDuration = const Duration(milliseconds: 200), Duration reverseTransitionDuration = const Duration(milliseconds: 200),
}) : assert(barrierDismissible != null), }) : super(
super(
barrierColor: barrierColor, barrierColor: barrierColor,
barrierDismissible: barrierDismissible, barrierDismissible: barrierDismissible,
barrierLabel: barrierLabel, barrierLabel: barrierLabel,

View File

@ -44,7 +44,7 @@ void main() {
matching: find.byType(Material), matching: find.byType(Material),
), ),
); );
final Material srcMaterial = srcMaterialElement.widget; final Material srcMaterial = srcMaterialElement.widget as Material;
expect(srcMaterial.color, Colors.green); expect(srcMaterial.color, Colors.green);
expect(srcMaterial.elevation, 4.0); expect(srcMaterial.elevation, 4.0);
expect(srcMaterial.shape, shape); expect(srcMaterial.shape, shape);
@ -69,7 +69,7 @@ void main() {
matching: find.byType(Material), matching: find.byType(Material),
), ),
); );
final Material closedMaterial = destMaterialElement.widget; final Material closedMaterial = destMaterialElement.widget as Material;
expect(closedMaterial.color, Colors.green); expect(closedMaterial.color, Colors.green);
expect(closedMaterial.elevation, 4.0); expect(closedMaterial.elevation, 4.0);
expect(closedMaterial.shape, shape); expect(closedMaterial.shape, shape);
@ -90,7 +90,7 @@ void main() {
// Jump to the start of the fade in. // Jump to the start of the fade in.
await tester.pump(const Duration(milliseconds: 60)); // 300ms * 1/5 = 60ms await tester.pump(const Duration(milliseconds: 60)); // 300ms * 1/5 = 60ms
final _TrackedData dataPreFade = _TrackedData( final _TrackedData dataPreFade = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -107,7 +107,7 @@ void main() {
await tester await tester
.pump(const Duration(milliseconds: 30)); // 300ms * 3/10 = 90ms .pump(const Duration(milliseconds: 30)); // 300ms * 3/10 = 90ms
final _TrackedData dataMidFadeIn = _TrackedData( final _TrackedData dataMidFadeIn = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -128,7 +128,7 @@ void main() {
); // 300ms * 2/5 = 120ms ); // 300ms * 2/5 = 120ms
final _TrackedData dataPostFadeIn = _TrackedData( final _TrackedData dataPostFadeIn = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -144,7 +144,7 @@ void main() {
// Jump almost to the end of the transition. // Jump almost to the end of the transition.
await tester.pump(const Duration(milliseconds: 180)); await tester.pump(const Duration(milliseconds: 180));
final _TrackedData dataTransitionDone = _TrackedData( final _TrackedData dataTransitionDone = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -170,7 +170,7 @@ void main() {
), ),
); );
final _TrackedData dataOpen = _TrackedData( final _TrackedData dataOpen = _TrackedData(
finalMaterialElement.widget, finalMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == finalMaterialElement), find.byElementPredicate((Element e) => e == finalMaterialElement),
), ),
@ -221,7 +221,7 @@ void main() {
), ),
); );
final _TrackedData dataOpen = _TrackedData( final _TrackedData dataOpen = _TrackedData(
initialMaterialElement.widget, initialMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == initialMaterialElement), find.byElementPredicate((Element e) => e == initialMaterialElement),
), ),
@ -245,7 +245,7 @@ void main() {
), ),
); );
final _TrackedData dataTransitionStart = _TrackedData( final _TrackedData dataTransitionStart = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -261,7 +261,7 @@ void main() {
// Jump to start of fade out: 1/5 of 300. // Jump to start of fade out: 1/5 of 300.
await tester.pump(const Duration(milliseconds: 60)); // 300 * 1/5 = 60 await tester.pump(const Duration(milliseconds: 60)); // 300 * 1/5 = 60
final _TrackedData dataPreFadeOut = _TrackedData( final _TrackedData dataPreFadeOut = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -277,7 +277,7 @@ void main() {
// Jump to the middle of the fade out. // Jump to the middle of the fade out.
await tester.pump(const Duration(milliseconds: 30)); // 300 * 3/10 = 90 await tester.pump(const Duration(milliseconds: 30)); // 300 * 3/10 = 90
final _TrackedData dataMidpoint = _TrackedData( final _TrackedData dataMidpoint = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -295,7 +295,7 @@ void main() {
// Jump to the end of the fade out. // Jump to the end of the fade out.
await tester.pump(const Duration(milliseconds: 30)); // 300 * 2/5 = 120 await tester.pump(const Duration(milliseconds: 30)); // 300 * 2/5 = 120
final _TrackedData dataPostFadeOut = _TrackedData( final _TrackedData dataPostFadeOut = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -311,7 +311,7 @@ void main() {
// Jump almost to the end of the transition. // Jump almost to the end of the transition.
await tester.pump(const Duration(milliseconds: 180)); await tester.pump(const Duration(milliseconds: 180));
final _TrackedData dataTransitionDone = _TrackedData( final _TrackedData dataTransitionDone = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -337,7 +337,7 @@ void main() {
), ),
); );
final _TrackedData dataClosed = _TrackedData( final _TrackedData dataClosed = _TrackedData(
finalMaterialElement.widget, finalMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == finalMaterialElement), find.byElementPredicate((Element e) => e == finalMaterialElement),
), ),
@ -388,7 +388,7 @@ void main() {
matching: find.byType(Material), matching: find.byType(Material),
), ),
); );
final Material srcMaterial = srcMaterialElement.widget; final Material srcMaterial = srcMaterialElement.widget as Material;
expect(srcMaterial.color, Colors.green); expect(srcMaterial.color, Colors.green);
expect(srcMaterial.elevation, 4.0); expect(srcMaterial.elevation, 4.0);
expect(srcMaterial.shape, shape); expect(srcMaterial.shape, shape);
@ -413,7 +413,7 @@ void main() {
matching: find.byType(Material), matching: find.byType(Material),
), ),
); );
final Material closedMaterial = destMaterialElement.widget; final Material closedMaterial = destMaterialElement.widget as Material;
expect(closedMaterial.color, Colors.green); expect(closedMaterial.color, Colors.green);
expect(closedMaterial.elevation, 4.0); expect(closedMaterial.elevation, 4.0);
expect(closedMaterial.shape, shape); expect(closedMaterial.shape, shape);
@ -434,7 +434,7 @@ void main() {
// The fade-out takes 1/5 of 300ms. Let's jump to the midpoint of that. // The fade-out takes 1/5 of 300ms. Let's jump to the midpoint of that.
await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/10 = 30ms await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/10 = 30ms
final _TrackedData dataMidFadeOut = _TrackedData( final _TrackedData dataMidFadeOut = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -452,7 +452,7 @@ void main() {
// Let's jump to the crossover point at 1/5 of 300ms. // Let's jump to the crossover point at 1/5 of 300ms.
await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/5 = 60ms await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/5 = 60ms
final _TrackedData dataMidpoint = _TrackedData( final _TrackedData dataMidpoint = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -469,7 +469,7 @@ void main() {
// Let's jump to the middle of the fade-in at 3/5 of 300ms // Let's jump to the middle of the fade-in at 3/5 of 300ms
await tester.pump(const Duration(milliseconds: 120)); // 300ms * 3/5 = 180ms await tester.pump(const Duration(milliseconds: 120)); // 300ms * 3/5 = 180ms
final _TrackedData dataMidFadeIn = _TrackedData( final _TrackedData dataMidFadeIn = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -487,7 +487,7 @@ void main() {
// Let's jump almost to the end of the transition. // Let's jump almost to the end of the transition.
await tester.pump(const Duration(milliseconds: 120)); await tester.pump(const Duration(milliseconds: 120));
final _TrackedData dataTransitionDone = _TrackedData( final _TrackedData dataTransitionDone = _TrackedData(
destMaterialElement.widget, destMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == destMaterialElement), find.byElementPredicate((Element e) => e == destMaterialElement),
), ),
@ -518,7 +518,7 @@ void main() {
), ),
); );
final _TrackedData dataOpen = _TrackedData( final _TrackedData dataOpen = _TrackedData(
finalMaterialElement.widget, finalMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == finalMaterialElement), find.byElementPredicate((Element e) => e == finalMaterialElement),
), ),
@ -567,7 +567,7 @@ void main() {
), ),
); );
final _TrackedData dataOpen = _TrackedData( final _TrackedData dataOpen = _TrackedData(
initialMaterialElement.widget, initialMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == initialMaterialElement), find.byElementPredicate((Element e) => e == initialMaterialElement),
), ),
@ -591,7 +591,7 @@ void main() {
), ),
); );
final _TrackedData dataTransitionStart = _TrackedData( final _TrackedData dataTransitionStart = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -606,7 +606,7 @@ void main() {
// Jump to mid-point of fade-out: 1/10 of 300ms. // Jump to mid-point of fade-out: 1/10 of 300ms.
await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/10 = 30ms await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/10 = 30ms
final _TrackedData dataMidFadeOut = _TrackedData( final _TrackedData dataMidFadeOut = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -627,7 +627,7 @@ void main() {
// Let's jump to the crossover point at 1/5 of 300ms. // Let's jump to the crossover point at 1/5 of 300ms.
await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/5 = 60ms await tester.pump(const Duration(milliseconds: 30)); // 300ms * 1/5 = 60ms
final _TrackedData dataMidpoint = _TrackedData( final _TrackedData dataMidpoint = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -644,7 +644,7 @@ void main() {
// Let's jump to the middle of the fade-in at 3/5 of 300ms // Let's jump to the middle of the fade-in at 3/5 of 300ms
await tester.pump(const Duration(milliseconds: 120)); // 300ms * 3/5 = 180ms await tester.pump(const Duration(milliseconds: 120)); // 300ms * 3/5 = 180ms
final _TrackedData dataMidFadeIn = _TrackedData( final _TrackedData dataMidFadeIn = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -662,7 +662,7 @@ void main() {
// Let's jump almost to the end of the transition. // Let's jump almost to the end of the transition.
await tester.pump(const Duration(milliseconds: 120)); await tester.pump(const Duration(milliseconds: 120));
final _TrackedData dataTransitionDone = _TrackedData( final _TrackedData dataTransitionDone = _TrackedData(
materialElement.widget, materialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == materialElement), find.byElementPredicate((Element e) => e == materialElement),
), ),
@ -692,7 +692,7 @@ void main() {
), ),
); );
final _TrackedData dataClosed = _TrackedData( final _TrackedData dataClosed = _TrackedData(
finalMaterialElement.widget, finalMaterialElement.widget as Material,
tester.getRect( tester.getRect(
find.byElementPredicate((Element e) => e == finalMaterialElement), find.byElementPredicate((Element e) => e == finalMaterialElement),
), ),
@ -731,7 +731,7 @@ void main() {
}); });
testWidgets('Action callbacks work', (WidgetTester tester) async { testWidgets('Action callbacks work', (WidgetTester tester) async {
VoidCallback open, close; late VoidCallback open, close;
await tester.pumpWidget(_boilerplate( await tester.pumpWidget(_boilerplate(
child: Center( child: Center(
child: OpenContainer( child: OpenContainer(
@ -805,7 +805,7 @@ void main() {
}); });
testWidgets('closed widget keeps state', (WidgetTester tester) async { testWidgets('closed widget keeps state', (WidgetTester tester) async {
VoidCallback open; late VoidCallback open;
await tester.pumpWidget(_boilerplate( await tester.pumpWidget(_boilerplate(
child: Center( child: Center(
child: OpenContainer( child: OpenContainer(
@ -1530,9 +1530,9 @@ void main() {
testWidgets( testWidgets(
'onClosed callback receives popped value when container has closed', 'onClosed callback receives popped value when container has closed',
(WidgetTester tester) async { (WidgetTester tester) async {
bool value = false; bool? value = false;
final Widget openContainer = OpenContainer<bool>( final Widget openContainer = OpenContainer<bool>(
onClosed: (bool poppedValue) { onClosed: (bool? poppedValue) {
value = poppedValue; value = poppedValue;
}, },
closedBuilder: (BuildContext context, VoidCallback action) { closedBuilder: (BuildContext context, VoidCallback action) {
@ -1573,9 +1573,9 @@ void main() {
}); });
Widget _createRootNavigatorTest({ Widget _createRootNavigatorTest({
@required Key appKey, required Key appKey,
@required Key nestedNavigatorKey, required Key nestedNavigatorKey,
@required bool useRootNavigator, required bool useRootNavigator,
}) { }) {
return Center( return Center(
child: SizedBox( child: SizedBox(
@ -1729,7 +1729,7 @@ void main() {
// equal to the RouteSettings passed to the OpenContainer // equal to the RouteSettings passed to the OpenContainer
final ModalRoute<dynamic> modalRoute = ModalRoute.of( final ModalRoute<dynamic> modalRoute = ModalRoute.of(
tester.element(find.text('Open')), tester.element(find.text('Open')),
); )!;
expect(modalRoute.settings, routeSettings); expect(modalRoute.settings, routeSettings);
}, },
); );
@ -1781,9 +1781,9 @@ Color _getScrimColor(WidgetTester tester) {
} }
void _expectMaterialPropertiesHaveAdvanced({ void _expectMaterialPropertiesHaveAdvanced({
@required _TrackedData biggerMaterial, required _TrackedData biggerMaterial,
@required _TrackedData smallerMaterial, required _TrackedData smallerMaterial,
@required WidgetTester tester, required WidgetTester tester,
}) { }) {
expect( expect(
biggerMaterial.material.elevation, biggerMaterial.material.elevation,
@ -1814,15 +1814,16 @@ class _TrackedData {
} }
double _getRadius(Material material) { double _getRadius(Material material) {
final RoundedRectangleBorder shape = material.shape; final RoundedRectangleBorder? shape =
material.shape as RoundedRectangleBorder?;
if (shape == null) { if (shape == null) {
return 0.0; return 0.0;
} }
final BorderRadius radius = shape.borderRadius; final BorderRadius radius = shape.borderRadius as BorderRadius;
return radius.topRight.x; return radius.topRight.x;
} }
Widget _boilerplate({@required Widget child}) { Widget _boilerplate({required Widget child}) {
return MaterialApp( return MaterialApp(
home: Scaffold( home: Scaffold(
body: child, body: child,
@ -1831,7 +1832,7 @@ Widget _boilerplate({@required Widget child}) {
} }
class _SizableContainer extends StatefulWidget { class _SizableContainer extends StatefulWidget {
const _SizableContainer({this.initialSize, this.child}); const _SizableContainer({required this.initialSize, required this.child});
final double initialSize; final double initialSize;
final Widget child; final Widget child;
@ -1842,7 +1843,7 @@ class _SizableContainer extends StatefulWidget {
} }
class _SizableContainerState extends State<_SizableContainer> { class _SizableContainerState extends State<_SizableContainer> {
_SizableContainerState({double size}) : _size = size; _SizableContainerState({required double size}) : _size = size;
double get size => _size; double get size => _size;
double _size; double _size;

View File

@ -585,7 +585,7 @@ void main() {
} }
class StatefulTestWidget extends StatefulWidget { class StatefulTestWidget extends StatefulWidget {
const StatefulTestWidget({Key key}) : super(key: key); const StatefulTestWidget({Key? key}) : super(key: key);
@override @override
StatefulTestWidgetState createState() => StatefulTestWidgetState(); StatefulTestWidgetState createState() => StatefulTestWidgetState();

View File

@ -63,7 +63,7 @@ void main() {
expect(_getOpacity(bottomRoute, tester), 1.0); expect(_getOpacity(bottomRoute, tester), 1.0);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
@ -103,7 +103,7 @@ void main() {
// Top route is still invisible, but moving towards the left. // Top route is still invisible, but moving towards the left.
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
expect(_getOpacity(topRoute, tester), 0.0); expect(_getOpacity(topRoute, tester), 0.0);
double topOffset = _getTranslationOffset( double? topOffset = _getTranslationOffset(
topRoute, topRoute,
tester, tester,
SharedAxisTransitionType.horizontal, SharedAxisTransitionType.horizontal,
@ -174,7 +174,7 @@ void main() {
), ),
); );
navigator.currentState.pushNamed('/a'); navigator.currentState!.pushNamed('/a');
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
@ -189,7 +189,7 @@ void main() {
expect(_getOpacity(topRoute, tester), 1.0); expect(_getOpacity(topRoute, tester), 1.0);
expect(find.text(bottomRoute), findsNothing); expect(find.text(bottomRoute), findsNothing);
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Top route is is not offset and fully visible. // Top route is is not offset and fully visible.
@ -228,7 +228,7 @@ void main() {
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(_getOpacity(bottomRoute, tester), expect(_getOpacity(bottomRoute, tester),
moreOrLessEquals(0, epsilon: 0.005)); moreOrLessEquals(0, epsilon: 0.005));
double bottomOffset = _getTranslationOffset( double? bottomOffset = _getTranslationOffset(
bottomRoute, bottomRoute,
tester, tester,
SharedAxisTransitionType.horizontal, SharedAxisTransitionType.horizontal,
@ -300,7 +300,7 @@ void main() {
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
// Jump to halfway point of transition. // Jump to halfway point of transition.
@ -308,7 +308,7 @@ void main() {
// Bottom route is fully faded out. // Bottom route is fully faded out.
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(_getOpacity(bottomRoute, tester), 0.0); expect(_getOpacity(bottomRoute, tester), 0.0);
final double halfwayBottomOffset = _getTranslationOffset( final double? halfwayBottomOffset = _getTranslationOffset(
bottomRoute, bottomRoute,
tester, tester,
SharedAxisTransitionType.horizontal, SharedAxisTransitionType.horizontal,
@ -318,7 +318,7 @@ void main() {
// Top route is fading/coming in. // Top route is fading/coming in.
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
final double halfwayTopOffset = _getTranslationOffset( final double? halfwayTopOffset = _getTranslationOffset(
topRoute, topRoute,
tester, tester,
SharedAxisTransitionType.horizontal, SharedAxisTransitionType.horizontal,
@ -330,7 +330,7 @@ void main() {
expect(halfwayTopOpacity, lessThan(1.0)); expect(halfwayTopOpacity, lessThan(1.0));
// Interrupt the transition with a pop. // Interrupt the transition with a pop.
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Nothing should change. // Nothing should change.
@ -426,8 +426,8 @@ void main() {
navigatorKey: navigator, navigatorKey: navigator,
contentBuilder: (RouteSettings settings) { contentBuilder: (RouteSettings settings) {
return _StatefulTestWidget( return _StatefulTestWidget(
key: ValueKey<String>(settings.name), key: ValueKey<String?>(settings.name),
name: settings.name, name: settings.name!,
); );
}, },
transitionType: SharedAxisTransitionType.horizontal, transitionType: SharedAxisTransitionType.horizontal,
@ -435,74 +435,74 @@ void main() {
); );
final _StatefulTestWidgetState bottomState = tester.state( final _StatefulTestWidgetState bottomState = tester.state(
find.byKey(const ValueKey<String>(bottomRoute)), find.byKey(const ValueKey<String?>(bottomRoute)),
); );
expect(bottomState.widget.name, bottomRoute); expect(bottomState.widget.name, bottomRoute);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
final _StatefulTestWidgetState topState = tester.state( final _StatefulTestWidgetState topState = tester.state(
find.byKey(const ValueKey<String>(topRoute)), find.byKey(const ValueKey<String?>(topRoute)),
); );
expect(topState.widget.name, topRoute); expect(topState.widget.name, topRoute);
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey( tester.state(find.byKey(
const ValueKey<String>(bottomRoute), const ValueKey<String?>(bottomRoute),
skipOffstage: false, skipOffstage: false,
)), )),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect(find.byKey(const ValueKey<String>(topRoute)), findsNothing); expect(find.byKey(const ValueKey<String?>(topRoute)), findsNothing);
}, },
); );
@ -525,21 +525,21 @@ void main() {
Finder fillContainerFinder = find Finder fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/')), of: find.byKey(const ValueKey<String?>('/')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
expect(tester.widget<Container>(fillContainerFinder).color, expect(tester.widget<Container>(fillContainerFinder).color,
defaultFillColor); defaultFillColor);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
fillContainerFinder = find fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/a')), of: find.byKey(const ValueKey<String?>('/a')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
@ -564,20 +564,20 @@ void main() {
Finder fillContainerFinder = find Finder fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/')), of: find.byKey(const ValueKey<String?>('/')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
expect(tester.widget<Container>(fillContainerFinder).color, Colors.green); expect(tester.widget<Container>(fillContainerFinder).color, Colors.green);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
fillContainerFinder = find fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/a')), of: find.byKey(const ValueKey<String?>('/a')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
@ -704,7 +704,7 @@ void main() {
expect(_getOpacity(bottomRoute, tester), 1.0); expect(_getOpacity(bottomRoute, tester), 1.0);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
@ -744,7 +744,7 @@ void main() {
// Top route is still invisible, but moving up. // Top route is still invisible, but moving up.
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
expect(_getOpacity(topRoute, tester), 0.0); expect(_getOpacity(topRoute, tester), 0.0);
double topOffset = _getTranslationOffset( double? topOffset = _getTranslationOffset(
topRoute, topRoute,
tester, tester,
SharedAxisTransitionType.vertical, SharedAxisTransitionType.vertical,
@ -815,7 +815,7 @@ void main() {
), ),
); );
navigator.currentState.pushNamed('/a'); navigator.currentState!.pushNamed('/a');
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
@ -830,7 +830,7 @@ void main() {
expect(_getOpacity(topRoute, tester), 1.0); expect(_getOpacity(topRoute, tester), 1.0);
expect(find.text(bottomRoute), findsNothing); expect(find.text(bottomRoute), findsNothing);
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Top route is is not offset and fully visible. // Top route is is not offset and fully visible.
@ -871,7 +871,7 @@ void main() {
_getOpacity(bottomRoute, tester), _getOpacity(bottomRoute, tester),
moreOrLessEquals(0, epsilon: 0.005), moreOrLessEquals(0, epsilon: 0.005),
); );
double bottomOffset = _getTranslationOffset( double? bottomOffset = _getTranslationOffset(
bottomRoute, bottomRoute,
tester, tester,
SharedAxisTransitionType.vertical, SharedAxisTransitionType.vertical,
@ -943,7 +943,7 @@ void main() {
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
// Jump to halfway point of transition. // Jump to halfway point of transition.
@ -951,7 +951,7 @@ void main() {
// Bottom route is fully faded out. // Bottom route is fully faded out.
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(_getOpacity(bottomRoute, tester), 0.0); expect(_getOpacity(bottomRoute, tester), 0.0);
final double halfwayBottomOffset = _getTranslationOffset( final double? halfwayBottomOffset = _getTranslationOffset(
bottomRoute, bottomRoute,
tester, tester,
SharedAxisTransitionType.vertical, SharedAxisTransitionType.vertical,
@ -961,7 +961,7 @@ void main() {
// Top route is fading/coming in. // Top route is fading/coming in.
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
final double halfwayTopOffset = _getTranslationOffset( final double? halfwayTopOffset = _getTranslationOffset(
topRoute, topRoute,
tester, tester,
SharedAxisTransitionType.vertical, SharedAxisTransitionType.vertical,
@ -973,7 +973,7 @@ void main() {
expect(halfwayTopOpacity, lessThan(1.0)); expect(halfwayTopOpacity, lessThan(1.0));
// Interrupt the transition with a pop. // Interrupt the transition with a pop.
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Nothing should change. // Nothing should change.
@ -1069,8 +1069,8 @@ void main() {
navigatorKey: navigator, navigatorKey: navigator,
contentBuilder: (RouteSettings settings) { contentBuilder: (RouteSettings settings) {
return _StatefulTestWidget( return _StatefulTestWidget(
key: ValueKey<String>(settings.name), key: ValueKey<String?>(settings.name),
name: settings.name, name: settings.name!,
); );
}, },
transitionType: SharedAxisTransitionType.vertical, transitionType: SharedAxisTransitionType.vertical,
@ -1078,74 +1078,74 @@ void main() {
); );
final _StatefulTestWidgetState bottomState = tester.state( final _StatefulTestWidgetState bottomState = tester.state(
find.byKey(const ValueKey<String>(bottomRoute)), find.byKey(const ValueKey<String?>(bottomRoute)),
); );
expect(bottomState.widget.name, bottomRoute); expect(bottomState.widget.name, bottomRoute);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
final _StatefulTestWidgetState topState = tester.state( final _StatefulTestWidgetState topState = tester.state(
find.byKey(const ValueKey<String>(topRoute)), find.byKey(const ValueKey<String?>(topRoute)),
); );
expect(topState.widget.name, topRoute); expect(topState.widget.name, topRoute);
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey( tester.state(find.byKey(
const ValueKey<String>(bottomRoute), const ValueKey<String?>(bottomRoute),
skipOffstage: false, skipOffstage: false,
)), )),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect(find.byKey(const ValueKey<String>(topRoute)), findsNothing); expect(find.byKey(const ValueKey<String?>(topRoute)), findsNothing);
}, },
); );
@ -1168,21 +1168,21 @@ void main() {
Finder fillContainerFinder = find Finder fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/')), of: find.byKey(const ValueKey<String?>('/')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
expect(tester.widget<Container>(fillContainerFinder).color, expect(tester.widget<Container>(fillContainerFinder).color,
defaultFillColor); defaultFillColor);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
fillContainerFinder = find fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/a')), of: find.byKey(const ValueKey<String?>('/a')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
@ -1207,20 +1207,20 @@ void main() {
Finder fillContainerFinder = find Finder fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/')), of: find.byKey(const ValueKey<String?>('/')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
expect(tester.widget<Container>(fillContainerFinder).color, Colors.green); expect(tester.widget<Container>(fillContainerFinder).color, Colors.green);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
fillContainerFinder = find fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/a')), of: find.byKey(const ValueKey<String?>('/a')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
@ -1340,7 +1340,7 @@ void main() {
expect(_getOpacity(bottomRoute, tester), 1.0); expect(_getOpacity(bottomRoute, tester), 1.0);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
@ -1413,7 +1413,7 @@ void main() {
), ),
); );
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(find.text(topRoute), findsOneWidget); expect(find.text(topRoute), findsOneWidget);
@ -1421,7 +1421,7 @@ void main() {
expect(_getOpacity(topRoute, tester), 1.0); expect(_getOpacity(topRoute, tester), 1.0);
expect(find.text(bottomRoute), findsNothing); expect(find.text(bottomRoute), findsNothing);
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Top route is full size and fully visible. // Top route is full size and fully visible.
@ -1498,7 +1498,7 @@ void main() {
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
// Jump to halfway point of transition. // Jump to halfway point of transition.
@ -1520,7 +1520,7 @@ void main() {
expect(halfwayTopOpacity, lessThan(1.0)); expect(halfwayTopOpacity, lessThan(1.0));
// Interrupt the transition with a pop. // Interrupt the transition with a pop.
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
// Nothing should change. // Nothing should change.
@ -1571,7 +1571,7 @@ void main() {
expect(find.text(bottomRoute), findsOneWidget); expect(find.text(bottomRoute), findsOneWidget);
expect(find.text(topRoute), findsNothing); expect(find.text(topRoute), findsNothing);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
// Jump to halfway point of transition. // Jump to halfway point of transition.
@ -1606,82 +1606,82 @@ void main() {
transitionType: SharedAxisTransitionType.scaled, transitionType: SharedAxisTransitionType.scaled,
contentBuilder: (RouteSettings settings) { contentBuilder: (RouteSettings settings) {
return _StatefulTestWidget( return _StatefulTestWidget(
key: ValueKey<String>(settings.name), key: ValueKey<String?>(settings.name),
name: settings.name, name: settings.name!,
); );
}, },
), ),
); );
final _StatefulTestWidgetState bottomState = tester.state( final _StatefulTestWidgetState bottomState = tester.state(
find.byKey(const ValueKey<String>(bottomRoute)), find.byKey(const ValueKey<String?>(bottomRoute)),
); );
expect(bottomState.widget.name, bottomRoute); expect(bottomState.widget.name, bottomRoute);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
final _StatefulTestWidgetState topState = tester.state( final _StatefulTestWidgetState topState = tester.state(
find.byKey(const ValueKey<String>(topRoute)), find.byKey(const ValueKey<String?>(topRoute)),
); );
expect(topState.widget.name, topRoute); expect(topState.widget.name, topRoute);
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey( tester.state(find.byKey(
const ValueKey<String>(bottomRoute), const ValueKey<String?>(bottomRoute),
skipOffstage: false, skipOffstage: false,
)), )),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
navigator.currentState.pop(); navigator.currentState!.pop();
await tester.pump(); await tester.pump();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pump(const Duration(milliseconds: 150)); await tester.pump(const Duration(milliseconds: 150));
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect( expect(
tester.state(find.byKey(const ValueKey<String>(topRoute))), tester.state(find.byKey(const ValueKey<String?>(topRoute))),
topState, topState,
); );
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect( expect(
tester.state(find.byKey(const ValueKey<String>(bottomRoute))), tester.state(find.byKey(const ValueKey<String?>(bottomRoute))),
bottomState, bottomState,
); );
expect(find.byKey(const ValueKey<String>(topRoute)), findsNothing); expect(find.byKey(const ValueKey<String?>(topRoute)), findsNothing);
}, },
); );
@ -1704,21 +1704,21 @@ void main() {
Finder fillContainerFinder = find Finder fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/')), of: find.byKey(const ValueKey<String?>('/')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
expect(tester.widget<Container>(fillContainerFinder).color, expect(tester.widget<Container>(fillContainerFinder).color,
defaultFillColor); defaultFillColor);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
fillContainerFinder = find fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/a')), of: find.byKey(const ValueKey<String?>('/a')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
@ -1743,20 +1743,20 @@ void main() {
Finder fillContainerFinder = find Finder fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/')), of: find.byKey(const ValueKey<String?>('/')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
expect(tester.widget<Container>(fillContainerFinder).color, Colors.green); expect(tester.widget<Container>(fillContainerFinder).color, Colors.green);
navigator.currentState.pushNamed(topRoute); navigator.currentState!.pushNamed(topRoute);
await tester.pump(); await tester.pump();
await tester.pumpAndSettle(); await tester.pumpAndSettle();
fillContainerFinder = find fillContainerFinder = find
.ancestor( .ancestor(
matching: find.byType(Container), matching: find.byType(Container),
of: find.byKey(const ValueKey<String>('/a')), of: find.byKey(const ValueKey<String?>('/a')),
) )
.last; .last;
expect(fillContainerFinder, findsOneWidget); expect(fillContainerFinder, findsOneWidget);
@ -1833,22 +1833,22 @@ void main() {
double _getOpacity(String key, WidgetTester tester) { double _getOpacity(String key, WidgetTester tester) {
final Finder finder = find.ancestor( final Finder finder = find.ancestor(
of: find.byKey(ValueKey<String>(key)), of: find.byKey(ValueKey<String?>(key)),
matching: find.byType(FadeTransition), matching: find.byType(FadeTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final FadeTransition transition = widget; final FadeTransition transition = widget as FadeTransition;
return a * transition.opacity.value; return a * transition.opacity.value;
}); });
} }
double _getTranslationOffset( double? _getTranslationOffset(
String key, String key,
WidgetTester tester, WidgetTester tester,
SharedAxisTransitionType transitionType, SharedAxisTransitionType transitionType,
) { ) {
final Finder finder = find.ancestor( final Finder finder = find.ancestor(
of: find.byKey(ValueKey<String>(key)), of: find.byKey(ValueKey<String?>(key)),
matching: find.byType(Transform), matching: find.byType(Transform),
); );
@ -1856,56 +1856,52 @@ double _getTranslationOffset(
case SharedAxisTransitionType.horizontal: case SharedAxisTransitionType.horizontal:
return tester.widgetList<Transform>(finder).fold<double>(0.0, return tester.widgetList<Transform>(finder).fold<double>(0.0,
(double a, Widget widget) { (double a, Widget widget) {
final Transform transition = widget; final Transform transition = widget as Transform;
final Vector3 translation = transition.transform.getTranslation(); final Vector3 translation = transition.transform.getTranslation();
return a + translation.x; return a + translation.x;
}); });
break;
case SharedAxisTransitionType.vertical: case SharedAxisTransitionType.vertical:
return tester.widgetList<Transform>(finder).fold<double>(0.0, return tester.widgetList<Transform>(finder).fold<double>(0.0,
(double a, Widget widget) { (double a, Widget widget) {
final Transform transition = widget; final Transform transition = widget as Transform;
final Vector3 translation = transition.transform.getTranslation(); final Vector3 translation = transition.transform.getTranslation();
return a + translation.y; return a + translation.y;
}); });
break;
case SharedAxisTransitionType.scaled: case SharedAxisTransitionType.scaled:
// SharedAxisTransitionType.scaled should not return a translation // SharedAxisTransitionType.scaled should not return a translation
// offset. // offset.
return null; return null;
break;
} }
return null; // unreachable
} }
double _getScale(String key, WidgetTester tester) { double _getScale(String key, WidgetTester tester) {
final Finder finder = find.ancestor( final Finder finder = find.ancestor(
of: find.byKey(ValueKey<String>(key)), of: find.byKey(ValueKey<String?>(key)),
matching: find.byType(ScaleTransition), matching: find.byType(ScaleTransition),
); );
return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) { return tester.widgetList(finder).fold<double>(1.0, (double a, Widget widget) {
final ScaleTransition transition = widget; final ScaleTransition transition = widget as ScaleTransition;
return a * transition.scale.value; return a * transition.scale.value;
}); });
} }
class _TestWidget extends StatelessWidget { class _TestWidget extends StatelessWidget {
const _TestWidget({ const _TestWidget({
this.navigatorKey, required this.navigatorKey,
this.contentBuilder, this.contentBuilder,
this.transitionType, required this.transitionType,
this.fillColor, this.fillColor,
}); });
final Key navigatorKey; final Key navigatorKey;
final _ContentBuilder contentBuilder; final _ContentBuilder? contentBuilder;
final SharedAxisTransitionType transitionType; final SharedAxisTransitionType transitionType;
final Color fillColor; final Color? fillColor;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
navigatorKey: navigatorKey, navigatorKey: navigatorKey as GlobalKey<NavigatorState>?,
theme: ThemeData( theme: ThemeData(
platform: TargetPlatform.android, platform: TargetPlatform.android,
pageTransitionsTheme: PageTransitionsTheme( pageTransitionsTheme: PageTransitionsTheme(
@ -1922,11 +1918,11 @@ class _TestWidget extends StatelessWidget {
settings: settings, settings: settings,
builder: (BuildContext context) { builder: (BuildContext context) {
return contentBuilder != null return contentBuilder != null
? contentBuilder(settings) ? contentBuilder!(settings)
: Container( : Container(
child: Center( child: Center(
key: ValueKey<String>(settings.name), key: ValueKey<String?>(settings.name),
child: Text(settings.name), child: Text(settings.name!),
), ),
); );
}, },
@ -1937,7 +1933,7 @@ class _TestWidget extends StatelessWidget {
} }
class _StatefulTestWidget extends StatefulWidget { class _StatefulTestWidget extends StatefulWidget {
const _StatefulTestWidget({Key key, this.name}) : super(key: key); const _StatefulTestWidget({Key? key, required this.name}) : super(key: key);
final String name; final String name;

View File

@ -15,7 +15,7 @@ function check_publish() {
for package_name in "$@"; do for package_name in "$@"; do
local dir="$REPO_DIR/packages/$package_name" local dir="$REPO_DIR/packages/$package_name"
echo "Checking that $package_name can be published." echo "Checking that $package_name can be published."
if (cd "$dir" && pub publish --dry-run > /dev/null); then if (cd "$dir" && flutter pub publish --dry-run > /dev/null); then
echo "Package $package_name is able to be published." echo "Package $package_name is able to be published."
else else
error "Unable to publish $package_name" error "Unable to publish $package_name"