Revert "migrate some material files to nullsafety (#67078)" (#67183)

This reverts commit 8143992262.
This commit is contained in:
Michael Goderbauer 2020-10-03 04:54:45 -07:00 committed by GitHub
parent cbf1e135c4
commit a0a65fc604
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 1244 additions and 1176 deletions

View file

@ -2,6 +2,8 @@
// 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:developer' show Timeline, Flow;
import 'dart:io' show Platform;
@ -121,7 +123,7 @@ class AboutListTile extends StatelessWidget {
/// derived from the nearest [Title] widget. The version, icon, and legalese
/// values default to the empty string.
const AboutListTile({
Key? key,
Key key,
this.icon,
this.child,
this.applicationName,
@ -138,13 +140,13 @@ class AboutListTile extends StatelessWidget {
///
/// This is not necessarily the same as the image shown in the dialog box
/// itself; which is controlled by the [applicationIcon] property.
final Widget? icon;
final Widget icon;
/// The label to show on this drawer item.
///
/// Defaults to a text widget that says "About Foo" where "Foo" is the
/// application name specified by [applicationName].
final Widget? child;
final Widget child;
/// The name of the application.
///
@ -153,14 +155,14 @@ class AboutListTile extends StatelessWidget {
///
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
/// Otherwise, defaults to [Platform.resolvedExecutable].
final String? applicationName;
final String applicationName;
/// The version of this build of the application.
///
/// This string is shown under the application name in the [AboutDialog].
///
/// Defaults to the empty string.
final String? applicationVersion;
final String applicationVersion;
/// The icon to show next to the application name in the [AboutDialog].
///
@ -171,14 +173,14 @@ class AboutListTile extends StatelessWidget {
///
/// This is not necessarily the same as the icon shown on the drawer item
/// itself, which is controlled by the [icon] property.
final Widget? applicationIcon;
final Widget applicationIcon;
/// A string to show in small print in the [AboutDialog].
///
/// Typically this is a copyright notice.
///
/// Defaults to the empty string.
final String? applicationLegalese;
final String applicationLegalese;
/// Widgets to add to the [AboutDialog] after the name, version, and legalese.
///
@ -186,14 +188,14 @@ class AboutListTile extends StatelessWidget {
/// or other information to show in the about box.
///
/// Defaults to nothing.
final List<Widget>? aboutBoxChildren;
final List<Widget> aboutBoxChildren;
/// Whether this list tile is part of a vertically dense list.
///
/// If this property is null, then its value is based on [ListTileTheme.dense].
///
/// Dense list tiles default to a smaller height.
final bool? dense;
final bool dense;
@override
Widget build(BuildContext context) {
@ -201,7 +203,7 @@ class AboutListTile extends StatelessWidget {
assert(debugCheckHasMaterialLocalizations(context));
return ListTile(
leading: icon,
title: child ?? Text(MaterialLocalizations.of(context)!.aboutListTileTitle(
title: child ?? Text(MaterialLocalizations.of(context).aboutListTileTitle(
applicationName ?? _defaultApplicationName(context),
)),
dense: dense,
@ -236,14 +238,14 @@ class AboutListTile extends StatelessWidget {
/// The [context], [useRootNavigator] and [routeSettings] arguments are passed to
/// [showDialog], the documentation for which discusses how it is used.
void showAboutDialog({
required BuildContext context,
String? applicationName,
String? applicationVersion,
Widget? applicationIcon,
String? applicationLegalese,
List<Widget>? children,
@required BuildContext context,
String applicationName,
String applicationVersion,
Widget applicationIcon,
String applicationLegalese,
List<Widget> children,
bool useRootNavigator = true,
RouteSettings? routeSettings,
RouteSettings routeSettings,
}) {
assert(context != null);
assert(useRootNavigator != null);
@ -283,16 +285,16 @@ void showAboutDialog({
/// The licenses shown on the [LicensePage] are those returned by the
/// [LicenseRegistry] API, which can be used to add more licenses to the list.
void showLicensePage({
required BuildContext context,
String? applicationName,
String? applicationVersion,
Widget? applicationIcon,
String? applicationLegalese,
@required BuildContext context,
String applicationName,
String applicationVersion,
Widget applicationIcon,
String applicationLegalese,
bool useRootNavigator = false,
}) {
assert(context != null);
assert(useRootNavigator != null);
Navigator.of(context, rootNavigator: useRootNavigator)!.push(MaterialPageRoute<void>(
Navigator.of(context, rootNavigator: useRootNavigator).push(MaterialPageRoute<void>(
builder: (BuildContext context) => LicensePage(
applicationName: applicationName,
applicationVersion: applicationVersion,
@ -328,7 +330,7 @@ class AboutDialog extends StatelessWidget {
/// derived from the nearest [Title] widget. The version, icon, and legalese
/// values default to the empty string.
const AboutDialog({
Key? key,
Key key,
this.applicationName,
this.applicationVersion,
this.applicationIcon,
@ -340,14 +342,14 @@ class AboutDialog extends StatelessWidget {
///
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
/// Otherwise, defaults to [Platform.resolvedExecutable].
final String? applicationName;
final String applicationName;
/// The version of this build of the application.
///
/// This string is shown under the application name.
///
/// Defaults to the empty string.
final String? applicationVersion;
final String applicationVersion;
/// The icon to show next to the application name.
///
@ -355,14 +357,14 @@ class AboutDialog extends StatelessWidget {
///
/// Typically this will be an [ImageIcon] widget. It should honor the
/// [IconTheme]'s [IconThemeData.size].
final Widget? applicationIcon;
final Widget applicationIcon;
/// A string to show in small print.
///
/// Typically this is a copyright notice.
///
/// Defaults to the empty string.
final String? applicationLegalese;
final String applicationLegalese;
/// Widgets to add to the dialog box after the name, version, and legalese.
///
@ -370,30 +372,30 @@ class AboutDialog extends StatelessWidget {
/// or other information to show in the about box.
///
/// Defaults to nothing.
final List<Widget>? children;
final List<Widget> children;
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context));
final String name = applicationName ?? _defaultApplicationName(context);
final String version = applicationVersion ?? _defaultApplicationVersion(context);
final Widget? icon = applicationIcon ?? _defaultApplicationIcon(context);
final Widget icon = applicationIcon ?? _defaultApplicationIcon(context);
return AlertDialog(
content: ListBody(
children: <Widget>[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
if (icon != null) IconTheme(data: Theme.of(context)!.iconTheme, child: icon),
if (icon != null) IconTheme(data: Theme.of(context).iconTheme, child: icon),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: ListBody(
children: <Widget>[
Text(name, style: Theme.of(context)!.textTheme.headline5),
Text(version, style: Theme.of(context)!.textTheme.bodyText2),
Text(name, style: Theme.of(context).textTheme.headline5),
Text(version, style: Theme.of(context).textTheme.bodyText2),
const SizedBox(height: _textVerticalSeparation),
Text(applicationLegalese ?? '', style: Theme.of(context)!.textTheme.caption),
Text(applicationLegalese ?? '', style: Theme.of(context).textTheme.caption),
],
),
),
@ -405,7 +407,7 @@ class AboutDialog extends StatelessWidget {
),
actions: <Widget>[
TextButton(
child: Text(MaterialLocalizations.of(context)!.viewLicensesButtonLabel),
child: Text(MaterialLocalizations.of(context).viewLicensesButtonLabel),
onPressed: () {
showLicensePage(
context: context,
@ -417,7 +419,7 @@ class AboutDialog extends StatelessWidget {
},
),
TextButton(
child: Text(MaterialLocalizations.of(context)!.closeButtonLabel),
child: Text(MaterialLocalizations.of(context).closeButtonLabel),
onPressed: () {
Navigator.pop(context);
},
@ -447,7 +449,7 @@ class LicensePage extends StatefulWidget {
/// The licenses shown on the [LicensePage] are those returned by the
/// [LicenseRegistry] API, which can be used to add more licenses to the list.
const LicensePage({
Key? key,
Key key,
this.applicationName,
this.applicationVersion,
this.applicationIcon,
@ -458,14 +460,14 @@ class LicensePage extends StatefulWidget {
///
/// Defaults to the value of [Title.title], if a [Title] widget can be found.
/// Otherwise, defaults to [Platform.resolvedExecutable].
final String? applicationName;
final String applicationName;
/// The version of this build of the application.
///
/// This string is shown under the application name.
///
/// Defaults to the empty string.
final String? applicationVersion;
final String applicationVersion;
/// The icon to show below the application name.
///
@ -473,33 +475,33 @@ class LicensePage extends StatefulWidget {
///
/// Typically this will be an [ImageIcon] widget. It should honor the
/// [IconTheme]'s [IconThemeData.size].
final Widget? applicationIcon;
final Widget applicationIcon;
/// A string to show in small print.
///
/// Typically this is a copyright notice.
///
/// Defaults to the empty string.
final String? applicationLegalese;
final String applicationLegalese;
@override
_LicensePageState createState() => _LicensePageState();
}
class _LicensePageState extends State<LicensePage> {
final ValueNotifier<int?> selectedId = ValueNotifier<int?>(null);
final ValueNotifier<int> selectedId = ValueNotifier<int>(null);
@override
Widget build(BuildContext context) {
return _MasterDetailFlow(
detailPageFABlessGutterWidth: _getGutterSize(context),
title: Text(MaterialLocalizations.of(context)!.licensesPageTitle),
title: Text(MaterialLocalizations.of(context).licensesPageTitle),
detailPageBuilder: _packageLicensePage,
masterViewBuilder: _packagesView,
);
}
Widget _packageLicensePage(BuildContext _, Object? args, ScrollController? scrollController) {
Widget _packageLicensePage(BuildContext _, Object args, ScrollController scrollController) {
assert(args is _DetailArguments);
final _DetailArguments detailArguments = args as _DetailArguments;
return _PackageLicensePage(
@ -526,9 +528,9 @@ class _LicensePageState extends State<LicensePage> {
class _AboutProgram extends StatelessWidget {
const _AboutProgram({
Key? key,
required this.name,
required this.version,
Key key,
@required this.name,
@required this.version,
this.icon,
this.legalese,
}) : assert(name != null),
@ -537,8 +539,8 @@ class _AboutProgram extends StatelessWidget {
final String name;
final String version;
final Widget? icon;
final String? legalese;
final Widget icon;
final String legalese;
@override
Widget build(BuildContext context) {
@ -551,26 +553,26 @@ class _AboutProgram extends StatelessWidget {
children: <Widget>[
Text(
name,
style: Theme.of(context)!.textTheme.headline5,
style: Theme.of(context).textTheme.headline5,
textAlign: TextAlign.center,
),
if (icon != null)
IconTheme(data: Theme.of(context)!.iconTheme, child: icon!),
IconTheme(data: Theme.of(context).iconTheme, child: icon),
Text(
version,
style: Theme.of(context)!.textTheme.bodyText2,
style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
const SizedBox(height: _textVerticalSeparation),
Text(
legalese ?? '',
style: Theme.of(context)!.textTheme.caption,
style: Theme.of(context).textTheme.caption,
textAlign: TextAlign.center,
),
const SizedBox(height: _textVerticalSeparation),
Text(
'Powered by Flutter',
style: Theme.of(context)!.textTheme.bodyText2,
style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
],
@ -581,17 +583,17 @@ class _AboutProgram extends StatelessWidget {
class _PackagesView extends StatefulWidget {
const _PackagesView({
Key? key,
required this.about,
required this.isLateral,
required this.selectedId,
Key key,
@required this.about,
@required this.isLateral,
@required this.selectedId,
}) : assert(about != null),
assert(isLateral != null),
super(key: key);
final Widget about;
final bool isLateral;
final ValueNotifier<int?> selectedId;
final ValueNotifier<int> selectedId;
@override
_PackagesViewState createState() => _PackagesViewState();
@ -615,17 +617,17 @@ class _PackagesViewState extends State<_PackagesView> {
builder: (BuildContext context, BoxConstraints constraints) {
switch (snapshot.connectionState) {
case ConnectionState.done:
_initDefaultDetailPage(snapshot.data!, context);
return ValueListenableBuilder<int?>(
_initDefaultDetailPage(snapshot.data, context);
return ValueListenableBuilder<int>(
valueListenable: widget.selectedId,
builder: (BuildContext context, int? selectedId, Widget? _) {
builder: (BuildContext context, int selectedId, Widget _) {
return Center(
child: Material(
color: Theme.of(context)!.cardColor,
color: Theme.of(context).cardColor,
elevation: 4.0,
child: Container(
constraints: BoxConstraints.loose(const Size.fromWidth(600.0)),
child: _packagesList(context, selectedId, snapshot.data!, widget.isLateral),
child: _packagesList(context, selectedId, snapshot.data, widget.isLateral),
),
),
);
@ -633,7 +635,7 @@ class _PackagesViewState extends State<_PackagesView> {
);
default:
return Material(
color: Theme.of(context)!.cardColor,
color: Theme.of(context).cardColor,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
@ -654,8 +656,8 @@ class _PackagesViewState extends State<_PackagesView> {
return;
}
final String packageName = data.packages[widget.selectedId.value ?? 0];
final List<int> bindings = data.packageLicenseBindings[packageName]!;
_MasterDetailFlow.of(context)!.setInitialDetailPage(
final List<int> bindings = data.packageLicenseBindings[packageName];
_MasterDetailFlow.of(context).setInitialDetailPage(
_DetailArguments(
packageName,
bindings.map((int i) => data.licenses[i]).toList(growable: false),
@ -665,7 +667,7 @@ class _PackagesViewState extends State<_PackagesView> {
Widget _packagesList(
final BuildContext context,
final int? selectedId,
final int selectedId,
final _LicenseData data,
final bool drawSelection,
) {
@ -678,7 +680,7 @@ class _PackagesViewState extends State<_PackagesView> {
.map<Widget>((MapEntry<int, String> entry) {
final String packageName = entry.value;
final int index = entry.key;
final List<int> bindings = data.packageLicenseBindings[packageName]!;
final List<int> bindings = data.packageLicenseBindings[packageName];
return _PackageListTile(
packageName: packageName,
index: index,
@ -686,7 +688,7 @@ class _PackagesViewState extends State<_PackagesView> {
numberLicenses: bindings.length,
onTap: () {
widget.selectedId.value = index;
_MasterDetailFlow.of(context)!.openDetailPage(_DetailArguments(
_MasterDetailFlow.of(context).openDetailPage(_DetailArguments(
packageName,
bindings.map((int i) => data.licenses[i]).toList(growable: false),
));
@ -700,27 +702,27 @@ class _PackagesViewState extends State<_PackagesView> {
class _PackageListTile extends StatelessWidget {
const _PackageListTile({
Key? key,
required this.packageName,
Key key,
this.packageName,
this.index,
required this.isSelected,
required this.numberLicenses,
this.isSelected,
this.numberLicenses,
this.onTap,
}) : super(key:key);
final String packageName;
final int? index;
final int index;
final bool isSelected;
final int numberLicenses;
final GestureTapCallback? onTap;
final GestureTapCallback onTap;
@override
Widget build(BuildContext context) {
return Ink(
color: isSelected ? Theme.of(context)!.highlightColor : Theme.of(context)!.cardColor,
color: isSelected ? Theme.of(context).highlightColor : Theme.of(context).cardColor,
child: ListTile(
title: Text(packageName),
subtitle: Text(MaterialLocalizations.of(context)!.licensesPackageDetailText(numberLicenses)),
subtitle: Text(MaterialLocalizations.of(context).licensesPackageDetailText(numberLicenses)),
selected: isSelected,
onTap: onTap,
),
@ -738,7 +740,7 @@ class _LicenseData {
// Special treatment for the first package since it should be the package
// for delivered application.
String? firstPackage;
String firstPackage;
void addLicense(LicenseEntry entry) {
// Before the license can be added, we must first record the packages to
@ -748,7 +750,7 @@ class _LicenseData {
// Bind this license to the package using the next index value. This
// creates a contract that this license must be inserted at this same
// index value.
packageLicenseBindings[package]!.add(licenses.length);
packageLicenseBindings[package].add(licenses.length);
}
licenses.add(entry); // Completion of the contract above.
}
@ -766,7 +768,7 @@ class _LicenseData {
/// Sort the packages using some comparison method, or by the default manner,
/// which is to put the application package first, followed by every other
/// package in case-insensitive alphabetical order.
void sortPackages([int Function(String a, String b)? compare]) {
void sortPackages([int compare(String a, String b)]) {
packages.sort(compare ?? (String a, String b) {
// Based on how LicenseRegistry currently behaves, the first package
// returned is the end user application license. This should be
@ -804,15 +806,15 @@ class _DetailArguments {
class _PackageLicensePage extends StatefulWidget {
const _PackageLicensePage({
Key? key,
required this.packageName,
required this.licenseEntries,
required this.scrollController,
Key key,
this.packageName,
this.licenseEntries,
this.scrollController,
}) : super(key: key);
final String packageName;
final List<LicenseEntry> licenseEntries;
final ScrollController? scrollController;
final ScrollController scrollController;
@override
_PackageLicensePageState createState() => _PackageLicensePageState();
@ -845,7 +847,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
return true;
}());
final List<LicenseParagraph> paragraphs =
await SchedulerBinding.instance!.scheduleTask<List<LicenseParagraph>>(
await SchedulerBinding.instance.scheduleTask<List<LicenseParagraph>>(
license.paragraphs.toList,
Priority.animation,
debugLabel: 'License',
@ -890,8 +892,8 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
@override
Widget build(BuildContext context) {
assert(debugCheckHasMaterialLocalizations(context));
final MaterialLocalizations localizations = MaterialLocalizations.of(context)!;
final ThemeData? theme = Theme.of(context);
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
final ThemeData theme = Theme.of(context);
final String title = widget.packageName;
final String subtitle = localizations.licensesPackageDetailText(widget.licenseEntries.length);
final double pad = _getGutterSize(context);
@ -914,7 +916,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
title: _PackageLicensePageTitle(
title,
subtitle,
theme!.appBarTheme.textTheme ?? theme.primaryTextTheme,
theme.appBarTheme.textTheme ?? theme.primaryTextTheme,
),
),
body: Center(
@ -941,7 +943,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
SliverAppBar(
automaticallyImplyLeading: false,
pinned: true,
backgroundColor: theme!.cardColor,
backgroundColor: theme.cardColor,
title: _PackageLicensePageTitle(title, subtitle, theme.textTheme),
),
SliverPadding(
@ -972,7 +974,7 @@ class _PackageLicensePageTitle extends StatelessWidget {
this.title,
this.subtitle,
this.theme, {
Key? key,
Key key,
}) : super(key: key);
final String title;
@ -999,7 +1001,7 @@ String _defaultApplicationName(BuildContext context) {
// someone really wants their application title to change dynamically, they
// can provide an explicit applicationName to the widgets defined in this
// file, instead of relying on the default.
final Title? ancestorTitle = context.findAncestorWidgetOfExactType<Title>();
final Title ancestorTitle = context.findAncestorWidgetOfExactType<Title>();
return ancestorTitle?.title ?? Platform.resolvedExecutable.split(Platform.pathSeparator).last;
}
@ -1008,7 +1010,7 @@ String _defaultApplicationVersion(BuildContext context) {
return '';
}
Widget? _defaultApplicationIcon(BuildContext context) {
Widget _defaultApplicationIcon(BuildContext context) {
// TODO(ianh): Get this from the embedder somehow.
return null;
}
@ -1018,7 +1020,7 @@ const double _wideGutterSize = 24.0;
const double _narrowGutterSize = 12.0;
double _getGutterSize(BuildContext context) =>
MediaQuery.of(context)!.size.width >= _materialGutterThreshold ? _wideGutterSize : _narrowGutterSize;
MediaQuery.of(context).size.width >= _materialGutterThreshold ? _wideGutterSize : _narrowGutterSize;
/// Signature for the builder callback used by [_MasterDetailFlow].
typedef _MasterViewBuilder = Widget Function(BuildContext context, bool isLateralUI);
@ -1027,7 +1029,7 @@ typedef _MasterViewBuilder = Widget Function(BuildContext context, bool isLatera
///
/// scrollController is provided when the page destination is the draggable
/// sheet in the lateral UI. Otherwise, it is null.
typedef _DetailPageBuilder = Widget Function(BuildContext context, Object? arguments, ScrollController? scrollController);
typedef _DetailPageBuilder = Widget Function(BuildContext context, Object arguments, ScrollController scrollController);
/// Signature for the builder callback used by [_MasterDetailFlow.actionBuilder].
///
@ -1076,9 +1078,9 @@ class _MasterDetailFlow extends StatefulWidget {
/// Creates a master detail navigation flow which is either nested or
/// lateral depending on screen width.
const _MasterDetailFlow({
Key? key,
required this.detailPageBuilder,
required this.masterViewBuilder,
Key key,
@required this.detailPageBuilder,
@required this.masterViewBuilder,
this.actionBuilder,
this.automaticallyImplyLeading = true,
this.breakpoint,
@ -1111,7 +1113,7 @@ class _MasterDetailFlow extends StatefulWidget {
/// This builder is usually a wrapper around the [masterViewBuilder] builder to provide the
/// extra UI required to make a page. However, this builder is optional, and the master page
/// can be built using the master view builder and the configuration for the lateral UI's app bar.
final _MasterViewBuilder? masterPageBuilder;
final _MasterViewBuilder masterPageBuilder;
/// Builder for the detail page.
///
@ -1122,29 +1124,29 @@ class _MasterDetailFlow extends StatefulWidget {
final _DetailPageBuilder detailPageBuilder;
/// Override the width of the master view in the lateral UI.
final double? masterViewWidth;
final double masterViewWidth;
/// Override the width of the floating action button gutter in the lateral UI.
final double? detailPageFABGutterWidth;
final double detailPageFABGutterWidth;
/// Override the width of the gutter when there is no floating action button.
final double? detailPageFABlessGutterWidth;
final double detailPageFABlessGutterWidth;
/// Add a floating action button to the lateral UI. If no [masterPageBuilder] is supplied, this
/// floating action button is also used on the nested master page.
///
/// See [Scaffold.floatingActionButton].
final FloatingActionButton? floatingActionButton;
final FloatingActionButton floatingActionButton;
/// The title for the lateral UI [AppBar].
///
/// See [AppBar.title].
final Widget? title;
final Widget title;
/// A widget to display before the title for the lateral UI [AppBar].
///
/// See [AppBar.leading].
final Widget? leading;
final Widget leading;
/// Override the framework from determining whether to show a leading widget or not.
///
@ -1155,10 +1157,10 @@ class _MasterDetailFlow extends StatefulWidget {
/// app bar or not.
///
/// See [AppBar.centerTitle].
final bool? centerTitle;
final bool centerTitle;
/// See [AppBar.flexibleSpace].
final Widget? flexibleSpace;
final Widget flexibleSpace;
/// Build actions for the lateral UI, and potentially the master page in the nested UI.
///
@ -1169,25 +1171,25 @@ class _MasterDetailFlow extends StatefulWidget {
/// by [_MasterDetailFlow], then [_ActionLevel.composite] indicates the
/// actions are for the
/// nested master page.
final _ActionBuilder? actionBuilder;
final _ActionBuilder actionBuilder;
/// Determine where the floating action button will go.
///
/// If null, [FloatingActionButtonLocation.endTop] is used.
///
/// Also see [Scaffold.floatingActionButtonLocation].
final FloatingActionButtonLocation? floatingActionButtonLocation;
final FloatingActionButtonLocation floatingActionButtonLocation;
/// Determine where the floating action button will go on the master page.
///
/// See [Scaffold.floatingActionButtonLocation].
final FloatingActionButtonLocation? floatingActionButtonMasterPageLocation;
final FloatingActionButtonLocation floatingActionButtonMasterPageLocation;
/// Forces display mode and style.
final _LayoutMode displayMode;
/// Width at which layout changes from nested to lateral.
final double? breakpoint;
final double breakpoint;
@override
_MasterDetailFlowState createState() => _MasterDetailFlowState();
@ -1200,11 +1202,11 @@ class _MasterDetailFlow extends StatefulWidget {
/// ```dart
/// _MasterDetailFlow.of(context).openDetailPage(arguments);
/// ```
static _MasterDetailFlowProxy? of(
static _MasterDetailFlowProxy of(
BuildContext context, {
bool nullOk = false,
}) {
_PageOpener? pageOpener = context.findAncestorStateOfType<_MasterDetailScaffoldState>();
_PageOpener pageOpener = context.findAncestorStateOfType<_MasterDetailScaffoldState>();
pageOpener ??= context.findAncestorStateOfType<_MasterDetailFlowState>();
assert(() {
if (pageOpener == null && !nullOk) {
@ -1251,10 +1253,10 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
_Focus focus = _Focus.master;
/// Cache of arguments passed when opening a detail page. Used when rebuilding.
Object? _cachedDetailArguments;
Object _cachedDetailArguments;
/// Record of the layout that was built.
_LayoutMode? _builtLayout;
_LayoutMode _builtLayout;
/// Key to access navigator in the nested layout.
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
@ -1263,7 +1265,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
void openDetailPage(Object arguments) {
_cachedDetailArguments = arguments;
if (_builtLayout == _LayoutMode.nested) {
_navigatorKey.currentState!.pushNamed(_navDetail, arguments: arguments);
_navigatorKey.currentState.pushNamed(_navDetail, arguments: arguments);
} else {
focus = _Focus.detail;
}
@ -1301,7 +1303,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
return WillPopScope(
// Push pop check into nested navigator.
onWillPop: () async => !(await _navigatorKey.currentState!.maybePop()),
onWillPop: () async => !(await _navigatorKey.currentState.maybePop()),
child: Navigator(
key: _navigatorKey,
initialRoute: 'initial',
@ -1341,11 +1343,11 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
return MaterialPageRoute<dynamic>(
builder: (BuildContext c) => BlockSemantics(
child: widget.masterPageBuilder != null
? widget.masterPageBuilder!(c, false)
? widget.masterPageBuilder(c, false)
: _MasterPage(
leading: widget.leading ??
(widget.automaticallyImplyLeading && Navigator.of(context)!.canPop()
? BackButton(onPressed: () => Navigator.of(context)!.pop())
(widget.automaticallyImplyLeading && Navigator.of(context).canPop()
? BackButton(onPressed: () => Navigator.of(context).pop())
: null),
title: widget.title,
centerTitle: widget.centerTitle,
@ -1360,13 +1362,13 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
);
}
MaterialPageRoute<void> _detailPageRoute(Object? arguments) {
MaterialPageRoute<void> _detailPageRoute(Object arguments) {
return MaterialPageRoute<dynamic>(builder: (BuildContext context) {
return WillPopScope(
onWillPop: () async {
// No need for setState() as rebuild happens on navigation pop.
focus = _Focus.master;
Navigator.of(context)!.pop();
Navigator.of(context).pop();
return false;
},
child: BlockSemantics(child: widget.detailPageBuilder(context, arguments, null)),
@ -1380,7 +1382,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
actionBuilder: widget.actionBuilder ?? (_, __) => const<Widget>[],
automaticallyImplyLeading: widget.automaticallyImplyLeading,
centerTitle: widget.centerTitle,
detailPageBuilder: (BuildContext context, Object? args, ScrollController? scrollController) =>
detailPageBuilder: (BuildContext context, Object args, ScrollController scrollController) =>
widget.detailPageBuilder(context, args ?? _cachedDetailArguments, scrollController),
floatingActionButton: widget.floatingActionButton,
detailPageFABlessGutterWidth: widget.detailPageFABlessGutterWidth,
@ -1397,7 +1399,7 @@ class _MasterDetailFlowState extends State<_MasterDetailFlow> implements _PageOp
class _MasterPage extends StatelessWidget {
const _MasterPage({
Key? key,
Key key,
this.leading,
this.title,
this.actionBuilder,
@ -1406,18 +1408,18 @@ class _MasterPage extends StatelessWidget {
this.floatingActionButton,
this.floatingActionButtonLocation,
this.masterViewBuilder,
required this.automaticallyImplyLeading,
this.automaticallyImplyLeading,
}) : super(key: key);
final _MasterViewBuilder? masterViewBuilder;
final Widget? title;
final Widget? leading;
final _MasterViewBuilder masterViewBuilder;
final Widget title;
final Widget leading;
final bool automaticallyImplyLeading;
final bool? centerTitle;
final Widget? flexibleSpace;
final _ActionBuilder? actionBuilder;
final FloatingActionButton? floatingActionButton;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final bool centerTitle;
final Widget flexibleSpace;
final _ActionBuilder actionBuilder;
final FloatingActionButton floatingActionButton;
final FloatingActionButtonLocation floatingActionButtonLocation;
@override
Widget build(BuildContext context) {
@ -1427,12 +1429,12 @@ class _MasterPage extends StatelessWidget {
leading: leading,
actions: actionBuilder == null
? const <Widget>[]
: actionBuilder!(context, _ActionLevel.composite),
: actionBuilder(context, _ActionLevel.composite),
centerTitle: centerTitle,
flexibleSpace: flexibleSpace,
automaticallyImplyLeading: automaticallyImplyLeading,
),
body: masterViewBuilder!(context, false),
body: masterViewBuilder(context, false),
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: floatingActionButtonLocation,
);
@ -1447,16 +1449,16 @@ const double _kDetailPageFABGutterWidth = 84.0;
class _MasterDetailScaffold extends StatefulWidget {
const _MasterDetailScaffold({
Key? key,
required this.detailPageBuilder,
required this.masterViewBuilder,
Key key,
@required this.detailPageBuilder,
@required this.masterViewBuilder,
this.actionBuilder,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.initialArguments,
this.leading,
this.title,
required this.automaticallyImplyLeading,
this.automaticallyImplyLeading,
this.centerTitle,
this.detailPageFABlessGutterWidth,
this.detailPageFABGutterWidth,
@ -1473,17 +1475,17 @@ class _MasterDetailScaffold extends StatefulWidget {
/// that uses the [ScrollController] provided. In fact, it is strongly recommended the entire
/// lateral page is scrollable.
final _DetailPageBuilder detailPageBuilder;
final _ActionBuilder? actionBuilder;
final FloatingActionButton? floatingActionButton;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final Object? initialArguments;
final Widget? leading;
final Widget? title;
final _ActionBuilder actionBuilder;
final FloatingActionButton floatingActionButton;
final FloatingActionButtonLocation floatingActionButtonLocation;
final Object initialArguments;
final Widget leading;
final Widget title;
final bool automaticallyImplyLeading;
final bool? centerTitle;
final double? detailPageFABlessGutterWidth;
final double? detailPageFABGutterWidth;
final double? masterViewWidth;
final bool centerTitle;
final double detailPageFABlessGutterWidth;
final double detailPageFABGutterWidth;
final double masterViewWidth;
@override
_MasterDetailScaffoldState createState() => _MasterDetailScaffoldState();
@ -1491,12 +1493,12 @@ class _MasterDetailScaffold extends StatefulWidget {
class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
implements _PageOpener {
late FloatingActionButtonLocation floatingActionButtonLocation;
late double detailPageFABGutterWidth;
late double detailPageFABlessGutterWidth;
late double masterViewWidth;
FloatingActionButtonLocation floatingActionButtonLocation;
double detailPageFABGutterWidth;
double detailPageFABlessGutterWidth;
double masterViewWidth;
final ValueNotifier<Object?> _detailArguments = ValueNotifier<Object?>(null);
final ValueNotifier<Object> _detailArguments = ValueNotifier<Object>(null);
@override
void initState() {
@ -1509,16 +1511,16 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
@override
void openDetailPage(Object arguments) {
SchedulerBinding.instance!
SchedulerBinding.instance
.addPostFrameCallback((_) => _detailArguments.value = arguments);
_MasterDetailFlow.of(context)!.openDetailPage(arguments);
_MasterDetailFlow.of(context).openDetailPage(arguments);
}
@override
void setInitialDetailPage(Object arguments) {
SchedulerBinding.instance!
SchedulerBinding.instance
.addPostFrameCallback((_) => _detailArguments.value = arguments);
_MasterDetailFlow.of(context)!.setInitialDetailPage(arguments);
_MasterDetailFlow.of(context).setInitialDetailPage(arguments);
}
@override
@ -1529,7 +1531,7 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
floatingActionButtonLocation: floatingActionButtonLocation,
appBar: AppBar(
title: widget.title,
actions: widget.actionBuilder!(context, _ActionLevel.top),
actions: widget.actionBuilder(context, _ActionLevel.top),
leading: widget.leading,
automaticallyImplyLeading: widget.automaticallyImplyLeading,
centerTitle: widget.centerTitle,
@ -1542,10 +1544,10 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
constraints:
BoxConstraints.tightFor(width: masterViewWidth),
child: IconTheme(
data: Theme.of(context)!.primaryIconTheme,
data: Theme.of(context).primaryIconTheme,
child: ButtonBar(
children:
widget.actionBuilder!(context, _ActionLevel.view),
widget.actionBuilder(context, _ActionLevel.view),
),
),
)
@ -1565,9 +1567,9 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
? detailPageFABlessGutterWidth
: detailPageFABGutterWidth,
),
child: ValueListenableBuilder<Object?>(
child: ValueListenableBuilder<Object>(
valueListenable: _detailArguments,
builder: (BuildContext context, Object? value, Widget? child) {
builder: (BuildContext context, Object value, Widget child) {
return AnimatedSwitcher(
transitionBuilder:
(Widget child, Animation<double> animation) =>
@ -1576,7 +1578,7 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
null, null, animation, null, child),
duration: const Duration(milliseconds: 500),
child: Container(
key: ValueKey<Object?>(value ?? widget.initialArguments),
key: ValueKey<Object>(value ?? widget.initialArguments),
constraints: const BoxConstraints.expand(),
child: _DetailView(
builder: widget.detailPageBuilder,
@ -1599,7 +1601,7 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
? Scaffold(
appBar: AppBar(
title: widget.title,
actions: widget.actionBuilder!(context, _ActionLevel.top),
actions: widget.actionBuilder(context, _ActionLevel.top),
leading: widget.leading,
automaticallyImplyLeading: widget.automaticallyImplyLeading,
centerTitle: widget.centerTitle,
@ -1613,23 +1615,23 @@ class _MasterDetailScaffoldState extends State<_MasterDetailScaffold>
class _DetailView extends StatelessWidget {
const _DetailView({
Key? key,
required _DetailPageBuilder builder,
Object? arguments,
Key key,
@required _DetailPageBuilder builder,
Object arguments,
}) : assert(builder != null),
_builder = builder,
_arguments = arguments,
super(key: key);
final _DetailPageBuilder _builder;
final Object? _arguments;
final Object _arguments;
@override
Widget build(BuildContext context) {
if (_arguments == null) {
return Container();
}
final double screenHeight = MediaQuery.of(context)!.size.height;
final double screenHeight = MediaQuery.of(context).size.height;
final double minHeight = (screenHeight - kToolbarHeight) / screenHeight;
return DraggableScrollableSheet(
@ -1641,7 +1643,7 @@ class _DetailView extends StatelessWidget {
return MouseRegion(
// TODO(TonicArtos): Remove MouseRegion workaround for pointer hover events passing through DraggableScrollableSheet once https://github.com/flutter/flutter/issues/59741 is resolved.
child: Card(
color: Theme.of(context)!.cardColor,
color: Theme.of(context).cardColor,
elevation: _kCardElevation,
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.fromLTRB(

View file

@ -2,6 +2,8 @@
// 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;
import 'package:flutter/cupertino.dart';
@ -164,7 +166,7 @@ class MaterialApp extends StatefulWidget {
///
/// The boolean arguments, [routes], and [navigatorObservers], must not be null.
const MaterialApp({
Key? key,
Key key,
this.navigatorKey,
this.home,
this.routes = const <String, WidgetBuilder>{},
@ -213,10 +215,10 @@ class MaterialApp extends StatefulWidget {
/// Creates a [MaterialApp] that uses the [Router] instead of a [Navigator].
const MaterialApp.router({
Key? key,
Key key,
this.routeInformationProvider,
required this.routeInformationParser,
required this.routerDelegate,
@required this.routeInformationParser,
@required this.routerDelegate,
this.backButtonDispatcher,
this.builder,
this.title = '',
@ -261,10 +263,10 @@ class MaterialApp extends StatefulWidget {
super(key: key);
/// {@macro flutter.widgets.widgetsApp.navigatorKey}
final GlobalKey<NavigatorState>? navigatorKey;
final GlobalKey<NavigatorState> navigatorKey;
/// {@macro flutter.widgets.widgetsApp.home}
final Widget? home;
final Widget home;
/// The application's top-level routing table.
///
@ -274,41 +276,41 @@ class MaterialApp extends StatefulWidget {
/// an appropriate transition, including [Hero] animations, to the new route.
///
/// {@macro flutter.widgets.widgetsApp.routes}
final Map<String, WidgetBuilder>? routes;
final Map<String, WidgetBuilder> routes;
/// {@macro flutter.widgets.widgetsApp.initialRoute}
final String? initialRoute;
final String initialRoute;
/// {@macro flutter.widgets.widgetsApp.onGenerateRoute}
final RouteFactory? onGenerateRoute;
final RouteFactory onGenerateRoute;
/// {@macro flutter.widgets.widgetsApp.onGenerateInitialRoutes}
final InitialRouteListFactory? onGenerateInitialRoutes;
final InitialRouteListFactory onGenerateInitialRoutes;
/// {@macro flutter.widgets.widgetsApp.onUnknownRoute}
final RouteFactory? onUnknownRoute;
final RouteFactory onUnknownRoute;
/// {@macro flutter.widgets.widgetsApp.navigatorObservers}
final List<NavigatorObserver>? navigatorObservers;
final List<NavigatorObserver> navigatorObservers;
/// {@macro flutter.widgets.widgetsApp.routeInformationProvider}
final RouteInformationProvider? routeInformationProvider;
final RouteInformationProvider routeInformationProvider;
/// {@macro flutter.widgets.widgetsApp.routeInformationParser}
final RouteInformationParser<Object>? routeInformationParser;
final RouteInformationParser<Object> routeInformationParser;
/// {@macro flutter.widgets.widgetsApp.routerDelegate}
final RouterDelegate<Object>? routerDelegate;
final RouterDelegate<Object> routerDelegate;
/// {@macro flutter.widgets.widgetsApp.backButtonDispatcher}
final BackButtonDispatcher? backButtonDispatcher;
final BackButtonDispatcher backButtonDispatcher;
/// {@macro flutter.widgets.widgetsApp.builder}
///
/// Material specific features such as [showDialog] and [showMenu], and widgets
/// such as [Tooltip], [PopupMenuButton], also require a [Navigator] to properly
/// function.
final TransitionBuilder? builder;
final TransitionBuilder builder;
/// {@macro flutter.widgets.widgetsApp.title}
///
@ -318,7 +320,7 @@ class MaterialApp extends StatefulWidget {
/// {@macro flutter.widgets.widgetsApp.onGenerateTitle}
///
/// This value is passed unmodified to [WidgetsApp.onGenerateTitle].
final GenerateAppTitle? onGenerateTitle;
final GenerateAppTitle onGenerateTitle;
/// Default visual properties, like colors fonts and shapes, for this app's
/// material widgets.
@ -337,7 +339,7 @@ class MaterialApp extends StatefulWidget {
/// and [darkTheme] in [MaterialApp].
/// * [ThemeData.brightness], which indicates the [Brightness] of a theme's
/// colors.
final ThemeData? theme;
final ThemeData theme;
/// The [ThemeData] to use when a 'dark mode' is requested by the system.
///
@ -359,7 +361,7 @@ class MaterialApp extends StatefulWidget {
/// and [darkTheme] in [MaterialApp].
/// * [ThemeData.brightness], which is typically set to the value of
/// [MediaQueryData.platformBrightness].
final ThemeData? darkTheme;
final ThemeData darkTheme;
/// The [ThemeData] to use when 'high contrast' is requested by the system.
///
@ -372,7 +374,7 @@ class MaterialApp extends StatefulWidget {
///
/// * [MediaQueryData.highContrast], which indicates the platform's
/// desire to increase contrast.
final ThemeData? highContrastTheme;
final ThemeData highContrastTheme;
/// The [ThemeData] to use when a 'dark mode' and 'high contrast' is requested
/// by the system.
@ -388,7 +390,7 @@ class MaterialApp extends StatefulWidget {
///
/// * [MediaQueryData.highContrast], which indicates the platform's
/// desire to increase contrast.
final ThemeData? highContrastDarkTheme;
final ThemeData highContrastDarkTheme;
/// Determines which theme will be used by the application if both [theme]
/// and [darkTheme] are provided.
@ -414,13 +416,13 @@ class MaterialApp extends StatefulWidget {
/// * [darkTheme], which is used when a dark mode is selected.
/// * [ThemeData.brightness], which indicates to various parts of the
/// system what kind of theme is being used.
final ThemeMode? themeMode;
final ThemeMode themeMode;
/// {@macro flutter.widgets.widgetsApp.color}
final Color? color;
final Color color;
/// {@macro flutter.widgets.widgetsApp.locale}
final Locale? locale;
final Locale locale;
/// {@macro flutter.widgets.widgetsApp.localizationsDelegates}
///
@ -513,17 +515,17 @@ class MaterialApp extends StatefulWidget {
/// which provides material localizations for many languages.
/// * The Flutter Internationalization Tutorial,
/// <https://flutter.dev/tutorials/internationalization/>.
final Iterable<LocalizationsDelegate<dynamic>>? localizationsDelegates;
final Iterable<LocalizationsDelegate<dynamic>> localizationsDelegates;
/// {@macro flutter.widgets.widgetsApp.localeListResolutionCallback}
///
/// This callback is passed along to the [WidgetsApp] built by this widget.
final LocaleListResolutionCallback? localeListResolutionCallback;
final LocaleListResolutionCallback localeListResolutionCallback;
/// {@macro flutter.widgets.widgetsApp.localeResolutionCallback}
///
/// This callback is passed along to the [WidgetsApp] built by this widget.
final LocaleResolutionCallback? localeResolutionCallback;
final LocaleResolutionCallback localeResolutionCallback;
/// {@macro flutter.widgets.widgetsApp.supportedLocales}
///
@ -585,7 +587,7 @@ class MaterialApp extends StatefulWidget {
/// ```
/// {@end-tool}
/// {@macro flutter.widgets.widgetsApp.shortcuts.seeAlso}
final Map<LogicalKeySet, Intent>? shortcuts;
final Map<LogicalKeySet, Intent> shortcuts;
/// {@macro flutter.widgets.widgetsApp.actions}
/// {@tool snippet}
@ -618,10 +620,10 @@ class MaterialApp extends StatefulWidget {
/// ```
/// {@end-tool}
/// {@macro flutter.widgets.widgetsApp.actions.seeAlso}
final Map<Type, Action<Intent>>? actions;
final Map<Type, Action<Intent>> actions;
/// {@macro flutter.widgets.widgetsApp.restorationScopeId}
final String? restorationScopeId;
final String restorationScopeId;
/// Turns on a [GridPaper] overlay that paints a baseline grid
/// Material apps.
@ -641,7 +643,7 @@ class MaterialApp extends StatefulWidget {
/// Used by the [MaterialApp].
static HeroController createMaterialHeroController() {
return HeroController(
createRectTween: (Rect? begin, Rect? end) {
createRectTween: (Rect begin, Rect end) {
return MaterialRectArcTween(begin: begin, end: end);
},
);
@ -651,7 +653,7 @@ class MaterialApp extends StatefulWidget {
class _MaterialScrollBehavior extends ScrollBehavior {
@override
TargetPlatform getPlatform(BuildContext context) {
return Theme.of(context)!.platform;
return Theme.of(context).platform;
}
@override
@ -669,14 +671,15 @@ class _MaterialScrollBehavior extends ScrollBehavior {
return GlowingOverscrollIndicator(
child: child,
axisDirection: axisDirection,
color: Theme.of(context)!.accentColor,
color: Theme.of(context).accentColor,
);
}
return null;
}
}
class _MaterialAppState extends State<MaterialApp> {
late HeroController _heroController;
HeroController _heroController;
bool get _usesRouter => widget.routerDelegate != null;
@ -693,7 +696,7 @@ class _MaterialAppState extends State<MaterialApp> {
// _MaterialLocalizationsDelegate.
Iterable<LocalizationsDelegate<dynamic>> get _localizationsDelegates sync* {
if (widget.localizationsDelegates != null)
yield* widget.localizationsDelegates!;
yield* widget.localizationsDelegates;
yield DefaultMaterialLocalizations.delegate;
yield DefaultCupertinoLocalizations.delegate;
}
@ -706,14 +709,14 @@ class _MaterialAppState extends State<MaterialApp> {
);
}
Widget _materialBuilder(BuildContext context, Widget? child) {
Widget _materialBuilder(BuildContext context, Widget child) {
// Resolve which theme to use based on brightness and high contrast.
final ThemeMode mode = widget.themeMode ?? ThemeMode.system;
final Brightness platformBrightness = MediaQuery.platformBrightnessOf(context);
final bool useDarkTheme = mode == ThemeMode.dark
|| (mode == ThemeMode.system && platformBrightness == ui.Brightness.dark);
final bool highContrast = MediaQuery.highContrastOf(context);
ThemeData? theme;
ThemeData theme;
if (useDarkTheme && highContrast && widget.highContrastDarkTheme != null) {
theme = widget.highContrastDarkTheme;
@ -741,10 +744,10 @@ class _MaterialAppState extends State<MaterialApp> {
// surround widget.builder with yet another builder so that
// a context separates them and Theme.of() correctly
// resolves to the theme we passed to AnimatedTheme.
return widget.builder!(context, child);
return widget.builder(context, child);
},
)
: child!,
: child,
);
}
@ -761,8 +764,8 @@ class _MaterialAppState extends State<MaterialApp> {
return WidgetsApp.router(
key: GlobalObjectKey(this),
routeInformationProvider: widget.routeInformationProvider,
routeInformationParser: widget.routeInformationParser!,
routerDelegate: widget.routerDelegate!,
routeInformationParser: widget.routeInformationParser,
routerDelegate: widget.routerDelegate,
backButtonDispatcher: widget.backButtonDispatcher,
builder: _materialBuilder,
title: widget.title,
@ -789,12 +792,12 @@ class _MaterialAppState extends State<MaterialApp> {
return WidgetsApp(
key: GlobalObjectKey(this),
navigatorKey: widget.navigatorKey,
navigatorObservers: widget.navigatorObservers!,
navigatorObservers: widget.navigatorObservers,
pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) {
return MaterialPageRoute<T>(settings: settings, builder: builder);
},
home: widget.home,
routes: widget.routes!,
routes: widget.routes,
initialRoute: widget.initialRoute,
onGenerateRoute: widget.onGenerateRoute,
onGenerateInitialRoutes: widget.onGenerateInitialRoutes,

View file

@ -2,6 +2,8 @@
// 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';
@ -190,7 +192,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
///
/// Typically used in the [Scaffold.appBar] property.
AppBar({
Key? key,
Key key,
this.leading,
this.automaticallyImplyLeading = true,
this.title,
@ -219,7 +221,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
assert(titleSpacing != null),
assert(toolbarOpacity != null),
assert(bottomOpacity != null),
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize.height ?? 0.0)),
preferredSize = Size.fromHeight(toolbarHeight ?? kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
super(key: key);
/// A widget to display before the [title].
@ -267,7 +269,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
///
/// * [Scaffold.appBar], in which an [AppBar] is usually placed.
/// * [Scaffold.drawer], in which the [Drawer] is usually placed.
final Widget? leading;
final Widget leading;
/// Controls whether we should try to imply the leading widget if null.
///
@ -306,7 +308,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// ),
/// )
/// ```
final Widget? title;
final Widget title;
/// Widgets to display in a row after the [title] widget.
///
@ -317,7 +319,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// The [actions] become the trailing component of the [NavigationToolbar] built
/// by this widget. The height of each action is constrained to be no bigger
/// than the [toolbarHeight].
final List<Widget>? actions;
final List<Widget> actions;
/// This widget is stacked behind the toolbar and the tab bar. It's height will
/// be the same as the app bar's overall height.
@ -327,7 +329,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// changes the [AppBar]'s height when scrolled.
///
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
final Widget? flexibleSpace;
final Widget flexibleSpace;
/// This widget appears across the bottom of the app bar.
///
@ -337,7 +339,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// See also:
///
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
final PreferredSizeWidget? bottom;
final PreferredSizeWidget bottom;
/// The z-coordinate at which to place this app bar relative to its parent.
///
@ -348,20 +350,20 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.elevation] of
/// [ThemeData.appBarTheme] is used. If that is also null, the default value
/// is 4.
final double? elevation;
final double elevation;
/// The color to paint the shadow below the app bar.
///
/// If this property is null, then [AppBarTheme.shadowColor] of
/// [ThemeData.appBarTheme] is used. If that is also null, the default value
/// is fully opaque black.
final Color? shadowColor;
final Color shadowColor;
/// The material's shape as well its shadow.
///
/// A shadow is only displayed if the [elevation] is greater than
/// zero.
final ShapeBorder? shape;
final ShapeBorder shape;
/// The color to use for the app bar's material. Typically this should be set
/// along with [brightness], [iconTheme], [textTheme].
@ -369,7 +371,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.color] of
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryColor] is used.
final Color? backgroundColor;
final Color backgroundColor;
/// The brightness of the app bar's material. Typically this is set along
/// with [backgroundColor], [iconTheme], [textTheme].
@ -377,7 +379,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.brightness] of
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryColorBrightness] is used.
final Brightness? brightness;
final Brightness brightness;
/// The color, opacity, and size to use for app bar icons. Typically this
/// is set along with [backgroundColor], [brightness], [textTheme].
@ -385,7 +387,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.iconTheme] of
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryIconTheme] is used.
final IconThemeData? iconTheme;
final IconThemeData iconTheme;
/// The color, opacity, and size to use for the icons that appear in the app
/// bar's [actions]. This should only be used when the [actions] should be
@ -395,7 +397,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.actionsIconTheme] of
/// [ThemeData.appBarTheme] is used. If that is also null, then this falls
/// back to [iconTheme].
final IconThemeData? actionsIconTheme;
final IconThemeData actionsIconTheme;
/// The typographic styles to use for text in the app bar. Typically this is
/// set along with [brightness] [backgroundColor], [iconTheme].
@ -403,7 +405,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.textTheme] of
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryTextTheme] is used.
final TextTheme? textTheme;
final TextTheme textTheme;
/// Whether this app bar is being displayed at the top of the screen.
///
@ -417,7 +419,7 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// If this property is null, then [AppBarTheme.centerTitle] of
/// [ThemeData.appBarTheme] is used. If that is also null, then value is
/// adapted to the current [TargetPlatform].
final bool? centerTitle;
final bool centerTitle;
/// Whether the title should be wrapped with header [Semantics].
///
@ -459,18 +461,18 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
/// Defines the height of the toolbar component of an [AppBar].
///
/// By default, the value of `toolbarHeight` is [kToolbarHeight].
final double? toolbarHeight;
final double toolbarHeight;
/// Defines the width of [leading] widget.
///
/// By default, the value of `leadingWidth` is 56.0.
final double? leadingWidth;
final double leadingWidth;
bool _getEffectiveCenterTitle(ThemeData theme) {
if (centerTitle != null)
return centerTitle!;
return centerTitle;
if (theme.appBarTheme.centerTitle != null)
return theme.appBarTheme.centerTitle!;
return theme.appBarTheme.centerTitle;
assert(theme.platform != null);
switch (theme.platform) {
case TargetPlatform.android:
@ -480,8 +482,9 @@ class AppBar extends StatefulWidget implements PreferredSizeWidget {
return false;
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return actions == null || actions!.length < 2;
return actions == null || actions.length < 2;
}
return null;
}
@override
@ -493,21 +496,21 @@ class _AppBarState extends State<AppBar> {
static const Color _defaultShadowColor = Color(0xFF000000);
void _handleDrawerButton() {
Scaffold.of(context)!.openDrawer();
Scaffold.of(context).openDrawer();
}
void _handleDrawerButtonEnd() {
Scaffold.of(context)!.openEndDrawer();
Scaffold.of(context).openEndDrawer();
}
@override
Widget build(BuildContext context) {
assert(!widget.primary || debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
final ThemeData? theme = Theme.of(context);
final ThemeData theme = Theme.of(context);
final AppBarTheme appBarTheme = AppBarTheme.of(context);
final ScaffoldState? scaffold = Scaffold.of(context, nullOk: true);
final ModalRoute<dynamic>? parentRoute = ModalRoute.of(context);
final ScaffoldState scaffold = Scaffold.of(context, nullOk: true);
final ModalRoute<dynamic> parentRoute = ModalRoute.of(context);
final bool hasDrawer = scaffold?.hasDrawer ?? false;
final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false;
@ -518,23 +521,23 @@ class _AppBarState extends State<AppBar> {
IconThemeData overallIconTheme = widget.iconTheme
?? appBarTheme.iconTheme
?? theme!.primaryIconTheme;
?? theme.primaryIconTheme;
IconThemeData actionsIconTheme = widget.actionsIconTheme
?? appBarTheme.actionsIconTheme
?? overallIconTheme;
TextStyle? centerStyle = widget.textTheme?.headline6
TextStyle centerStyle = widget.textTheme?.headline6
?? appBarTheme.textTheme?.headline6
?? theme!.primaryTextTheme.headline6;
TextStyle? sideStyle = widget.textTheme?.bodyText2
?? theme.primaryTextTheme.headline6;
TextStyle sideStyle = widget.textTheme?.bodyText2
?? appBarTheme.textTheme?.bodyText2
?? theme!.primaryTextTheme.bodyText2;
?? theme.primaryTextTheme.bodyText2;
if (widget.toolbarOpacity != 1.0) {
final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity);
if (centerStyle?.color != null)
centerStyle = centerStyle!.copyWith(color: centerStyle.color!.withOpacity(opacity));
centerStyle = centerStyle.copyWith(color: centerStyle.color.withOpacity(opacity));
if (sideStyle?.color != null)
sideStyle = sideStyle!.copyWith(color: sideStyle.color!.withOpacity(opacity));
sideStyle = sideStyle.copyWith(color: sideStyle.color.withOpacity(opacity));
overallIconTheme = overallIconTheme.copyWith(
opacity: opacity * (overallIconTheme.opacity ?? 1.0)
);
@ -543,13 +546,13 @@ class _AppBarState extends State<AppBar> {
);
}
Widget? leading = widget.leading;
Widget leading = widget.leading;
if (leading == null && widget.automaticallyImplyLeading) {
if (hasDrawer) {
leading = IconButton(
icon: const Icon(Icons.menu),
onPressed: _handleDrawerButton,
tooltip: MaterialLocalizations.of(context)!.openAppDrawerTooltip,
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
);
} else {
if (!hasEndDrawer && canPop)
@ -563,10 +566,10 @@ class _AppBarState extends State<AppBar> {
);
}
Widget? title = widget.title;
Widget title = widget.title;
if (title != null) {
bool? namesRoute;
switch (theme!.platform) {
bool namesRoute;
switch (theme.platform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
@ -599,7 +602,7 @@ class _AppBarState extends State<AppBar> {
// sizes. To opt out, wrap the [title] widget in a [MediaQuery] widget
// with [MediaQueryData.textScaleFactor] set to
// `MediaQuery.textScaleFactorOf(context)`.
final MediaQueryData mediaQueryData = MediaQuery.of(context)!;
final MediaQueryData mediaQueryData = MediaQuery.of(context);
title = MediaQuery(
data: mediaQueryData.copyWith(
textScaleFactor: math.min(
@ -611,18 +614,18 @@ class _AppBarState extends State<AppBar> {
);
}
Widget? actions;
if (widget.actions != null && widget.actions!.isNotEmpty) {
Widget actions;
if (widget.actions != null && widget.actions.isNotEmpty) {
actions = Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: widget.actions!,
children: widget.actions,
);
} else if (hasEndDrawer) {
actions = IconButton(
icon: const Icon(Icons.menu),
onPressed: _handleDrawerButtonEnd,
tooltip: MaterialLocalizations.of(context)!.openAppDrawerTooltip,
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
);
}
@ -638,7 +641,7 @@ class _AppBarState extends State<AppBar> {
leading: leading,
middle: title,
trailing: actions,
centerMiddle: widget._getEffectiveCenterTitle(theme!),
centerMiddle: widget._getEffectiveCenterTitle(theme),
middleSpacing: widget.titleSpacing,
);
@ -667,7 +670,7 @@ class _AppBarState extends State<AppBar> {
),
),
if (widget.bottomOpacity == 1.0)
widget.bottom!
widget.bottom
else
Opacity(
opacity: const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.bottomOpacity),
@ -746,7 +749,7 @@ class _AppBarState extends State<AppBar> {
}
class _FloatingAppBar extends StatefulWidget {
const _FloatingAppBar({ Key? key, required this.child }) : super(key: key);
const _FloatingAppBar({ Key key, this.child }) : super(key: key);
final Widget child;
@ -757,26 +760,26 @@ class _FloatingAppBar extends StatefulWidget {
// A wrapper for the widget created by _SliverAppBarDelegate that starts and
// stops the floating app bar's snap-into-view or snap-out-of-view animation.
class _FloatingAppBarState extends State<_FloatingAppBar> {
ScrollPosition? _position;
ScrollPosition _position;
@override
void didChangeDependencies() {
super.didChangeDependencies();
if (_position != null)
_position!.isScrollingNotifier.removeListener(_isScrollingListener);
_position.isScrollingNotifier.removeListener(_isScrollingListener);
_position = Scrollable.of(context)?.position;
if (_position != null)
_position!.isScrollingNotifier.addListener(_isScrollingListener);
_position.isScrollingNotifier.addListener(_isScrollingListener);
}
@override
void dispose() {
if (_position != null)
_position!.isScrollingNotifier.removeListener(_isScrollingListener);
_position.isScrollingNotifier.removeListener(_isScrollingListener);
super.dispose();
}
RenderSliverFloatingPersistentHeader? _headerRenderer() {
RenderSliverFloatingPersistentHeader _headerRenderer() {
return context.findAncestorRenderObjectOfType<RenderSliverFloatingPersistentHeader>();
}
@ -786,11 +789,11 @@ class _FloatingAppBarState extends State<_FloatingAppBar> {
// When a scroll stops, then maybe snap the appbar into view.
// Similarly, when a scroll starts, then maybe stop the snap animation.
final RenderSliverFloatingPersistentHeader? header = _headerRenderer();
if (_position!.isScrollingNotifier.value)
header?.maybeStopSnapAnimation(_position!.userScrollDirection);
final RenderSliverFloatingPersistentHeader header = _headerRenderer();
if (_position.isScrollingNotifier.value)
header?.maybeStopSnapAnimation(_position.userScrollDirection);
else
header?.maybeStartSnapAnimation(_position!.userScrollDirection);
header?.maybeStartSnapAnimation(_position.userScrollDirection);
}
@override
@ -799,69 +802,69 @@ class _FloatingAppBarState extends State<_FloatingAppBar> {
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
required this.leading,
required this.automaticallyImplyLeading,
required this.title,
required this.actions,
required this.flexibleSpace,
required this.bottom,
required this.elevation,
required this.shadowColor,
required this.forceElevated,
required this.backgroundColor,
required this.brightness,
required this.iconTheme,
required this.actionsIconTheme,
required this.textTheme,
required this.primary,
required this.centerTitle,
required this.excludeHeaderSemantics,
required this.titleSpacing,
required this.expandedHeight,
required this.collapsedHeight,
required this.topPadding,
required this.floating,
required this.pinned,
required this.vsync,
required this.snapConfiguration,
required this.stretchConfiguration,
required this.showOnScreenConfiguration,
required this.shape,
required this.toolbarHeight,
required this.leadingWidth,
@required this.leading,
@required this.automaticallyImplyLeading,
@required this.title,
@required this.actions,
@required this.flexibleSpace,
@required this.bottom,
@required this.elevation,
@required this.shadowColor,
@required this.forceElevated,
@required this.backgroundColor,
@required this.brightness,
@required this.iconTheme,
@required this.actionsIconTheme,
@required this.textTheme,
@required this.primary,
@required this.centerTitle,
@required this.excludeHeaderSemantics,
@required this.titleSpacing,
@required this.expandedHeight,
@required this.collapsedHeight,
@required this.topPadding,
@required this.floating,
@required this.pinned,
@required this.vsync,
@required this.snapConfiguration,
@required this.stretchConfiguration,
@required this.showOnScreenConfiguration,
@required this.shape,
@required this.toolbarHeight,
@required this.leadingWidth,
}) : assert(primary || topPadding == 0.0),
assert(
!floating || (snapConfiguration == null && showOnScreenConfiguration == null) || vsync != null,
'vsync cannot be null when snapConfiguration or showOnScreenConfiguration is not null, and floating is true',
),
_bottomHeight = bottom?.preferredSize.height ?? 0.0;
_bottomHeight = bottom?.preferredSize?.height ?? 0.0;
final Widget? leading;
final Widget leading;
final bool automaticallyImplyLeading;
final Widget? title;
final List<Widget>? actions;
final Widget? flexibleSpace;
final PreferredSizeWidget? bottom;
final double? elevation;
final Color? shadowColor;
final Widget title;
final List<Widget> actions;
final Widget flexibleSpace;
final PreferredSizeWidget bottom;
final double elevation;
final Color shadowColor;
final bool forceElevated;
final Color? backgroundColor;
final Brightness? brightness;
final IconThemeData? iconTheme;
final IconThemeData? actionsIconTheme;
final TextTheme? textTheme;
final Color backgroundColor;
final Brightness brightness;
final IconThemeData iconTheme;
final IconThemeData actionsIconTheme;
final TextTheme textTheme;
final bool primary;
final bool? centerTitle;
final bool centerTitle;
final bool excludeHeaderSemantics;
final double titleSpacing;
final double? expandedHeight;
final double expandedHeight;
final double collapsedHeight;
final double topPadding;
final bool floating;
final bool pinned;
final ShapeBorder? shape;
final double? toolbarHeight;
final double? leadingWidth;
final ShapeBorder shape;
final double toolbarHeight;
final double leadingWidth;
final double _bottomHeight;
@ -875,13 +878,13 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final TickerProvider vsync;
@override
final FloatingHeaderSnapConfiguration? snapConfiguration;
final FloatingHeaderSnapConfiguration snapConfiguration;
@override
final OverScrollHeaderStretchConfiguration? stretchConfiguration;
final OverScrollHeaderStretchConfiguration stretchConfiguration;
@override
final PersistentHeaderShowOnScreenConfiguration? showOnScreenConfiguration;
final PersistentHeaderShowOnScreenConfiguration showOnScreenConfiguration;
@override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
@ -891,7 +894,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
final bool isPinnedWithOpacityFade = pinned && floating && bottom != null && extraToolbarHeight == 0.0;
final double toolbarOpacity = !pinned || isPinnedWithOpacityFade
? (visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight)).clamp(0.0, 1.0)
? (visibleToolbarHeight / (toolbarHeight ?? kToolbarHeight)).clamp(0.0, 1.0) as double
: 1.0;
final Widget appBar = FlexibleSpaceBar.createSettings(
@ -921,7 +924,7 @@ class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
titleSpacing: titleSpacing,
shape: shape,
toolbarOpacity: toolbarOpacity,
bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0)),
bottomOpacity: pinned ? 1.0 : ((visibleMainHeight / _bottomHeight).clamp(0.0, 1.0) as double),
toolbarHeight: toolbarHeight,
leadingWidth: leadingWidth,
),
@ -1051,7 +1054,7 @@ class SliverAppBar extends StatefulWidget {
/// The arguments [forceElevated], [primary], [floating], [pinned], [snap]
/// and [automaticallyImplyLeading] must not be null.
const SliverAppBar({
Key? key,
Key key,
this.leading,
this.automaticallyImplyLeading = true,
this.title,
@ -1103,7 +1106,7 @@ class SliverAppBar extends StatefulWidget {
/// [IconButton] that opens the drawer. If there's no [Drawer] and the parent
/// [Navigator] can go back, the [AppBar] will use a [BackButton] that calls
/// [Navigator.maybePop].
final Widget? leading;
final Widget leading;
/// Controls whether we should try to imply the leading widget if null.
///
@ -1116,7 +1119,7 @@ class SliverAppBar extends StatefulWidget {
///
/// Typically a [Text] widget containing a description of the current contents
/// of the app.
final Widget? title;
final Widget title;
/// Widgets to display after the [title] widget.
///
@ -1149,7 +1152,7 @@ class SliverAppBar extends StatefulWidget {
/// )
/// ```
/// {@end-tool}
final List<Widget>? actions;
final List<Widget> actions;
/// This widget is stacked behind the toolbar and the tab bar. It's height will
/// be the same as the app bar's overall height.
@ -1158,7 +1161,7 @@ class SliverAppBar extends StatefulWidget {
/// must be large enough to accommodate the [SliverAppBar.flexibleSpace] widget.
///
/// Typically a [FlexibleSpaceBar]. See [FlexibleSpaceBar] for details.
final Widget? flexibleSpace;
final Widget flexibleSpace;
/// This widget appears across the bottom of the app bar.
///
@ -1168,7 +1171,7 @@ class SliverAppBar extends StatefulWidget {
/// See also:
///
/// * [PreferredSize], which can be used to give an arbitrary widget a preferred size.
final PreferredSizeWidget? bottom;
final PreferredSizeWidget bottom;
/// The z-coordinate at which to place this app bar when it is above other
/// content. This controls the size of the shadow below the app bar.
@ -1181,7 +1184,7 @@ class SliverAppBar extends StatefulWidget {
/// no content underneath it. For example, if the app bar is [pinned] but no
/// content is scrolled under it, or if it scrolls with the content, then no
/// shadow is drawn, regardless of the value of [elevation].
final double? elevation;
final double elevation;
/// The color to paint the shadow below the app bar. Typically this should be set
/// along with [elevation].
@ -1189,7 +1192,7 @@ class SliverAppBar extends StatefulWidget {
/// If this property is null, then [AppBarTheme.shadowColor] of
/// [ThemeData.appBarTheme] is used, if that is also null, the default value
/// is fully opaque black.
final Color? shadowColor;
final Color shadowColor;
/// Whether to show the shadow appropriate for the [elevation] even if the
/// content is not scrolled under the [AppBar].
@ -1208,7 +1211,7 @@ class SliverAppBar extends StatefulWidget {
/// If this property is null, then [AppBarTheme.color] of
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryColor] is used.
final Color? backgroundColor;
final Color backgroundColor;
/// The brightness of the app bar's material. Typically this is set along
/// with [backgroundColor], [iconTheme], [textTheme].
@ -1216,7 +1219,7 @@ class SliverAppBar extends StatefulWidget {
/// If this property is null, then [AppBarTheme.brightness] of
/// [ThemeData.appBarTheme] is used. If that is also null, then
/// [ThemeData.primaryColorBrightness] is used.
final Brightness? brightness;
final Brightness brightness;
/// The color, opacity, and size to use for app bar icons. Typically this
/// is set along with [backgroundColor], [brightness], [textTheme].
@ -1224,7 +1227,7 @@ class SliverAppBar extends StatefulWidget {
/// If this property is null, then [AppBarTheme.iconTheme] of
/// [ThemeData.appBarTheme] is used, if that is also null, then
/// [ThemeData.primaryIconTheme] is used.
final IconThemeData? iconTheme;
final IconThemeData iconTheme;
/// The color, opacity, and size to use for trailing app bar icons. This
/// should only be used when the trailing icons should be themed differently
@ -1233,7 +1236,7 @@ class SliverAppBar extends StatefulWidget {
/// If this property is null, then [AppBarTheme.actionsIconTheme] of
/// [ThemeData.appBarTheme] is used, if that is also null, then this falls
/// back to [iconTheme].
final IconThemeData? actionsIconTheme;
final IconThemeData actionsIconTheme;
/// The typographic styles to use for text in the app bar. Typically this is
/// set along with [brightness] [backgroundColor], [iconTheme].
@ -1241,7 +1244,7 @@ class SliverAppBar extends StatefulWidget {
/// If this property is null, then [AppBarTheme.textTheme] of
/// [ThemeData.appBarTheme] is used, if that is also null, then
/// [ThemeData.primaryTextTheme] is used.
final TextTheme? textTheme;
final TextTheme textTheme;
/// Whether this app bar is being displayed at the top of the screen.
///
@ -1252,7 +1255,7 @@ class SliverAppBar extends StatefulWidget {
/// Whether the title should be centered.
///
/// Defaults to being adapted to the current [TargetPlatform].
final bool? centerTitle;
final bool centerTitle;
/// Whether the title should be wrapped with header [Semantics].
///
@ -1276,7 +1279,7 @@ class SliverAppBar extends StatefulWidget {
/// If [pinned] and [floating] are true, with [bottom] set, the default
/// collapsed height is only the height of [PreferredSizeWidget.preferredSize]
/// with the [MediaQuery] top padding.
final double? collapsedHeight;
final double collapsedHeight;
/// The size of the app bar when it is fully expanded.
///
@ -1286,7 +1289,7 @@ class SliverAppBar extends StatefulWidget {
///
/// This does not include the status bar height (which will be automatically
/// included if [primary] is true).
final double? expandedHeight;
final double expandedHeight;
/// Whether the app bar should become visible as soon as the user scrolls
/// towards the app bar.
@ -1338,7 +1341,7 @@ class SliverAppBar extends StatefulWidget {
/// The material's shape as well as its shadow.
///
/// A shadow is only displayed if the [elevation] is greater than zero.
final ShapeBorder? shape;
final ShapeBorder shape;
/// If [snap] and [floating] are true then the floating app bar will "snap"
/// into view.
@ -1385,7 +1388,7 @@ class SliverAppBar extends StatefulWidget {
/// The callback function to be executed when a user over-scrolls to the
/// offset specified by [stretchTriggerOffset].
final AsyncCallback? onStretchTrigger;
final AsyncCallback onStretchTrigger;
/// Defines the height of the toolbar component of an [AppBar].
///
@ -1395,7 +1398,7 @@ class SliverAppBar extends StatefulWidget {
/// Defines the width of [leading] widget.
///
/// By default, the value of `leadingWidth` is 56.0.
final double? leadingWidth;
final double leadingWidth;
@override
_SliverAppBarState createState() => _SliverAppBarState();
@ -1404,9 +1407,9 @@ class SliverAppBar extends StatefulWidget {
// This class is only Stateful because it owns the TickerProvider used
// by the floating appbar snap animation (via FloatingHeaderSnapConfiguration).
class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMixin {
FloatingHeaderSnapConfiguration? _snapConfiguration;
OverScrollHeaderStretchConfiguration? _stretchConfiguration;
PersistentHeaderShowOnScreenConfiguration? _showOnScreenConfiguration;
FloatingHeaderSnapConfiguration _snapConfiguration;
OverScrollHeaderStretchConfiguration _stretchConfiguration;
PersistentHeaderShowOnScreenConfiguration _showOnScreenConfiguration;
void _updateSnapConfiguration() {
if (widget.snap && widget.floating) {
@ -1453,8 +1456,8 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
@override
Widget build(BuildContext context) {
assert(!widget.primary || debugCheckHasMediaQuery(context));
final double bottomHeight = widget.bottom?.preferredSize.height ?? 0.0;
final double topPadding = widget.primary ? MediaQuery.of(context)!.padding.top : 0.0;
final double bottomHeight = widget.bottom?.preferredSize?.height ?? 0.0;
final double topPadding = widget.primary ? MediaQuery.of(context).padding.top : 0.0;
final double collapsedHeight = (widget.pinned && widget.floating && widget.bottom != null)
? (widget.collapsedHeight ?? 0.0) + bottomHeight + topPadding
: (widget.collapsedHeight ?? widget.toolbarHeight) + bottomHeight + topPadding;
@ -1506,7 +1509,7 @@ class _SliverAppBarState extends State<SliverAppBar> with TickerProviderStateMix
// center it within its (NavigationToolbar) parent, and allow the
// parent to constrain the title's actual height.
class _AppBarTitleBox extends SingleChildRenderObjectWidget {
const _AppBarTitleBox({ Key? key, required Widget child }) : assert(child != null), super(key: key, child: child);
const _AppBarTitleBox({ Key key, @required Widget child }) : assert(child != null), super(key: key, child: child);
@override
_RenderAppBarTitleBox createRenderObject(BuildContext context) {
@ -1523,15 +1526,16 @@ class _AppBarTitleBox extends SingleChildRenderObjectWidget {
class _RenderAppBarTitleBox extends RenderAligningShiftedBox {
_RenderAppBarTitleBox({
RenderBox? child,
TextDirection? textDirection,
RenderBox child,
TextDirection textDirection,
}) : super(child: child, alignment: Alignment.center, textDirection: textDirection);
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
final BoxConstraints innerConstraints = constraints.copyWith(maxHeight: double.infinity);
child!.layout(innerConstraints, parentUsesSize: true);
size = constraints.constrain(child!.size);
child.layout(innerConstraints, parentUsesSize: true);
size = constraints.constrain(child.size);
alignChild();
}
}

View file

@ -2,6 +2,8 @@
// 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' show lerpDouble;
import 'package:flutter/foundation.dart';
@ -44,54 +46,54 @@ class AppBarTheme with Diagnosticable {
/// Default value for [AppBar.brightness].
///
/// If null, [AppBar] uses [ThemeData.primaryColorBrightness].
final Brightness? brightness;
final Brightness brightness;
/// Default value for [AppBar.backgroundColor].
///
/// If null, [AppBar] uses [ThemeData.primaryColor].
final Color? color;
final Color color;
/// Default value for [AppBar.elevation].
///
/// If null, [AppBar] uses a default value of 4.0.
final double? elevation;
final double elevation;
/// Default value for [AppBar.shadowColor].
///
/// If null, [AppBar] uses a default value of fully opaque black.
final Color? shadowColor;
final Color shadowColor;
/// Default value for [AppBar.iconTheme].
///
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
final IconThemeData? iconTheme;
final IconThemeData iconTheme;
/// Default value for [AppBar.actionsIconTheme].
///
/// If null, [AppBar] uses [ThemeData.primaryIconTheme].
final IconThemeData? actionsIconTheme;
final IconThemeData actionsIconTheme;
/// Default value for [AppBar.textTheme].
///
/// If null, [AppBar] uses [ThemeData.primaryTextTheme].
final TextTheme? textTheme;
final TextTheme textTheme;
/// Default value for [AppBar.centerTitle].
///
/// If null, the value is adapted to current [TargetPlatform].
final bool? centerTitle;
final bool centerTitle;
/// Creates a copy of this object with the given fields replaced with the
/// new values.
AppBarTheme copyWith({
IconThemeData? actionsIconTheme,
Brightness? brightness,
Color? color,
double? elevation,
Color? shadowColor,
IconThemeData? iconTheme,
TextTheme? textTheme,
bool? centerTitle,
IconThemeData actionsIconTheme,
Brightness brightness,
Color color,
double elevation,
Color shadowColor,
IconThemeData iconTheme,
TextTheme textTheme,
bool centerTitle,
}) {
return AppBarTheme(
brightness: brightness ?? this.brightness,
@ -107,7 +109,7 @@ class AppBarTheme with Diagnosticable {
/// The [ThemeData.appBarTheme] property of the ambient [Theme].
static AppBarTheme of(BuildContext context) {
return Theme.of(context)!.appBarTheme;
return Theme.of(context).appBarTheme;
}
/// Linearly interpolate between two AppBar themes.
@ -115,7 +117,7 @@ class AppBarTheme with Diagnosticable {
/// The argument `t` must not be null.
///
/// {@macro dart.ui.shadow.lerp}
static AppBarTheme lerp(AppBarTheme? a, AppBarTheme? b, double t) {
static AppBarTheme lerp(AppBarTheme a, AppBarTheme b, double t) {
assert(t != null);
return AppBarTheme(
brightness: t < 0.5 ? a?.brightness : b?.brightness,

View file

@ -2,6 +2,8 @@
// 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 'debug.dart';
@ -25,7 +27,7 @@ import 'theme.dart';
class BackButtonIcon extends StatelessWidget {
/// Creates an icon that shows the appropriate "back" image for
/// the current platform (as obtained from the [Theme]).
const BackButtonIcon({ Key? key }) : super(key: key);
const BackButtonIcon({ Key key }) : super(key: key);
/// Returns the appropriate "back" icon for the given `platform`.
static IconData _getIconData(TargetPlatform platform) {
@ -39,10 +41,12 @@ class BackButtonIcon extends StatelessWidget {
case TargetPlatform.macOS:
return Icons.arrow_back_ios;
}
assert(false);
return null;
}
@override
Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context)!.platform));
Widget build(BuildContext context) => Icon(_getIconData(Theme.of(context).platform));
}
/// A material design back button.
@ -74,13 +78,13 @@ class BackButtonIcon extends StatelessWidget {
class BackButton extends StatelessWidget {
/// Creates an [IconButton] with the appropriate "back" icon for the current
/// target platform.
const BackButton({ Key? key, this.color, this.onPressed }) : super(key: key);
const BackButton({ Key key, this.color, this.onPressed }) : super(key: key);
/// The color to use for the icon.
///
/// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
/// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
final Color? color;
final Color color;
/// An override callback to perform instead of the default behavior which is
/// to pop the [Navigator].
@ -90,7 +94,7 @@ class BackButton extends StatelessWidget {
/// situations.
///
/// Defaults to null.
final VoidCallback? onPressed;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
@ -98,10 +102,10 @@ class BackButton extends StatelessWidget {
return IconButton(
icon: const BackButtonIcon(),
color: color,
tooltip: MaterialLocalizations.of(context)!.backButtonTooltip,
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
onPressed: () {
if (onPressed != null) {
onPressed!();
onPressed();
} else {
Navigator.maybePop(context);
}
@ -128,13 +132,13 @@ class BackButton extends StatelessWidget {
/// * [IconButton], to create other material design icon buttons.
class CloseButton extends StatelessWidget {
/// Creates a Material Design close button.
const CloseButton({ Key? key, this.color, this.onPressed }) : super(key: key);
const CloseButton({ Key key, this.color, this.onPressed }) : super(key: key);
/// The color to use for the icon.
///
/// Defaults to the [IconThemeData.color] specified in the ambient [IconTheme],
/// which usually matches the ambient [Theme]'s [ThemeData.iconTheme].
final Color? color;
final Color color;
/// An override callback to perform instead of the default behavior which is
/// to pop the [Navigator].
@ -144,7 +148,7 @@ class CloseButton extends StatelessWidget {
/// situations.
///
/// Defaults to null.
final VoidCallback? onPressed;
final VoidCallback onPressed;
@override
Widget build(BuildContext context) {
@ -152,10 +156,10 @@ class CloseButton extends StatelessWidget {
return IconButton(
icon: const Icon(Icons.close),
color: color,
tooltip: MaterialLocalizations.of(context)!.closeButtonTooltip,
tooltip: MaterialLocalizations.of(context).closeButtonTooltip,
onPressed: () {
if (onPressed != null) {
onPressed!();
onPressed();
} else {
Navigator.maybePop(context);
}

View file

@ -2,6 +2,8 @@
// 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 'banner_theme.dart';
@ -33,10 +35,10 @@ class MaterialBanner extends StatelessWidget {
/// The [actions], [content], and [forceActionsBelow] must be non-null.
/// The [actions.length] must be greater than 0.
const MaterialBanner({
Key? key,
required this.content,
Key key,
@required this.content,
this.contentTextStyle,
required this.actions,
@required this.actions,
this.leading,
this.backgroundColor,
this.padding,
@ -56,7 +58,7 @@ class MaterialBanner extends StatelessWidget {
///
/// If `null`, [MaterialBannerThemeData.contentTextStyle] is used. If that is
/// also `null`, [TextTheme.bodyText2] of [ThemeData.textTheme] is used.
final TextStyle? contentTextStyle;
final TextStyle contentTextStyle;
/// The set of actions that are displayed at the bottom or trailing side of
/// the [MaterialBanner].
@ -67,13 +69,13 @@ class MaterialBanner extends StatelessWidget {
/// The (optional) leading widget of the [MaterialBanner].
///
/// Typically an [Icon] widget.
final Widget? leading;
final Widget leading;
/// The color of the surface of this [MaterialBanner].
///
/// If `null`, [MaterialBannerThemeData.backgroundColor] is used. If that is
/// also `null`, [ColorScheme.surface] of [ThemeData.colorScheme] is used.
final Color? backgroundColor;
final Color backgroundColor;
/// The amount of space by which to inset the [content].
///
@ -82,12 +84,12 @@ class MaterialBanner extends StatelessWidget {
///
/// If the [actions] are trailing the [content], this defaults to
/// `EdgeInsetsDirectional.only(start: 16.0, top: 2.0)`.
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry padding;
/// The amount of space by which to inset the [leading] widget.
///
/// This defaults to `EdgeInsetsDirectional.only(end: 16.0)`.
final EdgeInsetsGeometry? leadingPadding;
final EdgeInsetsGeometry leadingPadding;
/// An override to force the [actions] to be below the [content] regardless of
/// how many there are.
@ -102,7 +104,7 @@ class MaterialBanner extends StatelessWidget {
Widget build(BuildContext context) {
assert(actions.isNotEmpty);
final ThemeData? theme = Theme.of(context);
final ThemeData theme = Theme.of(context);
final MaterialBannerThemeData bannerTheme = MaterialBannerTheme.of(context);
final bool isSingleRow = actions.length == 1 && !forceActionsBelow;
@ -125,10 +127,10 @@ class MaterialBanner extends StatelessWidget {
final Color backgroundColor = this.backgroundColor
?? bannerTheme.backgroundColor
?? theme!.colorScheme.surface;
final TextStyle? textStyle = contentTextStyle
?? theme.colorScheme.surface;
final TextStyle textStyle = contentTextStyle
?? bannerTheme.contentTextStyle
?? theme!.textTheme.bodyText2;
?? theme.textTheme.bodyText2;
return Container(
color: backgroundColor,

View file

@ -2,6 +2,8 @@
// 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';
@ -36,25 +38,25 @@ class MaterialBannerThemeData with Diagnosticable {
});
/// The background color of a [MaterialBanner].
final Color? backgroundColor;
final Color backgroundColor;
/// Used to configure the [DefaultTextStyle] for the [MaterialBanner.content]
/// widget.
final TextStyle? contentTextStyle;
final TextStyle contentTextStyle;
/// The amount of space by which to inset [MaterialBanner.content].
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry padding;
/// The amount of space by which to inset [MaterialBanner.leading].
final EdgeInsetsGeometry? leadingPadding;
final EdgeInsetsGeometry leadingPadding;
/// Creates a copy of this object with the given fields replaced with the
/// new values.
MaterialBannerThemeData copyWith({
Color? backgroundColor,
TextStyle? contentTextStyle,
EdgeInsetsGeometry? padding,
EdgeInsetsGeometry? leadingPadding,
Color backgroundColor,
TextStyle contentTextStyle,
EdgeInsetsGeometry padding,
EdgeInsetsGeometry leadingPadding,
}) {
return MaterialBannerThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor,
@ -69,7 +71,7 @@ class MaterialBannerThemeData with Diagnosticable {
/// The argument `t` must not be null.
///
/// {@macro dart.ui.shadow.lerp}
static MaterialBannerThemeData lerp(MaterialBannerThemeData? a, MaterialBannerThemeData? b, double t) {
static MaterialBannerThemeData lerp(MaterialBannerThemeData a, MaterialBannerThemeData b, double t) {
assert(t != null);
return MaterialBannerThemeData(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
@ -121,13 +123,13 @@ class MaterialBannerTheme extends InheritedTheme {
/// Creates a banner theme that controls the configurations for
/// [MaterialBanner]s in its widget subtree.
const MaterialBannerTheme({
Key? key,
Key key,
this.data,
required Widget child,
Widget child,
}) : super(key: key, child: child);
/// The properties for descendant [MaterialBanner] widgets.
final MaterialBannerThemeData? data;
final MaterialBannerThemeData data;
/// The closest instance of this class's [data] value that encloses the given
/// context.
@ -141,13 +143,13 @@ class MaterialBannerTheme extends InheritedTheme {
/// MaterialBannerThemeData theme = MaterialBannerTheme.of(context);
/// ```
static MaterialBannerThemeData of(BuildContext context) {
final MaterialBannerTheme? bannerTheme = context.dependOnInheritedWidgetOfExactType<MaterialBannerTheme>();
return bannerTheme?.data ?? Theme.of(context)!.bannerTheme;
final MaterialBannerTheme bannerTheme = context.dependOnInheritedWidgetOfExactType<MaterialBannerTheme>();
return bannerTheme?.data ?? Theme.of(context).bannerTheme;
}
@override
Widget wrap(BuildContext context, Widget child) {
final MaterialBannerTheme? ancestorTheme = context.findAncestorWidgetOfExactType<MaterialBannerTheme>();
final MaterialBannerTheme ancestorTheme = context.findAncestorWidgetOfExactType<MaterialBannerTheme>();
return identical(this, ancestorTheme) ? child : MaterialBannerTheme(data: data, child: child);
}

View file

@ -2,6 +2,8 @@
// 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/rendering.dart';
import 'package:flutter/widgets.dart';
@ -48,7 +50,7 @@ class BottomAppBar extends StatefulWidget {
/// If the corresponding [BottomAppBarTheme] property is null, then the default
/// specified in the property's documentation will be used.
const BottomAppBar({
Key? key,
Key key,
this.color,
this.elevation,
this.shape,
@ -66,14 +68,14 @@ class BottomAppBar extends StatefulWidget {
///
/// Typically this the child will be a [Row], with the first child
/// being an [IconButton] with the [Icons.menu] icon.
final Widget? child;
final Widget child;
/// The bottom app bar's background color.
///
/// If this property is null then [BottomAppBarTheme.color] of
/// [ThemeData.bottomAppBarTheme] is used. If that's null then
/// [ThemeData.bottomAppBarColor] is used.
final Color? color;
final Color color;
/// The z-coordinate at which to place this bottom app bar relative to its
/// parent.
@ -84,14 +86,14 @@ class BottomAppBar extends StatefulWidget {
/// If this property is null then [BottomAppBarTheme.elevation] of
/// [ThemeData.bottomAppBarTheme] is used. If that's null, the default value
/// is 8.
final double? elevation;
final double elevation;
/// The notch that is made for the floating action button.
///
/// If this property is null then [BottomAppBarTheme.shape] of
/// [ThemeData.bottomAppBarTheme] is used. If that's null then the shape will
/// be rectangular with no notch.
final NotchedShape? shape;
final NotchedShape shape;
/// {@macro flutter.widgets.Clip}
///
@ -109,19 +111,19 @@ class BottomAppBar extends StatefulWidget {
}
class _BottomAppBarState extends State<BottomAppBar> {
late ValueListenable<ScaffoldGeometry> geometryListenable;
ValueListenable<ScaffoldGeometry> geometryListenable;
static const double _defaultElevation = 8.0;
@override
void didChangeDependencies() {
super.didChangeDependencies();
geometryListenable = Scaffold.geometryOf(context)!;
geometryListenable = Scaffold.geometryOf(context);
}
@override
Widget build(BuildContext context) {
final BottomAppBarTheme babTheme = BottomAppBarTheme.of(context);
final NotchedShape? notchedShape = widget.shape ?? babTheme.shape;
final NotchedShape notchedShape = widget.shape ?? babTheme.shape;
final CustomClipper<Path> clipper = notchedShape != null
? _BottomAppBarClipper(
geometry: geometryListenable,
@ -130,7 +132,7 @@ class _BottomAppBarState extends State<BottomAppBar> {
)
: const ShapeBorderClipper(shape: RoundedRectangleBorder());
final double elevation = widget.elevation ?? babTheme.elevation ?? _defaultElevation;
final Color color = widget.color ?? babTheme.color ?? Theme.of(context)!.bottomAppBarColor;
final Color color = widget.color ?? babTheme.color ?? Theme.of(context).bottomAppBarColor;
final Color effectiveColor = ElevationOverlay.applyOverlay(context, color, elevation);
return PhysicalShape(
clipper: clipper,
@ -141,7 +143,7 @@ class _BottomAppBarState extends State<BottomAppBar> {
type: MaterialType.transparency,
child: widget.child == null
? null
: SafeArea(child: widget.child!),
: SafeArea(child: widget.child),
),
);
}
@ -149,9 +151,9 @@ class _BottomAppBarState extends State<BottomAppBar> {
class _BottomAppBarClipper extends CustomClipper<Path> {
const _BottomAppBarClipper({
required this.geometry,
required this.shape,
required this.notchMargin,
@required this.geometry,
@required this.shape,
@required this.notchMargin,
}) : assert(geometry != null),
assert(shape != null),
assert(notchMargin != null),
@ -166,9 +168,9 @@ class _BottomAppBarClipper extends CustomClipper<Path> {
// button is the floating action button's bounding rectangle in the
// coordinate system whose origin is at the appBar's top left corner,
// or null if there is no floating action button.
final Rect? button = geometry.value.floatingActionButtonArea?.translate(
final Rect button = geometry.value.floatingActionButtonArea?.translate(
0.0,
geometry.value.bottomNavigationBarTop! * -1.0,
geometry.value.bottomNavigationBarTop * -1.0,
);
return shape.getOuterPath(Offset.zero & size, button?.inflate(notchMargin));
}

View file

@ -2,6 +2,8 @@
// 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' show lerpDouble;
import 'package:flutter/foundation.dart';
@ -37,20 +39,20 @@ class BottomAppBarTheme with Diagnosticable {
/// Default value for [BottomAppBar.color].
///
/// If null, [BottomAppBar] uses [ThemeData.bottomAppBarColor].
final Color? color;
final Color color;
/// Default value for [BottomAppBar.elevation].
final double? elevation;
final double elevation;
/// Default value for [BottomAppBar.shape].
final NotchedShape? shape;
final NotchedShape shape;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
BottomAppBarTheme copyWith({
Color? color,
double? elevation,
NotchedShape? shape,
Color color,
double elevation,
NotchedShape shape,
}) {
return BottomAppBarTheme(
color: color ?? this.color,
@ -61,7 +63,7 @@ class BottomAppBarTheme with Diagnosticable {
/// The [ThemeData.bottomAppBarTheme] property of the ambient [Theme].
static BottomAppBarTheme of(BuildContext context) {
return Theme.of(context)!.bottomAppBarTheme;
return Theme.of(context).bottomAppBarTheme;
}
/// Linearly interpolate between two BAB themes.
@ -69,7 +71,7 @@ class BottomAppBarTheme with Diagnosticable {
/// The argument `t` must not be null.
///
/// {@macro dart.ui.shadow.lerp}
static BottomAppBarTheme lerp(BottomAppBarTheme? a, BottomAppBarTheme? b, double t) {
static BottomAppBarTheme lerp(BottomAppBarTheme a, BottomAppBarTheme b, double t) {
assert(t != null);
return BottomAppBarTheme(
color: Color.lerp(a?.color, b?.color, t),

View file

@ -2,6 +2,8 @@
// 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' show Queue;
import 'dart:math' as math;
@ -170,16 +172,16 @@ class BottomNavigationBar extends StatefulWidget {
/// [BottomNavigationBarType.fixed] and `false` if [type] is
/// [BottomNavigationBarType.shifting].
BottomNavigationBar({
Key? key,
required this.items,
Key key,
@required this.items,
this.onTap,
this.currentIndex = 0,
this.elevation,
this.type,
Color? fixedColor,
Color fixedColor,
this.backgroundColor,
this.iconSize = 24.0,
Color? selectedItemColor,
Color selectedItemColor,
this.unselectedItemColor,
this.selectedIconTheme,
this.unselectedIconTheme,
@ -219,7 +221,7 @@ class BottomNavigationBar extends StatefulWidget {
/// The stateful widget that creates the bottom navigation bar needs to keep
/// track of the index of the selected [BottomNavigationBarItem] and call
/// `setState` to rebuild the bottom navigation bar with the new [currentIndex].
final ValueChanged<int>? onTap;
final ValueChanged<int> onTap;
/// The index into [items] for the current active [BottomNavigationBarItem].
final int currentIndex;
@ -229,26 +231,26 @@ class BottomNavigationBar extends StatefulWidget {
/// If null, defaults to `8.0`.
///
/// {@macro flutter.material.material.elevation}
final double? elevation;
final double elevation;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See documentation for [BottomNavigationBarType] for information on the
/// meaning of different types.
final BottomNavigationBarType? type;
final BottomNavigationBarType type;
/// The value of [selectedItemColor].
///
/// This getter only exists for backwards compatibility, the
/// [selectedItemColor] property is preferred.
Color? get fixedColor => selectedItemColor;
Color get fixedColor => selectedItemColor;
/// The color of the [BottomNavigationBar] itself.
///
/// If [type] is [BottomNavigationBarType.shifting] and the
/// [items] have [BottomNavigationBarItem.backgroundColor] set, the [items]'
/// backgroundColor will splash and overwrite this color.
final Color? backgroundColor;
final Color backgroundColor;
/// The size of all of the [BottomNavigationBarItem] icons.
///
@ -259,13 +261,13 @@ class BottomNavigationBar extends StatefulWidget {
/// [BottomNavigationBarItem.title].
///
/// If null then the [ThemeData.primaryColor] is used.
final Color? selectedItemColor;
final Color selectedItemColor;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.title]s.
///
/// If null then the [TextTheme.caption]'s color is used.
final Color? unselectedItemColor;
final Color unselectedItemColor;
/// The size, opacity, and color of the icon in the currently selected
/// [BottomNavigationBarItem.icon].
@ -276,7 +278,7 @@ class BottomNavigationBar extends StatefulWidget {
/// It this field is provided, it must contain non-null [IconThemeData.size]
/// and [IconThemeData.color] properties. Also, if this field is supplied,
/// [unselectedIconTheme] must be provided.
final IconThemeData? selectedIconTheme;
final IconThemeData selectedIconTheme;
/// The size, opacity, and color of the icon in the currently unselected
/// [BottomNavigationBarItem.icon]s.
@ -287,15 +289,15 @@ class BottomNavigationBar extends StatefulWidget {
/// It this field is provided, it must contain non-null [IconThemeData.size]
/// and [IconThemeData.color] properties. Also, if this field is supplied,
/// [unselectedIconTheme] must be provided.
final IconThemeData? unselectedIconTheme;
final IconThemeData unselectedIconTheme;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
/// selected.
final TextStyle? selectedLabelStyle;
final TextStyle selectedLabelStyle;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
/// selected.
final TextStyle? unselectedLabelStyle;
final TextStyle unselectedLabelStyle;
/// The font size of the [BottomNavigationBarItem] labels when they are selected.
///
@ -315,7 +317,7 @@ class BottomNavigationBar extends StatefulWidget {
final double unselectedFontSize;
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
final bool? showUnselectedLabels;
final bool showUnselectedLabels;
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
final bool showSelectedLabels;
@ -324,7 +326,7 @@ class BottomNavigationBar extends StatefulWidget {
/// tiles.
///
/// If this property is null, [SystemMouseCursors.click] will be used.
final MouseCursor? mouseCursor;
final MouseCursor mouseCursor;
@override
_BottomNavigationBarState createState() => _BottomNavigationBarState();
@ -342,14 +344,14 @@ class _BottomNavigationTile extends StatelessWidget {
this.colorTween,
this.flex,
this.selected = false,
required this.selectedLabelStyle,
required this.unselectedLabelStyle,
required this.selectedIconTheme,
required this.unselectedIconTheme,
@required this.selectedLabelStyle,
@required this.unselectedLabelStyle,
@required this.selectedIconTheme,
@required this.unselectedIconTheme,
this.showSelectedLabels,
this.showUnselectedLabels,
this.indexLabel,
required this.mouseCursor,
@required this.mouseCursor,
}) : assert(type != null),
assert(item != null),
assert(animation != null),
@ -362,17 +364,17 @@ class _BottomNavigationTile extends StatelessWidget {
final BottomNavigationBarItem item;
final Animation<double> animation;
final double iconSize;
final VoidCallback? onTap;
final ColorTween? colorTween;
final double? flex;
final VoidCallback onTap;
final ColorTween colorTween;
final double flex;
final bool selected;
final IconThemeData? selectedIconTheme;
final IconThemeData? unselectedIconTheme;
final IconThemeData selectedIconTheme;
final IconThemeData unselectedIconTheme;
final TextStyle selectedLabelStyle;
final TextStyle unselectedLabelStyle;
final String? indexLabel;
final bool? showSelectedLabels;
final bool? showUnselectedLabels;
final String indexLabel;
final bool showSelectedLabels;
final bool showUnselectedLabels;
final MouseCursor mouseCursor;
@override
@ -385,13 +387,13 @@ class _BottomNavigationTile extends StatelessWidget {
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
final double selectedFontSize = selectedLabelStyle.fontSize!;
final double selectedFontSize = selectedLabelStyle.fontSize;
final double selectedIconSize = selectedIconTheme?.size
?? bottomTheme.selectedIconTheme?.size
?? bottomTheme?.selectedIconTheme?.size
?? iconSize;
final double unselectedIconSize = unselectedIconTheme?.size
?? bottomTheme.unselectedIconTheme?.size
?? bottomTheme?.unselectedIconTheme?.size
?? iconSize;
// The amount that the selected icon is bigger than the unselected icons,
@ -420,7 +422,7 @@ class _BottomNavigationTile extends StatelessWidget {
// =======
double bottomPadding;
double topPadding;
if (showSelectedLabels! && !showUnselectedLabels!) {
if (showSelectedLabels && !showUnselectedLabels) {
bottomPadding = Tween<double>(
begin: selectedIconDiff / 2.0,
end: selectedFontSize / 2.0 - unselectedIconDiff / 2.0,
@ -429,7 +431,7 @@ class _BottomNavigationTile extends StatelessWidget {
begin: selectedFontSize + selectedIconDiff / 2.0,
end: selectedFontSize / 2.0 - unselectedIconDiff / 2.0,
).evaluate(animation);
} else if (!showSelectedLabels! && !showUnselectedLabels!) {
} else if (!showSelectedLabels && !showUnselectedLabels) {
bottomPadding = Tween<double>(
begin: selectedIconDiff / 2.0,
end: unselectedIconDiff / 2.0,
@ -454,7 +456,7 @@ class _BottomNavigationTile extends StatelessWidget {
size = 1;
break;
case BottomNavigationBarType.shifting:
size = (flex! * 1000.0).round();
size = (flex * 1000.0).round();
break;
}
@ -469,7 +471,7 @@ class _BottomNavigationTile extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_TileIcon(
colorTween: colorTween!,
colorTween: colorTween,
animation: animation,
iconSize: iconSize,
selected: selected,
@ -478,13 +480,13 @@ class _BottomNavigationTile extends StatelessWidget {
unselectedIconTheme: unselectedIconTheme ?? bottomTheme.unselectedIconTheme,
),
_Label(
colorTween: colorTween!,
colorTween: colorTween,
animation: animation,
item: item,
selectedLabelStyle: selectedLabelStyle,
unselectedLabelStyle: unselectedLabelStyle,
showSelectedLabels: showSelectedLabels ?? bottomTheme.showUnselectedLabels!,
showUnselectedLabels: showUnselectedLabels ?? bottomTheme.showUnselectedLabels!,
selectedLabelStyle: selectedLabelStyle ?? bottomTheme.selectedLabelStyle,
unselectedLabelStyle: unselectedLabelStyle ?? bottomTheme.unselectedLabelStyle,
showSelectedLabels: showSelectedLabels ?? bottomTheme.showUnselectedLabels,
showUnselectedLabels: showUnselectedLabels ?? bottomTheme.showUnselectedLabels,
),
],
),
@ -493,7 +495,7 @@ class _BottomNavigationTile extends StatelessWidget {
if (item.label != null) {
result = Tooltip(
message: item.label!,
message: item.label,
preferBelow: false,
verticalOffset: selectedIconSize + selectedFontSize,
child: result,
@ -523,14 +525,14 @@ class _BottomNavigationTile extends StatelessWidget {
class _TileIcon extends StatelessWidget {
const _TileIcon({
Key? key,
required this.colorTween,
required this.animation,
required this.iconSize,
required this.selected,
required this.item,
required this.selectedIconTheme,
required this.unselectedIconTheme,
Key key,
@required this.colorTween,
@required this.animation,
@required this.iconSize,
@required this.selected,
@required this.item,
@required this.selectedIconTheme,
@required this.unselectedIconTheme,
}) : assert(selected != null),
assert(item != null),
super(key: key);
@ -540,12 +542,12 @@ class _TileIcon extends StatelessWidget {
final double iconSize;
final bool selected;
final BottomNavigationBarItem item;
final IconThemeData? selectedIconTheme;
final IconThemeData? unselectedIconTheme;
final IconThemeData selectedIconTheme;
final IconThemeData unselectedIconTheme;
@override
Widget build(BuildContext context) {
final Color? iconColor = colorTween.evaluate(animation);
final Color iconColor = colorTween.evaluate(animation);
final IconThemeData defaultIconTheme = IconThemeData(
color: iconColor,
size: iconSize,
@ -571,14 +573,14 @@ class _TileIcon extends StatelessWidget {
class _Label extends StatelessWidget {
const _Label({
Key? key,
required this.colorTween,
required this.animation,
required this.item,
required this.selectedLabelStyle,
required this.unselectedLabelStyle,
required this.showSelectedLabels,
required this.showUnselectedLabels,
Key key,
@required this.colorTween,
@required this.animation,
@required this.item,
@required this.selectedLabelStyle,
@required this.unselectedLabelStyle,
@required this.showSelectedLabels,
@required this.showUnselectedLabels,
}) : assert(colorTween != null),
assert(animation != null),
assert(item != null),
@ -598,14 +600,14 @@ class _Label extends StatelessWidget {
@override
Widget build(BuildContext context) {
final double? selectedFontSize = selectedLabelStyle.fontSize;
final double? unselectedFontSize = unselectedLabelStyle.fontSize;
final double selectedFontSize = selectedLabelStyle.fontSize;
final double unselectedFontSize = unselectedLabelStyle.fontSize;
final TextStyle customStyle = TextStyle.lerp(
unselectedLabelStyle,
selectedLabelStyle,
animation.value,
)!;
);
Widget text = DefaultTextStyle.merge(
style: customStyle.copyWith(
fontSize: selectedFontSize,
@ -618,13 +620,13 @@ class _Label extends StatelessWidget {
transform: Matrix4.diagonal3(
Vector3.all(
Tween<double>(
begin: unselectedFontSize! / selectedFontSize!,
begin: unselectedFontSize / selectedFontSize,
end: 1.0,
).evaluate(animation),
),
),
alignment: Alignment.bottomCenter,
child: item.title ?? Text(item.label!),
child: item.title ?? Text(item.label),
),
);
@ -660,7 +662,7 @@ class _Label extends StatelessWidget {
if (item.label != null) {
// Do not grow text in bottom navigation bar when we can show a tooltip
// instead.
final MediaQueryData mediaQueryData = MediaQuery.of(context)!;
final MediaQueryData mediaQueryData = MediaQuery.of(context);
text = MediaQuery(
data: mediaQueryData.copyWith(
textScaleFactor: math.min(1.0, mediaQueryData.textScaleFactor),
@ -675,14 +677,14 @@ class _Label extends StatelessWidget {
class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerProviderStateMixin {
List<AnimationController> _controllers = <AnimationController>[];
late List<CurvedAnimation> _animations;
List<CurvedAnimation> _animations;
// A queue of color splashes currently being animated.
final Queue<_Circle> _circles = Queue<_Circle>();
// Last splash circle's color, and the final color of the control after
// animation is complete.
Color? _backgroundColor;
Color _backgroundColor;
static final Animatable<double> _flexTween = Tween<double>(begin: 1.0, end: 1.5);
@ -733,6 +735,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
case BottomNavigationBarType.fixed:
return true;
}
assert(false);
return false;
}
@override
@ -765,7 +769,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
_Circle(
state: this,
index: index,
color: widget.items[index].backgroundColor!,
color: widget.items[index].backgroundColor,
vsync: this,
)..controller.addStatusListener(
(AnimationStatus status) {
@ -816,17 +820,17 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
// If the given [TextStyle] has a non-null `fontSize`, it should be used.
// Otherwise, the [selectedFontSize] parameter should be used.
static TextStyle _effectiveTextStyle(TextStyle? textStyle, double fontSize) {
static TextStyle _effectiveTextStyle(TextStyle textStyle, double fontSize) {
textStyle ??= const TextStyle();
// Prefer the font size on textStyle if present.
return textStyle.fontSize == null ? textStyle.copyWith(fontSize: fontSize) : textStyle;
}
List<Widget> _createTiles() {
final MaterialLocalizations localizations = MaterialLocalizations.of(context)!;
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
assert(localizations != null);
final ThemeData themeData = Theme.of(context)!;
final ThemeData themeData = Theme.of(context);
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
final TextStyle effectiveSelectedLabelStyle =
@ -856,7 +860,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
colorTween = ColorTween(
begin: widget.unselectedItemColor
?? bottomTheme.unselectedItemColor
?? themeData.textTheme.caption!.color,
?? themeData.textTheme.caption.color,
end: widget.selectedItemColor
?? bottomTheme.selectedItemColor
?? widget.fixedColor
@ -889,12 +893,12 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
unselectedLabelStyle: effectiveUnselectedLabelStyle,
onTap: () {
if (widget.onTap != null)
widget.onTap!(i);
widget.onTap(i);
},
colorTween: colorTween,
flex: _evaluateFlex(_animations[i]),
selected: i == widget.currentIndex,
showSelectedLabels: widget.showSelectedLabels,
showSelectedLabels: widget.showSelectedLabels ?? bottomTheme.showSelectedLabels,
showUnselectedLabels: widget.showUnselectedLabels ?? bottomTheme.showUnselectedLabels ?? _defaultShowUnselected,
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
mouseCursor: effectiveMouseCursor,
@ -923,8 +927,8 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
final BottomNavigationBarThemeData bottomTheme = BottomNavigationBarTheme.of(context);
// Labels apply up to _bottomMargin padding. Remainder is media padding.
final double additionalBottomPadding = math.max(MediaQuery.of(context)!.padding.bottom - widget.selectedFontSize / 2.0, 0.0);
Color? backgroundColor;
final double additionalBottomPadding = math.max(MediaQuery.of(context).padding.bottom - widget.selectedFontSize / 2.0, 0.0);
Color backgroundColor;
switch (_effectiveType) {
case BottomNavigationBarType.fixed:
backgroundColor = widget.backgroundColor ?? bottomTheme.backgroundColor;
@ -943,7 +947,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
child: CustomPaint(
painter: _RadialPainter(
circles: _circles.toList(),
textDirection: Directionality.of(context)!,
textDirection: Directionality.of(context),
),
child: Material( // Splashes.
type: MaterialType.transparency,
@ -966,10 +970,10 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
// Describes an animating color splash circle.
class _Circle {
_Circle({
required this.state,
required this.index,
required this.color,
required TickerProvider vsync,
@required this.state,
@required this.index,
@required this.color,
@required TickerProvider vsync,
}) : assert(state != null),
assert(index != null),
assert(color != null) {
@ -987,8 +991,8 @@ class _Circle {
final _BottomNavigationBarState state;
final int index;
final Color color;
late AnimationController controller;
late CurvedAnimation animation;
AnimationController controller;
CurvedAnimation animation;
double get horizontalLeadingOffset {
double weightSum(Iterable<Animation<double>> animations) {
@ -1013,8 +1017,8 @@ class _Circle {
// Paints the animating color splash circles.
class _RadialPainter extends CustomPainter {
_RadialPainter({
required this.circles,
required this.textDirection,
@required this.circles,
@required this.textDirection,
}) : assert(circles != null),
assert(textDirection != null);

View file

@ -2,6 +2,8 @@
// 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' show lerpDouble;
import 'package:flutter/foundation.dart';
@ -48,78 +50,78 @@ class BottomNavigationBarThemeData with Diagnosticable {
/// The color of the [BottomNavigationBar] itself.
///
/// See [BottomNavigationBar.backgroundColor].
final Color? backgroundColor;
final Color backgroundColor;
/// The z-coordinate of the [BottomNavigationBar].
///
/// See [BottomNavigationBar.elevation].
final double? elevation;
final double elevation;
/// The size, opacity, and color of the icon in the currently selected
/// [BottomNavigationBarItem.icon].
///
/// See [BottomNavigationBar.selectedIconTheme].
final IconThemeData? selectedIconTheme;
final IconThemeData selectedIconTheme;
/// The size, opacity, and color of the icon in the currently unselected
/// [BottomNavigationBarItem.icon]s.
///
/// See [BottomNavigationBar.unselectedIconTheme].
final IconThemeData? unselectedIconTheme;
final IconThemeData unselectedIconTheme;
/// The color of the selected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.title].
///
/// See [BottomNavigationBar.selectedItemColor].
final Color? selectedItemColor;
final Color selectedItemColor;
/// The color of the unselected [BottomNavigationBarItem.icon] and
/// [BottomNavigationBarItem.title]s.
///
/// See [BottomNavigationBar.unselectedItemColor].
final Color? unselectedItemColor;
final Color unselectedItemColor;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are
/// selected.
///
/// See [BottomNavigationBar.selectedLabelStyle].
final TextStyle? selectedLabelStyle;
final TextStyle selectedLabelStyle;
/// The [TextStyle] of the [BottomNavigationBarItem] labels when they are not
/// selected.
///
/// See [BottomNavigationBar.unselectedLabelStyle].
final TextStyle? unselectedLabelStyle;
final TextStyle unselectedLabelStyle;
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
///
/// See [BottomNavigationBar.showSelectedLabels].
final bool? showSelectedLabels;
final bool showSelectedLabels;
/// Whether the labels are shown for the selected [BottomNavigationBarItem].
///
/// See [BottomNavigationBar.showUnselectedLabels].
final bool? showUnselectedLabels;
final bool showUnselectedLabels;
/// Defines the layout and behavior of a [BottomNavigationBar].
///
/// See [BottomNavigationBar.type].
final BottomNavigationBarType? type;
final BottomNavigationBarType type;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
BottomNavigationBarThemeData copyWith({
Color? backgroundColor,
double? elevation,
IconThemeData? selectedIconTheme,
IconThemeData? unselectedIconTheme,
Color? selectedItemColor,
Color? unselectedItemColor,
TextStyle? selectedLabelStyle,
TextStyle? unselectedLabelStyle,
bool? showSelectedLabels,
bool? showUnselectedLabels,
BottomNavigationBarType? type,
Color backgroundColor,
double elevation,
IconThemeData selectedIconTheme,
IconThemeData unselectedIconTheme,
Color selectedItemColor,
Color unselectedItemColor,
TextStyle selectedLabelStyle,
TextStyle unselectedLabelStyle,
bool showSelectedLabels,
bool showUnselectedLabels,
BottomNavigationBarType type,
}) {
return BottomNavigationBarThemeData(
backgroundColor: backgroundColor ?? this.backgroundColor,
@ -141,7 +143,7 @@ class BottomNavigationBarThemeData with Diagnosticable {
/// The argument `t` must not be null.
///
/// {@macro dart.ui.shadow.lerp}
static BottomNavigationBarThemeData lerp(BottomNavigationBarThemeData? a, BottomNavigationBarThemeData? b, double t) {
static BottomNavigationBarThemeData lerp(BottomNavigationBarThemeData a, BottomNavigationBarThemeData b, double t) {
assert(t != null);
return BottomNavigationBarThemeData(
backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
@ -233,9 +235,9 @@ class BottomNavigationBarTheme extends InheritedWidget {
///
/// The [data] must not be null.
const BottomNavigationBarTheme({
Key? key,
required this.data,
required Widget child,
Key key,
@required this.data,
Widget child,
}) : assert(data != null), super(key: key, child: child);
/// The properties used for all descendant [BottomNavigationBar] widgets.
@ -252,8 +254,8 @@ class BottomNavigationBarTheme extends InheritedWidget {
/// BottomNavigationBarThemeData theme = BottomNavigationBarTheme.of(context);
/// ```
static BottomNavigationBarThemeData of(BuildContext context) {
final BottomNavigationBarTheme? bottomNavTheme = context.dependOnInheritedWidgetOfExactType<BottomNavigationBarTheme>();
return bottomNavTheme?.data ?? Theme.of(context)!.bottomNavigationBarTheme;
final BottomNavigationBarTheme bottomNavTheme = context.dependOnInheritedWidgetOfExactType<BottomNavigationBarTheme>();
return bottomNavTheme?.data ?? Theme.of(context).bottomNavigationBarTheme;
}
@override

View file

@ -2,6 +2,8 @@
// 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' show lerpDouble;
import 'package:flutter/foundation.dart';
@ -33,7 +35,7 @@ typedef BottomSheetDragStartHandler = void Function(DragStartDetails details);
/// Used by [BottomSheet.onDragEnd].
typedef BottomSheetDragEndHandler = void Function(
DragEndDetails details, {
required bool isClosing,
bool isClosing,
});
/// A material design bottom sheet.
@ -70,7 +72,7 @@ class BottomSheet extends StatefulWidget {
/// [ScaffoldState.showBottomSheet], for persistent bottom sheets, or by
/// [showModalBottomSheet], for modal bottom sheets.
const BottomSheet({
Key? key,
Key key,
this.animationController,
this.enableDrag = true,
this.onDragStart,
@ -79,8 +81,8 @@ class BottomSheet extends StatefulWidget {
this.elevation,
this.shape,
this.clipBehavior,
required this.onClosing,
required this.builder,
@required this.onClosing,
@required this.builder,
}) : assert(enableDrag != null),
assert(onClosing != null),
assert(builder != null),
@ -92,7 +94,7 @@ class BottomSheet extends StatefulWidget {
///
/// The BottomSheet widget will manipulate the position of this animation, it
/// is not just a passive observer.
final AnimationController? animationController;
final AnimationController animationController;
/// Called when the bottom sheet begins to close.
///
@ -118,7 +120,7 @@ class BottomSheet extends StatefulWidget {
///
/// Would typically be used to change the bottom sheet animation curve so
/// that it tracks the user's finger accurately.
final BottomSheetDragStartHandler? onDragStart;
final BottomSheetDragStartHandler onDragStart;
/// Called when the user stops dragging the bottom sheet, if [enableDrag]
/// is true.
@ -126,28 +128,28 @@ class BottomSheet extends StatefulWidget {
/// Would typically be used to reset the bottom sheet animation curve, so
/// that it animates non-linearly. Called before [onClosing] if the bottom
/// sheet is closing.
final BottomSheetDragEndHandler? onDragEnd;
final BottomSheetDragEndHandler onDragEnd;
/// The bottom sheet's background color.
///
/// Defines the bottom sheet's [Material.color].
///
/// Defaults to null and falls back to [Material]'s default.
final Color? backgroundColor;
final Color backgroundColor;
/// The z-coordinate at which to place this material relative to its parent.
///
/// This controls the size of the shadow below the material.
///
/// Defaults to 0. The value is non-negative.
final double? elevation;
final double elevation;
/// The shape of the bottom sheet.
///
/// Defines the bottom sheet's [Material.shape].
///
/// Defaults to null and falls back to [Material]'s default.
final ShapeBorder? shape;
final ShapeBorder shape;
/// {@macro flutter.widgets.Clip}
///
@ -161,7 +163,7 @@ class BottomSheet extends StatefulWidget {
/// If this property is null then [BottomSheetThemeData.clipBehavior] of
/// [ThemeData.bottomSheetTheme] is used. If that's null then the behavior
/// will be [Clip.none].
final Clip? clipBehavior;
final Clip clipBehavior;
@override
_BottomSheetState createState() => _BottomSheetState();
@ -187,15 +189,15 @@ class _BottomSheetState extends State<BottomSheet> {
final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child');
double get _childHeight {
final RenderBox renderBox = _childKey.currentContext!.findRenderObject() as RenderBox;
final RenderBox renderBox = _childKey.currentContext.findRenderObject() as RenderBox;
return renderBox.size.height;
}
bool get _dismissUnderway => widget.animationController!.status == AnimationStatus.reverse;
bool get _dismissUnderway => widget.animationController.status == AnimationStatus.reverse;
void _handleDragStart(DragStartDetails details) {
if (widget.onDragStart != null) {
widget.onDragStart!(details);
widget.onDragStart(details);
}
}
@ -203,7 +205,7 @@ class _BottomSheetState extends State<BottomSheet> {
assert(widget.enableDrag);
if (_dismissUnderway)
return;
widget.animationController!.value -= details.primaryDelta! / _childHeight;
widget.animationController.value -= details.primaryDelta / (_childHeight ?? details.primaryDelta);
}
void _handleDragEnd(DragEndDetails details) {
@ -213,22 +215,22 @@ class _BottomSheetState extends State<BottomSheet> {
bool isClosing = false;
if (details.velocity.pixelsPerSecond.dy > _minFlingVelocity) {
final double flingVelocity = -details.velocity.pixelsPerSecond.dy / _childHeight;
if (widget.animationController!.value > 0.0) {
widget.animationController!.fling(velocity: flingVelocity);
if (widget.animationController.value > 0.0) {
widget.animationController.fling(velocity: flingVelocity);
}
if (flingVelocity < 0.0) {
isClosing = true;
}
} else if (widget.animationController!.value < _closeProgressThreshold) {
if (widget.animationController!.value > 0.0)
widget.animationController!.fling(velocity: -1.0);
} else if (widget.animationController.value < _closeProgressThreshold) {
if (widget.animationController.value > 0.0)
widget.animationController.fling(velocity: -1.0);
isClosing = true;
} else {
widget.animationController!.forward();
widget.animationController.forward();
}
if (widget.onDragEnd != null) {
widget.onDragEnd!(
widget.onDragEnd(
details,
isClosing: isClosing,
);
@ -248,10 +250,10 @@ class _BottomSheetState extends State<BottomSheet> {
@override
Widget build(BuildContext context) {
final BottomSheetThemeData bottomSheetTheme = Theme.of(context)!.bottomSheetTheme;
final Color? color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor;
final BottomSheetThemeData bottomSheetTheme = Theme.of(context).bottomSheetTheme;
final Color color = widget.backgroundColor ?? bottomSheetTheme.backgroundColor;
final double elevation = widget.elevation ?? bottomSheetTheme.elevation ?? 0;
final ShapeBorder? shape = widget.shape ?? bottomSheetTheme.shape;
final ShapeBorder shape = widget.shape ?? bottomSheetTheme.shape;
final Clip clipBehavior = widget.clipBehavior ?? bottomSheetTheme.clipBehavior ?? Clip.none;
final Widget bottomSheet = Material(
@ -312,7 +314,7 @@ class _ModalBottomSheetLayout extends SingleChildLayoutDelegate {
class _ModalBottomSheet<T> extends StatefulWidget {
const _ModalBottomSheet({
Key? key,
Key key,
this.route,
this.backgroundColor,
this.elevation,
@ -324,12 +326,12 @@ class _ModalBottomSheet<T> extends StatefulWidget {
assert(enableDrag != null),
super(key: key);
final _ModalBottomSheetRoute<T>? route;
final _ModalBottomSheetRoute<T> route;
final bool isScrollControlled;
final Color? backgroundColor;
final double? elevation;
final ShapeBorder? shape;
final Clip? clipBehavior;
final Color backgroundColor;
final double elevation;
final ShapeBorder shape;
final Clip clipBehavior;
final bool enableDrag;
@override
@ -340,7 +342,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
ParametricCurve<double> animationCurve = _modalBottomSheetCurve;
String _getRouteLabel(MaterialLocalizations localizations) {
switch (Theme.of(context)!.platform) {
switch (Theme.of(context).platform) {
case TargetPlatform.iOS:
case TargetPlatform.macOS:
return '';
@ -350,6 +352,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
case TargetPlatform.windows:
return localizations.dialogLabel;
}
return null;
}
void handleDragStart(DragStartDetails details) {
@ -357,10 +360,10 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
animationCurve = Curves.linear;
}
void handleDragEnd(DragEndDetails details, {bool? isClosing}) {
void handleDragEnd(DragEndDetails details, {bool isClosing}) {
// Allow the bottom sheet to animate smoothly from its current position.
animationCurve = _BottomSheetSuspendedCurve(
widget.route!.animation!.value,
widget.route.animation.value,
curve: _modalBottomSheetCurve,
);
}
@ -369,20 +372,20 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
Widget build(BuildContext context) {
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
final MediaQueryData? mediaQuery = MediaQuery.of(context);
final MaterialLocalizations localizations = MaterialLocalizations.of(context)!;
final MediaQueryData mediaQuery = MediaQuery.of(context);
final MaterialLocalizations localizations = MaterialLocalizations.of(context);
final String routeLabel = _getRouteLabel(localizations);
return AnimatedBuilder(
animation: widget.route!.animation!,
animation: widget.route.animation,
child: BottomSheet(
animationController: widget.route!._animationController,
animationController: widget.route._animationController,
onClosing: () {
if (widget.route!.isCurrent) {
if (widget.route.isCurrent) {
Navigator.pop(context);
}
},
builder: widget.route!.builder!,
builder: widget.route.builder,
backgroundColor: widget.backgroundColor,
elevation: widget.elevation,
shape: widget.shape,
@ -391,11 +394,11 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
onDragStart: handleDragStart,
onDragEnd: handleDragEnd,
),
builder: (BuildContext context, Widget? child) {
builder: (BuildContext context, Widget child) {
// Disable the initial animation when accessible navigation is on so
// that the semantics are added to the tree at the correct time.
final double animationValue = animationCurve.transform(
mediaQuery!.accessibleNavigation ? 1.0 : widget.route!.animation!.value
mediaQuery.accessibleNavigation ? 1.0 : widget.route.animation.value
);
return Semantics(
scopesRoute: true,
@ -426,21 +429,21 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
this.modalBarrierColor,
this.isDismissible = true,
this.enableDrag = true,
required this.isScrollControlled,
RouteSettings? settings,
@required this.isScrollControlled,
RouteSettings settings,
}) : assert(isScrollControlled != null),
assert(isDismissible != null),
assert(enableDrag != null),
super(settings: settings);
final WidgetBuilder? builder;
final ThemeData? theme;
final WidgetBuilder builder;
final ThemeData theme;
final bool isScrollControlled;
final Color? backgroundColor;
final double? elevation;
final ShapeBorder? shape;
final Clip? clipBehavior;
final Color? modalBarrierColor;
final Color backgroundColor;
final double elevation;
final ShapeBorder shape;
final Clip clipBehavior;
final Color modalBarrierColor;
final bool isDismissible;
final bool enableDrag;
@ -454,23 +457,23 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
bool get barrierDismissible => isDismissible;
@override
final String? barrierLabel;
final String barrierLabel;
@override
Color get barrierColor => modalBarrierColor ?? Colors.black54;
AnimationController? _animationController;
AnimationController _animationController;
@override
AnimationController createAnimationController() {
assert(_animationController == null);
_animationController = BottomSheet.createAnimationController(navigator!.overlay!);
return _animationController!;
_animationController = BottomSheet.createAnimationController(navigator.overlay);
return _animationController;
}
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context)!.bottomSheetTheme;
final BottomSheetThemeData sheetTheme = theme?.bottomSheetTheme ?? Theme.of(context).bottomSheetTheme;
// By definition, the bottom sheet is aligned to the bottom of the page
// and isn't exposed to the top padding of the MediaQuery.
Widget bottomSheet = MediaQuery.removePadding(
@ -478,8 +481,8 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
removeTop: true,
child: _ModalBottomSheet<T>(
route: this,
backgroundColor: backgroundColor ?? sheetTheme.modalBackgroundColor ?? sheetTheme.backgroundColor,
elevation: elevation ?? sheetTheme.modalElevation ?? sheetTheme.elevation,
backgroundColor: backgroundColor ?? sheetTheme?.modalBackgroundColor ?? sheetTheme?.backgroundColor,
elevation: elevation ?? sheetTheme?.modalElevation ?? sheetTheme?.elevation,
shape: shape,
clipBehavior: clipBehavior,
isScrollControlled: isScrollControlled,
@ -487,7 +490,7 @@ class _ModalBottomSheetRoute<T> extends PopupRoute<T> {
),
);
if (theme != null)
bottomSheet = Theme(data: theme!, child: bottomSheet);
bottomSheet = Theme(data: theme, child: bottomSheet);
return bottomSheet;
}
}
@ -541,7 +544,7 @@ class _BottomSheetSuspendedCurve extends ParametricCurve<double> {
final double curveProgress = (t - startingPoint) / (1 - startingPoint);
final double transformed = curve.transform(curveProgress);
return lerpDouble(startingPoint, 1, transformed)!;
return lerpDouble(startingPoint, 1, transformed);
}
@override
@ -645,18 +648,18 @@ class _BottomSheetSuspendedCurve extends ParametricCurve<double> {
/// that grows and then becomes scrollable once it reaches its maximum size.
/// * <https://material.io/design/components/sheets-bottom.html#modal-bottom-sheet>
Future<T> showModalBottomSheet<T>({
required BuildContext context,
required WidgetBuilder builder,
Color? backgroundColor,
double? elevation,
ShapeBorder? shape,
Clip? clipBehavior,
Color? barrierColor,
@required BuildContext context,
@required WidgetBuilder builder,
Color backgroundColor,
double elevation,
ShapeBorder shape,
Clip clipBehavior,
Color barrierColor,
bool isScrollControlled = false,
bool useRootNavigator = false,
bool isDismissible = true,
bool enableDrag = true,
RouteSettings? routeSettings,
RouteSettings routeSettings,
}) {
assert(context != null);
assert(builder != null);
@ -667,11 +670,11 @@ Future<T> showModalBottomSheet<T>({
assert(debugCheckHasMediaQuery(context));
assert(debugCheckHasMaterialLocalizations(context));
return Navigator.of(context, rootNavigator: useRootNavigator)!.push(_ModalBottomSheetRoute<T>(
return Navigator.of(context, rootNavigator: useRootNavigator).push(_ModalBottomSheetRoute<T>(
builder: builder,
theme: Theme.of(context, shadowThemeOnly: true),
isScrollControlled: isScrollControlled,
barrierLabel: MaterialLocalizations.of(context)!.modalBarrierDismissLabel,
barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
backgroundColor: backgroundColor,
elevation: elevation,
shape: shape,
@ -723,18 +726,18 @@ Future<T> showModalBottomSheet<T>({
/// * [Scaffold.of], for information about how to obtain the [BuildContext].
/// * <https://material.io/design/components/sheets-bottom.html#standard-bottom-sheet>
PersistentBottomSheetController<T> showBottomSheet<T>({
required BuildContext context,
required WidgetBuilder builder,
Color? backgroundColor,
double? elevation,
ShapeBorder? shape,
Clip? clipBehavior,
@required BuildContext context,
@required WidgetBuilder builder,
Color backgroundColor,
double elevation,
ShapeBorder shape,
Clip clipBehavior,
}) {
assert(context != null);
assert(builder != null);
assert(debugCheckHasScaffold(context));
return Scaffold.of(context)!.showBottomSheet<T>(
return Scaffold.of(context).showBottomSheet<T>(
builder,
backgroundColor: backgroundColor,
elevation: elevation,

View file

@ -2,6 +2,8 @@
// 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';
@ -49,8 +51,8 @@ class RawMaterialButton extends StatefulWidget {
/// [elevation], [focusElevation], [hoverElevation], [highlightElevation], and
/// [disabledElevation] must be non-negative.
const RawMaterialButton({
Key? key,
required this.onPressed,
Key key,
@required this.onPressed,
this.onLongPress,
this.onHighlightChanged,
this.mouseCursor,
@ -73,7 +75,7 @@ class RawMaterialButton extends StatefulWidget {
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
MaterialTapTargetSize? materialTapTargetSize,
MaterialTapTargetSize materialTapTargetSize,
this.child,
this.enableFeedback = true,
}) : materialTapTargetSize = materialTapTargetSize ?? MaterialTapTargetSize.padded,
@ -97,7 +99,7 @@ class RawMaterialButton extends StatefulWidget {
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback? onPressed;
final VoidCallback onPressed;
/// Called when the button is long-pressed.
///
@ -106,7 +108,7 @@ class RawMaterialButton extends StatefulWidget {
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback? onLongPress;
final VoidCallback onLongPress;
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
/// callback.
@ -114,7 +116,7 @@ class RawMaterialButton extends StatefulWidget {
/// If [onPressed] changes from null to non-null while a gesture is ongoing,
/// this can fire during the build phase (in which case calling
/// [State.setState] is not allowed).
final ValueChanged<bool>? onHighlightChanged;
final ValueChanged<bool> onHighlightChanged;
/// {@template flutter.material.button.mouseCursor}
/// The cursor for a mouse pointer when it enters or is hovering over the
@ -130,7 +132,7 @@ class RawMaterialButton extends StatefulWidget {
///
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
/// {@endtemplate}
final MouseCursor? mouseCursor;
final MouseCursor mouseCursor;
/// Defines the default text style, with [Material.textStyle], for the
/// button's [child].
@ -142,22 +144,22 @@ class RawMaterialButton extends StatefulWidget {
/// * [MaterialState.hovered].
/// * [MaterialState.focused].
/// * [MaterialState.disabled].
final TextStyle? textStyle;
final TextStyle textStyle;
/// The color of the button's [Material].
final Color? fillColor;
final Color fillColor;
/// The color for the button's [Material] when it has the input focus.
final Color? focusColor;
final Color focusColor;
/// The color for the button's [Material] when a pointer is hovering over it.
final Color? hoverColor;
final Color hoverColor;
/// The highlight color for the button's [InkWell].
final Color? highlightColor;
final Color highlightColor;
/// The splash color for the button's [InkWell].
final Color? splashColor;
final Color splashColor;
/// The elevation for the button's [Material] when the button
/// is [enabled] but not pressed.
@ -273,7 +275,7 @@ class RawMaterialButton extends StatefulWidget {
final Duration animationDuration;
/// Typically the button's label.
final Widget? child;
final Widget child;
/// Whether the button is enabled or disabled.
///
@ -291,7 +293,7 @@ class RawMaterialButton extends StatefulWidget {
final MaterialTapTargetSize materialTapTargetSize;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
@ -332,7 +334,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
setState(() {
_updateState(MaterialState.pressed, value);
if (widget.onHighlightChanged != null) {
widget.onHighlightChanged!(value);
widget.onHighlightChanged(value);
}
});
}
@ -393,11 +395,11 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
@override
Widget build(BuildContext context) {
final Color? effectiveTextColor = MaterialStateProperty.resolveAs<Color>(widget.textStyle?.color, _states);
final ShapeBorder? effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(widget.shape, _states);
final Color effectiveTextColor = MaterialStateProperty.resolveAs<Color>(widget.textStyle?.color, _states);
final ShapeBorder effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(widget.shape, _states);
final Offset densityAdjustment = widget.visualDensity.baseSizeAdjustment;
final BoxConstraints effectiveConstraints = widget.visualDensity.effectiveConstraints(widget.constraints);
final MouseCursor? effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
widget.mouseCursor ?? MaterialStateMouseCursor.clickable,
_states,
);
@ -485,9 +487,9 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
/// "tap target", but not its material or its ink splashes.
class _InputPadding extends SingleChildRenderObjectWidget {
const _InputPadding({
Key? key,
Widget? child,
required this.minSize,
Key key,
Widget child,
this.minSize,
}) : super(key: key, child: child);
final Size minSize;
@ -504,7 +506,7 @@ class _InputPadding extends SingleChildRenderObjectWidget {
}
class _RenderInputPadding extends RenderShiftedBox {
_RenderInputPadding(this._minSize, [RenderBox? child]) : super(child);
_RenderInputPadding(this._minSize, [RenderBox child]) : super(child);
Size get minSize => _minSize;
Size _minSize;
@ -518,57 +520,58 @@ class _RenderInputPadding extends RenderShiftedBox {
@override
double computeMinIntrinsicWidth(double height) {
if (child != null)
return math.max(child!.getMinIntrinsicWidth(height), minSize.width);
return math.max(child.getMinIntrinsicWidth(height), minSize.width);
return 0.0;
}
@override
double computeMinIntrinsicHeight(double width) {
if (child != null)
return math.max(child!.getMinIntrinsicHeight(width), minSize.height);
return math.max(child.getMinIntrinsicHeight(width), minSize.height);
return 0.0;
}
@override
double computeMaxIntrinsicWidth(double height) {
if (child != null)
return math.max(child!.getMaxIntrinsicWidth(height), minSize.width);
return math.max(child.getMaxIntrinsicWidth(height), minSize.width);
return 0.0;
}
@override
double computeMaxIntrinsicHeight(double width) {
if (child != null)
return math.max(child!.getMaxIntrinsicHeight(width), minSize.height);
return math.max(child.getMaxIntrinsicHeight(width), minSize.height);
return 0.0;
}
@override
void performLayout() {
final BoxConstraints constraints = this.constraints;
if (child != null) {
child!.layout(constraints, parentUsesSize: true);
final double height = math.max(child!.size.width, minSize.width);
final double width = math.max(child!.size.height, minSize.height);
child.layout(constraints, parentUsesSize: true);
final double height = math.max(child.size.width, minSize.width);
final double width = math.max(child.size.height, minSize.height);
size = constraints.constrain(Size(height, width));
final BoxParentData childParentData = child!.parentData as BoxParentData;
childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset);
final BoxParentData childParentData = child.parentData as BoxParentData;
childParentData.offset = Alignment.center.alongOffset(size - child.size as Offset);
} else {
size = Size.zero;
}
}
@override
bool hitTest(BoxHitTestResult result, { required Offset position }) {
bool hitTest(BoxHitTestResult result, { Offset position }) {
if (super.hitTest(result, position: position)) {
return true;
}
final Offset center = child!.size.center(Offset.zero);
final Offset center = child.size.center(Offset.zero);
return result.addWithRawTransform(
transform: MatrixUtils.forceToPoint(center),
position: center,
hitTest: (BoxHitTestResult result, Offset? position) {
hitTest: (BoxHitTestResult result, Offset position) {
assert(position == center);
return child!.hitTest(result, position: center);
return child.hitTest(result, position: center);
},
);
}

View file

@ -2,6 +2,8 @@
// 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 'package:flutter/rendering.dart';
@ -54,7 +56,7 @@ class ButtonBar extends StatelessWidget {
/// Both [buttonMinWidth] and [buttonHeight] must be non-negative if they
/// are not null.
const ButtonBar({
Key? key,
Key key,
this.alignment,
this.mainAxisSize,
this.buttonTextTheme,
@ -75,13 +77,13 @@ class ButtonBar extends StatelessWidget {
///
/// If null then it will use [ButtonBarThemeData.alignment]. If that is null,
/// it will default to [MainAxisAlignment.end].
final MainAxisAlignment? alignment;
final MainAxisAlignment alignment;
/// How much horizontal space is available. See [Row.mainAxisSize].
///
/// If null then it will use the surrounding [ButtonBarThemeData.mainAxisSize].
/// If that is null, it will default to [MainAxisSize.max].
final MainAxisSize? mainAxisSize;
final MainAxisSize mainAxisSize;
/// Overrides the surrounding [ButtonBarThemeData.buttonTextTheme] to define a
/// button's base colors, size, internal padding and shape.
@ -89,21 +91,21 @@ class ButtonBar extends StatelessWidget {
/// If null then it will use the surrounding
/// [ButtonBarThemeData.buttonTextTheme]. If that is null, it will default to
/// [ButtonTextTheme.primary].
final ButtonTextTheme? buttonTextTheme;
final ButtonTextTheme buttonTextTheme;
/// Overrides the surrounding [ButtonThemeData.minWidth] to define a button's
/// minimum width.
///
/// If null then it will use the surrounding [ButtonBarThemeData.buttonMinWidth].
/// If that is null, it will default to 64.0 logical pixels.
final double? buttonMinWidth;
final double buttonMinWidth;
/// Overrides the surrounding [ButtonThemeData.height] to define a button's
/// minimum height.
///
/// If null then it will use the surrounding [ButtonBarThemeData.buttonHeight].
/// If that is null, it will default to 36.0 logical pixels.
final double? buttonHeight;
final double buttonHeight;
/// Overrides the surrounding [ButtonThemeData.padding] to define the padding
/// for a button's child (typically the button's label).
@ -111,14 +113,14 @@ class ButtonBar extends StatelessWidget {
/// If null then it will use the surrounding [ButtonBarThemeData.buttonPadding].
/// If that is null, it will default to 8.0 logical pixels on the left
/// and right.
final EdgeInsetsGeometry? buttonPadding;
final EdgeInsetsGeometry buttonPadding;
/// Overrides the surrounding [ButtonThemeData.alignedDropdown] to define whether
/// a [DropdownButton] menu's width will match the button's width.
///
/// If null then it will use the surrounding [ButtonBarThemeData.buttonAlignedDropdown].
/// If that is null, it will default to false.
final bool? buttonAlignedDropdown;
final bool buttonAlignedDropdown;
/// Defines whether a [ButtonBar] should size itself with a minimum size
/// constraint or with padding.
@ -127,7 +129,7 @@ class ButtonBar extends StatelessWidget {
///
/// If null then it will use the surrounding [ButtonBarThemeData.layoutBehavior].
/// If that is null, it will default [ButtonBarLayoutBehavior.padded].
final ButtonBarLayoutBehavior? layoutBehavior;
final ButtonBarLayoutBehavior layoutBehavior;
/// Defines the vertical direction of a [ButtonBar]'s children if it
/// overflows.
@ -143,7 +145,7 @@ class ButtonBar extends StatelessWidget {
/// If null then it will use the surrounding
/// [ButtonBarThemeData.overflowDirection]. If that is null, it will
/// default to [VerticalDirection.down].
final VerticalDirection? overflowDirection;
final VerticalDirection overflowDirection;
/// The spacing between buttons when the button bar overflows.
///
@ -159,7 +161,7 @@ class ButtonBar extends StatelessWidget {
///
/// If null then no spacing will be added in between buttons in
/// an overflow state.
final double? overflowButtonSpacing;
final double overflowButtonSpacing;
/// The buttons to arrange horizontally.
///
@ -214,6 +216,8 @@ class ButtonBar extends StatelessWidget {
child: child,
);
}
assert(false);
return null;
}
}
@ -235,14 +239,14 @@ class _ButtonBarRow extends Flex {
/// Creates a button bar that attempts to display in a row, but displays in
/// a column if there is insufficient horizontal space.
_ButtonBarRow({
required List<Widget> children,
List<Widget> children,
Axis direction = Axis.horizontal,
MainAxisSize mainAxisSize = MainAxisSize.max,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection? textDirection,
TextDirection textDirection,
VerticalDirection overflowDirection = VerticalDirection.down,
TextBaseline? textBaseline,
TextBaseline textBaseline,
this.overflowButtonSpacing,
}) : super(
children: children,
@ -255,7 +259,7 @@ class _ButtonBarRow extends Flex {
textBaseline: textBaseline,
);
final double? overflowButtonSpacing;
final double overflowButtonSpacing;
@override
_RenderButtonBarRow createRenderObject(BuildContext context) {
@ -264,7 +268,7 @@ class _ButtonBarRow extends Flex {
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
textDirection: getEffectiveTextDirection(context)!,
textDirection: getEffectiveTextDirection(context),
verticalDirection: verticalDirection,
textBaseline: textBaseline,
overflowButtonSpacing: overflowButtonSpacing,
@ -303,14 +307,14 @@ class _RenderButtonBarRow extends RenderFlex {
/// Creates a button bar that attempts to display in a row, but displays in
/// a column if there is insufficient horizontal space.
_RenderButtonBarRow({
List<RenderBox>? children,
List<RenderBox> children,
Axis direction = Axis.horizontal,
MainAxisSize mainAxisSize = MainAxisSize.max,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
required TextDirection textDirection,
@required TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline? textBaseline,
TextBaseline textBaseline,
this.overflowButtonSpacing,
}) : assert(textDirection != null),
assert(overflowButtonSpacing == null || overflowButtonSpacing >= 0),
@ -326,13 +330,13 @@ class _RenderButtonBarRow extends RenderFlex {
);
bool _hasCheckedLayoutWidth = false;
double? overflowButtonSpacing;
double overflowButtonSpacing;
@override
BoxConstraints get constraints {
if (_hasCheckedLayoutWidth)
return super.constraints;
return super.constraints.copyWith(maxWidth: double.infinity);
return super.constraints?.copyWith(maxWidth: double.infinity);
}
@override
@ -355,7 +359,7 @@ class _RenderButtonBarRow extends RenderFlex {
super.performLayout();
} else {
final BoxConstraints childConstraints = constraints.copyWith(minWidth: 0.0);
RenderBox? child;
RenderBox child;
double currentHeight = 0.0;
switch (verticalDirection) {
case VerticalDirection.down:
@ -377,7 +381,7 @@ class _RenderButtonBarRow extends RenderFlex {
// alignment for a row. For [MainAxisAlignment.spaceAround],
// [MainAxisAlignment.spaceBetween] and [MainAxisAlignment.spaceEvenly]
// cases, use [MainAxisAlignment.start].
switch (textDirection!) {
switch (textDirection) {
case TextDirection.ltr:
switch (mainAxisAlignment) {
case MainAxisAlignment.center:
@ -418,7 +422,7 @@ class _RenderButtonBarRow extends RenderFlex {
}
if (overflowButtonSpacing != null && child != null)
currentHeight += overflowButtonSpacing!;
currentHeight += overflowButtonSpacing;
}
size = constraints.constrain(Size(constraints.maxWidth, currentHeight));
}

View file

@ -2,6 +2,8 @@
// 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' show lerpDouble;
import 'package:flutter/foundation.dart';
@ -44,10 +46,10 @@ class ButtonBarThemeData with Diagnosticable {
assert(buttonHeight == null || buttonHeight >= 0.0);
/// How the children should be placed along the horizontal axis.
final MainAxisAlignment? alignment;
final MainAxisAlignment alignment;
/// How much horizontal space is available. See [Row.mainAxisSize].
final MainAxisSize? mainAxisSize;
final MainAxisSize mainAxisSize;
/// Defines a [ButtonBar] button's base colors, and the defaults for
/// the button's minimum size, internal padding, and shape.
@ -57,7 +59,7 @@ class ButtonBarThemeData with Diagnosticable {
///
/// Despite the name, this property is not a [TextTheme], its value is not a
/// collection of [TextStyle]s.
final ButtonTextTheme? buttonTextTheme;
final ButtonTextTheme buttonTextTheme;
/// The minimum width for [ButtonBar] buttons.
///
@ -66,19 +68,19 @@ class ButtonBarThemeData with Diagnosticable {
///
/// The actual horizontal space allocated for a button's child is
/// at least this value less the theme's horizontal [ButtonThemeData.padding].
final double? buttonMinWidth;
final double buttonMinWidth;
/// The minimum height for [ButtonBar] buttons.
///
/// This will override the surrounding [ButtonThemeData.height] setting
/// for buttons contained in the [ButtonBar].
final double? buttonHeight;
final double buttonHeight;
/// Padding for a [ButtonBar] button's child (typically the button's label).
///
/// This will override the surrounding [ButtonThemeData.padding] setting
/// for buttons contained in the [ButtonBar].
final EdgeInsetsGeometry? buttonPadding;
final EdgeInsetsGeometry buttonPadding;
/// If true, then a [DropdownButton] menu's width will match the [ButtonBar]
/// button's width.
@ -93,11 +95,11 @@ class ButtonBarThemeData with Diagnosticable {
///
/// This property only affects [DropdownButton] contained in a [ButtonBar]
/// and its menu.
final bool? buttonAlignedDropdown;
final bool buttonAlignedDropdown;
/// Defines whether a [ButtonBar] should size itself with a minimum size
/// constraint or with padding.
final ButtonBarLayoutBehavior? layoutBehavior;
final ButtonBarLayoutBehavior layoutBehavior;
/// Defines the vertical direction of a [ButtonBar]'s children if it
/// overflows.
@ -109,20 +111,20 @@ class ButtonBarThemeData with Diagnosticable {
/// the first action will be at the bottom of the column if this
/// property is set to [VerticalDirection.up], since it "starts" at the
/// bottom and "ends" at the top.
final VerticalDirection? overflowDirection;
final VerticalDirection overflowDirection;
/// Creates a copy of this object but with the given fields replaced with the
/// new values.
ButtonBarThemeData copyWith({
MainAxisAlignment? alignment,
MainAxisSize? mainAxisSize,
ButtonTextTheme? buttonTextTheme,
double? buttonMinWidth,
double? buttonHeight,
EdgeInsetsGeometry? buttonPadding,
bool? buttonAlignedDropdown,
ButtonBarLayoutBehavior? layoutBehavior,
VerticalDirection? overflowDirection,
MainAxisAlignment alignment,
MainAxisSize mainAxisSize,
ButtonTextTheme buttonTextTheme,
double buttonMinWidth,
double buttonHeight,
EdgeInsetsGeometry buttonPadding,
bool buttonAlignedDropdown,
ButtonBarLayoutBehavior layoutBehavior,
VerticalDirection overflowDirection,
}) {
return ButtonBarThemeData(
alignment: alignment ?? this.alignment,
@ -142,20 +144,20 @@ class ButtonBarThemeData with Diagnosticable {
/// If both arguments are null, then null is returned.
///
/// {@macro dart.ui.shadow.lerp}
static ButtonBarThemeData? lerp(ButtonBarThemeData? a, ButtonBarThemeData? b, double t) {
static ButtonBarThemeData lerp(ButtonBarThemeData a, ButtonBarThemeData b, double t) {
assert(t != null);
if (a == null && b == null)
return null;
return ButtonBarThemeData(
alignment: t < 0.5 ? a?.alignment : b?.alignment,
mainAxisSize: t < 0.5 ? a?.mainAxisSize : b?.mainAxisSize,
buttonTextTheme: t < 0.5 ? a?.buttonTextTheme : b?.buttonTextTheme,
alignment: t < 0.5 ? a.alignment : b.alignment,
mainAxisSize: t < 0.5 ? a.mainAxisSize : b.mainAxisSize,
buttonTextTheme: t < 0.5 ? a.buttonTextTheme : b.buttonTextTheme,
buttonMinWidth: lerpDouble(a?.buttonMinWidth, b?.buttonMinWidth, t),
buttonHeight: lerpDouble(a?.buttonHeight, b?.buttonHeight, t),
buttonPadding: EdgeInsetsGeometry.lerp(a?.buttonPadding, b?.buttonPadding, t),
buttonAlignedDropdown: t < 0.5 ? a?.buttonAlignedDropdown : b?.buttonAlignedDropdown,
layoutBehavior: t < 0.5 ? a?.layoutBehavior : b?.layoutBehavior,
overflowDirection: t < 0.5 ? a?.overflowDirection : b?.overflowDirection,
buttonAlignedDropdown: t < 0.5 ? a.buttonAlignedDropdown : b.buttonAlignedDropdown,
layoutBehavior: t < 0.5 ? a.layoutBehavior : b.layoutBehavior,
overflowDirection: t < 0.5 ? a.overflowDirection : b.overflowDirection,
);
}
@ -233,9 +235,9 @@ class ButtonBarTheme extends InheritedWidget {
///
/// The [data] must not be null.
const ButtonBarTheme({
Key? key,
required this.data,
required Widget child,
Key key,
@required this.data,
Widget child,
}) : assert(data != null), super(key: key, child: child);
/// The properties used for all descendant [ButtonBar] widgets.
@ -251,8 +253,8 @@ class ButtonBarTheme extends InheritedWidget {
/// ButtonBarThemeData theme = ButtonBarTheme.of(context);
/// ```
static ButtonBarThemeData of(BuildContext context) {
final ButtonBarTheme? buttonBarTheme = context.dependOnInheritedWidgetOfExactType<ButtonBarTheme>();
return buttonBarTheme?.data ?? Theme.of(context)!.buttonBarTheme;
final ButtonBarTheme buttonBarTheme = context.dependOnInheritedWidgetOfExactType<ButtonBarTheme>();
return buttonBarTheme?.data ?? Theme.of(context).buttonBarTheme;
}
@override

View file

@ -2,6 +2,8 @@
// 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' show lerpDouble;
import 'package:flutter/foundation.dart';
@ -120,10 +122,10 @@ class ButtonStyle with Diagnosticable {
///
/// The color of the [textStyle] is typically not used directly, the
/// [foregroundColor] is used instead.
final MaterialStateProperty<TextStyle>? textStyle;
final MaterialStateProperty<TextStyle> textStyle;
/// The button's background fill color.
final MaterialStateProperty<Color>? backgroundColor;
final MaterialStateProperty<Color> backgroundColor;
/// The color for the button's [Text] and [Icon] widget descendants.
///
@ -131,11 +133,11 @@ class ButtonStyle with Diagnosticable {
/// of the components that compute defaults from [ButtonStyle] values
/// compute a default [foregroundColor] and use that instead of the
/// [textStyle]'s color.
final MaterialStateProperty<Color>? foregroundColor;
final MaterialStateProperty<Color> foregroundColor;
/// The highlight color that's typically used to indicate that
/// the button is focused, hovered, or pressed.
final MaterialStateProperty<Color>? overlayColor;
final MaterialStateProperty<Color> overlayColor;
/// The shadow color of the button's [Material].
///
@ -143,35 +145,35 @@ class ButtonStyle with Diagnosticable {
/// dark themes, so by default the button classes add a
/// semi-transparent overlay to indicate elevation. See
/// [ThemeData.applyElevationOverlayColor].
final MaterialStateProperty<Color>? shadowColor;
final MaterialStateProperty<Color> shadowColor;
/// The elevation of the button's [Material].
final MaterialStateProperty<double>? elevation;
final MaterialStateProperty<double> elevation;
/// The padding between the button's boundary and its child.
final MaterialStateProperty<EdgeInsetsGeometry>? padding;
final MaterialStateProperty<EdgeInsetsGeometry> padding;
/// The minimum size of the button itself.
///
/// The size of the rectangle the button lies within may be larger
/// per [tapTargetSize].
final MaterialStateProperty<Size>? minimumSize;
final MaterialStateProperty<Size> minimumSize;
/// The color and weight of the button's outline.
///
/// This value is combined with [shape] to create a shape decorated
/// with an outline.
final MaterialStateProperty<BorderSide>? side;
final MaterialStateProperty<BorderSide> side;
/// The shape of the button's underlying [Material].
///
/// This shape is combined with [side] to create a shape decorated
/// with an outline.
final MaterialStateProperty<OutlinedBorder>? shape;
final MaterialStateProperty<OutlinedBorder> shape;
/// The cursor for a mouse pointer when it enters or is hovering over
/// this button's [InkWell].
final MaterialStateProperty<MouseCursor>? mouseCursor;
final MaterialStateProperty<MouseCursor> mouseCursor;
/// Defines how compact the button's layout will be.
///
@ -181,7 +183,7 @@ class ButtonStyle with Diagnosticable {
///
/// * [ThemeData.visualDensity], which specifies the [visualDensity] for all widgets
/// within a [Theme].
final VisualDensity? visualDensity;
final VisualDensity visualDensity;
/// Configures the minimum size of the area within which the button may be pressed.
///
@ -189,12 +191,12 @@ class ButtonStyle with Diagnosticable {
/// a transparent margin that responds to taps.
///
/// Always defaults to [ThemeData.materialTapTargetSize].
final MaterialTapTargetSize? tapTargetSize;
final MaterialTapTargetSize tapTargetSize;
/// Defines the duration of animated changes for [shape] and [elevation].
///
/// Typically the component default value is [kThemeChangeDuration].
final Duration? animationDuration;
final Duration animationDuration;
/// Whether detected gestures should provide acoustic and/or haptic feedback.
///
@ -206,26 +208,26 @@ class ButtonStyle with Diagnosticable {
/// See also:
///
/// * [Feedback] for providing platform-specific feedback to certain actions.
final bool? enableFeedback;
final bool enableFeedback;
/// Returns a copy of this ButtonStyle with the given fields replaced with
/// the new values.
ButtonStyle copyWith({
MaterialStateProperty<TextStyle>? textStyle,
MaterialStateProperty<Color>? backgroundColor,
MaterialStateProperty<Color>? foregroundColor,
MaterialStateProperty<Color>? overlayColor,
MaterialStateProperty<Color>? shadowColor,
MaterialStateProperty<double>? elevation,
MaterialStateProperty<EdgeInsetsGeometry>? padding,
MaterialStateProperty<Size>? minimumSize,
MaterialStateProperty<BorderSide>? side,
MaterialStateProperty<OutlinedBorder>? shape,
MaterialStateProperty<MouseCursor>? mouseCursor,
VisualDensity? visualDensity,
MaterialTapTargetSize? tapTargetSize,
Duration? animationDuration,
bool? enableFeedback,
MaterialStateProperty<TextStyle> textStyle,
MaterialStateProperty<Color> backgroundColor,
MaterialStateProperty<Color> foregroundColor,
MaterialStateProperty<Color> overlayColor,
MaterialStateProperty<Color> shadowColor,
MaterialStateProperty<double> elevation,
MaterialStateProperty<EdgeInsetsGeometry> padding,
MaterialStateProperty<Size> minimumSize,
MaterialStateProperty<BorderSide> side,
MaterialStateProperty<OutlinedBorder> shape,
MaterialStateProperty<MouseCursor> mouseCursor,
VisualDensity visualDensity,
MaterialTapTargetSize tapTargetSize,
Duration animationDuration,
bool enableFeedback,
}) {
return ButtonStyle(
textStyle: textStyle ?? this.textStyle,
@ -251,7 +253,7 @@ class ButtonStyle with Diagnosticable {
///
/// In other words, [style] is used to fill in unspecified (null) fields
/// this ButtonStyle.
ButtonStyle merge(ButtonStyle? style) {
ButtonStyle merge(ButtonStyle style) {
if (style == null)
return this;
return copyWith(
@ -339,7 +341,7 @@ class ButtonStyle with Diagnosticable {
}
/// Linearly interpolate between two [ButtonStyle]s.
static ButtonStyle? lerp(ButtonStyle? a, ButtonStyle? b, double t) {
static ButtonStyle lerp(ButtonStyle a, ButtonStyle b, double t) {
assert (t != null);
if (a == null && b == null)
return null;
@ -354,15 +356,15 @@ class ButtonStyle with Diagnosticable {
minimumSize: _lerpProperties<Size>(a?.minimumSize, b?.minimumSize, t, Size.lerp),
side: _lerpSides(a?.side, b?.side, t),
shape: _lerpShapes(a?.shape, b?.shape, t),
mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
visualDensity: t < 0.5 ? a?.visualDensity : b?.visualDensity,
tapTargetSize: t < 0.5 ? a?.tapTargetSize : b?.tapTargetSize,
animationDuration: t < 0.5 ? a?.animationDuration : b?.animationDuration,
enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
mouseCursor: t < 0.5 ? a.mouseCursor : b.mouseCursor,
visualDensity: t < 0.5 ? a.visualDensity : b.visualDensity,
tapTargetSize: t < 0.5 ? a.tapTargetSize : b.tapTargetSize,
animationDuration: t < 0.5 ? a.animationDuration : b.animationDuration,
enableFeedback: t < 0.5 ? a.enableFeedback : b.enableFeedback,
);
}
static MaterialStateProperty<T>? _lerpProperties<T>(MaterialStateProperty<T>? a, MaterialStateProperty<T>? b, double t, T? Function(T?, T?, double) lerpFunction ) {
static MaterialStateProperty<T> _lerpProperties<T>(MaterialStateProperty<T> a, MaterialStateProperty<T> b, double t, T Function(T, T, double) lerpFunction ) {
// Avoid creating a _LerpProperties object for a common case.
if (a == null && b == null)
return null;
@ -370,14 +372,14 @@ class ButtonStyle with Diagnosticable {
}
// Special case because BorderSide.lerp() doesn't support null arguments
static MaterialStateProperty<BorderSide>? _lerpSides(MaterialStateProperty<BorderSide>? a, MaterialStateProperty<BorderSide>? b, double t) {
static MaterialStateProperty<BorderSide> _lerpSides(MaterialStateProperty<BorderSide> a, MaterialStateProperty<BorderSide> b, double t) {
if (a == null && b == null)
return null;
return _LerpSides(a, b, t);
}
// TODO(hansmuller): OutlinedBorder needs a lerp method - https://github.com/flutter/flutter/issues/60555.
static MaterialStateProperty<OutlinedBorder>? _lerpShapes(MaterialStateProperty<OutlinedBorder>? a, MaterialStateProperty<OutlinedBorder>? b, double t) {
static MaterialStateProperty<OutlinedBorder> _lerpShapes(MaterialStateProperty<OutlinedBorder> a, MaterialStateProperty<OutlinedBorder> b, double t) {
if (a == null && b == null)
return null;
return _LerpShapes(a, b, t);
@ -387,15 +389,15 @@ class ButtonStyle with Diagnosticable {
class _LerpProperties<T> implements MaterialStateProperty<T> {
const _LerpProperties(this.a, this.b, this.t, this.lerpFunction);
final MaterialStateProperty<T>? a;
final MaterialStateProperty<T>? b;
final MaterialStateProperty<T> a;
final MaterialStateProperty<T> b;
final double t;
final T? Function(T?, T?, double) lerpFunction;
final T Function(T, T, double) lerpFunction;
@override
T? resolve(Set<MaterialState> states) {
final T? resolvedA = a?.resolve(states);
final T? resolvedB = b?.resolve(states);
T resolve(Set<MaterialState> states) {
final T resolvedA = a?.resolve(states);
final T resolvedB = b?.resolve(states);
return lerpFunction(resolvedA, resolvedB, t);
}
}
@ -403,18 +405,18 @@ class _LerpProperties<T> implements MaterialStateProperty<T> {
class _LerpSides implements MaterialStateProperty<BorderSide> {
const _LerpSides(this.a, this.b, this.t);
final MaterialStateProperty<BorderSide>? a;
final MaterialStateProperty<BorderSide>? b;
final MaterialStateProperty<BorderSide> a;
final MaterialStateProperty<BorderSide> b;
final double t;
@override
BorderSide? resolve(Set<MaterialState> states) {
final BorderSide? resolvedA = a?.resolve(states);
final BorderSide? resolvedB = b?.resolve(states);
BorderSide resolve(Set<MaterialState> states) {
final BorderSide resolvedA = a?.resolve(states);
final BorderSide resolvedB = b?.resolve(states);
if (resolvedA == null && resolvedB == null)
return null;
if (resolvedA == null)
return BorderSide.lerp(BorderSide(width: 0, color: resolvedB!.color.withAlpha(0)), resolvedB, t);
return BorderSide.lerp(BorderSide(width: 0, color: resolvedB.color.withAlpha(0)), resolvedB, t);
if (resolvedB == null)
return BorderSide.lerp(BorderSide(width: 0, color: resolvedA.color.withAlpha(0)), resolvedA, t);
return BorderSide.lerp(resolvedA, resolvedB, t);
@ -424,14 +426,14 @@ class _LerpSides implements MaterialStateProperty<BorderSide> {
class _LerpShapes implements MaterialStateProperty<OutlinedBorder> {
const _LerpShapes(this.a, this.b, this.t);
final MaterialStateProperty<OutlinedBorder>? a;
final MaterialStateProperty<OutlinedBorder>? b;
final MaterialStateProperty<OutlinedBorder> a;
final MaterialStateProperty<OutlinedBorder> b;
final double t;
@override
OutlinedBorder? resolve(Set<MaterialState> states) {
final OutlinedBorder? resolvedA = a?.resolve(states);
final OutlinedBorder? resolvedB = b?.resolve(states);
return ShapeBorder.lerp(resolvedA, resolvedB, t) as OutlinedBorder?;
OutlinedBorder resolve(Set<MaterialState> states) {
final OutlinedBorder resolvedA = a?.resolve(states);
final OutlinedBorder resolvedB = b?.resolve(states);
return ShapeBorder.lerp(resolvedA, resolvedB, t) as OutlinedBorder;
}
}

View file

@ -2,6 +2,8 @@
// 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';
@ -30,14 +32,14 @@ import 'theme_data.dart';
abstract class ButtonStyleButton extends StatefulWidget {
/// Create a [ButtonStyleButton].
const ButtonStyleButton({
Key? key,
required this.onPressed,
required this.onLongPress,
required this.style,
required this.focusNode,
required this.autofocus,
required this.clipBehavior,
required this.child,
Key key,
@required this.onPressed,
@required this.onLongPress,
@required this.style,
@required this.focusNode,
@required this.autofocus,
@required this.clipBehavior,
@required this.child,
}) : assert(autofocus != null),
assert(clipBehavior != null),
super(key: key);
@ -49,7 +51,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback? onPressed;
final VoidCallback onPressed;
/// Called when the button is long-pressed.
///
@ -58,7 +60,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback? onLongPress;
final VoidCallback onLongPress;
/// Customizes this button's appearance.
///
@ -68,7 +70,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
/// [MaterialStateProperty]s in [themeStyleOf] and [defaultStyleOf].
///
/// Null by default.
final ButtonStyle? style;
final ButtonStyle style;
/// {@macro flutter.widgets.Clip}
///
@ -76,13 +78,13 @@ abstract class ButtonStyleButton extends StatefulWidget {
final Clip clipBehavior;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
/// Typically the button's label.
final Widget? child;
final Widget child;
/// Returns a non-null [ButtonStyle] that's based primarily on the [Theme]'s
/// [ThemeData.textTheme] and [ThemeData.colorScheme].
@ -115,7 +117,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
///
/// * [defaultStyleOf], Returns the default [ButtonStyle] for this button.
@protected
ButtonStyle? themeStyleOf(BuildContext context);
ButtonStyle themeStyleOf(BuildContext context);
/// Whether the button is enabled or disabled.
///
@ -137,7 +139,7 @@ abstract class ButtonStyleButton extends StatefulWidget {
/// Returns null if [value] is null, otherwise `MaterialStateProperty.all<T>(value)`.
///
/// A convenience method for subclasses.
static MaterialStateProperty<T>? allOrNull<T>(T? value) => value == null ? null : MaterialStateProperty.all<T>(value);
static MaterialStateProperty<T> allOrNull<T>(T value) => value == null ? null : MaterialStateProperty.all<T>(value);
/// Returns an interpolated value based on the [textScaleFactor] parameter:
///
@ -163,9 +165,9 @@ abstract class ButtonStyleButton extends StatefulWidget {
} else if (textScaleFactor >= 3) {
return geometry3x;
} else if (textScaleFactor <= 2) {
return EdgeInsetsGeometry.lerp(geometry1x, geometry2x, textScaleFactor - 1)!;
return EdgeInsetsGeometry.lerp(geometry1x, geometry2x, textScaleFactor - 1);
}
return EdgeInsetsGeometry.lerp(geometry2x, geometry3x, textScaleFactor - 2)!;
return EdgeInsetsGeometry.lerp(geometry2x, geometry3x, textScaleFactor - 2);
}
}
@ -178,9 +180,9 @@ abstract class ButtonStyleButton extends StatefulWidget {
/// * [ElevatedButton], a filled button whose material elevates when pressed.
/// * [OutlinedButton], similar to [TextButton], but with an outline.
class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStateMixin {
AnimationController? _controller;
double? _elevation;
Color? _backgroundColor;
AnimationController _controller;
double _elevation;
Color _backgroundColor;
final Set<MaterialState> _states = <MaterialState>{};
bool get _hovered => _states.contains(MaterialState.hovered);
@ -243,54 +245,54 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
@override
Widget build(BuildContext context) {
final ButtonStyle? widgetStyle = widget.style;
final ButtonStyle? themeStyle = widget.themeStyleOf(context);
final ButtonStyle widgetStyle = widget.style;
final ButtonStyle themeStyle = widget.themeStyleOf(context);
final ButtonStyle defaultStyle = widget.defaultStyleOf(context);
assert(defaultStyle != null);
T? effectiveValue<T>(T? Function(ButtonStyle? style) getProperty) {
final T? widgetValue = getProperty(widgetStyle);
final T? themeValue = getProperty(themeStyle);
final T? defaultValue = getProperty(defaultStyle);
T effectiveValue<T>(T Function(ButtonStyle style) getProperty) {
final T widgetValue = getProperty(widgetStyle);
final T themeValue = getProperty(themeStyle);
final T defaultValue = getProperty(defaultStyle);
return widgetValue ?? themeValue ?? defaultValue;
}
T? resolve<T>(MaterialStateProperty<T>? Function(ButtonStyle? style) getProperty) {
T resolve<T>(MaterialStateProperty<T> Function(ButtonStyle style) getProperty) {
return effectiveValue(
(ButtonStyle? style) => getProperty(style)?.resolve(_states),
(ButtonStyle style) => getProperty(style)?.resolve(_states),
);
}
final double? resolvedElevation = resolve<double>((ButtonStyle? style) => style?.elevation);
final TextStyle? resolvedTextStyle = resolve<TextStyle>((ButtonStyle? style) => style?.textStyle);
Color? resolvedBackgroundColor = resolve<Color>((ButtonStyle? style) => style?.backgroundColor);
final Color? resolvedForegroundColor = resolve<Color>((ButtonStyle? style) => style?.foregroundColor);
final Color? resolvedShadowColor = resolve<Color>((ButtonStyle? style) => style?.shadowColor);
final EdgeInsetsGeometry? resolvedPadding = resolve<EdgeInsetsGeometry>((ButtonStyle? style) => style?.padding);
final Size? resolvedMinimumSize = resolve<Size>((ButtonStyle? style) => style?.minimumSize);
final BorderSide? resolvedSide = resolve<BorderSide>((ButtonStyle? style) => style?.side);
final OutlinedBorder? resolvedShape = resolve<OutlinedBorder>((ButtonStyle? style) => style?.shape);
final double resolvedElevation = resolve<double>((ButtonStyle style) => style?.elevation);
final TextStyle resolvedTextStyle = resolve<TextStyle>((ButtonStyle style) => style?.textStyle);
Color resolvedBackgroundColor = resolve<Color>((ButtonStyle style) => style?.backgroundColor);
final Color resolvedForegroundColor = resolve<Color>((ButtonStyle style) => style?.foregroundColor);
final Color resolvedShadowColor = resolve<Color>((ButtonStyle style) => style?.shadowColor);
final EdgeInsetsGeometry resolvedPadding = resolve<EdgeInsetsGeometry>((ButtonStyle style) => style?.padding);
final Size resolvedMinimumSize = resolve<Size>((ButtonStyle style) => style?.minimumSize);
final BorderSide resolvedSide = resolve<BorderSide>((ButtonStyle style) => style?.side);
final OutlinedBorder resolvedShape = resolve<OutlinedBorder>((ButtonStyle style) => style?.shape);
final MaterialStateMouseCursor resolvedMouseCursor = _MouseCursor(
(Set<MaterialState> states) => effectiveValue((ButtonStyle? style) => style?.mouseCursor?.resolve(states)),
(Set<MaterialState> states) => effectiveValue((ButtonStyle style) => style?.mouseCursor?.resolve(states)),
);
final MaterialStateProperty<Color> overlayColor = MaterialStateProperty.resolveWith<Color>(
(Set<MaterialState> states) => effectiveValue((ButtonStyle? style) => style?.overlayColor?.resolve(states)),
(Set<MaterialState> states) => effectiveValue((ButtonStyle style) => style?.overlayColor?.resolve(states)),
);
final VisualDensity? resolvedVisualDensity = effectiveValue((ButtonStyle? style) => style?.visualDensity);
final MaterialTapTargetSize? resolvedTapTargetSize = effectiveValue((ButtonStyle? style) => style?.tapTargetSize);
final Duration? resolvedAnimationDuration = effectiveValue((ButtonStyle? style) => style?.animationDuration);
final bool? resolvedEnableFeedback = effectiveValue((ButtonStyle? style) => style?.enableFeedback);
final Offset densityAdjustment = resolvedVisualDensity!.baseSizeAdjustment;
final VisualDensity resolvedVisualDensity = effectiveValue((ButtonStyle style) => style?.visualDensity);
final MaterialTapTargetSize resolvedTapTargetSize = effectiveValue((ButtonStyle style) => style?.tapTargetSize);
final Duration resolvedAnimationDuration = effectiveValue((ButtonStyle style) => style?.animationDuration);
final bool resolvedEnableFeedback = effectiveValue((ButtonStyle style) => style?.enableFeedback);
final Offset densityAdjustment = resolvedVisualDensity.baseSizeAdjustment;
final BoxConstraints effectiveConstraints = resolvedVisualDensity.effectiveConstraints(
BoxConstraints(
minWidth: resolvedMinimumSize!.width,
minWidth: resolvedMinimumSize.width,
minHeight: resolvedMinimumSize.height,
),
);
final EdgeInsetsGeometry padding = resolvedPadding!.add(
final EdgeInsetsGeometry padding = resolvedPadding.add(
EdgeInsets.only(
left: densityAdjustment.dx,
top: densityAdjustment.dy,
@ -303,12 +305,12 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
// elevation is changing, change the elevation first. Material implicitly
// animates its elevation but not its color. SKIA renders non-zero
// elevations as a shadow colored fill behind the Material's background.
if (resolvedAnimationDuration! > Duration.zero
if (resolvedAnimationDuration > Duration.zero
&& _elevation != null
&& _backgroundColor != null
&& _elevation != resolvedElevation
&& _backgroundColor!.value != resolvedBackgroundColor!.value
&& _backgroundColor!.opacity == 1
&& _backgroundColor.value != resolvedBackgroundColor.value
&& _backgroundColor.opacity == 1
&& resolvedBackgroundColor.opacity < 1
&& resolvedElevation == 0) {
if (_controller?.duration != resolvedAnimationDuration) {
@ -324,8 +326,8 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
});
}
resolvedBackgroundColor = _backgroundColor; // Defer changing the background color.
_controller!.value = 0;
_controller!.forward();
_controller.value = 0;
_controller.forward();
}
_elevation = resolvedElevation;
_backgroundColor = resolvedBackgroundColor;
@ -333,9 +335,9 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
final Widget result = ConstrainedBox(
constraints: effectiveConstraints,
child: Material(
elevation: resolvedElevation!,
elevation: resolvedElevation,
textStyle: resolvedTextStyle?.copyWith(color: resolvedForegroundColor),
shape: resolvedShape!.copyWith(side: resolvedSide),
shape: resolvedShape.copyWith(side: resolvedSide),
color: resolvedBackgroundColor,
shadowColor: resolvedShadowColor,
type: resolvedBackgroundColor == null ? MaterialType.transparency : MaterialType.button,
@ -372,7 +374,7 @@ class _ButtonStyleState extends State<ButtonStyleButton> with TickerProviderStat
);
Size minSize;
switch (resolvedTapTargetSize!) {
switch (resolvedTapTargetSize) {
case MaterialTapTargetSize.padded:
minSize = Size(
kMinInteractiveDimension + densityAdjustment.dx,
@ -404,7 +406,7 @@ class _MouseCursor extends MaterialStateMouseCursor {
final MaterialPropertyResolver<MouseCursor> resolveCallback;
@override
MouseCursor? resolve(Set<MaterialState> states) => resolveCallback(states);
MouseCursor resolve(Set<MaterialState> states) => resolveCallback(states);
@override
String get debugDescription => 'ButtonStyleButton_MouseCursor';
@ -417,9 +419,9 @@ class _MouseCursor extends MaterialStateMouseCursor {
/// "tap target", but not its material or its ink splashes.
class _InputPadding extends SingleChildRenderObjectWidget {
const _InputPadding({
Key? key,
Widget? child,
required this.minSize,
Key key,
Widget child,
this.minSize,
}) : super(key: key, child: child);
final Size minSize;
@ -436,7 +438,7 @@ class _InputPadding extends SingleChildRenderObjectWidget {
}
class _RenderInputPadding extends RenderShiftedBox {
_RenderInputPadding(this._minSize, [RenderBox? child]) : super(child);
_RenderInputPadding(this._minSize, [RenderBox child]) : super(child);
Size get minSize => _minSize;
Size _minSize;
@ -450,28 +452,28 @@ class _RenderInputPadding extends RenderShiftedBox {
@override
double computeMinIntrinsicWidth(double height) {
if (child != null)
return math.max(child!.getMinIntrinsicWidth(height), minSize.width);
return math.max(child.getMinIntrinsicWidth(height), minSize.width);
return 0.0;
}
@override
double computeMinIntrinsicHeight(double width) {
if (child != null)
return math.max(child!.getMinIntrinsicHeight(width), minSize.height);
return math.max(child.getMinIntrinsicHeight(width), minSize.height);
return 0.0;
}
@override
double computeMaxIntrinsicWidth(double height) {
if (child != null)
return math.max(child!.getMaxIntrinsicWidth(height), minSize.width);
return math.max(child.getMaxIntrinsicWidth(height), minSize.width);
return 0.0;
}
@override
double computeMaxIntrinsicHeight(double width) {
if (child != null)
return math.max(child!.getMaxIntrinsicHeight(width), minSize.height);
return math.max(child.getMaxIntrinsicHeight(width), minSize.height);
return 0.0;
}
@ -479,29 +481,29 @@ class _RenderInputPadding extends RenderShiftedBox {
void performLayout() {
final BoxConstraints constraints = this.constraints;
if (child != null) {
child!.layout(constraints, parentUsesSize: true);
final double height = math.max(child!.size.width, minSize.width);
final double width = math.max(child!.size.height, minSize.height);
child.layout(constraints, parentUsesSize: true);
final double height = math.max(child.size.width, minSize.width);
final double width = math.max(child.size.height, minSize.height);
size = constraints.constrain(Size(height, width));
final BoxParentData childParentData = child!.parentData as BoxParentData;
childParentData.offset = Alignment.center.alongOffset(size - child!.size as Offset);
final BoxParentData childParentData = child.parentData as BoxParentData;
childParentData.offset = Alignment.center.alongOffset(size - child.size as Offset);
} else {
size = Size.zero;
}
}
@override
bool hitTest(BoxHitTestResult result, { required Offset position }) {
bool hitTest(BoxHitTestResult result, { Offset position }) {
if (super.hitTest(result, position: position)) {
return true;
}
final Offset center = child!.size.center(Offset.zero);
final Offset center = child.size.center(Offset.zero);
return result.addWithRawTransform(
transform: MatrixUtils.forceToPoint(center),
position: center,
hitTest: (BoxHitTestResult result, Offset? position) {
hitTest: (BoxHitTestResult result, Offset position) {
assert(position == center);
return child!.hitTest(result, position: center);
return child.hitTest(result, position: center);
},
);
}

View file

@ -2,6 +2,8 @@
// 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';
@ -79,23 +81,23 @@ class ButtonTheme extends InheritedTheme {
/// The [textTheme], [minWidth], [height], and [colorScheme] arguments
/// must not be null.
ButtonTheme({
Key? key,
Key key,
ButtonTextTheme textTheme = ButtonTextTheme.normal,
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
double minWidth = 88.0,
double height = 36.0,
EdgeInsetsGeometry? padding,
ShapeBorder? shape,
EdgeInsetsGeometry padding,
ShapeBorder shape,
bool alignedDropdown = false,
Color? buttonColor,
Color? disabledColor,
Color? focusColor,
Color? hoverColor,
Color? highlightColor,
Color? splashColor,
ColorScheme? colorScheme,
MaterialTapTargetSize? materialTapTargetSize,
required Widget child,
Color buttonColor,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
ColorScheme colorScheme,
MaterialTapTargetSize materialTapTargetSize,
Widget child,
}) : assert(textTheme != null),
assert(minWidth != null && minWidth >= 0.0),
assert(height != null && height >= 0.0),
@ -124,9 +126,9 @@ class ButtonTheme extends InheritedTheme {
///
/// The [data] argument must not be null.
const ButtonTheme.fromButtonThemeData({
Key? key,
required this.data,
required Widget child,
Key key,
@required this.data,
Widget child,
}) : assert(data != null),
super(key: key, child: child);
@ -175,21 +177,21 @@ class ButtonTheme extends InheritedTheme {
'This feature was deprecated after v1.9.1.'
)
ButtonTheme.bar({
Key? key,
Key key,
ButtonTextTheme textTheme = ButtonTextTheme.accent,
double minWidth = 64.0,
double height = 36.0,
EdgeInsetsGeometry padding = const EdgeInsets.symmetric(horizontal: 8.0),
ShapeBorder? shape,
ShapeBorder shape,
bool alignedDropdown = false,
Color? buttonColor,
Color? disabledColor,
Color? focusColor,
Color? hoverColor,
Color? highlightColor,
Color? splashColor,
ColorScheme? colorScheme,
required Widget child,
Color buttonColor,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
ColorScheme colorScheme,
Widget child,
ButtonBarLayoutBehavior layoutBehavior = ButtonBarLayoutBehavior.padded,
}) : assert(textTheme != null),
assert(minWidth != null && minWidth >= 0.0),
@ -224,10 +226,10 @@ class ButtonTheme extends InheritedTheme {
/// ButtonThemeData theme = ButtonTheme.of(context);
/// ```
static ButtonThemeData of(BuildContext context) {
final ButtonTheme? inheritedButtonTheme = context.dependOnInheritedWidgetOfExactType<ButtonTheme>();
ButtonThemeData? buttonTheme = inheritedButtonTheme?.data;
final ButtonTheme inheritedButtonTheme = context.dependOnInheritedWidgetOfExactType<ButtonTheme>();
ButtonThemeData buttonTheme = inheritedButtonTheme?.data;
if (buttonTheme?.colorScheme == null) { // if buttonTheme or buttonTheme.colorScheme is null
final ThemeData theme = Theme.of(context)!;
final ThemeData theme = Theme.of(context);
buttonTheme ??= theme.buttonTheme;
if (buttonTheme.colorScheme == null) {
buttonTheme = buttonTheme.copyWith(
@ -236,12 +238,12 @@ class ButtonTheme extends InheritedTheme {
assert(buttonTheme.colorScheme != null);
}
}
return buttonTheme!;
return buttonTheme;
}
@override
Widget wrap(BuildContext context, Widget child) {
final ButtonTheme? ancestorTheme = context.findAncestorWidgetOfExactType<ButtonTheme>();
final ButtonTheme ancestorTheme = context.findAncestorWidgetOfExactType<ButtonTheme>();
return identical(this, ancestorTheme) ? child : ButtonTheme.fromButtonThemeData(data: data, child: child);
}
@ -287,18 +289,18 @@ class ButtonThemeData with Diagnosticable {
this.textTheme = ButtonTextTheme.normal,
this.minWidth = 88.0,
this.height = 36.0,
EdgeInsetsGeometry? padding,
ShapeBorder? shape,
EdgeInsetsGeometry padding,
ShapeBorder shape,
this.layoutBehavior = ButtonBarLayoutBehavior.padded,
this.alignedDropdown = false,
Color? buttonColor,
Color? disabledColor,
Color? focusColor,
Color? hoverColor,
Color? highlightColor,
Color? splashColor,
Color buttonColor,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
this.colorScheme,
MaterialTapTargetSize? materialTapTargetSize,
MaterialTapTargetSize materialTapTargetSize,
}) : assert(textTheme != null),
assert(minWidth != null && minWidth >= 0.0),
assert(height != null && height >= 0.0),
@ -367,7 +369,7 @@ class ButtonThemeData with Diagnosticable {
/// and [FlatButton].
EdgeInsetsGeometry get padding {
if (_padding != null)
return _padding!;
return _padding;
switch (textTheme) {
case ButtonTextTheme.normal:
case ButtonTextTheme.accent:
@ -375,8 +377,10 @@ class ButtonThemeData with Diagnosticable {
case ButtonTextTheme.primary:
return const EdgeInsets.symmetric(horizontal: 24.0);
}
assert(false);
return EdgeInsets.zero;
}
final EdgeInsetsGeometry? _padding;
final EdgeInsetsGeometry _padding;
/// The shape of a button's material.
///
@ -394,7 +398,7 @@ class ButtonThemeData with Diagnosticable {
/// and [FlatButton].
ShapeBorder get shape {
if (_shape != null)
return _shape!;
return _shape;
switch (textTheme) {
case ButtonTextTheme.normal:
case ButtonTextTheme.accent:
@ -406,8 +410,9 @@ class ButtonThemeData with Diagnosticable {
borderRadius: BorderRadius.all(Radius.circular(4.0)),
);
}
return const RoundedRectangleBorder();
}
final ShapeBorder? _shape;
final ShapeBorder _shape;
/// If true, then a [DropdownButton] menu's width will match the button's
/// width.
@ -432,7 +437,7 @@ class ButtonThemeData with Diagnosticable {
///
/// * [getFillColor], which is used by [RaisedButton] to compute its
/// background fill color.
final Color? _buttonColor;
final Color _buttonColor;
/// The background fill color for disabled [RaisedButton]s.
///
@ -442,7 +447,7 @@ class ButtonThemeData with Diagnosticable {
///
/// * [getDisabledFillColor], which is used by [RaisedButton] to compute its
/// background fill color.
final Color? _disabledColor;
final Color _disabledColor;
/// The fill color of the button when it has the input focus.
///
@ -455,7 +460,7 @@ class ButtonThemeData with Diagnosticable {
///
/// * [getFocusColor], which is used by [RaisedButton], [OutlineButton]
/// and [FlatButton].
final Color? _focusColor;
final Color _focusColor;
/// The fill color of the button when a pointer is hovering over it.
///
@ -468,7 +473,7 @@ class ButtonThemeData with Diagnosticable {
///
/// * [getHoverColor], which is used by [RaisedButton], [OutlineButton]
/// and [FlatButton].
final Color? _hoverColor;
final Color _hoverColor;
/// The color of the overlay that appears when a button is pressed.
///
@ -478,7 +483,7 @@ class ButtonThemeData with Diagnosticable {
///
/// * [getHighlightColor], which is used by [RaisedButton], [OutlineButton]
/// and [FlatButton].
final Color? _highlightColor;
final Color _highlightColor;
/// The color of the ink "splash" overlay that appears when a button is tapped.
///
@ -488,7 +493,7 @@ class ButtonThemeData with Diagnosticable {
///
/// * [getSplashColor], which is used by [RaisedButton], [OutlineButton]
/// and [FlatButton].
final Color? _splashColor;
final Color _splashColor;
/// A set of thirteen colors that can be used to derive the button theme's
/// colors.
@ -500,7 +505,7 @@ class ButtonThemeData with Diagnosticable {
/// The colors for new button classes can be defined exclusively in terms
/// of [colorScheme]. When it's possible, the existing buttons will
/// (continue to) gradually migrate to it.
final ColorScheme? colorScheme;
final ColorScheme colorScheme;
// The minimum size of a button's tap target.
//
@ -510,14 +515,14 @@ class ButtonThemeData with Diagnosticable {
//
// * [getMaterialTargetTapSize], which is used by [RaisedButton],
// [OutlineButton] and [FlatButton].
final MaterialTapTargetSize? _materialTapTargetSize;
final MaterialTapTargetSize _materialTapTargetSize;
/// The [button]'s overall brightness.
///
/// Returns the button's [MaterialButton.colorBrightness] if it is non-null,
/// otherwise the color scheme's [ColorScheme.brightness] is returned.
Brightness getBrightness(MaterialButton button) {
return button.colorBrightness ?? colorScheme!.brightness;
return button.colorBrightness ?? colorScheme.brightness;
}
/// Defines the [button]'s base colors, and the defaults for the button's
@ -540,10 +545,10 @@ class ButtonThemeData with Diagnosticable {
/// used as the `disabledTextColor`. It will be resolved in the [MaterialState.disabled] state.
Color getDisabledTextColor(MaterialButton button) {
if (button.textColor is MaterialStateProperty<Color>)
return button.textColor!;
return button.textColor;
if (button.disabledTextColor != null)
return button.disabledTextColor!;
return colorScheme!.onSurface.withOpacity(0.38);
return button.disabledTextColor;
return colorScheme.onSurface.withOpacity(0.38);
}
/// The [button]'s background color when [MaterialButton.onPressed] is null
@ -558,10 +563,10 @@ class ButtonThemeData with Diagnosticable {
/// with its opacity set to 0.38.
Color getDisabledFillColor(MaterialButton button) {
if (button.disabledColor != null)
return button.disabledColor!;
return button.disabledColor;
if (_disabledColor != null)
return _disabledColor!;
return colorScheme!.onSurface.withOpacity(0.38);
return _disabledColor;
return colorScheme.onSurface.withOpacity(0.38);
}
/// The button's background fill color or null for buttons that don't have
@ -589,8 +594,8 @@ class ButtonThemeData with Diagnosticable {
/// otherwise the color scheme's ColorScheme.primary color. If the button
/// is not enabled then the colorScheme's [ColorScheme.onSurface] color
/// with opacity 0.12.
Color? getFillColor(MaterialButton button) {
final Color? fillColor = button.enabled ? button.color : button.disabledColor;
Color getFillColor(MaterialButton button) {
final Color fillColor = button.enabled ? button.color : button.disabledColor;
if (fillColor != null)
return fillColor;
@ -603,12 +608,15 @@ class ButtonThemeData with Diagnosticable {
switch (getTextTheme(button)) {
case ButtonTextTheme.normal:
case ButtonTextTheme.accent:
return button.enabled ? colorScheme!.primary : getDisabledFillColor(button);
return button.enabled ? colorScheme.primary : getDisabledFillColor(button);
case ButtonTextTheme.primary:
return button.enabled
? _buttonColor ?? colorScheme!.primary
: colorScheme!.onSurface.withOpacity(0.12);
? _buttonColor ?? colorScheme.primary
: colorScheme.onSurface.withOpacity(0.12);
}
assert(false);
return null;
}
/// The foreground color of the [button]'s text and icon.
@ -633,26 +641,29 @@ class ButtonThemeData with Diagnosticable {
return getDisabledTextColor(button);
if (button.textColor != null)
return button.textColor!;
return button.textColor;
switch (getTextTheme(button)) {
case ButtonTextTheme.normal:
return getBrightness(button) == Brightness.dark ? Colors.white : Colors.black87;
case ButtonTextTheme.accent:
return colorScheme!.secondary;
return colorScheme.secondary;
case ButtonTextTheme.primary:
final Color? fillColor = getFillColor(button);
final Color fillColor = getFillColor(button);
final bool fillIsDark = fillColor != null
? ThemeData.estimateBrightnessForColor(fillColor) == Brightness.dark
: getBrightness(button) == Brightness.dark;
if (fillIsDark)
return Colors.white;
if (button is FlatButton || button is OutlineButton)
return colorScheme!.primary;
return colorScheme.primary;
return Colors.black;
}
assert(false);
return null;
}
/// The color of the ink "splash" overlay that appears when the (enabled)
@ -670,16 +681,16 @@ class ButtonThemeData with Diagnosticable {
/// Otherwise, returns [getTextColor] with an opacity of 0.12.
Color getSplashColor(MaterialButton button) {
if (button.splashColor != null)
return button.splashColor!;
return button.splashColor;
if (_splashColor != null && (button is RaisedButton || button is OutlineButton))
return _splashColor!;
return _splashColor;
if (_splashColor != null && button is FlatButton) {
switch (getTextTheme(button)) {
case ButtonTextTheme.normal:
case ButtonTextTheme.accent:
return _splashColor!;
return _splashColor;
case ButtonTextTheme.primary:
break;
}
@ -725,7 +736,7 @@ class ButtonThemeData with Diagnosticable {
/// * [ButtonTextTheme.primary], returns [Colors.transparent].
Color getHighlightColor(MaterialButton button) {
if (button.highlightColor != null)
return button.highlightColor!;
return button.highlightColor;
switch (getTextTheme(button)) {
case ButtonTextTheme.normal:
@ -734,6 +745,9 @@ class ButtonThemeData with Diagnosticable {
case ButtonTextTheme.primary:
return Colors.transparent;
}
assert(false);
return Colors.transparent;
}
/// The [button]'s elevation when it is enabled and has not been pressed.
@ -743,7 +757,7 @@ class ButtonThemeData with Diagnosticable {
/// If button is a [FlatButton] then elevation is 0.0, otherwise it is 2.0.
double getElevation(MaterialButton button) {
if (button.elevation != null)
return button.elevation!;
return button.elevation;
if (button is FlatButton)
return 0.0;
return 2.0;
@ -757,7 +771,7 @@ class ButtonThemeData with Diagnosticable {
/// elevation is 0.0, otherwise the highlight elevation is 4.0.
double getFocusElevation(MaterialButton button) {
if (button.focusElevation != null)
return button.focusElevation!;
return button.focusElevation;
if (button is FlatButton)
return 0.0;
if (button is OutlineButton)
@ -773,7 +787,7 @@ class ButtonThemeData with Diagnosticable {
/// elevation is 0.0, otherwise the highlight elevation is 4.0.
double getHoverElevation(MaterialButton button) {
if (button.hoverElevation != null)
return button.hoverElevation!;
return button.hoverElevation;
if (button is FlatButton)
return 0.0;
if (button is OutlineButton)
@ -789,7 +803,7 @@ class ButtonThemeData with Diagnosticable {
/// elevation is 0.0, otherwise the highlight elevation is 8.0.
double getHighlightElevation(MaterialButton button) {
if (button.highlightElevation != null)
return button.highlightElevation!;
return button.highlightElevation;
if (button is FlatButton)
return 0.0;
if (button is OutlineButton)
@ -805,7 +819,7 @@ class ButtonThemeData with Diagnosticable {
/// Otherwise the disabled elevation is 0.0.
double getDisabledElevation(MaterialButton button) {
if (button.disabledElevation != null)
return button.disabledElevation!;
return button.disabledElevation;
return 0.0;
}
@ -824,13 +838,13 @@ class ButtonThemeData with Diagnosticable {
/// otherwise.
EdgeInsetsGeometry getPadding(MaterialButton button) {
if (button.padding != null)
return button.padding!;
return button.padding;
if (button is MaterialButtonWithIconMixin)
return const EdgeInsetsDirectional.only(start: 12.0, end: 16.0);
if (_padding != null)
return _padding!;
return _padding;
switch (getTextTheme(button)) {
case ButtonTextTheme.normal:
@ -839,6 +853,8 @@ class ButtonThemeData with Diagnosticable {
case ButtonTextTheme.primary:
return const EdgeInsets.symmetric(horizontal: 24.0);
}
assert(false);
return EdgeInsets.zero;
}
/// The shape of the [button]'s [Material].
@ -879,21 +895,21 @@ class ButtonThemeData with Diagnosticable {
/// Creates a copy of this button theme data object with the matching fields
/// replaced with the non-null parameter values.
ButtonThemeData copyWith({
ButtonTextTheme? textTheme,
ButtonBarLayoutBehavior? layoutBehavior,
double? minWidth,
double? height,
EdgeInsetsGeometry? padding,
ShapeBorder? shape,
bool? alignedDropdown,
Color? buttonColor,
Color? disabledColor,
Color? focusColor,
Color? hoverColor,
Color? highlightColor,
Color? splashColor,
ColorScheme? colorScheme,
MaterialTapTargetSize? materialTapTargetSize,
ButtonTextTheme textTheme,
ButtonBarLayoutBehavior layoutBehavior,
double minWidth,
double height,
EdgeInsetsGeometry padding,
ShapeBorder shape,
bool alignedDropdown,
Color buttonColor,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
ColorScheme colorScheme,
MaterialTapTargetSize materialTapTargetSize,
}) {
return ButtonThemeData(
textTheme: textTheme ?? this.textTheme,

View file

@ -2,6 +2,8 @@
// 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';
import 'package:flutter/foundation.dart';
@ -63,8 +65,8 @@ class MaterialButton extends StatelessWidget {
/// [highlightElevation], and [disabledElevation] must be non-negative, if
/// specified.
const MaterialButton({
Key? key,
required this.onPressed,
Key key,
@required this.onPressed,
this.onLongPress,
this.onHighlightChanged,
this.mouseCursor,
@ -111,7 +113,7 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback? onPressed;
final VoidCallback onPressed;
/// The callback that is called when the button is long-pressed.
///
@ -120,7 +122,7 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [enabled], which is true if the button is enabled.
final VoidCallback? onLongPress;
final VoidCallback onLongPress;
/// Called by the underlying [InkWell] widget's [InkWell.onHighlightChanged]
/// callback.
@ -128,16 +130,16 @@ class MaterialButton extends StatelessWidget {
/// If [onPressed] changes from null to non-null while a gesture is ongoing,
/// this can fire during the build phase (in which case calling
/// [State.setState] is not allowed).
final ValueChanged<bool>? onHighlightChanged;
final ValueChanged<bool> onHighlightChanged;
/// {@macro flutter.material.button.mouseCursor}
final MouseCursor? mouseCursor;
final MouseCursor mouseCursor;
/// Defines the button's base colors, and the defaults for the button's minimum
/// size, internal padding, and shape.
///
/// Defaults to `ButtonTheme.of(context).textTheme`.
final ButtonTextTheme? textTheme;
final ButtonTextTheme textTheme;
/// The color to use for this button's text.
///
@ -155,7 +157,7 @@ class MaterialButton extends StatelessWidget {
///
/// * [disabledTextColor], the text color to use when the button has been
/// disabled.
final Color? textColor;
final Color textColor;
/// The color to use for this button's text when the button is disabled.
///
@ -172,7 +174,7 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [textColor] - The color to use for this button's text when the button is [enabled].
final Color? disabledTextColor;
final Color disabledTextColor;
/// The button's fill color, displayed by its [Material], while it
/// is in its default (unpressed, [enabled]) state.
@ -182,7 +184,7 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [disabledColor] - the fill color of the button when the button is disabled.
final Color? color;
final Color color;
/// The fill color of the button when the button is disabled.
///
@ -192,7 +194,7 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [color] - the fill color of the button when the button is [enabled].
final Color? disabledColor;
final Color disabledColor;
/// The splash color of the button's [InkWell].
///
@ -205,20 +207,20 @@ class MaterialButton extends StatelessWidget {
///
/// The appearance of the splash can be configured with the theme's splash
/// factory, [ThemeData.splashFactory].
final Color? splashColor;
final Color splashColor;
/// The fill color of the button's [Material] when it has the input focus.
///
/// The button changed focus color when the button has the input focus. It
/// appears behind the button's child.
final Color? focusColor;
final Color focusColor;
/// The fill color of the button's [Material] when a pointer is hovering over
/// it.
///
/// The button changes fill color when a pointer is hovering over the button.
/// It appears behind the button's child.
final Color? hoverColor;
final Color hoverColor;
/// The highlight color of the button's [InkWell].
///
@ -229,7 +231,7 @@ class MaterialButton extends StatelessWidget {
/// If [textTheme] is [ButtonTextTheme.primary], the default highlight color is
/// transparent (in other words the highlight doesn't appear). Otherwise it's
/// the current theme's highlight color, [ThemeData.highlightColor].
final Color? highlightColor;
final Color highlightColor;
/// The z-coordinate at which to place this button relative to its parent.
///
@ -246,7 +248,7 @@ class MaterialButton extends StatelessWidget {
/// button.
/// * [disabledElevation], the elevation when the button is disabled.
/// * [highlightElevation], the elevation when the button is pressed.
final double? elevation;
final double elevation;
/// The elevation for the button's [Material] when the button
/// is [enabled] and a pointer is hovering over it.
@ -259,7 +261,7 @@ class MaterialButton extends StatelessWidget {
/// * [focusElevation], the elevation when the button is focused.
/// * [disabledElevation], the elevation when the button is disabled.
/// * [highlightElevation], the elevation when the button is pressed.
final double? hoverElevation;
final double hoverElevation;
/// The elevation for the button's [Material] when the button
/// is [enabled] and has the input focus.
@ -273,7 +275,7 @@ class MaterialButton extends StatelessWidget {
/// button.
/// * [disabledElevation], the elevation when the button is disabled.
/// * [highlightElevation], the elevation when the button is pressed.
final double? focusElevation;
final double focusElevation;
/// The elevation for the button's [Material] relative to its parent when the
/// button is [enabled] and pressed.
@ -291,7 +293,7 @@ class MaterialButton extends StatelessWidget {
/// * [hoverElevation], the elevation when a pointer is hovering over the
/// button.
/// * [disabledElevation], the elevation when the button is disabled.
final double? highlightElevation;
final double highlightElevation;
/// The elevation for the button's [Material] relative to its parent when the
/// button is not [enabled].
@ -302,7 +304,7 @@ class MaterialButton extends StatelessWidget {
///
/// * [elevation], the default elevation.
/// * [highlightElevation], the elevation when the button is pressed.
final double? disabledElevation;
final double disabledElevation;
/// The theme brightness to use for this button.
///
@ -313,12 +315,12 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [ButtonTextTheme], uses [Brightness] to determine text color.
final Brightness? colorBrightness;
final Brightness colorBrightness;
/// The button's label.
///
/// Often a [Text] widget in all caps.
final Widget? child;
final Widget child;
/// Whether the button is enabled or disabled.
///
@ -330,7 +332,7 @@ class MaterialButton extends StatelessWidget {
///
/// Defaults to the value from the current [ButtonTheme],
/// [ButtonThemeData.padding].
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry padding;
/// Defines how compact the button's layout will be.
///
@ -340,7 +342,7 @@ class MaterialButton extends StatelessWidget {
///
/// * [ThemeData.visualDensity], which specifies the [visualDensity] for all
/// widgets within a [Theme].
final VisualDensity? visualDensity;
final VisualDensity visualDensity;
/// The shape of the button's [Material].
///
@ -350,7 +352,7 @@ class MaterialButton extends StatelessWidget {
///
/// Defaults to the value from the current [ButtonTheme],
/// [ButtonThemeData.shape].
final ShapeBorder? shape;
final ShapeBorder shape;
/// {@macro flutter.widgets.Clip}
///
@ -358,7 +360,7 @@ class MaterialButton extends StatelessWidget {
final Clip clipBehavior;
/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode? focusNode;
final FocusNode focusNode;
/// {@macro flutter.widgets.Focus.autofocus}
final bool autofocus;
@ -366,7 +368,7 @@ class MaterialButton extends StatelessWidget {
/// Defines the duration of animated changes for [shape] and [elevation].
///
/// The default value is [kThemeChangeDuration].
final Duration? animationDuration;
final Duration animationDuration;
/// Configures the minimum size of the tap target.
///
@ -375,17 +377,17 @@ class MaterialButton extends StatelessWidget {
/// See also:
///
/// * [MaterialTapTargetSize], for a description of how this affects tap targets.
final MaterialTapTargetSize? materialTapTargetSize;
final MaterialTapTargetSize materialTapTargetSize;
/// The smallest horizontal extent that the button will occupy.
///
/// Defaults to the value from the current [ButtonTheme].
final double? minWidth;
final double minWidth;
/// The vertical extent of the button.
///
/// Defaults to the value from the current [ButtonTheme].
final double? height;
final double height;
/// Whether detected gestures should provide acoustic and/or haptic feedback.
///
@ -399,7 +401,7 @@ class MaterialButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final ThemeData theme = Theme.of(context)!;
final ThemeData theme = Theme.of(context);
final ButtonThemeData buttonTheme = ButtonTheme.of(context);
return RawMaterialButton(
@ -409,9 +411,9 @@ class MaterialButton extends StatelessWidget {
onHighlightChanged: onHighlightChanged,
mouseCursor: mouseCursor,
fillColor: buttonTheme.getFillColor(this),
textStyle: theme.textTheme.button!.copyWith(color: buttonTheme.getTextColor(this)),
focusColor: focusColor ?? buttonTheme.getFocusColor(this),
hoverColor: hoverColor ?? buttonTheme.getHoverColor(this),
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
focusColor: focusColor ?? buttonTheme.getFocusColor(this) ?? theme.focusColor,
hoverColor: hoverColor ?? buttonTheme.getHoverColor(this) ?? theme.hoverColor,
highlightColor: highlightColor ?? theme.highlightColor,
splashColor: splashColor ?? theme.splashColor,
elevation: buttonTheme.getElevation(this),

File diff suppressed because it is too large Load diff

View file

@ -30,7 +30,7 @@ void main() {
expect(themeData.showUnselectedLabels, null);
expect(themeData.type, null);
const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData(), child: SizedBox());
const BottomNavigationBarTheme theme = BottomNavigationBarTheme(data: BottomNavigationBarThemeData());
expect(theme.data.backgroundColor, null);
expect(theme.data.elevation, null);
expect(theme.data.selectedIconTheme, null);