Unverified Commit 19078b1a authored by Alexandre Ardhuin's avatar Alexandre Ardhuin Committed by GitHub

migrate cupertino to nullsafety (#66493)

parent 48ce83a8
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
/// Flutter widgets implementing the current iOS design language.
///
/// To use, import `package:flutter/cupertino.dart`.
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math;
import 'dart:ui' show ImageFilter;
......@@ -58,7 +56,7 @@ const _HeroTag _defaultHeroTag = _HeroTag(null);
class _HeroTag {
const _HeroTag(this.navigator);
final NavigatorState navigator;
final NavigatorState? navigator;
// Let the Hero tag be described in tree dumps.
@override
......@@ -88,10 +86,10 @@ class _HeroTag {
/// When `updateSystemUiOverlay` is true, the nav bar will update the OS
/// status bar's color theme based on the background color of the nav bar.
Widget _wrapWithBackground({
Border border,
Color backgroundColor,
Brightness brightness,
Widget child,
Border? border,
required Color backgroundColor,
Brightness? brightness,
required Widget child,
bool updateSystemUiOverlay = true,
}) {
Widget result = child;
......@@ -137,7 +135,7 @@ Widget _wrapWithBackground({
// `actionsForegroundColor`. CupertinoThemes can be used to support these
// scenarios now. To support `actionsForegroundColor`, the nav bar rewraps
// its children with a CupertinoTheme.
Widget _wrapActiveColor(Color color, BuildContext context, Widget child) {
Widget _wrapActiveColor(Color? color, BuildContext context, Widget child) {
if (color == null) {
return child;
}
......@@ -150,7 +148,7 @@ Widget _wrapActiveColor(Color color, BuildContext context, Widget child) {
// Whether the current route supports nav bar hero transitions from or to.
bool _isTransitionable(BuildContext context) {
final ModalRoute<dynamic> route = ModalRoute.of(context);
final ModalRoute<dynamic>? route = ModalRoute.of(context);
// Fullscreen dialogs never transitions their nav bar with other push-style
// pages' nav bars or with other fullscreen dialog pages on the way in or on
......@@ -209,7 +207,7 @@ bool _isTransitionable(BuildContext context) {
class CupertinoNavigationBar extends StatefulWidget implements ObstructingPreferredSizeWidget {
/// Creates a navigation bar in the iOS style.
const CupertinoNavigationBar({
Key key,
Key? key,
this.leading,
this.automaticallyImplyLeading = true,
this.automaticallyImplyMiddle = true,
......@@ -245,7 +243,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
/// If null and [automaticallyImplyLeading] is true, an appropriate button
/// will be automatically created.
/// {@endtemplate}
final Widget leading;
final Widget? leading;
/// {@template flutter.cupertino.navBar.automaticallyImplyLeading}
/// Controls whether we should try to imply the leading widget if null.
......@@ -286,7 +284,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
/// Has no effect when [leading] is not null or if [automaticallyImplyLeading]
/// is false.
/// {@endtemplate}
final String previousPageTitle;
final String? previousPageTitle;
/// Widget to place in the middle of the navigation bar. Normally a title or
/// a segmented control.
......@@ -294,13 +292,13 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
/// If null and [automaticallyImplyMiddle] is true, an appropriate [Text]
/// title will be created if the current route is a [CupertinoPageRoute] and
/// has a `title`.
final Widget middle;
final Widget? middle;
/// {@template flutter.cupertino.navBar.trailing}
/// Widget to place at the end of the navigation bar. Normally additional actions
/// taken on the page such as a search or edit function.
/// {@endtemplate}
final Widget trailing;
final Widget? trailing;
// TODO(xster): https://github.com/flutter/flutter/issues/10469 implement
// support for double row navigation bars.
......@@ -312,7 +310,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
///
/// Defaults to [CupertinoTheme]'s `barBackgroundColor` if null.
/// {@endtemplate}
final Color backgroundColor;
final Color? backgroundColor;
/// {@template flutter.cupertino.navBar.brightness}
/// The brightness of the specified [backgroundColor].
......@@ -324,7 +322,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
/// If set to null, the value of the property will be inferred from the relative
/// luminance of [backgroundColor].
/// {@endtemplate}
final Brightness brightness;
final Brightness? brightness;
/// {@template flutter.cupertino.navBar.padding}
/// Padding for the contents of the navigation bar.
......@@ -339,7 +337,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
///
/// Vertical padding won't change the height of the nav bar.
/// {@endtemplate}
final EdgeInsetsDirectional padding;
final EdgeInsetsDirectional? padding;
/// {@template flutter.cupertino.navBar.border}
/// The border of the navigation bar. By default renders a single pixel bottom border side.
......@@ -361,7 +359,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
'Use CupertinoTheme and primaryColor to propagate color. '
'This feature was deprecated after v1.1.2.'
)
final Color actionsForegroundColor;
final Color? actionsForegroundColor;
/// {@template flutter.cupertino.navBar.transitionBetweenRoutes}
/// Whether to transition between navigation bars.
......@@ -422,7 +420,7 @@ class CupertinoNavigationBar extends StatefulWidget implements ObstructingPrefer
// don't change when rebuilding the nav bar, causing the sub-components to
// lose their own states.
class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
_NavigationBarStaticComponentsKeys keys;
late _NavigationBarStaticComponentsKeys keys;
@override
void initState() {
......@@ -462,7 +460,7 @@ class _CupertinoNavigationBarState extends State<CupertinoNavigationBar> {
),
);
final Color actionsForegroundColor = CupertinoDynamicColor.resolve(
final Color? actionsForegroundColor = CupertinoDynamicColor.resolve(
widget.actionsForegroundColor,
context,
);
......@@ -563,7 +561,7 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
///
/// The [largeTitle] argument is required and must not be null.
const CupertinoSliverNavigationBar({
Key key,
Key? key,
this.largeTitle,
this.leading,
this.automaticallyImplyLeading = true,
......@@ -609,12 +607,12 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
///
/// This parameter must either be non-null or the route must have a title
/// ([CupertinoPageRoute.title]) and [automaticallyImplyTitle] must be true.
final Widget largeTitle;
final Widget? largeTitle;
/// {@macro flutter.cupertino.navBar.leading}
///
/// This widget is visible in both collapsed and expanded states.
final Widget leading;
final Widget? leading;
/// {@macro flutter.cupertino.navBar.automaticallyImplyLeading}
final bool automaticallyImplyLeading;
......@@ -629,7 +627,7 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
final bool automaticallyImplyTitle;
/// {@macro flutter.cupertino.navBar.previousPageTitle}
final String previousPageTitle;
final String? previousPageTitle;
/// A widget to place in the middle of the static navigation bar instead of
/// the [largeTitle].
......@@ -637,21 +635,21 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
/// This widget is visible in both collapsed and expanded states. The text
/// supplied in [largeTitle] will no longer appear in collapsed state if a
/// [middle] widget is provided.
final Widget middle;
final Widget? middle;
/// {@macro flutter.cupertino.navBar.trailing}
///
/// This widget is visible in both collapsed and expanded states.
final Widget trailing;
final Widget? trailing;
/// {@macro flutter.cupertino.navBar.backgroundColor}
final Color backgroundColor;
final Color? backgroundColor;
/// {@macro flutter.cupertino.navBar.brightness}
final Brightness brightness;
final Brightness? brightness;
/// {@macro flutter.cupertino.navBar.padding}
final EdgeInsetsDirectional padding;
final EdgeInsetsDirectional? padding;
/// {@macro flutter.cupertino.navBar.border}
final Border border;
......@@ -664,7 +662,7 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
'Use CupertinoTheme and primaryColor to propagate color. '
'This feature was deprecated after v1.1.2.'
)
final Color actionsForegroundColor;
final Color? actionsForegroundColor;
/// {@macro flutter.cupertino.navBar.transitionBetweenRoutes}
final bool transitionBetweenRoutes;
......@@ -673,7 +671,7 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
final Object heroTag;
/// True if the navigation bar's background color has no transparency.
bool get opaque => backgroundColor.alpha == 0xFF;
bool get opaque => backgroundColor?.alpha == 0xFF;
@override
_CupertinoSliverNavigationBarState createState() => _CupertinoSliverNavigationBarState();
......@@ -683,7 +681,7 @@ class CupertinoSliverNavigationBar extends StatefulWidget {
// don't change when rebuilding the nav bar, causing the sub-components to
// lose their own states.
class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigationBar> {
_NavigationBarStaticComponentsKeys keys;
late _NavigationBarStaticComponentsKeys keys;
@override
void initState() {
......@@ -716,7 +714,7 @@ class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigation
actionsForegroundColor,
context,
MediaQuery(
data: MediaQuery.of(context).copyWith(textScaleFactor: 1),
data: MediaQuery.of(context)!.copyWith(textScaleFactor: 1),
child: SliverPersistentHeader(
pinned: true, // iOS navigation bars are always pinned.
delegate: _LargeTitleNavigationBarSliverDelegate(
......@@ -730,7 +728,7 @@ class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigation
actionsForegroundColor: actionsForegroundColor,
transitionBetweenRoutes: widget.transitionBetweenRoutes,
heroTag: widget.heroTag,
persistentHeight: _kNavBarPersistentHeight + MediaQuery.of(context).padding.top,
persistentHeight: _kNavBarPersistentHeight + MediaQuery.of(context)!.padding.top,
alwaysShowMiddle: widget.middle != null,
),
),
......@@ -742,29 +740,29 @@ class _CupertinoSliverNavigationBarState extends State<CupertinoSliverNavigation
class _LargeTitleNavigationBarSliverDelegate
extends SliverPersistentHeaderDelegate with DiagnosticableTreeMixin {
_LargeTitleNavigationBarSliverDelegate({
@required this.keys,
@required this.components,
@required this.userMiddle,
@required this.backgroundColor,
@required this.brightness,
@required this.border,
@required this.padding,
@required this.actionsForegroundColor,
@required this.transitionBetweenRoutes,
@required this.heroTag,
@required this.persistentHeight,
@required this.alwaysShowMiddle,
required this.keys,
required this.components,
required this.userMiddle,
required this.backgroundColor,
required this.brightness,
required this.border,
required this.padding,
required this.actionsForegroundColor,
required this.transitionBetweenRoutes,
required this.heroTag,
required this.persistentHeight,
required this.alwaysShowMiddle,
}) : assert(persistentHeight != null),
assert(alwaysShowMiddle != null),
assert(transitionBetweenRoutes != null);
final _NavigationBarStaticComponentsKeys keys;
final _NavigationBarStaticComponents components;
final Widget userMiddle;
final Widget? userMiddle;
final Color backgroundColor;
final Brightness brightness;
final Border border;
final EdgeInsetsDirectional padding;
final Brightness? brightness;
final Border? border;
final EdgeInsetsDirectional? padding;
final Color actionsForegroundColor;
final bool transitionBetweenRoutes;
final Object heroTag;
......@@ -792,7 +790,7 @@ class _LargeTitleNavigationBarSliverDelegate
final Widget navBar = _wrapWithBackground(
border: border,
backgroundColor: CupertinoDynamicColor.resolve(backgroundColor, context),
backgroundColor: CupertinoDynamicColor.resolve(backgroundColor, context)!,
brightness: brightness,
child: DefaultTextStyle(
style: CupertinoTheme.of(context).textTheme.textStyle,
......@@ -829,7 +827,7 @@ class _LargeTitleNavigationBarSliverDelegate
style: CupertinoTheme.of(context).textTheme.navLargeTitleTextStyle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
child: components.largeTitle,
child: components.largeTitle!,
),
),
),
......@@ -900,22 +898,22 @@ class _LargeTitleNavigationBarSliverDelegate
/// doesn't scroll.
class _PersistentNavigationBar extends StatelessWidget {
const _PersistentNavigationBar({
Key key,
this.components,
Key? key,
required this.components,
this.padding,
this.middleVisible,
}) : super(key: key);
final _NavigationBarStaticComponents components;
final EdgeInsetsDirectional padding;
final EdgeInsetsDirectional? padding;
/// Whether the middle widget has a visible animated opacity. A null value
/// means the middle opacity will not be animated.
final bool middleVisible;
final bool? middleVisible;
@override
Widget build(BuildContext context) {
Widget middle = components.middle;
Widget? middle = components.middle;
if (middle != null) {
middle = DefaultTextStyle(
......@@ -927,15 +925,15 @@ class _PersistentNavigationBar extends StatelessWidget {
middle = middleVisible == null
? middle
: AnimatedOpacity(
opacity: middleVisible ? 1.0 : 0.0,
opacity: middleVisible! ? 1.0 : 0.0,
duration: _kNavBarTitleFadeDuration,
child: middle,
);
}
Widget leading = components.leading;
final Widget backChevron = components.backChevron;
final Widget backLabel = components.backLabel;
Widget? leading = components.leading;
final Widget? backChevron = components.backChevron;
final Widget? backLabel = components.backLabel;
if (leading == null && backChevron != null && backLabel != null) {
leading = CupertinoNavigationBarBackButton._assemble(
......@@ -955,15 +953,15 @@ class _PersistentNavigationBar extends StatelessWidget {
if (padding != null) {
paddedToolbar = Padding(
padding: EdgeInsets.only(
top: padding.top,
bottom: padding.bottom,
top: padding!.top,
bottom: padding!.bottom,
),
child: paddedToolbar,
);
}
return SizedBox(
height: _kNavBarPersistentHeight + MediaQuery.of(context).padding.top,
height: _kNavBarPersistentHeight + MediaQuery.of(context)!.padding.top,
child: SafeArea(
bottom: false,
child: paddedToolbar,
......@@ -1005,17 +1003,17 @@ class _NavigationBarStaticComponentsKeys {
@immutable
class _NavigationBarStaticComponents {
_NavigationBarStaticComponents({
@required _NavigationBarStaticComponentsKeys keys,
@required ModalRoute<dynamic> route,
@required Widget userLeading,
@required bool automaticallyImplyLeading,
@required bool automaticallyImplyTitle,
@required String previousPageTitle,
@required Widget userMiddle,
@required Widget userTrailing,
@required Widget userLargeTitle,
@required EdgeInsetsDirectional padding,
@required bool large,
required _NavigationBarStaticComponentsKeys keys,
required ModalRoute<dynamic>? route,
required Widget? userLeading,
required bool automaticallyImplyLeading,
required bool automaticallyImplyTitle,
required String? previousPageTitle,
required Widget? userMiddle,
required Widget? userTrailing,
required Widget? userLargeTitle,
required EdgeInsetsDirectional? padding,
required bool large,
}) : leading = createLeading(
leadingKey: keys.leadingKey,
userLeading: userLeading,
......@@ -1057,29 +1055,29 @@ class _NavigationBarStaticComponents {
large: large,
);
static Widget _derivedTitle({
bool automaticallyImplyTitle,
ModalRoute<dynamic> currentRoute,
static Widget? _derivedTitle({
required bool automaticallyImplyTitle,
ModalRoute<dynamic>? currentRoute,
}) {
// Auto use the CupertinoPageRoute's title if middle not provided.
if (automaticallyImplyTitle &&
currentRoute is CupertinoRouteTransitionMixin &&
currentRoute.title != null) {
return Text(currentRoute.title);
return Text(currentRoute.title!);
}
return null;
}
final KeyedSubtree leading;
static KeyedSubtree createLeading({
@required GlobalKey leadingKey,
@required Widget userLeading,
@required ModalRoute<dynamic> route,
@required bool automaticallyImplyLeading,
@required EdgeInsetsDirectional padding,
final KeyedSubtree? leading;
static KeyedSubtree? createLeading({
required GlobalKey leadingKey,
required Widget? userLeading,
required ModalRoute<dynamic>? route,
required bool automaticallyImplyLeading,
required EdgeInsetsDirectional? padding,
}) {
Widget leadingContent;
Widget? leadingContent;
if (userLeading != null) {
leadingContent = userLeading;
......@@ -1092,7 +1090,7 @@ class _NavigationBarStaticComponents {
leadingContent = CupertinoButton(
child: const Text('Close'),
padding: EdgeInsets.zero,
onPressed: () { route.navigator.maybePop(); },
onPressed: () { route.navigator!.maybePop(); },
);
}
......@@ -1116,12 +1114,12 @@ class _NavigationBarStaticComponents {
);
}
final KeyedSubtree backChevron;
static KeyedSubtree createBackChevron({
@required GlobalKey backChevronKey,
@required Widget userLeading,
@required ModalRoute<dynamic> route,
@required bool automaticallyImplyLeading,
final KeyedSubtree? backChevron;
static KeyedSubtree? createBackChevron({
required GlobalKey backChevronKey,
required Widget? userLeading,
required ModalRoute<dynamic>? route,
required bool automaticallyImplyLeading,
}) {
if (
userLeading != null ||
......@@ -1138,13 +1136,13 @@ class _NavigationBarStaticComponents {
/// This widget is not decorated with a font since the font style could
/// animate during transitions.
final KeyedSubtree backLabel;
static KeyedSubtree createBackLabel({
@required GlobalKey backLabelKey,
@required Widget userLeading,
@required ModalRoute<dynamic> route,
@required bool automaticallyImplyLeading,
@required String previousPageTitle,
final KeyedSubtree? backLabel;
static KeyedSubtree? createBackLabel({
required GlobalKey backLabelKey,
required Widget? userLeading,
required ModalRoute<dynamic>? route,
required bool automaticallyImplyLeading,
required String? previousPageTitle,
}) {
if (
userLeading != null ||
......@@ -1167,16 +1165,16 @@ class _NavigationBarStaticComponents {
/// This widget is not decorated with a font since the font style could
/// animate during transitions.
final KeyedSubtree middle;
static KeyedSubtree createMiddle({
@required GlobalKey middleKey,
@required Widget userMiddle,
@required Widget userLargeTitle,
@required bool large,
@required bool automaticallyImplyTitle,
@required ModalRoute<dynamic> route,
final KeyedSubtree? middle;
static KeyedSubtree? createMiddle({
required GlobalKey middleKey,
required Widget? userMiddle,
required Widget? userLargeTitle,
required bool large,
required bool automaticallyImplyTitle,
required ModalRoute<dynamic>? route,
}) {
Widget middleContent = userMiddle;
Widget? middleContent = userMiddle;
if (large) {
middleContent ??= userLargeTitle;
......@@ -1197,11 +1195,11 @@ class _NavigationBarStaticComponents {
);
}
final KeyedSubtree trailing;
static KeyedSubtree createTrailing({
@required GlobalKey trailingKey,
@required Widget userTrailing,
@required EdgeInsetsDirectional padding,
final KeyedSubtree? trailing;
static KeyedSubtree? createTrailing({
required GlobalKey trailingKey,
required Widget? userTrailing,
required EdgeInsetsDirectional? padding,
}) {
if (userTrailing == null) {
return null;
......@@ -1225,19 +1223,19 @@ class _NavigationBarStaticComponents {
/// This widget is not decorated with a font since the font style could
/// animate during transitions.
final KeyedSubtree largeTitle;
static KeyedSubtree createLargeTitle({
@required GlobalKey largeTitleKey,
@required Widget userLargeTitle,
@required bool large,
@required bool automaticImplyTitle,
@required ModalRoute<dynamic> route,
final KeyedSubtree? largeTitle;
static KeyedSubtree? createLargeTitle({
required GlobalKey largeTitleKey,
required Widget? userLargeTitle,
required bool large,
required bool automaticImplyTitle,
required ModalRoute<dynamic>? route,
}) {
if (!large) {
return null;
}
final Widget largeTitleContent = userLargeTitle ?? _derivedTitle(
final Widget? largeTitleContent = userLargeTitle ?? _derivedTitle(
automaticallyImplyTitle: automaticImplyTitle,
currentRoute: route,
);
......@@ -1249,7 +1247,7 @@ class _NavigationBarStaticComponents {
return KeyedSubtree(
key: largeTitleKey,
child: largeTitleContent,
child: largeTitleContent!,
);
}
}
......@@ -1273,7 +1271,7 @@ class CupertinoNavigationBarBackButton extends StatelessWidget {
///
/// The [color] parameter must not be null.
const CupertinoNavigationBarBackButton({
Key key,
Key? key,
this.color,
this.previousPageTitle,
this.onPressed,
......@@ -1295,12 +1293,12 @@ class CupertinoNavigationBarBackButton extends StatelessWidget {
/// Can be used to override the color of the back button chevron and label.
///
/// Defaults to [CupertinoTheme]'s `primaryColor` if null.
final Color color;
final Color? color;
/// An override for showing the previous route's title. If null, it will be
/// automatically derived from [CupertinoPageRoute.title] if the current and
/// previous routes are both [CupertinoPageRoute]s.
final String previousPageTitle;
final String? previousPageTitle;
/// An override callback to perform instead of the default behavior which is
/// to pop the [Navigator].
......@@ -1310,15 +1308,15 @@ class CupertinoNavigationBarBackButton extends StatelessWidget {
/// situations.
///
/// Defaults to null.
final VoidCallback onPressed;
final VoidCallback? onPressed;
final Widget _backChevron;
final Widget? _backChevron;
final Widget _backLabel;
final Widget? _backLabel;
@override
Widget build(BuildContext context) {
final ModalRoute<dynamic> currentRoute = ModalRoute.of(context);
final ModalRoute<dynamic>? currentRoute = ModalRoute.of(context);
if (onPressed == null) {
assert(
currentRoute?.canPop == true,
......@@ -1362,7 +1360,7 @@ class CupertinoNavigationBarBackButton extends StatelessWidget {
padding: EdgeInsets.zero,
onPressed: () {
if (onPressed != null) {
onPressed();
onPressed!();
} else {
Navigator.maybePop(context);
}
......@@ -1373,12 +1371,12 @@ class CupertinoNavigationBarBackButton extends StatelessWidget {
class _BackChevron extends StatelessWidget {
const _BackChevron({ Key key }) : super(key: key);
const _BackChevron({ Key? key }) : super(key: key);
@override
Widget build(BuildContext context) {
final TextDirection textDirection = Directionality.of(context);
final TextStyle textStyle = DefaultTextStyle.of(context).style;
final TextDirection textDirection = Directionality.of(context)!;
final TextStyle textStyle = DefaultTextStyle.of(context).style!;
// Replicate the Icon logic here to get a tightly sized icon and add
// custom non-square padding.
......@@ -1415,17 +1413,17 @@ class _BackChevron extends StatelessWidget {
/// is true.
class _BackLabel extends StatelessWidget {
const _BackLabel({
Key key,
@required this.specifiedPreviousTitle,
@required this.route,
Key? key,
required this.specifiedPreviousTitle,
required this.route,
}) : super(key: key);
final String specifiedPreviousTitle;
final ModalRoute<dynamic> route;
final String? specifiedPreviousTitle;
final ModalRoute<dynamic>? route;
// `child` is never passed in into ValueListenableBuilder so it's always
// null here and unused.
Widget _buildPreviousTitleWidget(BuildContext context, String previousTitle, Widget child) {
Widget _buildPreviousTitleWidget(BuildContext context, String? previousTitle, Widget? child) {
if (previousTitle == null) {
return const SizedBox(height: 0.0, width: 0.0);
}
......@@ -1451,12 +1449,12 @@ class _BackLabel extends StatelessWidget {
Widget build(BuildContext context) {
if (specifiedPreviousTitle != null) {
return _buildPreviousTitleWidget(context, specifiedPreviousTitle, null);
} else if (route is CupertinoRouteTransitionMixin<dynamic> && !route.isFirst) {
} else if (route is CupertinoRouteTransitionMixin<dynamic> && !route!.isFirst) {
final CupertinoRouteTransitionMixin<dynamic> cupertinoRoute = route as CupertinoRouteTransitionMixin<dynamic>;
// There is no timing issue because the previousTitle Listenable changes
// happen during route modifications before the ValueListenableBuilder
// is built.
return ValueListenableBuilder<String>(
return ValueListenableBuilder<String?>(
valueListenable: cupertinoRoute.previousTitle,
builder: _buildPreviousTitleWidget,
);
......@@ -1476,32 +1474,32 @@ class _BackLabel extends StatelessWidget {
/// navigation bar in each route.
class _TransitionableNavigationBar extends StatelessWidget {
_TransitionableNavigationBar({
@required this.componentsKeys,
@required this.backgroundColor,
@required this.backButtonTextStyle,
@required this.titleTextStyle,
@required this.largeTitleTextStyle,
@required this.border,
@required this.hasUserMiddle,
@required this.largeExpanded,
@required this.child,
required this.componentsKeys,
required this.backgroundColor,
required this.backButtonTextStyle,
required this.titleTextStyle,
required this.largeTitleTextStyle,
required this.border,
required this.hasUserMiddle,
required this.largeExpanded,
required this.child,
}) : assert(componentsKeys != null),
assert(largeExpanded != null),
assert(!largeExpanded || largeTitleTextStyle != null),
super(key: componentsKeys.navBarBoxKey);
final _NavigationBarStaticComponentsKeys componentsKeys;
final Color backgroundColor;
final Color? backgroundColor;
final TextStyle backButtonTextStyle;
final TextStyle titleTextStyle;
final TextStyle largeTitleTextStyle;
final Border border;
final TextStyle? largeTitleTextStyle;
final Border? border;
final bool hasUserMiddle;
final bool largeExpanded;
final Widget child;
RenderBox get renderBox {
final RenderBox box = componentsKeys.navBarBoxKey.currentContext.findRenderObject() as RenderBox;
final RenderBox box = componentsKeys.navBarBoxKey.currentContext!.findRenderObject() as RenderBox;
assert(
box.attached,
'_TransitionableNavigationBar.renderBox should be called when building '
......@@ -1514,7 +1512,7 @@ class _TransitionableNavigationBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
assert(() {
bool inHero;
bool inHero = false;
context.visitAncestorElements((Element ancestor) {
if (ancestor is ComponentElement) {
assert(
......@@ -1528,11 +1526,10 @@ class _TransitionableNavigationBar extends StatelessWidget {
inHero = true;
}
}
inHero ??= false;
return true;
});
assert(
inHero == true,
inHero,
'_TransitionableNavigationBar should only be added as the immediate '
'child of Hero widgets.',
);
......@@ -1559,9 +1556,9 @@ class _TransitionableNavigationBar extends StatelessWidget {
/// results.
class _NavigationBarTransition extends StatelessWidget {
_NavigationBarTransition({
@required this.animation,
@required this.topNavBar,
@required this.bottomNavBar,
required this.animation,
required this.topNavBar,
required this.bottomNavBar,
}) : heightTween = Tween<double>(
begin: bottomNavBar.renderBox.size.height,
end: topNavBar.renderBox.size.height,
......@@ -1589,7 +1586,7 @@ class _NavigationBarTransition extends StatelessWidget {
animation: animation,
bottomNavBar: bottomNavBar,
topNavBar: topNavBar,
directionality: Directionality.of(context),
directionality: Directionality.of(context)!,
);
final List<Widget> children = <Widget>[
......@@ -1597,11 +1594,11 @@ class _NavigationBarTransition extends StatelessWidget {
// moving components without any components inside it itself.
AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) {
builder: (BuildContext context, Widget? child) {
return _wrapWithBackground(
// Don't update the system status bar color mid-flight.
updateSystemUiOverlay: false,
backgroundColor: backgroundTween.evaluate(animation),
backgroundColor: backgroundTween.evaluate(animation)!,
border: borderTween.evaluate(animation),
child: SizedBox(
height: heightTween.evaluate(animation),
......@@ -1611,29 +1608,28 @@ class _NavigationBarTransition extends StatelessWidget {
},
),
// Draw all the components on top of the empty bar box.
componentsTransition.bottomBackChevron,
componentsTransition.bottomBackLabel,
componentsTransition.bottomLeading,
componentsTransition.bottomMiddle,
componentsTransition.bottomLargeTitle,
componentsTransition.bottomTrailing,
if (componentsTransition.bottomBackChevron != null) componentsTransition.bottomBackChevron!,
if (componentsTransition.bottomBackLabel != null) componentsTransition.bottomBackLabel!,
if (componentsTransition.bottomLeading != null) componentsTransition.bottomLeading!,
if (componentsTransition.bottomMiddle != null) componentsTransition.bottomMiddle!,
if (componentsTransition.bottomLargeTitle != null) componentsTransition.bottomLargeTitle!,
if (componentsTransition.bottomTrailing != null) componentsTransition.bottomTrailing!,
// Draw top components on top of the bottom components.
componentsTransition.topLeading,
componentsTransition.topBackChevron,
componentsTransition.topBackLabel,
componentsTransition.topMiddle,
componentsTransition.topLargeTitle,
componentsTransition.topTrailing,
if (componentsTransition.topLeading != null) componentsTransition.topLeading!,
if (componentsTransition.topBackChevron != null) componentsTransition.topBackChevron!,
if (componentsTransition.topBackLabel != null) componentsTransition.topBackLabel!,
if (componentsTransition.topMiddle != null) componentsTransition.topMiddle!,
if (componentsTransition.topLargeTitle != null) componentsTransition.topLargeTitle!,
if (componentsTransition.topTrailing != null) componentsTransition.topTrailing!,
];
children.removeWhere((Widget child) => child == null);
// The actual outer box is big enough to contain both the bottom and top
// navigation bars. It's not a direct Rect lerp because some components
// can actually be outside the linearly lerp'ed Rect in the middle of
// the animation, such as the topLargeTitle.
return SizedBox(
height: math.max(heightTween.begin, heightTween.end) + MediaQuery.of(context).padding.top,
height: math.max(heightTween.begin!, heightTween.end!) + MediaQuery.of(context)!.padding.top,
width: double.infinity,
child: Stack(
children: children,
......@@ -1666,10 +1662,10 @@ class _NavigationBarTransition extends StatelessWidget {
@immutable
class _NavigationBarComponentsTransition {
_NavigationBarComponentsTransition({
@required this.animation,
@required _TransitionableNavigationBar bottomNavBar,
@required _TransitionableNavigationBar topNavBar,
@required TextDirection directionality,
required this.animation,
required _TransitionableNavigationBar bottomNavBar,
required _TransitionableNavigationBar topNavBar,
required TextDirection directionality,
}) : bottomComponents = bottomNavBar.componentsKeys,
topComponents = topNavBar.componentsKeys,
bottomNavBarBox = bottomNavBar.renderBox,
......@@ -1712,8 +1708,8 @@ class _NavigationBarComponentsTransition {
final TextStyle topBackButtonTextStyle;
final TextStyle bottomTitleTextStyle;
final TextStyle topTitleTextStyle;
final TextStyle bottomLargeTitleTextStyle;
final TextStyle topLargeTitleTextStyle;
final TextStyle? bottomLargeTitleTextStyle;
final TextStyle? topLargeTitleTextStyle;
final bool bottomHasUserMiddle;
final bool topHasUserMiddle;
......@@ -1731,9 +1727,9 @@ class _NavigationBarComponentsTransition {
// translate it into a RelativeBox in the transition navigation bar box.
RelativeRect positionInTransitionBox(
GlobalKey key, {
@required RenderBox from,
required RenderBox from,
}) {
final RenderBox componentBox = key.currentContext.findRenderObject() as RenderBox;
final RenderBox componentBox = key.currentContext!.findRenderObject() as RenderBox;
assert(componentBox.attached);
return RelativeRect.fromRect(
......@@ -1753,15 +1749,15 @@ class _NavigationBarComponentsTransition {
// BoxConstraints of the 'from' widget so that animating font sizes etc don't
// produce rounding error artifacts with a linearly resizing rect.
RelativeRectTween slideFromLeadingEdge({
@required GlobalKey fromKey,
@required RenderBox fromNavBarBox,
@required GlobalKey toKey,
@required RenderBox toNavBarBox,
required GlobalKey fromKey,
required RenderBox fromNavBarBox,
required GlobalKey toKey,
required RenderBox toNavBarBox,
}) {
final RelativeRect fromRect = positionInTransitionBox(fromKey, from: fromNavBarBox);
final RenderBox fromBox = fromKey.currentContext.findRenderObject() as RenderBox;
final RenderBox toBox = toKey.currentContext.findRenderObject() as RenderBox;
final RenderBox fromBox = fromKey.currentContext!.findRenderObject() as RenderBox;
final RenderBox toBox = toKey.currentContext!.findRenderObject() as RenderBox;
// We move a box with the size of the 'from' render object such that its
// upper left corner is at the upper left corner of the 'to' render object.
......@@ -1799,8 +1795,8 @@ class _NavigationBarComponentsTransition {
));
}
Widget get bottomLeading {
final KeyedSubtree bottomLeading = bottomComponents.leadingKey.currentWidget as KeyedSubtree;
Widget? get bottomLeading {
final KeyedSubtree? bottomLeading = bottomComponents.leadingKey.currentWidget as KeyedSubtree?;
if (bottomLeading == null) {
return null;
......@@ -1815,8 +1811,8 @@ class _NavigationBarComponentsTransition {
);
}
Widget get bottomBackChevron {
final KeyedSubtree bottomBackChevron = bottomComponents.backChevronKey.currentWidget as KeyedSubtree;
Widget? get bottomBackChevron {
final KeyedSubtree? bottomBackChevron = bottomComponents.backChevronKey.currentWidget as KeyedSubtree?;
if (bottomBackChevron == null) {
return null;
......@@ -1834,8 +1830,8 @@ class _NavigationBarComponentsTransition {
);
}
Widget get bottomBackLabel {
final KeyedSubtree bottomBackLabel = bottomComponents.backLabelKey.currentWidget as KeyedSubtree;
Widget? get bottomBackLabel {
final KeyedSubtree? bottomBackLabel = bottomComponents.backLabelKey.currentWidget as KeyedSubtree?;
if (bottomBackLabel == null) {
return null;
......@@ -1866,10 +1862,10 @@ class _NavigationBarComponentsTransition {
);
}
Widget get bottomMiddle {
final KeyedSubtree bottomMiddle = bottomComponents.middleKey.currentWidget as KeyedSubtree;
final KeyedSubtree topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree;
final KeyedSubtree topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree;
Widget? get bottomMiddle {
final KeyedSubtree? bottomMiddle = bottomComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?;
// The middle component is non-null when the nav bar is a large title
// nav bar but would be invisible when expanded, therefore don't show it here.
......@@ -1925,10 +1921,10 @@ class _NavigationBarComponentsTransition {
return null;
}
Widget get bottomLargeTitle {
final KeyedSubtree bottomLargeTitle = bottomComponents.largeTitleKey.currentWidget as KeyedSubtree;
final KeyedSubtree topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree;
final KeyedSubtree topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree;
Widget? get bottomLargeTitle {
final KeyedSubtree? bottomLargeTitle = bottomComponents.largeTitleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?;
if (bottomLargeTitle == null || !bottomLargeExpanded) {
return null;
......@@ -1996,8 +1992,8 @@ class _NavigationBarComponentsTransition {
return null;
}
Widget get bottomTrailing {
final KeyedSubtree bottomTrailing = bottomComponents.trailingKey.currentWidget as KeyedSubtree;
Widget? get bottomTrailing {
final KeyedSubtree? bottomTrailing = bottomComponents.trailingKey.currentWidget as KeyedSubtree?;
if (bottomTrailing == null) {
return null;
......@@ -2012,8 +2008,8 @@ class _NavigationBarComponentsTransition {
);
}
Widget get topLeading {
final KeyedSubtree topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree;
Widget? get topLeading {
final KeyedSubtree? topLeading = topComponents.leadingKey.currentWidget as KeyedSubtree?;
if (topLeading == null) {
return null;
......@@ -2028,9 +2024,9 @@ class _NavigationBarComponentsTransition {
);
}
Widget get topBackChevron {
final KeyedSubtree topBackChevron = topComponents.backChevronKey.currentWidget as KeyedSubtree;
final KeyedSubtree bottomBackChevron = bottomComponents.backChevronKey.currentWidget as KeyedSubtree;
Widget? get topBackChevron {
final KeyedSubtree? topBackChevron = topComponents.backChevronKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? bottomBackChevron = bottomComponents.backChevronKey.currentWidget as KeyedSubtree?;
if (topBackChevron == null) {
return null;
......@@ -2042,7 +2038,7 @@ class _NavigationBarComponentsTransition {
// If it's the first page with a back chevron, shift in slightly from the
// right.
if (bottomBackChevron == null) {
final RenderBox topBackChevronBox = topComponents.backChevronKey.currentContext.findRenderObject() as RenderBox;
final RenderBox topBackChevronBox = topComponents.backChevronKey.currentContext!.findRenderObject() as RenderBox;
from = to.shift(
Offset(
forwardDirection * topBackChevronBox.size.width * 2.0,
......@@ -2068,19 +2064,19 @@ class _NavigationBarComponentsTransition {
);
}
Widget get topBackLabel {
final KeyedSubtree bottomMiddle = bottomComponents.middleKey.currentWidget as KeyedSubtree;
final KeyedSubtree bottomLargeTitle = bottomComponents.largeTitleKey.currentWidget as KeyedSubtree;
final KeyedSubtree topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree;
Widget? get topBackLabel {
final KeyedSubtree? bottomMiddle = bottomComponents.middleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? bottomLargeTitle = bottomComponents.largeTitleKey.currentWidget as KeyedSubtree?;
final KeyedSubtree? topBackLabel = topComponents.backLabelKey.currentWidget as KeyedSubtree?;
if (topBackLabel == null) {
return null;
}
final RenderAnimatedOpacity topBackLabelOpacity =
final RenderAnimatedOpacity? topBackLabelOpacity =
topComponents.backLabelKey.currentContext?.findAncestorRenderObjectOfType<RenderAnimatedOpacity>();
Animation<double> midClickOpacity;
Animation<double>? midClickOpacity;
if (topBackLabelOpacity != null && topBackLabelOpacity.opacity.value < 1.0) {
midClickOpacity = animation.drive(Tween<double>(
begin: 0.0,
......@@ -2144,8 +2140,8 @@ class _NavigationBarComponentsTransition {
return null;
}
Widget get topMiddle {
final KeyedSubtree topMiddle = topComponents.middleKey.currentWidget as KeyedSubtree;
Widget? get topMiddle {
final KeyedSubtree? topMiddle = topComponents.middleKey.currentWidget as KeyedSubtree?;
if (topMiddle == null) {
return null;
......@@ -2182,8 +2178,8 @@ class _NavigationBarComponentsTransition {
);
}
Widget get topTrailing {
final KeyedSubtree topTrailing = topComponents.trailingKey.currentWidget as KeyedSubtree;
Widget? get topTrailing {
final KeyedSubtree? topTrailing = topComponents.trailingKey.currentWidget as KeyedSubtree?;
if (topTrailing == null) {
return null;
......@@ -2198,8 +2194,8 @@ class _NavigationBarComponentsTransition {
);
}
Widget get topLargeTitle {
final KeyedSubtree topLargeTitle = topComponents.largeTitleKey.currentWidget as KeyedSubtree;
Widget? get topLargeTitle {
final KeyedSubtree? topLargeTitle = topComponents.largeTitleKey.currentWidget as KeyedSubtree?;
if (topLargeTitle == null || !topLargeExpanded) {
return null;
......@@ -2235,9 +2231,9 @@ class _NavigationBarComponentsTransition {
/// Navigation bars' hero rect tween that will move between the static bars
/// but keep a constant size that's the bigger of both navigation bars.
CreateRectTween _linearTranslateWithLargestRectSizeTween = (Rect begin, Rect end) {
CreateRectTween _linearTranslateWithLargestRectSizeTween = (Rect? begin, Rect? end) {
final Size largestSize = Size(
math.max(begin.size.width, end.size.width),
math.max(begin!.size.width, end!.size.width),
math.max(begin.size.height, end.size.height),
);
return RectTween(
......@@ -2300,11 +2296,11 @@ final HeroFlightShuttleBuilder _navBarHeroFlightShuttleBuilder = (
assert(toNavBar.componentsKeys != null);
assert(
fromNavBar.componentsKeys.navBarBoxKey.currentContext.owner != null,
fromNavBar.componentsKeys.navBarBoxKey.currentContext!.owner != null,
'The from nav bar to Hero must have been mounted in the previous frame',
);
assert(
toNavBar.componentsKeys.navBarBoxKey.currentContext.owner != null,
toNavBar.componentsKeys.navBarBoxKey.currentContext!.owner != null,
'The to nav bar to Hero must have been mounted in the previous frame',
);
......@@ -2315,7 +2311,6 @@ final HeroFlightShuttleBuilder _navBarHeroFlightShuttleBuilder = (
bottomNavBar: fromNavBar,
topNavBar: toNavBar,
);
break;
case HeroFlightDirection.pop:
return _NavigationBarTransition(
animation: animation,
......@@ -2323,5 +2318,4 @@ final HeroFlightShuttleBuilder _navBarHeroFlightShuttleBuilder = (
topNavBar: fromNavBar,
);
}
return null;
};
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/widgets.dart';
import 'colors.dart';
......@@ -22,11 +20,11 @@ import 'theme.dart';
class CupertinoPageScaffold extends StatefulWidget {
/// Creates a layout for pages with a navigation bar at the top.
const CupertinoPageScaffold({
Key key,
Key? key,
this.navigationBar,
this.backgroundColor,
this.resizeToAvoidBottomInset = true,
@required this.child,
required this.child,
}) : assert(child != null),
assert(resizeToAvoidBottomInset != null),
super(key: key);
......@@ -48,7 +46,7 @@ class CupertinoPageScaffold extends StatefulWidget {
/// in many ways, such as querying [MediaQuery.textScaleFactorOf] against
/// [CupertinoApp]'s [BuildContext].
// TODO(xster): document its page transition animation when ready
final ObstructingPreferredSizeWidget navigationBar;
final ObstructingPreferredSizeWidget? navigationBar;
/// Widget to show in the main content area.
///
......@@ -61,7 +59,7 @@ class CupertinoPageScaffold extends StatefulWidget {
/// The color of the widget that underlies the entire scaffold.
///
/// By default uses [CupertinoTheme]'s `scaffoldBackgroundColor` when null.
final Color backgroundColor;
final Color? backgroundColor;
/// Whether the [child] should size itself to avoid the window's bottom inset.
///
......@@ -95,12 +93,12 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
Widget build(BuildContext context) {
Widget paddedContent = widget.child;
final MediaQueryData existingMediaQuery = MediaQuery.of(context);
final MediaQueryData existingMediaQuery = MediaQuery.of(context)!;
if (widget.navigationBar != null) {
// TODO(xster): Use real size after partial layout instead of preferred size.
// https://github.com/flutter/flutter/issues/12912
final double topPadding =
widget.navigationBar.preferredSize.height + existingMediaQuery.padding.top;
widget.navigationBar!.preferredSize.height + existingMediaQuery.padding.top;
// Propagate bottom padding and include viewInsets if appropriate
final double bottomPadding = widget.resizeToAvoidBottomInset
......@@ -113,7 +111,7 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
? existingMediaQuery.viewInsets.copyWith(bottom: 0.0)
: existingMediaQuery.viewInsets;
final bool fullObstruction = widget.navigationBar.shouldFullyObstruct(context);
final bool fullObstruction = widget.navigationBar!.shouldFullyObstruct(context);
// If navigation bar is opaquely obstructing, directly shift the main content
// down. If translucent, let main content draw behind navigation bar but hint the
......@@ -176,7 +174,7 @@ class _CupertinoPageScaffoldState extends State<CupertinoPageScaffold> {
right: 0.0,
child: MediaQuery(
data: existingMediaQuery.copyWith(textScaleFactor: 1),
child: widget.navigationBar,
child: widget.navigationBar!,
),
),
// Add a touch handler the size of the status bar on top of all contents
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:collection';
import 'dart:math' as math;
......@@ -66,7 +64,7 @@ const Duration _kFadeDuration = Duration(milliseconds: 165);
/// * [CupertinoSegmentedControl], a segmented control widget in the style used
/// up until iOS 13.
/// * <https://developer.apple.com/design/human-interface-guidelines/ios/controls/segmented-controls/>
class CupertinoSegmentedControl<T> extends StatefulWidget {
class CupertinoSegmentedControl<T extends Object> extends StatefulWidget {
/// Creates an iOS-style segmented control bar.
///
/// The [children] and [onValueChanged] arguments must not be null. The
......@@ -83,9 +81,9 @@ class CupertinoSegmentedControl<T> extends StatefulWidget {
/// appear as selected. The [groupValue] must be either null or one of the keys
/// in the [children] map.
CupertinoSegmentedControl({
Key key,
@required this.children,
@required this.onValueChanged,
Key? key,
required this.children,
required this.onValueChanged,
this.groupValue,
this.unselectedColor,
this.selectedColor,
......@@ -112,7 +110,7 @@ class CupertinoSegmentedControl<T> extends StatefulWidget {
///
/// This must be one of the keys in the [Map] of [children].
/// If this attribute is null, no widget will be initially selected.
final T groupValue;
final T? groupValue;
/// The callback that is called when a new option is tapped.
///
......@@ -165,49 +163,49 @@ class CupertinoSegmentedControl<T> extends StatefulWidget {
/// text color of the selected widget.
///
/// Defaults to [CupertinoTheme]'s `primaryContrastingColor` if null.
final Color unselectedColor;
final Color? unselectedColor;
/// The color used to fill the background of the selected widget and as the text
/// color of unselected widgets.
///
/// Defaults to [CupertinoTheme]'s `primaryColor` if null.
final Color selectedColor;
final Color? selectedColor;
/// The color used as the border around each widget.
///
/// Defaults to [CupertinoTheme]'s `primaryColor` if null.
final Color borderColor;
final Color? borderColor;
/// The color used to fill the background of the widget the user is
/// temporarily interacting with through a long press or drag.
///
/// Defaults to the selectedColor at 20% opacity if null.
final Color pressedColor;
final Color? pressedColor;
/// The CupertinoSegmentedControl will be placed inside this padding.
///
/// Defaults to EdgeInsets.symmetric(horizontal: 16.0)
final EdgeInsetsGeometry padding;
final EdgeInsetsGeometry? padding;
@override
_SegmentedControlState<T> createState() => _SegmentedControlState<T>();
}
class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
class _SegmentedControlState<T extends Object> extends State<CupertinoSegmentedControl<T>>
with TickerProviderStateMixin<CupertinoSegmentedControl<T>> {
T _pressedKey;
T? _pressedKey;
final List<AnimationController> _selectionControllers = <AnimationController>[];
final List<ColorTween> _childTweens = <ColorTween>[];
ColorTween _forwardBackgroundColorTween;
ColorTween _reverseBackgroundColorTween;
ColorTween _textColorTween;
late ColorTween _forwardBackgroundColorTween;
late ColorTween _reverseBackgroundColorTween;
late ColorTween _textColorTween;
Color _selectedColor;
Color _unselectedColor;
Color _borderColor;
Color _pressedColor;
Color? _selectedColor;
Color? _unselectedColor;
Color? _borderColor;
Color? _pressedColor;
AnimationController createAnimationController() {
return AnimationController(
......@@ -343,7 +341,7 @@ class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
_pressedKey = null;
}
Color getTextColor(int index, T currentKey) {
Color? getTextColor(int index, T currentKey) {
if (_selectionControllers[index].isAnimating)
return _textColorTween.evaluate(_selectionControllers[index]);
if (widget.groupValue == currentKey)
......@@ -351,7 +349,7 @@ class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
return _selectedColor;
}
Color getBackgroundColor(int index, T currentKey) {
Color? getBackgroundColor(int index, T currentKey) {
if (_selectionControllers[index].isAnimating)
return _childTweens[index].evaluate(_selectionControllers[index]);
if (widget.groupValue == currentKey)
......@@ -366,13 +364,13 @@ class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
final List<Widget> _gestureChildren = <Widget>[];
final List<Color> _backgroundColors = <Color>[];
int index = 0;
int selectedIndex;
int pressedIndex;
int? selectedIndex;
int? pressedIndex;
for (final T currentKey in widget.children.keys) {
selectedIndex = (widget.groupValue == currentKey) ? index : selectedIndex;
pressedIndex = (_pressedKey == currentKey) ? index : pressedIndex;
final TextStyle textStyle = DefaultTextStyle.of(context).style.copyWith(
final TextStyle textStyle = DefaultTextStyle.of(context).style!.copyWith(
color: getTextColor(index, currentKey),
);
final IconThemeData iconTheme = IconThemeData(
......@@ -406,7 +404,7 @@ class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
),
);
_backgroundColors.add(getBackgroundColor(index, currentKey));
_backgroundColors.add(getBackgroundColor(index, currentKey)!);
_gestureChildren.add(child);
index += 1;
}
......@@ -416,7 +414,7 @@ class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
selectedIndex: selectedIndex,
pressedIndex: pressedIndex,
backgroundColors: _backgroundColors,
borderColor: _borderColor,
borderColor: _borderColor!,
);
return Padding(
......@@ -431,26 +429,26 @@ class _SegmentedControlState<T> extends State<CupertinoSegmentedControl<T>>
class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
_SegmentedControlRenderWidget({
Key key,
Key? key,
List<Widget> children = const <Widget>[],
@required this.selectedIndex,
@required this.pressedIndex,
@required this.backgroundColors,
@required this.borderColor,
required this.selectedIndex,
required this.pressedIndex,
required this.backgroundColors,
required this.borderColor,
}) : super(
key: key,
children: children,
);
final int selectedIndex;
final int pressedIndex;
final int? selectedIndex;
final int? pressedIndex;
final List<Color> backgroundColors;
final Color borderColor;
@override
RenderObject createRenderObject(BuildContext context) {
return _RenderSegmentedControl<T>(
textDirection: Directionality.of(context),
textDirection: Directionality.of(context)!,
selectedIndex: selectedIndex,
pressedIndex: pressedIndex,
backgroundColors: backgroundColors,
......@@ -461,7 +459,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
@override
void updateRenderObject(BuildContext context, _RenderSegmentedControl<T> renderObject) {
renderObject
..textDirection = Directionality.of(context)
..textDirection = Directionality.of(context)!
..selectedIndex = selectedIndex
..pressedIndex = pressedIndex
..backgroundColors = backgroundColors
......@@ -470,20 +468,20 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
}
class _SegmentedControlContainerBoxParentData extends ContainerBoxParentData<RenderBox> {
RRect surroundingRect;
RRect? surroundingRect;
}
typedef _NextChild = RenderBox Function(RenderBox child);
typedef _NextChild = RenderBox? Function(RenderBox child);
class _RenderSegmentedControl<T> extends RenderBox
with ContainerRenderObjectMixin<RenderBox, ContainerBoxParentData<RenderBox>>,
RenderBoxContainerDefaultsMixin<RenderBox, ContainerBoxParentData<RenderBox>> {
_RenderSegmentedControl({
@required int selectedIndex,
@required int pressedIndex,
@required TextDirection textDirection,
@required List<Color> backgroundColors,
@required Color borderColor,
required int? selectedIndex,
required int? pressedIndex,
required TextDirection textDirection,
required List<Color> backgroundColors,
required Color borderColor,
}) : assert(textDirection != null),
_textDirection = textDirection,
_selectedIndex = selectedIndex,
......@@ -491,9 +489,9 @@ class _RenderSegmentedControl<T> extends RenderBox
_backgroundColors = backgroundColors,
_borderColor = borderColor;
int get selectedIndex => _selectedIndex;
int _selectedIndex;
set selectedIndex(int value) {
int? get selectedIndex => _selectedIndex;
int? _selectedIndex;
set selectedIndex(int? value) {
if (_selectedIndex == value) {
return;
}
......@@ -501,9 +499,9 @@ class _RenderSegmentedControl<T> extends RenderBox
markNeedsPaint();
}
int get pressedIndex => _pressedIndex;
int _pressedIndex;
set pressedIndex(int value) {
int? get pressedIndex => _pressedIndex;
int? _pressedIndex;
set pressedIndex(int? value) {
if (_pressedIndex == value) {
return;
}
......@@ -543,7 +541,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMinIntrinsicWidth(double height) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double minWidth = 0.0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
......@@ -556,7 +554,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMaxIntrinsicWidth(double height) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double maxWidth = 0.0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
......@@ -569,7 +567,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMinIntrinsicHeight(double width) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double minHeight = 0.0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
......@@ -582,7 +580,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMaxIntrinsicHeight(double width) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double maxHeight = 0.0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
......@@ -594,7 +592,7 @@ class _RenderSegmentedControl<T> extends RenderBox
}
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
double? computeDistanceToActualBaseline(TextBaseline baseline) {
return defaultComputeDistanceToHighestActualBaseline(baseline);
}
......@@ -605,8 +603,8 @@ class _RenderSegmentedControl<T> extends RenderBox
}
}
void _layoutRects(_NextChild nextChild, RenderBox leftChild, RenderBox rightChild) {
RenderBox child = leftChild;
void _layoutRects(_NextChild nextChild, RenderBox? leftChild, RenderBox? rightChild) {
RenderBox? child = leftChild;
double start = 0.0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
......@@ -640,7 +638,7 @@ class _RenderSegmentedControl<T> extends RenderBox
}
childWidth = math.min(childWidth, constraints.maxWidth / childCount);
RenderBox child = firstChild;
RenderBox? child = firstChild;
while (child != null) {
final double boxHeight = child.getMaxIntrinsicHeight(childWidth);
maxHeight = math.max(maxHeight, boxHeight);
......@@ -682,7 +680,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
void paint(PaintingContext context, Offset offset) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
int index = 0;
while (child != null) {
_paintChild(context, offset, child, index);
......@@ -697,13 +695,13 @@ class _RenderSegmentedControl<T> extends RenderBox
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
context.canvas.drawRRect(
childParentData.surroundingRect.shift(offset),
childParentData.surroundingRect!.shift(offset),
Paint()
..color = backgroundColors[childIndex]
..style = PaintingStyle.fill,
);
context.canvas.drawRRect(
childParentData.surroundingRect.shift(offset),
childParentData.surroundingRect!.shift(offset),
Paint()
..color = borderColor
..strokeWidth = 1.0
......@@ -714,18 +712,18 @@ class _RenderSegmentedControl<T> extends RenderBox
}
@override
bool hitTestChildren(BoxHitTestResult result, { @required Offset position }) {
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
assert(position != null);
RenderBox child = lastChild;
RenderBox? child = lastChild;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData = child.parentData as _SegmentedControlContainerBoxParentData;
if (childParentData.surroundingRect.contains(position)) {
if (childParentData.surroundingRect!.contains(position)) {
return result.addWithPaintOffset(
offset: childParentData.offset,
position: position,
hitTest: (BoxHitTestResult result, Offset localOffset) {
assert(localOffset == position - childParentData.offset);
return child.hitTest(result, position: localOffset);
return child!.hitTest(result, position: localOffset);
},
);
}
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:math' as math;
import 'package:flutter/foundation.dart';
......@@ -76,10 +74,10 @@ const Duration _kOpacityAnimationDuration = Duration(milliseconds: 470);
const Duration _kHighlightAnimationDuration = Duration(milliseconds: 200);
class _FontWeightTween extends Tween<FontWeight> {
_FontWeightTween({ FontWeight begin, FontWeight end }) : super(begin: begin, end: end);
_FontWeightTween({ required FontWeight begin, required FontWeight end }) : super(begin: begin, end: end);
@override
FontWeight lerp(double t) => FontWeight.lerp(begin, end, t);
FontWeight lerp(double t) => FontWeight.lerp(begin, end, t)!;
}
/// An iOS 13 style segmented control.
......@@ -140,9 +138,9 @@ class CupertinoSlidingSegmentedControl<T> extends StatefulWidget {
/// appear as selected. The [groupValue] must be either null or one of the keys
/// in the [children] map.
CupertinoSlidingSegmentedControl({
Key key,
@required this.children,
@required this.onValueChanged,
Key? key,
required this.children,
required this.onValueChanged,
this.groupValue,
this.thumbColor = _kThumbColor,
this.padding = _kHorizontalItemPadding,
......@@ -168,7 +166,7 @@ class CupertinoSlidingSegmentedControl<T> extends StatefulWidget {
///
/// This must be one of the keys in the [Map] of [children].
/// If this attribute is null, no widget will be initially selected.
final T groupValue;
final T? groupValue;
/// The callback that is called when a new option is tapped.
///
......@@ -215,7 +213,7 @@ class CupertinoSlidingSegmentedControl<T> extends StatefulWidget {
/// }
/// ```
/// {@end-tool}
final ValueChanged<T> onValueChanged;
final ValueChanged<T?> onValueChanged;
/// The color used to paint the rounded rect behind the [children] and the separators.
///
......@@ -248,11 +246,11 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
final Map<T, AnimationController> _pressControllers = <T, AnimationController>{};
final Tween<double> _pressTween = Tween<double>(begin: 1, end: 0.2);
List<T> keys;
late List<T> keys;
AnimationController thumbController;
AnimationController separatorOpacityController;
AnimationController thumbScaleController;
late AnimationController thumbController;
late AnimationController separatorOpacityController;
late AnimationController thumbScaleController;
final TapGestureRecognizer tap = TapGestureRecognizer();
final HorizontalDragGestureRecognizer drag = HorizontalDragGestureRecognizer();
......@@ -320,8 +318,8 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
// Update animation controllers.
for (final T oldKey in oldWidget.children.keys) {
if (!widget.children.containsKey(oldKey)) {
_highlightControllers[oldKey].dispose();
_pressControllers[oldKey].dispose();
_highlightControllers[oldKey]!.dispose();
_pressControllers[oldKey]!.dispose();
_highlightControllers.remove(oldKey);
_pressControllers.remove(oldKey);
......@@ -360,16 +358,16 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
}
// Play highlight animation for the child located at _highlightControllers[at].
void _animateHighlightController({ T at, bool forward }) {
void _animateHighlightController({ T? at, required bool forward }) {
if (at == null)
return;
final AnimationController controller = _highlightControllers[at];
final AnimationController? controller = _highlightControllers[at];
assert(!forward || controller != null);
controller?.animateTo(forward ? 1 : 0, duration: _kHighlightAnimationDuration, curve: Curves.ease);
}
T _highlighted;
set highlighted(T newValue) {
T? _highlighted;
set highlighted(T? newValue) {
if (_highlighted == newValue)
return;
_animateHighlightController(at: newValue, forward: true);
......@@ -377,8 +375,8 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
_highlighted = newValue;
}
T _pressed;
set pressed(T newValue) {
T? _pressed;
set pressed(T? newValue) {
if (_pressed == newValue)
return;
......@@ -386,7 +384,7 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
_pressControllers[_pressed]?.animateTo(0, duration: _kOpacityAnimationDuration, curve: Curves.ease);
}
if (newValue != _highlighted && newValue != null) {
_pressControllers[newValue].animateTo(1, duration: _kOpacityAnimationDuration, curve: Curves.ease);
_pressControllers[newValue]!.animateTo(1, duration: _kOpacityAnimationDuration, curve: Curves.ease);
}
_pressed = newValue;
}
......@@ -395,13 +393,13 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
widget.onValueChanged(_highlighted);
}
T indexToKey(int index) => index == null ? null : keys[index];
T? indexToKey(int? index) => index == null ? null : keys[index];
@override
Widget build(BuildContext context) {
debugCheckHasDirectionality(context);
switch (Directionality.of(context)) {
switch (Directionality.of(context)!) {
case TextDirection.ltr:
keys = widget.children.keys.toList(growable: false);
break;
......@@ -415,11 +413,11 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
..._highlightControllers.values,
..._pressControllers.values,
]),
builder: (BuildContext context, Widget child) {
builder: (BuildContext context, Widget? child) {
final List<Widget> children = <Widget>[];
for (final T currentKey in keys) {
final TextStyle textStyle = DefaultTextStyle.of(context).style.copyWith(
fontWeight: _highlightTween.evaluate(_highlightControllers[currentKey]),
final TextStyle textStyle = DefaultTextStyle.of(context).style!.copyWith(
fontWeight: _highlightTween.evaluate(_highlightControllers[currentKey]!),
);
final Widget child = DefaultTextStyle(
......@@ -430,7 +428,7 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
inMutuallyExclusiveGroup: true,
selected: widget.groupValue == currentKey,
child: Opacity(
opacity: _pressTween.evaluate(_pressControllers[currentKey]),
opacity: _pressTween.evaluate(_pressControllers[currentKey]!),
// Expand the hitTest area to be as large as the Opacity widget.
child: MetaData(
behavior: HitTestBehavior.opaque,
......@@ -443,7 +441,7 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
children.add(child);
}
final int selectedIndex = widget.groupValue == null ? null : keys.indexOf(widget.groupValue);
final int? selectedIndex = widget.groupValue == null ? null : keys.indexOf(widget.groupValue as T);
final Widget box = _SegmentedControlRenderWidget<T>(
children: children,
......@@ -470,15 +468,15 @@ class _SegmentedControlState<T> extends State<CupertinoSlidingSegmentedControl<T
class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
_SegmentedControlRenderWidget({
Key key,
Key? key,
List<Widget> children = const <Widget>[],
@required this.selectedIndex,
@required this.thumbColor,
@required this.state,
required this.selectedIndex,
required this.thumbColor,
required this.state,
}) : super(key: key, children: children);
final int selectedIndex;
final Color thumbColor;
final int? selectedIndex;
final Color? thumbColor;
final _SegmentedControlState<T> state;
@override
......@@ -501,7 +499,7 @@ class _SegmentedControlRenderWidget<T> extends MultiChildRenderObjectWidget {
class _ChildAnimationManifest {
_ChildAnimationManifest({
this.opacity = 1,
@required this.separatorOpacity,
required this.separatorOpacity,
}) : assert(separatorOpacity != null),
assert(opacity != null),
separatorTween = Tween<double>(begin: separatorOpacity, end: separatorOpacity),
......@@ -550,9 +548,9 @@ class _RenderSegmentedControl<T> extends RenderBox
with ContainerRenderObjectMixin<RenderBox, ContainerBoxParentData<RenderBox>>,
RenderBoxContainerDefaultsMixin<RenderBox, ContainerBoxParentData<RenderBox>> {
_RenderSegmentedControl({
@required int selectedIndex,
@required Color thumbColor,
@required this.state,
required int? selectedIndex,
required Color? thumbColor,
required this.state,
}) : _highlightedIndex = selectedIndex,
_thumbColor = thumbColor,
assert(state != null) {
......@@ -569,29 +567,29 @@ class _RenderSegmentedControl<T> extends RenderBox
final _SegmentedControlState<T> state;
Map<RenderBox, _ChildAnimationManifest> _childAnimations = <RenderBox, _ChildAnimationManifest>{};
Map<RenderBox, _ChildAnimationManifest>? _childAnimations = <RenderBox, _ChildAnimationManifest>{};
// The current **Unscaled** Thumb Rect.
Rect currentThumbRect;
Rect? currentThumbRect;
Tween<Rect> _currentThumbTween;
Tween<Rect?>? _currentThumbTween;
Tween<double> _thumbScaleTween = Tween<double>(begin: _kMinThumbScale, end: 1);
double currentThumbScale = 1;
// The current position of the active drag pointer.
Offset _localDragOffset;
Offset? _localDragOffset;
// Whether the current drag gesture started on a selected segment.
bool _startedOnSelectedSegment;
bool? _startedOnSelectedSegment;
@override
void insert(RenderBox child, { RenderBox after }) {
void insert(RenderBox child, { RenderBox? after }) {
super.insert(child, after: after);
if (_childAnimations == null)
return;
assert(_childAnimations[child] == null);
_childAnimations[child] = _ChildAnimationManifest(separatorOpacity: 1);
assert(_childAnimations![child] == null);
_childAnimations![child] = _ChildAnimationManifest(separatorOpacity: 1);
}
@override
......@@ -620,9 +618,9 @@ class _RenderSegmentedControl<T> extends RenderBox
// when true some animation tweens will be updated in paint phase.
bool _needsThumbAnimationUpdate = false;
int get highlightedIndex => _highlightedIndex;
int _highlightedIndex;
set highlightedIndex(int value) {
int? get highlightedIndex => _highlightedIndex;
int? _highlightedIndex;
set highlightedIndex(int? value) {
if (_highlightedIndex == value) {
return;
}
......@@ -644,16 +642,16 @@ class _RenderSegmentedControl<T> extends RenderBox
markNeedsSemanticsUpdate();
}
void guardedSetHighlightedIndex(int value) {
void guardedSetHighlightedIndex(int? value) {
// Ignore set highlightedIndex when the user is dragging the thumb around.
if (_startedOnSelectedSegment == true)
return;
highlightedIndex = value;
}
int get pressedIndex => _pressedIndex;
int _pressedIndex;
set pressedIndex(int value) {
int? get pressedIndex => _pressedIndex;
int? _pressedIndex;
set pressedIndex(int? value) {
if (_pressedIndex == value) {
return;
}
......@@ -664,9 +662,9 @@ class _RenderSegmentedControl<T> extends RenderBox
state.pressed = state.indexToKey(value);
}
Color get thumbColor => _thumbColor;
Color _thumbColor;
set thumbColor(Color value) {
Color? get thumbColor => _thumbColor;
Color? _thumbColor;
set thumbColor(Color? value) {
if (_thumbColor == value) {
return;
}
......@@ -686,13 +684,13 @@ class _RenderSegmentedControl<T> extends RenderBox
}
}
int indexFromLocation(Offset location) {
int? indexFromLocation(Offset location) {
return childCount == 0
? null
// This assumes all children have the same width.
: ((location.dx / (size.width / childCount))
: (location.dx / (size.width / childCount))
.floor()
.clamp(0, childCount - 1) as int);
.clamp(0, childCount - 1);
}
void _onTapUp(TapUpDetails details) {
......@@ -703,20 +701,20 @@ class _RenderSegmentedControl<T> extends RenderBox
void _onDown(DragDownDetails details) {
assert(size.contains(details.localPosition));
_localDragOffset = details.localPosition;
final int index = indexFromLocation(_localDragOffset);
final int? index = indexFromLocation(_localDragOffset!);
_startedOnSelectedSegment = index == highlightedIndex;
pressedIndex = index;
if (_startedOnSelectedSegment) {
if (_startedOnSelectedSegment!) {
_playThumbScaleAnimation(isExpanding: false);
}
}
void _onUpdate(DragUpdateDetails details) {
_localDragOffset = details.localPosition;
final int newIndex = indexFromLocation(_localDragOffset);
final int? newIndex = indexFromLocation(_localDragOffset!);
if (_startedOnSelectedSegment) {
if (_startedOnSelectedSegment!) {
highlightedIndex = newIndex;
pressedIndex = newIndex;
} else {
......@@ -725,7 +723,7 @@ class _RenderSegmentedControl<T> extends RenderBox
}
void _onEnd(DragEndDetails details) {
if (_startedOnSelectedSegment) {
if (_startedOnSelectedSegment!) {
_playThumbScaleAnimation(isExpanding: true);
state.didChangeSelectedViaGesture();
}
......@@ -740,7 +738,7 @@ class _RenderSegmentedControl<T> extends RenderBox
}
void _onCancel() {
if (_startedOnSelectedSegment) {
if (_startedOnSelectedSegment!) {
_playThumbScaleAnimation(isExpanding: true);
}
......@@ -749,7 +747,7 @@ class _RenderSegmentedControl<T> extends RenderBox
_startedOnSelectedSegment = null;
}
void _playThumbScaleAnimation({ @required bool isExpanding }) {
void _playThumbScaleAnimation({ required bool isExpanding }) {
assert(isExpanding != null);
_thumbScaleTween = Tween<double>(begin: currentThumbScale, end: isExpanding ? 1 : _kMinThumbScale);
state.thumbScaleController.animateWith(_kThumbSpringAnimationSimulation);
......@@ -762,7 +760,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMinIntrinsicWidth(double height) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double maxMinChildWidth = 0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData =
......@@ -776,7 +774,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMaxIntrinsicWidth(double height) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double maxMaxChildWidth = 0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData =
......@@ -790,7 +788,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMinIntrinsicHeight(double width) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double maxMinChildHeight = 0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData =
......@@ -804,7 +802,7 @@ class _RenderSegmentedControl<T> extends RenderBox
@override
double computeMaxIntrinsicHeight(double width) {
RenderBox child = firstChild;
RenderBox? child = firstChild;
double maxMaxChildHeight = 0;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData =
......@@ -817,7 +815,7 @@ class _RenderSegmentedControl<T> extends RenderBox
}
@override
double computeDistanceToActualBaseline(TextBaseline baseline) {
double? computeDistanceToActualBaseline(TextBaseline baseline) {
return defaultComputeDistanceToHighestActualBaseline(baseline);
}
......@@ -843,7 +841,7 @@ class _RenderSegmentedControl<T> extends RenderBox
(constraints.maxWidth - totalSeparatorWidth) / childCount,
);
RenderBox child = firstChild;
RenderBox? child = firstChild;
while (child != null) {
final double boxHeight = child.getMaxIntrinsicHeight(childWidth);
maxHeight = math.max(maxHeight, boxHeight);
......@@ -890,13 +888,13 @@ class _RenderSegmentedControl<T> extends RenderBox
for (int i = 0; i < childCount - 1; i += 1) {
// The separator associated with the last child will not be painted (unless
// a new trailing segment is added), and its opacity will always be 1.
final bool shouldFadeOut = i == highlightedIndex || i == highlightedIndex - 1;
final bool shouldFadeOut = i == highlightedIndex || i == highlightedIndex! - 1;
final RenderBox child = children[i];
_childAnimations[child] = _ChildAnimationManifest(separatorOpacity: shouldFadeOut ? 0 : 1);
_childAnimations![child] = _ChildAnimationManifest(separatorOpacity: shouldFadeOut ? 0 : 1);
}
}
final RenderBox selectedChild = children[highlightedIndex];
final RenderBox selectedChild = children[highlightedIndex!];
final _SegmentedControlContainerBoxParentData childParentData =
selectedChild.parentData as _SegmentedControlContainerBoxParentData;
......@@ -910,9 +908,9 @@ class _RenderSegmentedControl<T> extends RenderBox
for (int i = 0; i < childCount - 1; i += 1) {
// The separator associated with the last child will not be painted (unless
// a new segment is appended to the child list), and its opacity will always be 1.
final bool shouldFadeOut = i == highlightedIndex || i == highlightedIndex - 1;
final bool shouldFadeOut = i == highlightedIndex || i == highlightedIndex! - 1;
final RenderBox child = children[i];
final _ChildAnimationManifest manifest = _childAnimations[child];
final _ChildAnimationManifest manifest = _childAnimations![child]!;
assert(manifest != null);
manifest.separatorTween = Tween<double>(
begin: manifest.separatorOpacity,
......@@ -921,8 +919,8 @@ class _RenderSegmentedControl<T> extends RenderBox
}
_needsThumbAnimationUpdate = false;
} else if (_currentThumbTween != null && unscaledThumbTargetRect != _currentThumbTween.begin) {
_currentThumbTween = RectTween(begin: _currentThumbTween.begin, end: unscaledThumbTargetRect);
} else if (_currentThumbTween != null && unscaledThumbTargetRect != _currentThumbTween!.begin) {
_currentThumbTween = RectTween(begin: _currentThumbTween!.begin, end: unscaledThumbTargetRect);
}
for (int index = 0; index < childCount - 1; index += 1) {
......@@ -935,9 +933,9 @@ class _RenderSegmentedControl<T> extends RenderBox
currentThumbScale = _thumbScaleTween.evaluate(state.thumbScaleController);
final Rect thumbRect = Rect.fromCenter(
center: currentThumbRect.center,
width: currentThumbRect.width * currentThumbScale,
height: currentThumbRect.height * currentThumbScale,
center: currentThumbRect!.center,
width: currentThumbRect!.width * currentThumbScale,
height: currentThumbRect!.height * currentThumbScale,
);
_paintThumb(context, offset, thumbRect);
......@@ -964,8 +962,8 @@ class _RenderSegmentedControl<T> extends RenderBox
final Paint paint = Paint();
final _ChildAnimationManifest manifest = _childAnimations == null ? null : _childAnimations[child];
final double opacity = manifest?.separatorTween?.evaluate(state.separatorOpacityController) ?? 1;
final _ChildAnimationManifest? manifest = _childAnimations == null ? null : _childAnimations![child];
final double opacity = manifest?.separatorTween.evaluate(state.separatorOpacityController) ?? 1;
manifest?.separatorOpacity = opacity;
paint.color = _kSeparatorColor.withOpacity(_kSeparatorColor.opacity * opacity);
......@@ -1015,14 +1013,14 @@ class _RenderSegmentedControl<T> extends RenderBox
context.canvas.drawRRect(
thumbRRect,
Paint()..color = thumbColor,
Paint()..color = thumbColor!,
);
}
@override
bool hitTestChildren(BoxHitTestResult result, { @required Offset position }) {
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
assert(position != null);
RenderBox child = lastChild;
RenderBox? child = lastChild;
while (child != null) {
final _SegmentedControlContainerBoxParentData childParentData =
child.parentData as _SegmentedControlContainerBoxParentData;
......@@ -1032,7 +1030,7 @@ class _RenderSegmentedControl<T> extends RenderBox
position: position,
hitTest: (BoxHitTestResult result, Offset localOffset) {
assert(localOffset == position - childParentData.offset);
return child.hitTest(result, position: localOffset);
return child!.hitTest(result, position: localOffset);
},
);
}
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'bottom_tab_bar.dart';
......@@ -207,9 +205,9 @@ class CupertinoTabScaffold extends StatefulWidget {
///
/// The [tabBar] and [tabBuilder] arguments must not be null.
CupertinoTabScaffold({
Key key,
@required this.tabBar,
@required this.tabBuilder,
Key? key,
required this.tabBar,
required this.tabBuilder,
this.controller,
this.backgroundColor,
this.resizeToAvoidBottomInset = true,
......@@ -258,7 +256,7 @@ class CupertinoTabScaffold extends StatefulWidget {
/// index value.
///
/// Defaults to null.
final CupertinoTabController controller;
final CupertinoTabController? controller;
/// An [IndexedWidgetBuilder] that's called when tabs become active.
///
......@@ -280,7 +278,7 @@ class CupertinoTabScaffold extends StatefulWidget {
/// The color of the widget that underlies the entire scaffold.
///
/// By default uses [CupertinoTheme]'s `scaffoldBackgroundColor` when null.
final Color backgroundColor;
final Color? backgroundColor;
/// Whether the body should size itself to avoid the window's bottom inset.
///
......@@ -296,7 +294,7 @@ class CupertinoTabScaffold extends StatefulWidget {
}
class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
CupertinoTabController _controller;
CupertinoTabController? _controller;
@override
void initState() {
......@@ -317,7 +315,7 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
if (shouldDisposeOldController) {
_controller?.dispose();
} else if (_controller?._isDisposed == false) {
_controller.removeListener(_onCurrentIndexChange);
_controller!.removeListener(_onCurrentIndexChange);
}
newController.addListener(_onCurrentIndexChange);
......@@ -326,8 +324,8 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
void _onCurrentIndexChange() {
assert(
_controller.index >= 0 && _controller.index < widget.tabBar.items.length,
"The $runtimeType's current index ${_controller.index} is "
_controller!.index >= 0 && _controller!.index < widget.tabBar.items.length,
"The $runtimeType's current index ${_controller!.index} is "
'out of bounds for the tab bar with ${widget.tabBar.items.length} tabs'
);
......@@ -341,20 +339,20 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
super.didUpdateWidget(oldWidget);
if (widget.controller != oldWidget.controller) {
_updateTabController(shouldDisposeOldController: oldWidget.controller == null);
} else if (_controller.index >= widget.tabBar.items.length) {
} else if (_controller!.index >= widget.tabBar.items.length) {
// If a new [tabBar] with less than (_controller.index + 1) items is provided,
// clamp the current index.
_controller.index = widget.tabBar.items.length - 1;
_controller!.index = widget.tabBar.items.length - 1;
}
}
@override
Widget build(BuildContext context) {
final MediaQueryData existingMediaQuery = MediaQuery.of(context);
MediaQueryData newMediaQuery = MediaQuery.of(context);
final MediaQueryData existingMediaQuery = MediaQuery.of(context)!;
MediaQueryData newMediaQuery = MediaQuery.of(context)!;
Widget content = _TabSwitchingView(
currentTabIndex: _controller.index,
currentTabIndex: _controller!.index,
tabCount: widget.tabBar.items.length,
tabBuilder: widget.tabBuilder,
);
......@@ -417,12 +415,11 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
// our own listener to update the [_controller.currentIndex] on top of a possibly user
// provided callback.
child: widget.tabBar.copyWith(
currentIndex: _controller.index,
currentIndex: _controller!.index,
onTap: (int newIndex) {
_controller.index = newIndex;
_controller!.index = newIndex;
// Chain the user's original callback.
if (widget.tabBar.onTap != null)
widget.tabBar.onTap(newIndex);
widget.tabBar.onTap?.call(newIndex);
},
),
),
......@@ -438,7 +435,7 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
if (widget.controller == null) {
_controller?.dispose();
} else if (_controller?._isDisposed == false) {
_controller.removeListener(_onCurrentIndexChange);
_controller!.removeListener(_onCurrentIndexChange);
}
super.dispose();
......@@ -449,9 +446,9 @@ class _CupertinoTabScaffoldState extends State<CupertinoTabScaffold> {
/// at a time and on stage. Off stage tabs' animations are stopped.
class _TabSwitchingView extends StatefulWidget {
const _TabSwitchingView({
@required this.currentTabIndex,
@required this.tabCount,
@required this.tabBuilder,
required this.currentTabIndex,
required this.tabCount,
required this.tabBuilder,
}) : assert(currentTabIndex != null),
assert(tabCount != null && tabCount > 0),
assert(tabBuilder != null);
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'package:flutter/widgets.dart';
import 'app.dart' show CupertinoApp;
......@@ -43,7 +41,7 @@ import 'route.dart';
class CupertinoTabView extends StatefulWidget {
/// Creates the content area for a tab in a [CupertinoTabScaffold].
const CupertinoTabView({
Key key,
Key? key,
this.builder,
this.navigatorKey,
this.defaultTitle,
......@@ -68,7 +66,7 @@ class CupertinoTabView extends StatefulWidget {
/// * Calling [State.setState] on a descendant [StatefulWidget]'s [State]
/// * Modifying an [InheritedWidget] that a descendant registered itself
/// as a dependent to.
final WidgetBuilder builder;
final WidgetBuilder? builder;
/// A key to use when building this widget's [Navigator].
///
......@@ -81,10 +79,10 @@ class CupertinoTabView extends StatefulWidget {
/// tab's state in the process; in that case, the [navigatorObservers]
/// must also be changed, since the previous observers will be attached to the
/// previous navigator.
final GlobalKey<NavigatorState> navigatorKey;
final GlobalKey<NavigatorState>? navigatorKey;
/// The title of the default route.
final String defaultTitle;
final String? defaultTitle;
/// This tab view's routing table.
///
......@@ -105,12 +103,12 @@ class CupertinoTabView extends StatefulWidget {
///
/// This routing table is not shared with any routing tables of ancestor or
/// descendant [Navigator]s.
final Map<String, WidgetBuilder> routes;
final Map<String, WidgetBuilder>? routes;
/// The route generator callback used when the tab view is navigated to a named route.
///
/// This is used if [routes] does not contain the requested route.
final RouteFactory onGenerateRoute;
final RouteFactory? onGenerateRoute;
/// Called when [onGenerateRoute] also fails to generate a route.
///
......@@ -120,7 +118,7 @@ class CupertinoTabView extends StatefulWidget {
///
/// The default implementation pushes a route that displays an ugly error
/// message.
final RouteFactory onUnknownRoute;
final RouteFactory? onUnknownRoute;
/// The list of observers for the [Navigator] created in this tab view.
///
......@@ -134,8 +132,8 @@ class CupertinoTabView extends StatefulWidget {
}
class _CupertinoTabViewState extends State<CupertinoTabView> {
HeroController _heroController;
List<NavigatorObserver> _navigatorObservers;
late HeroController _heroController;
late List<NavigatorObserver> _navigatorObservers;
@override
void initState() {
......@@ -169,15 +167,15 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
);
}
Route<dynamic> _onGenerateRoute(RouteSettings settings) {
final String name = settings.name;
WidgetBuilder routeBuilder;
String title;
Route<dynamic>? _onGenerateRoute(RouteSettings settings) {
final String? name = settings.name;
WidgetBuilder? routeBuilder;
String? title;
if (name == Navigator.defaultRouteName && widget.builder != null) {
routeBuilder = widget.builder;
routeBuilder = widget.builder!;
title = widget.defaultTitle;
} else if (widget.routes != null) {
routeBuilder = widget.routes[name];
routeBuilder = widget.routes![name];
}
if (routeBuilder != null) {
return CupertinoPageRoute<dynamic>(
......@@ -187,11 +185,11 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
);
}
if (widget.onGenerateRoute != null)
return widget.onGenerateRoute(settings);
return widget.onGenerateRoute!(settings);
return null;
}
Route<dynamic> _onUnknownRoute(RouteSettings settings) {
Route<dynamic>? _onUnknownRoute(RouteSettings settings) {
assert(() {
if (widget.onUnknownRoute == null) {
throw FlutterError(
......@@ -208,7 +206,7 @@ class _CupertinoTabViewState extends State<CupertinoTabView> {
}
return true;
}());
final Route<dynamic> result = widget.onUnknownRoute(settings);
final Route<dynamic>? result = widget.onUnknownRoute!(settings);
assert(() {
if (result == null) {
throw FlutterError(
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:ui' as ui show BoxHeightStyle, BoxWidthStyle;
import 'package:flutter/gestures.dart';
......@@ -89,7 +87,7 @@ enum OverlayVisibilityMode {
class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDetectorBuilder {
_CupertinoTextFieldSelectionGestureDetectorBuilder({
@required _CupertinoTextFieldState state,
required _CupertinoTextFieldState state,
}) : _state = state,
super(delegate: state);
......@@ -102,7 +100,7 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
// this handler. If the clear button widget recognizes the up event,
// then do not handle it.
if (_state._clearGlobalKey.currentContext != null) {
final RenderBox renderBox = _state._clearGlobalKey.currentContext.findRenderObject() as RenderBox;
final RenderBox renderBox = _state._clearGlobalKey.currentContext!.findRenderObject() as RenderBox;
final Offset localOffset = renderBox.globalToLocal(details.globalPosition);
if (renderBox.hitTest(BoxHitTestResult(), position: localOffset)) {
return;
......@@ -111,7 +109,7 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
super.onSingleTapUp(details);
_state._requestKeyboard();
if (_state.widget.onTap != null)
_state.widget.onTap();
_state.widget.onTap!();
}
@override
......@@ -218,7 +216,7 @@ class CupertinoTextField extends StatefulWidget {
/// * [maxLength], which discusses the precise meaning of "number of
/// characters" and how it may differ from the intuitive meaning.
const CupertinoTextField({
Key key,
Key? key,
this.controller,
this.focusNode,
this.decoration = _kDefaultRoundedBorderDecoration,
......@@ -233,7 +231,7 @@ class CupertinoTextField extends StatefulWidget {
this.suffix,
this.suffixMode = OverlayVisibilityMode.always,
this.clearButtonMode = OverlayVisibilityMode.never,
TextInputType keyboardType,
TextInputType? keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
......@@ -241,14 +239,14 @@ class CupertinoTextField extends StatefulWidget {
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.readOnly = false,
ToolbarOptions toolbarOptions,
ToolbarOptions? toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscuringCharacter = '•',
this.obscureText = false,
this.autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
SmartDashesType? smartDashesType,
SmartQuotesType? smartQuotesType,
this.enableSuggestions = true,
this.maxLines = 1,
this.minLines,
......@@ -278,7 +276,8 @@ class CupertinoTextField extends StatefulWidget {
}) : assert(textAlign != null),
assert(readOnly != null),
assert(autofocus != null),
assert(obscuringCharacter != null && obscuringCharacter.length == 1),
// TODO(a14n): uncomment when issue is fixed, https://github.com/dart-lang/sdk/issues/43407
assert(obscuringCharacter != null/* && obscuringCharacter.length == 1*/),
assert(obscureText != null),
assert(autocorrect != null),
smartDashesType = smartDashesType ?? (obscureText ? SmartDashesType.disabled : SmartDashesType.enabled),
......@@ -327,16 +326,16 @@ class CupertinoTextField extends StatefulWidget {
/// Controls the text being edited.
///
/// If null, this widget will create its own [TextEditingController].
final TextEditingController controller;
final TextEditingController? controller;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode focusNode;
final FocusNode? focusNode;
/// Controls the [BoxDecoration] of the box behind the text input.
///
/// Defaults to having a rounded rectangle grey border and can be null to have
/// no box decoration.
final BoxDecoration decoration;
final BoxDecoration? decoration;
/// Padding around the text entry area between the [prefix] and [suffix]
/// or the clear button when [clearButtonMode] is not never.
......@@ -351,7 +350,7 @@ class CupertinoTextField extends StatefulWidget {
///
/// The text style of the placeholder text matches that of the text field's
/// main text entry except a lighter font weight and a grey font color.
final String placeholder;
final String? placeholder;
/// The style to use for the placeholder text.
///
......@@ -362,10 +361,10 @@ class CupertinoTextField extends StatefulWidget {
/// Defaults to the [style] property with w300 font weight and grey color.
///
/// If specifically set to null, placeholder's style will be the same as [style].
final TextStyle placeholderStyle;
final TextStyle? placeholderStyle;
/// An optional [Widget] to display before the text.
final Widget prefix;
final Widget? prefix;
/// Controls the visibility of the [prefix] widget based on the state of
/// text entry when the [prefix] argument is not null.
......@@ -376,7 +375,7 @@ class CupertinoTextField extends StatefulWidget {
final OverlayVisibilityMode prefixMode;
/// An optional [Widget] to display after the text.
final Widget suffix;
final Widget? suffix;
/// Controls the visibility of the [suffix] widget based on the state of
/// text entry when the [suffix] argument is not null.
......@@ -403,7 +402,7 @@ class CupertinoTextField extends StatefulWidget {
///
/// Defaults to [TextInputAction.newline] if [keyboardType] is
/// [TextInputType.multiline] and [TextInputAction.done] otherwise.
final TextInputAction textInputAction;
final TextInputAction? textInputAction;
/// {@macro flutter.widgets.editableText.textCapitalization}
final TextCapitalization textCapitalization;
......@@ -413,10 +412,10 @@ class CupertinoTextField extends StatefulWidget {
/// Also serves as a base for the [placeholder] text's style.
///
/// Defaults to the standard iOS font style from [CupertinoTheme] if null.
final TextStyle style;
final TextStyle? style;
/// {@macro flutter.widgets.editableText.strutStyle}
final StrutStyle strutStyle;
final StrutStyle? strutStyle;
/// {@macro flutter.widgets.editableText.textAlign}
final TextAlign textAlign;
......@@ -429,13 +428,13 @@ class CupertinoTextField extends StatefulWidget {
final ToolbarOptions toolbarOptions;
/// {@macro flutter.widgets.inputDecorator.textAlignVertical}
final TextAlignVertical textAlignVertical;
final TextAlignVertical? textAlignVertical;
/// {@macro flutter.widgets.editableText.readOnly}
final bool readOnly;
/// {@macro flutter.widgets.editableText.showCursor}
final bool showCursor;
final bool? showCursor;
/// {@macro flutter.widgets.editableText.autofocus}
final bool autofocus;
......@@ -459,10 +458,10 @@ class CupertinoTextField extends StatefulWidget {
final bool enableSuggestions;
/// {@macro flutter.widgets.editableText.maxLines}
final int maxLines;
final int? maxLines;
/// {@macro flutter.widgets.editableText.minLines}
final int minLines;
final int? minLines;
/// {@macro flutter.widgets.editableText.expands}
final bool expands;
......@@ -509,7 +508,7 @@ class CupertinoTextField extends StatefulWidget {
///
/// * [LengthLimitingTextInputFormatter] for more information on how it
/// counts characters, and how it may differ from the intuitive meaning.
final int maxLength;
final int? maxLength;
/// If true, prevents the field from allowing more than [maxLength]
/// characters.
......@@ -520,10 +519,10 @@ class CupertinoTextField extends StatefulWidget {
final bool maxLengthEnforced;
/// {@macro flutter.widgets.editableText.onChanged}
final ValueChanged<String> onChanged;
final ValueChanged<String>? onChanged;
/// {@macro flutter.widgets.editableText.onEditingComplete}
final VoidCallback onEditingComplete;
final VoidCallback? onEditingComplete;
/// {@macro flutter.widgets.editableText.onSubmitted}
///
......@@ -532,23 +531,23 @@ class CupertinoTextField extends StatefulWidget {
/// * [EditableText.onSubmitted] for an example of how to handle moving to
/// the next/previous field when using [TextInputAction.next] and
/// [TextInputAction.previous] for [textInputAction].
final ValueChanged<String> onSubmitted;
final ValueChanged<String>? onSubmitted;
/// {@macro flutter.widgets.editableText.inputFormatters}
final List<TextInputFormatter> inputFormatters;
final List<TextInputFormatter>? inputFormatters;
/// Disables the text field when false.
///
/// Text fields in disabled states have a light grey background and don't
/// respond to touch events including the [prefix], [suffix] and the clear
/// button.
final bool enabled;
final bool? enabled;
/// {@macro flutter.widgets.editableText.cursorWidth}
final double cursorWidth;
/// {@macro flutter.widgets.editableText.cursorHeight}
final double cursorHeight;
final double? cursorHeight;
/// {@macro flutter.widgets.editableText.cursorRadius}
final Radius cursorRadius;
......@@ -558,7 +557,7 @@ class CupertinoTextField extends StatefulWidget {
/// Defaults to the [CupertinoThemeData.primaryColor] of the ambient theme,
/// which itself defaults to [CupertinoColors.activeBlue] in the light theme
/// and [CupertinoColors.activeOrange] in the dark theme.
final Color cursorColor;
final Color? cursorColor;
/// Controls how tall the selection highlight boxes are computed to be.
///
......@@ -575,7 +574,7 @@ class CupertinoTextField extends StatefulWidget {
/// This setting is only honored on iOS devices.
///
/// If null, defaults to [Brightness.light].
final Brightness keyboardAppearance;
final Brightness? keyboardAppearance;
/// {@macro flutter.widgets.editableText.scrollPadding}
final EdgeInsets scrollPadding;
......@@ -587,23 +586,23 @@ class CupertinoTextField extends StatefulWidget {
final DragStartBehavior dragStartBehavior;
/// {@macro flutter.widgets.editableText.scrollController}
final ScrollController scrollController;
final ScrollController? scrollController;
/// {@macro flutter.widgets.editableText.scrollPhysics}
final ScrollPhysics scrollPhysics;
final ScrollPhysics? scrollPhysics;
/// {@macro flutter.widgets.editableText.selectionEnabled}
bool get selectionEnabled => enableInteractiveSelection;
/// {@macro flutter.material.textfield.onTap}
final GestureTapCallback onTap;
final GestureTapCallback? onTap;
/// {@macro flutter.widgets.editableText.autofillHints}
/// {@macro flutter.services.autofill.autofillHints}
final Iterable<String> autofillHints;
final Iterable<String>? autofillHints;
/// {@macro flutter.material.textfield.restorationId}
final String restorationId;
final String? restorationId;
@override
_CupertinoTextFieldState createState() => _CupertinoTextFieldState();
......@@ -649,15 +648,15 @@ class CupertinoTextField extends StatefulWidget {
class _CupertinoTextFieldState extends State<CupertinoTextField> with RestorationMixin, AutomaticKeepAliveClientMixin<CupertinoTextField> implements TextSelectionGestureDetectorBuilderDelegate {
final GlobalKey _clearGlobalKey = GlobalKey();
RestorableTextEditingController _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller.value;
RestorableTextEditingController? _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller!.value;
FocusNode _focusNode;
FocusNode? _focusNode;
FocusNode get _effectiveFocusNode => widget.focusNode ?? (_focusNode ??= FocusNode());
bool _showSelectionHandles = false;
_CupertinoTextFieldSelectionGestureDetectorBuilder _selectionGestureDetectorBuilder;
late _CupertinoTextFieldSelectionGestureDetectorBuilder _selectionGestureDetectorBuilder;
// API for TextSelectionGestureDetectorBuilderDelegate.
@override
......@@ -683,10 +682,10 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
void didUpdateWidget(CupertinoTextField oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.controller == null && oldWidget.controller != null) {
_createLocalController(oldWidget.controller.value);
_createLocalController(oldWidget.controller!.value);
} else if (widget.controller != null && oldWidget.controller == null) {
unregisterFromRestoration(_controller);
_controller.dispose();
unregisterFromRestoration(_controller!);
_controller!.dispose();
_controller = null;
}
final bool isEnabled = widget.enabled ?? true;
......@@ -697,7 +696,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
}
@override
void restoreState(RestorationBucket oldBucket, bool initialRestore) {
void restoreState(RestorationBucket? oldBucket, bool initialRestore) {
if (_controller != null) {
_registerController();
}
......@@ -705,11 +704,11 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
void _registerController() {
assert(_controller != null);
registerForRestoration(_controller, 'controller');
_controller.value.addListener(updateKeepAlive);
registerForRestoration(_controller!, 'controller');
_controller!.value.addListener(updateKeepAlive);
}
void _createLocalController([TextEditingValue value]) {
void _createLocalController([TextEditingValue? value]) {
assert(_controller == null);
_controller = value == null
? RestorableTextEditingController()
......@@ -720,7 +719,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
}
@override
String get restorationId => widget.restorationId;
String? get restorationId => widget.restorationId;
@override
void dispose() {
......@@ -729,13 +728,13 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
super.dispose();
}
EditableTextState get _editableText => editableTextKey.currentState;
EditableTextState? get _editableText => editableTextKey.currentState;
void _requestKeyboard() {
_editableText?.requestKeyboard();
}
bool _shouldShowSelectionHandles(SelectionChangedCause cause) {
bool _shouldShowSelectionHandles(SelectionChangedCause? cause) {
// When the text field is activated by something that doesn't trigger the
// selection overlay, we shouldn't show the handles either.
if (!_selectionGestureDetectorBuilder.shouldShowSelectionToolbar)
......@@ -754,7 +753,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
return false;
}
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause cause) {
void _handleSelectionChanged(TextSelection selection, SelectionChangedCause? cause) {
if (cause == SelectionChangedCause.longPress) {
_editableText?.bringIntoView(selection.base);
}
......@@ -767,11 +766,11 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
}
@override
bool get wantKeepAlive => _controller?.value?.text?.isNotEmpty == true;
bool get wantKeepAlive => _controller?.value.text.isNotEmpty == true;
bool _shouldShowAttachment({
OverlayVisibilityMode attachment,
bool hasText,
required OverlayVisibilityMode attachment,
required bool hasText,
}) {
switch (attachment) {
case OverlayVisibilityMode.never:
......@@ -783,8 +782,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
case OverlayVisibilityMode.notEditing:
return !hasText;
}
assert(false);
return null;
}
bool _showPrefixWidget(TextEditingValue text) {
......@@ -821,7 +818,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
// like a prefix or suffix, in which case it's aligned to the center.
TextAlignVertical get _textAlignVertical {
if (widget.textAlignVertical != null) {
return widget.textAlignVertical;
return widget.textAlignVertical!;
}
return _hasDecoration ? TextAlignVertical.center : TextAlignVertical.top;
}
......@@ -840,11 +837,11 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
return ValueListenableBuilder<TextEditingValue>(
valueListenable: _effectiveController,
child: editableText,
builder: (BuildContext context, TextEditingValue text, Widget child) {
builder: (BuildContext context, TextEditingValue? text, Widget? child) {
return Row(children: <Widget>[
// Insert a prefix at the front if the prefix visibility mode matches
// the current text state.
if (_showPrefixWidget(text)) widget.prefix,
if (_showPrefixWidget(text!)) widget.prefix!,
// In the middle part, stack the placeholder on top of the main EditableText
// if needed.
Expanded(
......@@ -856,7 +853,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
child: Padding(
padding: widget.padding,
child: Text(
widget.placeholder,
widget.placeholder!,
maxLines: widget.maxLines,
overflow: TextOverflow.ellipsis,
style: placeholderStyle,
......@@ -864,13 +861,13 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
),
),
),
child,
child!,
],
),
),
// First add the explicit suffix if the suffix visibility mode matches.
if (_showSuffixWidget(text))
widget.suffix
widget.suffix!
// Otherwise, try to show a clear button if its visibility mode matches.
else if (_showClearButton(text))
GestureDetector(
......@@ -881,7 +878,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
final bool textChanged = _effectiveController.text.isNotEmpty;
_effectiveController.clear();
if (widget.onChanged != null && textChanged)
widget.onChanged(_effectiveController.text);
widget.onChanged!(_effectiveController.text);
} : null,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6.0),
......@@ -904,33 +901,33 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
final TextEditingController controller = _effectiveController;
final List<TextInputFormatter> formatters = widget.inputFormatters ?? <TextInputFormatter>[];
final bool enabled = widget.enabled ?? true;
final Offset cursorOffset = Offset(_iOSHorizontalCursorOffsetPixels / MediaQuery.of(context).devicePixelRatio, 0);
final Offset cursorOffset = Offset(_iOSHorizontalCursorOffsetPixels / MediaQuery.of(context)!.devicePixelRatio, 0);
if (widget.maxLength != null && widget.maxLengthEnforced) {
formatters.add(LengthLimitingTextInputFormatter(widget.maxLength));
}
final CupertinoThemeData themeData = CupertinoTheme.of(context);
final TextStyle resolvedStyle = widget.style?.copyWith(
final TextStyle? resolvedStyle = widget.style?.copyWith(
color: CupertinoDynamicColor.resolve(widget.style?.color, context),
backgroundColor: CupertinoDynamicColor.resolve(widget.style?.backgroundColor, context),
);
final TextStyle textStyle = themeData.textTheme.textStyle.merge(resolvedStyle);
final TextStyle resolvedPlaceholderStyle = widget.placeholderStyle?.copyWith(
final TextStyle? resolvedPlaceholderStyle = widget.placeholderStyle?.copyWith(
color: CupertinoDynamicColor.resolve(widget.placeholderStyle?.color, context),
backgroundColor: CupertinoDynamicColor.resolve(widget.placeholderStyle?.backgroundColor, context),
);
final TextStyle placeholderStyle = textStyle.merge(resolvedPlaceholderStyle);
final Brightness keyboardAppearance = widget.keyboardAppearance ?? CupertinoTheme.brightnessOf(context);
final Brightness keyboardAppearance = widget.keyboardAppearance ?? CupertinoTheme.brightnessOf(context)!;
final Color cursorColor = CupertinoDynamicColor.resolve(widget.cursorColor, context) ?? themeData.primaryColor;
final Color disabledColor = CupertinoDynamicColor.resolve(_kDisabledBackground, context);
final Color? disabledColor = CupertinoDynamicColor.resolve(_kDisabledBackground, context);
final Color decorationColor = CupertinoDynamicColor.resolve(widget.decoration?.color, context);
final Color? decorationColor = CupertinoDynamicColor.resolve(widget.decoration?.color, context);
final BoxBorder border = widget.decoration?.border;
final BoxBorder? border = widget.decoration?.border;
Border resolvedBorder = border as Border;
if (border is Border) {
BorderSide resolveBorderSide(BorderSide side) {
......@@ -948,7 +945,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
);
}
final BoxDecoration effectiveDecoration = widget.decoration?.copyWith(
final BoxDecoration? effectiveDecoration = widget.decoration?.copyWith(
border: resolvedBorder,
color: enabled ? decorationColor : (decorationColor ?? disabledColor),
);
......@@ -1001,7 +998,7 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with Restoratio
cursorOffset: cursorOffset,
paintCursorAboveText: true,
autocorrectionTextRectColor: selectionColor,
backgroundCursorColor: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context),
backgroundCursorColor: CupertinoDynamicColor.resolve(CupertinoColors.inactiveGray, context)!,
selectionHeightStyle: widget.selectionHeightStyle,
selectionWidthStyle: widget.selectionWidthStyle,
scrollPadding: widget.scrollPadding,
......
......@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// @dart = 2.8
import 'dart:collection';
import 'dart:math' as math;
import 'dart:ui' as ui;
......@@ -68,24 +66,24 @@ const EdgeInsets _kToolbarButtonPadding = EdgeInsets.symmetric(vertical: 10.0, h
// Generates the child that's passed into CupertinoTextSelectionToolbar.
class _CupertinoTextSelectionToolbarWrapper extends StatefulWidget {
const _CupertinoTextSelectionToolbarWrapper({
Key key,
this.arrowTipX,
this.barTopY,
Key? key,
required this.arrowTipX,
required this.barTopY,
this.clipboardStatus,
this.handleCut,
this.handleCopy,
this.handlePaste,
this.handleSelectAll,
this.isArrowPointingDown,
required this.isArrowPointingDown,
}) : super(key: key);
final double arrowTipX;
final double barTopY;
final ClipboardStatusNotifier clipboardStatus;
final VoidCallback handleCut;
final VoidCallback handleCopy;
final VoidCallback handlePaste;
final VoidCallback handleSelectAll;
final ClipboardStatusNotifier? clipboardStatus;
final VoidCallback? handleCut;
final VoidCallback? handleCopy;
final VoidCallback? handlePaste;
final VoidCallback? handleSelectAll;
final bool isArrowPointingDown;
@override
......@@ -93,7 +91,7 @@ class _CupertinoTextSelectionToolbarWrapper extends StatefulWidget {
}
class _CupertinoTextSelectionToolbarWrapperState extends State<_CupertinoTextSelectionToolbarWrapper> {
ClipboardStatusNotifier _clipboardStatus;
late ClipboardStatusNotifier _clipboardStatus;
void _onChangedClipboardStatus() {
setState(() {
......@@ -115,16 +113,16 @@ class _CupertinoTextSelectionToolbarWrapperState extends State<_CupertinoTextSel
if (oldWidget.clipboardStatus == null && widget.clipboardStatus != null) {
_clipboardStatus.removeListener(_onChangedClipboardStatus);
_clipboardStatus.dispose();
_clipboardStatus = widget.clipboardStatus;
_clipboardStatus = widget.clipboardStatus!;
} else if (oldWidget.clipboardStatus != null) {
if (widget.clipboardStatus == null) {
_clipboardStatus = ClipboardStatusNotifier();
_clipboardStatus.addListener(_onChangedClipboardStatus);
oldWidget.clipboardStatus.removeListener(_onChangedClipboardStatus);
oldWidget.clipboardStatus!.removeListener(_onChangedClipboardStatus);
} else if (widget.clipboardStatus != oldWidget.clipboardStatus) {
_clipboardStatus = widget.clipboardStatus;
_clipboardStatus = widget.clipboardStatus!;
_clipboardStatus.addListener(_onChangedClipboardStatus);
oldWidget.clipboardStatus.removeListener(_onChangedClipboardStatus);
oldWidget.clipboardStatus!.removeListener(_onChangedClipboardStatus);
}
}
if (widget.handlePaste != null) {
......@@ -154,12 +152,12 @@ class _CupertinoTextSelectionToolbarWrapperState extends State<_CupertinoTextSel
}
final List<Widget> items = <Widget>[];
final CupertinoLocalizations localizations = CupertinoLocalizations.of(context);
final CupertinoLocalizations? localizations = CupertinoLocalizations.of(context);
final EdgeInsets arrowPadding = widget.isArrowPointingDown
? EdgeInsets.only(bottom: _kToolbarArrowSize.height)
: EdgeInsets.only(top: _kToolbarArrowSize.height);
final Widget onePhysicalPixelVerticalDivider =
SizedBox(width: 1.0 / MediaQuery.of(context).devicePixelRatio);
SizedBox(width: 1.0 / MediaQuery.of(context)!.devicePixelRatio);
void addToolbarButton(
String text,
......@@ -185,17 +183,17 @@ class _CupertinoTextSelectionToolbarWrapperState extends State<_CupertinoTextSel
}
if (widget.handleCut != null) {
addToolbarButton(localizations.cutButtonLabel, widget.handleCut);
addToolbarButton(localizations!.cutButtonLabel, widget.handleCut!);
}
if (widget.handleCopy != null) {
addToolbarButton(localizations.copyButtonLabel, widget.handleCopy);
addToolbarButton(localizations!.copyButtonLabel, widget.handleCopy!);
}
if (widget.handlePaste != null
&& _clipboardStatus.value == ClipboardStatus.pasteable) {
addToolbarButton(localizations.pasteButtonLabel, widget.handlePaste);
addToolbarButton(localizations!.pasteButtonLabel, widget.handlePaste!);
}
if (widget.handleSelectAll != null) {
addToolbarButton(localizations.selectAllButtonLabel, widget.handleSelectAll);
addToolbarButton(localizations!.selectAllButtonLabel, widget.handleSelectAll!);
}
return CupertinoTextSelectionToolbar._(
......@@ -221,11 +219,11 @@ class _CupertinoTextSelectionToolbarWrapperState extends State<_CupertinoTextSel
@visibleForTesting
class CupertinoTextSelectionToolbar extends SingleChildRenderObjectWidget {
const CupertinoTextSelectionToolbar._({
Key key,
double barTopY,
double arrowTipX,
bool isArrowPointingDown,
Widget child,
Key? key,
required double barTopY,
required double arrowTipX,
required bool isArrowPointingDown,
Widget? child,
}) : _barTopY = barTopY,
_arrowTipX = arrowTipX,
_isArrowPointingDown = isArrowPointingDown,
......@@ -257,7 +255,7 @@ class _ToolbarParentData extends BoxParentData {
// The x offset from the tip of the arrow to the center of the toolbar.
// Positive if the tip of the arrow has a larger x-coordinate than the
// center of the toolbar.
double arrowXOffsetFromCenter;
double? arrowXOffsetFromCenter;
@override
String toString() => 'offset=$offset, arrowXOffsetFromCenter=$arrowXOffsetFromCenter';
}
......@@ -267,7 +265,7 @@ class _ToolbarRenderBox extends RenderShiftedBox {
this._barTopY,
this._arrowTipX,
this._isArrowPointingDown,
RenderBox child,
RenderBox? child,
) : super(child);
......@@ -325,37 +323,37 @@ class _ToolbarRenderBox extends RenderShiftedBox {
.deflate(const EdgeInsets.symmetric(horizontal: _kToolbarScreenPadding))
.loosen();
child.layout(heightConstraint.enforce(enforcedConstraint), parentUsesSize: true,);
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData;
child!.layout(heightConstraint.enforce(enforcedConstraint), parentUsesSize: true,);
final _ToolbarParentData childParentData = child!.parentData as _ToolbarParentData;
// The local x-coordinate of the center of the toolbar.
final double lowerBound = child.size.width/2 + _kToolbarScreenPadding;
final double upperBound = size.width - child.size.width/2 - _kToolbarScreenPadding;
final double adjustedCenterX = _arrowTipX.clamp(lowerBound, upperBound) as double;
final double lowerBound = child!.size.width/2 + _kToolbarScreenPadding;
final double upperBound = size.width - child!.size.width/2 - _kToolbarScreenPadding;
final double adjustedCenterX = _arrowTipX.clamp(lowerBound, upperBound);
childParentData.offset = Offset(adjustedCenterX - child.size.width / 2, _barTopY);
childParentData.offset = Offset(adjustedCenterX - child!.size.width / 2, _barTopY);
childParentData.arrowXOffsetFromCenter = _arrowTipX - adjustedCenterX;
}
// The path is described in the toolbar's coordinate system.
Path _clipPath() {
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData;
final _ToolbarParentData childParentData = child!.parentData as _ToolbarParentData;
final Path rrect = Path()
..addRRect(
RRect.fromRectAndRadius(
Offset(0, _isArrowPointingDown ? 0 : _kToolbarArrowSize.height,)
& Size(child.size.width, child.size.height - _kToolbarArrowSize.height),
Offset(0, _isArrowPointingDown ? 0 : _kToolbarArrowSize.height)
& Size(child!.size.width, child!.size.height - _kToolbarArrowSize.height),
_kToolbarBorderRadius,
),
);
final double arrowTipX = child.size.width / 2 + childParentData.arrowXOffsetFromCenter;
final double arrowTipX = child!.size.width / 2 + childParentData.arrowXOffsetFromCenter!;
final double arrowBottomY = _isArrowPointingDown
? child.size.height - _kToolbarArrowSize.height
? child!.size.height - _kToolbarArrowSize.height
: _kToolbarArrowSize.height;
final double arrowTipY = _isArrowPointingDown ? child.size.height : 0;
final double arrowTipY = _isArrowPointingDown ? child!.size.height : 0;
final Path arrow = Path()
..moveTo(arrowTipX, arrowTipY)
......@@ -372,17 +370,17 @@ class _ToolbarRenderBox extends RenderShiftedBox {
return;
}
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData;
final _ToolbarParentData childParentData = child!.parentData as _ToolbarParentData;
context.pushClipPath(
needsCompositing,
offset + childParentData.offset,
Offset.zero & child.size,
Offset.zero & child!.size,
_clipPath(),
(PaintingContext innerContext, Offset innerOffset) => innerContext.paintChild(child, innerOffset),
(PaintingContext innerContext, Offset innerOffset) => innerContext.paintChild(child!, innerOffset),
);
}
Paint _debugPaint;
Paint? _debugPaint;
@override
void debugPaintSize(PaintingContext context, Offset offset) {
......@@ -395,15 +393,15 @@ class _ToolbarRenderBox extends RenderShiftedBox {
..shader = ui.Gradient.linear(
const Offset(0.0, 0.0),
const Offset(10.0, 10.0),
<Color>[const Color(0x00000000), const Color(0xFFFF00FF), const Color(0xFFFF00FF), const Color(0x00000000)],
<double>[0.25, 0.25, 0.75, 0.75],
const <Color>[Color(0x00000000), Color(0xFFFF00FF), Color(0xFFFF00FF), Color(0x00000000)],
const <double>[0.25, 0.25, 0.75, 0.75],
TileMode.repeated,
)
..strokeWidth = 2.0
..style = PaintingStyle.stroke;
final _ToolbarParentData childParentData = child.parentData as _ToolbarParentData;
context.canvas.drawPath(_clipPath().shift(offset + childParentData.offset), _debugPaint);
final _ToolbarParentData childParentData = child!.parentData as _ToolbarParentData;
context.canvas.drawPath(_clipPath().shift(offset + childParentData.offset), _debugPaint!);
return true;
}());
}
......@@ -463,7 +461,7 @@ class _CupertinoTextSelectionControls extends TextSelectionControls {
ClipboardStatusNotifier clipboardStatus,
) {
assert(debugCheckHasMediaQuery(context));
final MediaQueryData mediaQuery = MediaQuery.of(context);
final MediaQueryData mediaQuery = MediaQuery.of(context)!;
// The toolbar should appear below the TextField when there is not enough
// space above the TextField to show it, assuming there's always enough space
......@@ -478,7 +476,7 @@ class _CupertinoTextSelectionControls extends TextSelectionControls {
final double arrowTipX = (position.dx + globalEditableRegion.left).clamp(
_kArrowScreenPadding + mediaQuery.padding.left,
mediaQuery.size.width - mediaQuery.padding.right - _kArrowScreenPadding,
) as double;
);
// The y-coordinate has to be calculated instead of directly quoting position.dy,
// since the caller (TextSelectionOverlay._buildToolbar) does not know whether
......@@ -532,8 +530,6 @@ class _CupertinoTextSelectionControls extends TextSelectionControls {
case TextSelectionHandleType.collapsed:
return const SizedBox();
}
assert(type != null);
return null;
}
/// Gets anchor for cupertino-style text selection handles.
......@@ -570,9 +566,9 @@ class _CupertinoTextSelectionControls extends TextSelectionControls {
// Renders the content of the selection menu and maintains the page state.
class _CupertinoTextSelectionToolbarContent extends StatefulWidget {
const _CupertinoTextSelectionToolbarContent({
Key key,
@required this.children,
@required this.isArrowPointingDown,
Key? key,
required this.children,
required this.isArrowPointingDown,
}) : assert(children != null),
// This ignore is used because .isNotEmpty isn't compatible with const.
assert(children.length > 0), // ignore: prefer_is_empty
......@@ -587,9 +583,9 @@ class _CupertinoTextSelectionToolbarContent extends StatefulWidget {
class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSelectionToolbarContent> with TickerProviderStateMixin {
// Controls the fading of the buttons within the menu during page transitions.
AnimationController _controller;
late AnimationController _controller;
int _page = 0;
int _nextPage;
int? _nextPage;
void _handleNextPage() {
_controller.reverse();
......@@ -609,7 +605,7 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
}
setState(() {
_page = _nextPage;
_page = _nextPage!;
_nextPage = null;
});
_controller.forward();
......@@ -666,7 +662,7 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
pressedOpacity: 0.7,
child: const Text('◀', style: _kToolbarButtonFontStyle),
),
dividerWidth: 1.0 / MediaQuery.of(context).devicePixelRatio,
dividerWidth: 1.0 / MediaQuery.of(context)!.devicePixelRatio,
nextButton: CupertinoButton(
borderRadius: null,
color: _kToolbarBackgroundColor,
......@@ -698,13 +694,13 @@ class _CupertinoTextSelectionToolbarContentState extends State<_CupertinoTextSel
// _CupertinoTextSelectionToolbarItemsElement, paginates the menu items.
class _CupertinoTextSelectionToolbarItems extends RenderObjectWidget {
_CupertinoTextSelectionToolbarItems({
Key key,
@required this.page,
@required this.children,
@required this.backButton,
@required this.dividerWidth,
@required this.nextButton,
@required this.nextButtonDisabled,
Key? key,
required this.page,
required this.children,
required this.backButton,
required this.dividerWidth,
required this.nextButton,
required this.nextButtonDisabled,
}) : assert(children != null),
assert(children.isNotEmpty),
assert(backButton != null),
......@@ -746,7 +742,7 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
_CupertinoTextSelectionToolbarItems widget,
) : super(widget);
List<Element> _children;
late List<Element> _children;
final Map<_CupertinoTextSelectionToolbarItemsSlot, Element> slotToChild = <_CupertinoTextSelectionToolbarItemsSlot, Element>{};
// We keep a set of forgotten children to avoid O(n^2) work walking _children
......@@ -759,7 +755,7 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
@override
_CupertinoTextSelectionToolbarItemsRenderBox get renderObject => super.renderObject as _CupertinoTextSelectionToolbarItemsRenderBox;
void _updateRenderObject(RenderBox child, _CupertinoTextSelectionToolbarItemsSlot slot) {
void _updateRenderObject(RenderBox? child, _CupertinoTextSelectionToolbarItemsSlot slot) {
switch (slot) {
case _CupertinoTextSelectionToolbarItemsSlot.backButton:
renderObject.backButton = child;
......@@ -783,7 +779,7 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
}
if (slot is IndexedSlot) {
assert(renderObject.debugValidateChild(child));
renderObject.insert(child as RenderBox, after: slot?.value?.renderObject as RenderBox);
renderObject.insert(child as RenderBox, after: slot.value?.renderObject as RenderBox);
return;
}
assert(false, 'slot must be _CupertinoTextSelectionToolbarItemsSlot or IndexedSlot');
......@@ -793,11 +789,11 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
@override
void moveRenderObjectChild(RenderObject child, IndexedSlot<Element> oldSlot, IndexedSlot<Element> newSlot) {
assert(child.parent == renderObject);
renderObject.move(child as RenderBox, after: newSlot?.value?.renderObject as RenderBox);
renderObject.move(child as RenderBox, after: newSlot.value.renderObject as RenderBox);
}
static bool _shouldPaint(Element child) {
return (child.renderObject.parentData as ToolbarItemsParentData).shouldPaint;
return (child.renderObject!.parentData as ToolbarItemsParentData).shouldPaint;
}
@override
......@@ -842,8 +838,8 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
// Mount or update slotted child.
void _mountChild(Widget widget, _CupertinoTextSelectionToolbarItemsSlot slot) {
final Element oldChild = slotToChild[slot];
final Element newChild = updateChild(oldChild, widget, slot);
final Element? oldChild = slotToChild[slot];
final Element? newChild = updateChild(oldChild, widget, slot);
if (oldChild != null) {
slotToChild.remove(slot);
}
......@@ -853,7 +849,7 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
}
@override
void mount(Element parent, dynamic newSlot) {
void mount(Element? parent, dynamic newSlot) {
super.mount(parent, newSlot);
// Mount slotted children.
_mountChild(widget.backButton, _CupertinoTextSelectionToolbarItemsSlot.backButton);
......@@ -861,10 +857,10 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
_mountChild(widget.nextButtonDisabled, _CupertinoTextSelectionToolbarItemsSlot.nextButtonDisabled);
// Mount list children.
_children = List<Element>(widget.children.length);
Element previousChild;
_children = List<Element>.filled(widget.children.length, _NullElement.instance);
Element? previousChild;
for (int i = 0; i < _children.length; i += 1) {
final Element newChild = inflateWidget(widget.children[i], IndexedSlot<Element>(i, previousChild));
final Element newChild = inflateWidget(widget.children[i], IndexedSlot<Element?>(i, previousChild));
_children[i] = newChild;
previousChild = newChild;
}
......@@ -903,8 +899,8 @@ class _CupertinoTextSelectionToolbarItemsElement extends RenderObjectElement {
// The custom RenderBox that helps paginate the menu items.
class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with ContainerRenderObjectMixin<RenderBox, ToolbarItemsParentData>, RenderBoxContainerDefaultsMixin<RenderBox, ToolbarItemsParentData> {
_CupertinoTextSelectionToolbarItemsRenderBox({
@required double dividerWidth,
@required int page,
required double dividerWidth,
required int page,
}) : assert(dividerWidth != null),
assert(page != null),
_dividerWidth = dividerWidth,
......@@ -913,7 +909,7 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
final Map<_CupertinoTextSelectionToolbarItemsSlot, RenderBox> slottedChildren = <_CupertinoTextSelectionToolbarItemsSlot, RenderBox>{};
RenderBox _updateChild(RenderBox oldChild, RenderBox newChild, _CupertinoTextSelectionToolbarItemsSlot slot) {
RenderBox? _updateChild(RenderBox? oldChild, RenderBox? newChild, _CupertinoTextSelectionToolbarItemsSlot slot) {
if (oldChild != null) {
dropChild(oldChild);
slottedChildren.remove(slot);
......@@ -949,21 +945,21 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
markNeedsLayout();
}
RenderBox _backButton;
RenderBox get backButton => _backButton;
set backButton(RenderBox value) {
RenderBox? _backButton;
RenderBox? get backButton => _backButton;
set backButton(RenderBox? value) {
_backButton = _updateChild(_backButton, value, _CupertinoTextSelectionToolbarItemsSlot.backButton);
}
RenderBox _nextButton;
RenderBox get nextButton => _nextButton;
set nextButton(RenderBox value) {
RenderBox? _nextButton;
RenderBox? get nextButton => _nextButton;
set nextButton(RenderBox? value) {
_nextButton = _updateChild(_nextButton, value, _CupertinoTextSelectionToolbarItemsSlot.nextButton);
}
RenderBox _nextButtonDisabled;
RenderBox get nextButtonDisabled => _nextButtonDisabled;
set nextButtonDisabled(RenderBox value) {
RenderBox? _nextButtonDisabled;
RenderBox? get nextButtonDisabled => _nextButtonDisabled;
set nextButtonDisabled(RenderBox? value) {
_nextButtonDisabled = _updateChild(_nextButtonDisabled, value, _CupertinoTextSelectionToolbarItemsSlot.nextButtonDisabled);
}
......@@ -975,15 +971,15 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
}
// Layout slotted children.
_backButton.layout(constraints.loosen(), parentUsesSize: true);
_nextButton.layout(constraints.loosen(), parentUsesSize: true);
_nextButtonDisabled.layout(constraints.loosen(), parentUsesSize: true);
_backButton!.layout(constraints.loosen(), parentUsesSize: true);
_nextButton!.layout(constraints.loosen(), parentUsesSize: true);
_nextButtonDisabled!.layout(constraints.loosen(), parentUsesSize: true);
final double subsequentPageButtonsWidth =
_backButton.size.width + _nextButton.size.width;
_backButton!.size.width + _nextButton!.size.width;
double currentButtonPosition = 0.0;
double toolbarWidth; // The width of the whole widget.
double firstPageWidth;
late double toolbarWidth; // The width of the whole widget.
late double firstPageWidth;
int currentPage = 0;
int i = -1;
visitChildren((RenderObject renderObjectChild) {
......@@ -1002,7 +998,7 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
if (currentPage == 0) {
// If this is the last child, it's ok to fit without a forward button.
paginationButtonsWidth =
i == childCount - 1 ? 0.0 : _nextButton.size.width;
i == childCount - 1 ? 0.0 : _nextButton!.size.width;
} else {
paginationButtonsWidth = subsequentPageButtonsWidth;
}
......@@ -1022,8 +1018,8 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
currentButtonPosition + paginationButtonsWidth + child.size.width;
if (currentWidth > constraints.maxWidth) {
currentPage++;
currentButtonPosition = _backButton.size.width + dividerWidth;
paginationButtonsWidth = _backButton.size.width + _nextButton.size.width;
currentButtonPosition = _backButton!.size.width + dividerWidth;
paginationButtonsWidth = _backButton!.size.width + _nextButton!.size.width;
child.layout(
BoxConstraints.loose(Size(
firstPageWidth - paginationButtonsWidth,
......@@ -1037,7 +1033,7 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
childParentData.shouldPaint = currentPage == page;
if (currentPage == 0) {
firstPageWidth = currentButtonPosition + _nextButton.size.width;
firstPageWidth = currentButtonPosition + _nextButton!.size.width;
}
if (currentPage == page) {
toolbarWidth = currentButtonPosition;
......@@ -1050,21 +1046,21 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
// Position page nav buttons.
if (currentPage > 0) {
final ToolbarItemsParentData nextButtonParentData =
_nextButton.parentData as ToolbarItemsParentData;
_nextButton!.parentData as ToolbarItemsParentData;
final ToolbarItemsParentData nextButtonDisabledParentData =
_nextButtonDisabled.parentData as ToolbarItemsParentData;
_nextButtonDisabled!.parentData as ToolbarItemsParentData;
final ToolbarItemsParentData backButtonParentData =
_backButton.parentData as ToolbarItemsParentData;
_backButton!.parentData as ToolbarItemsParentData;
// The forward button always shows if there is more than one page, even on
// the last page (it's just disabled).
if (page == currentPage) {
nextButtonDisabledParentData.offset = Offset(toolbarWidth, 0.0);
nextButtonDisabledParentData.shouldPaint = true;
toolbarWidth += nextButtonDisabled.size.width;
toolbarWidth += nextButtonDisabled!.size.width;
} else {
nextButtonParentData.offset = Offset(toolbarWidth, 0.0);
nextButtonParentData.shouldPaint = true;
toolbarWidth += nextButton.size.width;
toolbarWidth += nextButton!.size.width;
}
if (page > 0) {
backButtonParentData.offset = Offset.zero;
......@@ -1102,7 +1098,7 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
}
// Returns true iff the single child is hit by the given position.
static bool hitTestChild(RenderBox child, BoxHitTestResult result, { Offset position }) {
static bool hitTestChild(RenderBox? child, BoxHitTestResult result, { required Offset position }) {
if (child == null) {
return false;
}
......@@ -1119,10 +1115,10 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
}
@override
bool hitTestChildren(BoxHitTestResult result, { Offset position }) {
bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
// Hit test list children.
// The x, y parameters have the top left of the node's box as the origin.
RenderBox child = lastChild;
RenderBox? child = lastChild;
while (child != null) {
final ToolbarItemsParentData childParentData = child.parentData as ToolbarItemsParentData;
......@@ -1186,13 +1182,13 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
void visitChildren(RenderObjectVisitor visitor) {
// Visit the slotted children.
if (_backButton != null) {
visitor(_backButton);
visitor(_backButton!);
}
if (_nextButton != null) {
visitor(_nextButton);
visitor(_nextButton!);
}
if (_nextButtonDisabled != null) {
visitor(_nextButtonDisabled);
visitor(_nextButtonDisabled!);
}
// Visit the list children.
super.visitChildren(visitor);
......@@ -1214,9 +1210,6 @@ class _CupertinoTextSelectionToolbarItemsRenderBox extends RenderBox with Contai
List<DiagnosticsNode> debugDescribeChildren() {
final List<DiagnosticsNode> value = <DiagnosticsNode>[];
visitChildren((RenderObject renderObjectChild) {
if (renderObjectChild == null) {
return;
}
final RenderBox child = renderObjectChild as RenderBox;
if (child == backButton) {
value.add(child.toDiagnosticsNode(name: 'back button'));
......@@ -1244,3 +1237,20 @@ enum _CupertinoTextSelectionToolbarItemsSlot {
/// Text selection controls that follows iOS design conventions.
final TextSelectionControls cupertinoTextSelectionControls = _CupertinoTextSelectionControls();
class _NullElement extends Element {
_NullElement() : super(_NullWidget());
static _NullElement instance = _NullElement();
@override
bool get debugDoingBuild => throw UnimplementedError();
@override
void performRebuild() { }
}
class _NullWidget extends Widget {
@override
Element createElement() => throw UnimplementedError();
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment