diff --git a/.ci.yaml b/.ci.yaml index bbe9b2369aacc..6024a16ff0aaf 100644 --- a/.ci.yaml +++ b/.ci.yaml @@ -1935,7 +1935,6 @@ targets: - name: Linux_build_test flutter_gallery__transition_perf recipe: devicelab/devicelab_drone_build_test presubmit: false - bringup: true # New target https://github.com/flutter/flutter/issues/103542 timeout: 60 properties: tags: > @@ -3222,7 +3221,6 @@ targets: - name: Mac_ios complex_layout_scroll_perf_bad_impeller_ios__timeline_summary recipe: devicelab/devicelab_drone presubmit: false - bringup: true timeout: 60 properties: tags: > @@ -3535,7 +3533,6 @@ targets: task_name: microbenchmarks_impeller_ios - name: Mac_ios native_platform_view_ui_tests_ios - bringup: true recipe: devicelab/devicelab_drone presubmit: false timeout: 60 diff --git a/bin/internal/engine.version b/bin/internal/engine.version index 145557766b515..789e74016159b 100644 --- a/bin/internal/engine.version +++ b/bin/internal/engine.version @@ -1 +1 @@ -ddc5bb3302544f218599b863586052c0de974ebc +c0a06da6b228eb8c777f99cbab401d2f644fbc68 diff --git a/bin/internal/fuchsia-linux.version b/bin/internal/fuchsia-linux.version index 5904cf6dbfb3b..d8a0fc856f427 100644 --- a/bin/internal/fuchsia-linux.version +++ b/bin/internal/fuchsia-linux.version @@ -1 +1 @@ -ej74uu6Dtncz7eKatdlEBu3i7wwMvcsDesvWsvbwkD0C +r45MRYVf5_xaCG8bvxdKFwoZtHfF8FtmUzCYGHwuZXQC diff --git a/bin/internal/fuchsia-mac.version b/bin/internal/fuchsia-mac.version index c43422ec6fded..81dfded7ab583 100644 --- a/bin/internal/fuchsia-mac.version +++ b/bin/internal/fuchsia-mac.version @@ -1 +1 @@ -_eyzEmI9ppaXY6q-WkhtHU___ZmInvC-T8EOPCAM064C +JwUV4fO7YBCZli3yNGrmBYr0ofXAbtaqrBZaZR2egCMC diff --git a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart index ab73fb588ebbe..c605072714d85 100644 --- a/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart +++ b/dev/benchmarks/macrobenchmarks/lib/src/web/bench_pageview_scroll_linethrough.dart @@ -36,6 +36,7 @@ class _MyScrollContainerState extends State<_MyScrollContainer> { static const Duration stepDuration = Duration(milliseconds: 500); late PageController pageController; + final _CustomPainter _painter = _CustomPainter('aa'); int pageNumber = 0; @override @@ -57,6 +58,7 @@ class _MyScrollContainerState extends State<_MyScrollContainer> { @override void dispose() { pageController.dispose(); + _painter._textPainter.dispose(); super.dispose(); } @@ -66,7 +68,7 @@ class _MyScrollContainerState extends State<_MyScrollContainer> { controller: pageController, itemBuilder: (BuildContext context, int position) { return CustomPaint( - painter: _CustomPainter('aa'), + painter: _painter, size: const Size(300, 500), ); }); diff --git a/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo.dart b/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo.dart index ae2ac0516e095..c311b39978fac 100644 --- a/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo.dart +++ b/dev/integration_tests/flutter_gallery/lib/demo/transformations/transformations_demo.dart @@ -182,6 +182,7 @@ class BoardPainter extends CustomPainter { ); final Vertices vertices = board!.getVerticesForBoardPoint(boardPoint, color); canvas.drawVertices(vertices, BlendMode.color, Paint()); + vertices.dispose(); } board!.forEach(drawBoardPoint); diff --git a/dev/tools/gen_defaults/lib/action_chip_template.dart b/dev/tools/gen_defaults/lib/action_chip_template.dart index abbe5e14ffa19..b225c75a04e5f 100644 --- a/dev/tools/gen_defaults/lib/action_chip_template.dart +++ b/dev/tools/gen_defaults/lib/action_chip_template.dart @@ -31,10 +31,10 @@ class _${blockName}DefaultsM3 extends ChipThemeData { Color? get backgroundColor => ${componentColor("$tokenGroup$variant.container")}; @override - Color? get shadowColor => ${color("$tokenGroup.container.shadow-color")}; + Color? get shadowColor => ${colorOrTransparent("$tokenGroup.container.shadow-color")}; @override - @override Color? get surfaceTintColor => ${color("$tokenGroup.container.surface-tint-layer.color")}; + Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")}; @override Color? get selectedColor => ${componentColor("$tokenGroup$variant.selected.container")}; diff --git a/dev/tools/gen_defaults/lib/app_bar_template.dart b/dev/tools/gen_defaults/lib/app_bar_template.dart index 6df3f5dbebdfc..de72bf363d613 100644 --- a/dev/tools/gen_defaults/lib/app_bar_template.dart +++ b/dev/tools/gen_defaults/lib/app_bar_template.dart @@ -34,7 +34,10 @@ class _${blockName}DefaultsM3 extends AppBarTheme { Color? get foregroundColor => ${color('md.comp.top-app-bar.small.headline.color')}; @override - Color? get surfaceTintColor => ${componentColor('md.comp.top-app-bar.small.container.surface-tint-layer')}; + Color? get shadowColor => ${colorOrTransparent('md.comp.top-app-bar.small.container.shadow-color')}; + + @override + Color? get surfaceTintColor => ${colorOrTransparent('md.comp.top-app-bar.small.container.surface-tint-layer.color')}; @override IconThemeData? get iconTheme => IconThemeData( diff --git a/dev/tools/gen_defaults/lib/button_template.dart b/dev/tools/gen_defaults/lib/button_template.dart index c65ac6bd813c7..aab88d252efa0 100644 --- a/dev/tools/gen_defaults/lib/button_template.dart +++ b/dev/tools/gen_defaults/lib/button_template.dart @@ -24,7 +24,7 @@ class ButtonTemplate extends TokenTemplate { } return ''' - ButtonStyleButton.allOrNull(Colors.transparent)'''; + const MaterialStatePropertyAll(Colors.transparent)'''; } String _elevation() { @@ -49,7 +49,15 @@ class ButtonTemplate extends TokenTemplate { } return ''' - ButtonStyleButton.allOrNull(0.0)'''; + const MaterialStatePropertyAll(0.0)'''; + } + + String _elevationColor(String token) { + if (tokens.containsKey(token)) { + return 'MaterialStatePropertyAll(${color(token)})'; + } else { + return 'const MaterialStatePropertyAll(Colors.transparent)'; + } } @override @@ -96,34 +104,30 @@ class _${blockName}DefaultsM3 extends ButtonStyle { return null; }); -${tokens.containsKey("$tokenGroup.container.shadow-color") ? ''' @override MaterialStateProperty? get shadowColor => - ButtonStyleButton.allOrNull(${color("$tokenGroup.container.shadow-color")});''' : ''' - // No default shadow color'''} + ${_elevationColor("$tokenGroup.container.shadow-color")}; -${tokens.containsKey("$tokenGroup.container.surface-tint-layer.color") ? ''' @override MaterialStateProperty? get surfaceTintColor => - ButtonStyleButton.allOrNull(${color("$tokenGroup.container.surface-tint-layer.color")});''' : ''' - // No default surface tint color'''} + ${_elevationColor("$tokenGroup.container.surface-tint-layer.color")}; @override MaterialStateProperty? get elevation =>${_elevation()}; @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(_scaledPadding(context)); + MaterialStatePropertyAll(_scaledPadding(context)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(64.0, ${tokens["$tokenGroup.container.height"]})); + const MaterialStatePropertyAll(Size(64.0, ${tokens["$tokenGroup.container.height"]})); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); ${tokens.containsKey("$tokenGroup.outline.color") ? ''' @override @@ -138,7 +142,7 @@ ${tokens.containsKey("$tokenGroup.outline.color") ? ''' @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(${shape("$tokenGroup.container")}); + const MaterialStatePropertyAll(${shape("$tokenGroup.container", '')}); @override MaterialStateProperty? get mouseCursor => diff --git a/dev/tools/gen_defaults/lib/card_template.dart b/dev/tools/gen_defaults/lib/card_template.dart index ec038b3b8693d..011c745fc24b4 100644 --- a/dev/tools/gen_defaults/lib/card_template.dart +++ b/dev/tools/gen_defaults/lib/card_template.dart @@ -25,10 +25,10 @@ class _${blockName}DefaultsM3 extends CardTheme { Color? get color => ${componentColor("md.comp.elevated-card.container")}; @override - Color? get shadowColor => ${color("md.comp.elevated-card.container.shadow-color")}; + Color? get shadowColor => ${colorOrTransparent("md.comp.elevated-card.container.shadow-color")}; @override - Color? get surfaceTintColor => ${color("md.comp.elevated-card.container.surface-tint-layer.color")}; + Color? get surfaceTintColor => ${colorOrTransparent("md.comp.elevated-card.container.surface-tint-layer.color")}; } '''; } diff --git a/dev/tools/gen_defaults/lib/dialog_template.dart b/dev/tools/gen_defaults/lib/dialog_template.dart index 6fe11741fdd90..2f2ab654ddaf8 100644 --- a/dev/tools/gen_defaults/lib/dialog_template.dart +++ b/dev/tools/gen_defaults/lib/dialog_template.dart @@ -27,9 +27,14 @@ class _${blockName}DefaultsM3 extends DialogTheme { @override Color? get iconColor => _colors.secondary; - // TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160 @override - Color? get backgroundColor => ElevationOverlay.colorWithOverlay(${componentColor("md.comp.dialog.container")}, _colors.primary, ${elevation("md.comp.dialog.container")}); + Color? get backgroundColor => ${componentColor("md.comp.dialog.container")}; + + @override + Color? get shadowColor => ${colorOrTransparent("md.comp.dialog.container.shadow-color")}; + + @override + Color? get surfaceTintColor => ${colorOrTransparent("md.comp.dialog.container.surface-tint-layer.color")}; @override TextStyle? get titleTextStyle => ${textStyle("md.comp.dialog.headline")}; diff --git a/dev/tools/gen_defaults/lib/filter_chip_template.dart b/dev/tools/gen_defaults/lib/filter_chip_template.dart index 6a179f8df0dbb..4e5ae73b7c4cb 100644 --- a/dev/tools/gen_defaults/lib/filter_chip_template.dart +++ b/dev/tools/gen_defaults/lib/filter_chip_template.dart @@ -31,10 +31,10 @@ class _${blockName}DefaultsM3 extends ChipThemeData { Color? get backgroundColor => ${componentColor("$tokenGroup$variant.container")}; @override - Color? get shadowColor => ${color("$tokenGroup.container.shadow-color")}; + Color? get shadowColor => ${colorOrTransparent("$tokenGroup.container.shadow-color")}; @override - @override Color? get surfaceTintColor => ${color("$tokenGroup.container.surface-tint-layer.color")}; + Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")}; @override Color? get selectedColor => isEnabled diff --git a/dev/tools/gen_defaults/lib/icon_button_template.dart b/dev/tools/gen_defaults/lib/icon_button_template.dart index 10a2009c9f8f0..f6cbadff0db2c 100644 --- a/dev/tools/gen_defaults/lib/icon_button_template.dart +++ b/dev/tools/gen_defaults/lib/icon_button_template.dart @@ -9,6 +9,15 @@ class IconButtonTemplate extends TokenTemplate { super.colorSchemePrefix = '_colors.', }); + + String _elevationColor(String token) { + if (tokens.containsKey(token)) { + return 'MaterialStatePropertyAll(${color(token)})'; + } else { + return 'const MaterialStatePropertyAll(Colors.transparent)'; + } + } + @override String generate() => ''' class _${blockName}DefaultsM3 extends ButtonStyle { @@ -26,7 +35,7 @@ class _${blockName}DefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get backgroundColor => - ButtonStyleButton.allOrNull(Colors.transparent); + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get foregroundColor => @@ -66,37 +75,41 @@ class _${blockName}DefaultsM3 extends ButtonStyle { return null; }); - // No default shadow color + @override + MaterialStateProperty? get elevation => + const MaterialStatePropertyAll(0.0); - // No default surface tint color + @override + MaterialStateProperty? get shadowColor => + ${_elevationColor("md.comp.icon-button.container.shadow-color")}; @override - MaterialStateProperty? get elevation => - ButtonStyleButton.allOrNull(0.0); + MaterialStateProperty? get surfaceTintColor => + ${_elevationColor("md.comp.icon-button.container.surface-tint-layer.color")}; @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(const EdgeInsets.all(8.0)); + const MaterialStatePropertyAll(EdgeInsets.all(8.0)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(${tokens["md.comp.icon-button.state-layer.size"]}, ${tokens["md.comp.icon-button.state-layer.size"]})); + const MaterialStatePropertyAll(Size(${tokens["md.comp.icon-button.state-layer.size"]}, ${tokens["md.comp.icon-button.state-layer.size"]})); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); @override MaterialStateProperty? get iconSize => - ButtonStyleButton.allOrNull(${tokens["md.comp.icon-button.icon.size"]}); + const MaterialStatePropertyAll(${tokens["md.comp.icon-button.icon.size"]}); // No default side @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(${shape("md.comp.icon-button.state-layer")}); + const MaterialStatePropertyAll(${shape("md.comp.icon-button.state-layer", "")}); @override MaterialStateProperty? get mouseCursor => diff --git a/dev/tools/gen_defaults/lib/input_chip_template.dart b/dev/tools/gen_defaults/lib/input_chip_template.dart index cfa907297997c..5fb9037a87247 100644 --- a/dev/tools/gen_defaults/lib/input_chip_template.dart +++ b/dev/tools/gen_defaults/lib/input_chip_template.dart @@ -30,10 +30,10 @@ class _${blockName}DefaultsM3 extends ChipThemeData { Color? get backgroundColor => ${componentColor("$tokenGroup$variant.container")}; @override - Color? get shadowColor => ${color("$tokenGroup.container.shadow-color")}; + Color? get shadowColor => ${colorOrTransparent("$tokenGroup.container.shadow-color")}; @override - @override Color? get surfaceTintColor => ${color("$tokenGroup.container.surface-tint-layer.color")}; + Color? get surfaceTintColor => ${colorOrTransparent("$tokenGroup.container.surface-tint-layer.color")}; @override Color? get selectedColor => ${componentColor("$tokenGroup$variant.selected.container")}; diff --git a/dev/tools/gen_defaults/lib/navigation_bar_template.dart b/dev/tools/gen_defaults/lib/navigation_bar_template.dart index 1f5f263ba4c5f..48d47e35c1f0a 100644 --- a/dev/tools/gen_defaults/lib/navigation_bar_template.dart +++ b/dev/tools/gen_defaults/lib/navigation_bar_template.dart @@ -26,7 +26,9 @@ class _${blockName}DefaultsM3 extends NavigationBarThemeData { @override Color? get backgroundColor => ${componentColor("md.comp.navigation-bar.container")}; - @override Color? get surfaceTintColor => ${color("md.comp.navigation-bar.container.surface-tint-layer.color")}; + @override Color? get shadowColor => ${colorOrTransparent("md.comp.navigation-bar.container.shadow-color")}; + + @override Color? get surfaceTintColor => ${colorOrTransparent("md.comp.navigation-bar.container.surface-tint-layer.color")}; @override MaterialStateProperty? get iconTheme { return MaterialStateProperty.resolveWith((Set states) { diff --git a/dev/tools/gen_defaults/lib/template.dart b/dev/tools/gen_defaults/lib/template.dart index c21a8b2f6df63..05d3e8f9352e2 100644 --- a/dev/tools/gen_defaults/lib/template.dart +++ b/dev/tools/gen_defaults/lib/template.dart @@ -97,16 +97,28 @@ abstract class TokenTemplate { /// If there is a value for the given token, this will return /// the value prepended with [colorSchemePrefix]. /// - /// Otherwise it will return 'null'. + /// Otherwise it will return [defaultValue]. /// /// See also: /// * [componentColor], that provides support for an optional opacity. - String color(String colorToken) { + String color(String colorToken, [String defaultValue = 'null']) { return tokens.containsKey(colorToken) ? '$colorSchemePrefix${tokens[colorToken]}' - : 'null'; + : defaultValue; } + /// Generate a [ColorScheme] color name for the given token or a transparent + /// color if there is no value for the token. + /// + /// If there is a value for the given token, this will return + /// the value prepended with [colorSchemePrefix]. + /// + /// Otherwise it will return 'Colors.transparent'. + /// + /// See also: + /// * [componentColor], that provides support for an optional opacity. + String? colorOrTransparent(String token) => color(token, 'Colors.transparent'); + /// Generate a [ColorScheme] color name for the given component's color /// with opacity if available. /// @@ -154,18 +166,18 @@ abstract class TokenTemplate { /// Currently supports family: /// - "SHAPE_FAMILY_ROUNDED_CORNERS" which maps to [RoundedRectangleBorder]. /// - "SHAPE_FAMILY_CIRCULAR" which maps to a [StadiumBorder]. - String shape(String componentToken) { + String shape(String componentToken, [String prefix = 'const ']) { final Map shape = tokens[tokens['$componentToken.shape']!]! as Map; switch (shape['family']) { case 'SHAPE_FAMILY_ROUNDED_CORNERS': - return 'const RoundedRectangleBorder(borderRadius: ' + return '${prefix}RoundedRectangleBorder(borderRadius: ' 'BorderRadius.only(' 'topLeft: Radius.circular(${shape['topLeft']}), ' 'topRight: Radius.circular(${shape['topRight']}), ' 'bottomLeft: Radius.circular(${shape['bottomLeft']}), ' 'bottomRight: Radius.circular(${shape['bottomRight']})))'; case 'SHAPE_FAMILY_CIRCULAR': - return 'const StadiumBorder()'; + return '${prefix}StadiumBorder()'; } print('Unsupported shape family type: ${shape['family']} for $componentToken'); return ''; diff --git a/examples/api/test/material/appbar/app_bar.1_test.dart b/examples/api/test/material/appbar/app_bar.1_test.dart index 2713cf41bffb7..180605347f360 100644 --- a/examples/api/test/material/appbar/app_bar.1_test.dart +++ b/examples/api/test/material/appbar/app_bar.1_test.dart @@ -16,7 +16,7 @@ void main() { expect(find.widgetWithText(AppBar, 'AppBar Demo'), findsOneWidget); Material appbarMaterial = _getAppBarMaterial(tester); - expect(appbarMaterial.shadowColor, null); + expect(appbarMaterial.shadowColor, Colors.transparent); expect(appbarMaterial.elevation, 0); await tester.drag(find.text('Item 4'), _kOffset, touchSlopY: 0, warnIfMissed: false); diff --git a/packages/flutter/lib/src/cupertino/date_picker.dart b/packages/flutter/lib/src/cupertino/date_picker.dart index 3aedc8d672a5c..68ab6d56fb069 100644 --- a/packages/flutter/lib/src/cupertino/date_picker.dart +++ b/packages/flutter/lib/src/cupertino/date_picker.dart @@ -482,8 +482,11 @@ class CupertinoDatePicker extends StatefulWidget { // because there's no other way to get the information we want without // laying out the text. painter.layout(); - - return painter.maxIntrinsicWidth; + try { + return painter.maxIntrinsicWidth; + } finally { + painter.dispose(); + } } } @@ -1663,6 +1666,7 @@ class _CupertinoTimerPickerState extends State { @override void dispose() { PaintingBinding.instance.systemFonts.removeListener(_handleSystemFontsChange); + textPainter.dispose(); super.dispose(); } diff --git a/packages/flutter/lib/src/material/action_chip.dart b/packages/flutter/lib/src/material/action_chip.dart index 070119ff69e3a..29a9bde24058c 100644 --- a/packages/flutter/lib/src/material/action_chip.dart +++ b/packages/flutter/lib/src/material/action_chip.dart @@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart'; import 'chip.dart'; import 'chip_theme.dart'; +import 'colors.dart'; import 'debug.dart'; import 'theme.dart'; import 'theme_data.dart'; @@ -196,10 +197,10 @@ class _ActionChipDefaultsM3 extends ChipThemeData { Color? get backgroundColor => null; @override - Color? get shadowColor => null; + Color? get shadowColor => Colors.transparent; @override - @override Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; + Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; @override Color? get selectedColor => null; diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart index 2e740df38cba6..8c4f37f02c13b 100644 --- a/packages/flutter/lib/src/material/app_bar.dart +++ b/packages/flutter/lib/src/material/app_bar.dart @@ -12,6 +12,7 @@ import 'package:flutter/widgets.dart'; import 'app_bar_theme.dart'; import 'back_button.dart'; import 'color_scheme.dart'; +import 'colors.dart'; import 'constants.dart'; import 'debug.dart'; import 'flexible_space_bar.dart'; @@ -2370,6 +2371,9 @@ class _AppBarDefaultsM3 extends AppBarTheme { @override Color? get foregroundColor => _colors.onSurface; + @override + Color? get shadowColor => Colors.transparent; + @override Color? get surfaceTintColor => _colors.surfaceTint; diff --git a/packages/flutter/lib/src/material/choice_chip.dart b/packages/flutter/lib/src/material/choice_chip.dart index e9888d1766aba..0342171be1884 100644 --- a/packages/flutter/lib/src/material/choice_chip.dart +++ b/packages/flutter/lib/src/material/choice_chip.dart @@ -213,7 +213,7 @@ class _FilterChipDefaultsM3 extends ChipThemeData { Color? get shadowColor => Theme.of(context).colorScheme.shadow; @override - @override Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; + Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; @override Color? get selectedColor => isEnabled diff --git a/packages/flutter/lib/src/material/dialog.dart b/packages/flutter/lib/src/material/dialog.dart index 4a5e8dd6e0178..405a579afb624 100644 --- a/packages/flutter/lib/src/material/dialog.dart +++ b/packages/flutter/lib/src/material/dialog.dart @@ -11,7 +11,6 @@ import 'color_scheme.dart'; import 'colors.dart'; import 'debug.dart'; import 'dialog_theme.dart'; -import 'elevation_overlay.dart'; import 'ink_well.dart'; import 'material.dart'; import 'material_localizations.dart'; @@ -46,6 +45,8 @@ class Dialog extends StatelessWidget { super.key, this.backgroundColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.insetAnimationDuration = const Duration(milliseconds: 100), this.insetAnimationCurve = Curves.decelerate, this.insetPadding = _defaultInsetPadding, @@ -53,7 +54,8 @@ class Dialog extends StatelessWidget { this.shape, this.alignment, this.child, - }) : assert(clipBehavior != null); + }) : assert(clipBehavior != null), + assert(elevation == null || elevation >= 0.0); /// {@template flutter.material.dialog.backgroundColor} /// The background color of the surface of this [Dialog]. @@ -67,12 +69,63 @@ class Dialog extends StatelessWidget { /// {@template flutter.material.dialog.elevation} /// The z-coordinate of this [Dialog]. /// - /// If null then [DialogTheme.elevation] is used, and if that's null then the - /// dialog's elevation is 24.0. + /// Controls how far above the parent the dialog will appear. Elevation is + /// represented by a drop shadow if [shadowColor] is non null, + /// and a surface tint overlay on the background color if [surfaceTintColor] is + /// non null. + /// + /// If null then [DialogTheme.elevation] is used, and if that is null then + /// the elevation will match the Material Design specification for Dialogs. + /// + /// See also: + /// * [Material.elevation], which describes how [elevation] effects the + /// drop shadow or surface tint overlay. + /// * [shadowColor], color of the drop shadow used to indicate the elevation. + /// * [surfaceTintColor], color of an overlay on top of the background + /// color used to indicate the elevation. + /// * , the Material + /// Design specification for dialogs. /// {@endtemplate} - /// {@macro flutter.material.material.elevation} final double? elevation; + /// {@template flutter.material.dialog.shadowColor} + /// The color used to paint a drop shadow under the dialog's [Material], + /// which reflects the dialog's [elevation]. + /// + /// If null and [ThemeData.useMaterial3] is true then no drop shadow will + /// be rendered. + /// + /// If null and [ThemeData.useMaterial3] is false then it will default to + /// [ThemeData.shadowColor]. + /// + /// See also: + /// * [Material.shadowColor], which describes how the drop shadow is painted. + /// * [elevation], which affects how the drop shadow is painted. + /// * [surfaceTintColor], which can be used to indicate elevation through + /// tinting the background color. + /// {@endtemplate} + final Color? shadowColor; + + /// {@template flutter.material.dialog.surfaceTintColor} + /// The color used as a surface tint overlay on the dialog's background color, + /// which reflects the dialog's [elevation]. + /// + /// If [ThemeData.useMaterial3] is false property has no effect. + /// + /// If null and [ThemeData.useMaterial3] is true then [ThemeData]'s + /// [ColorScheme.surfaceTint] will be used. + /// + /// To disable this feature, set [surfaceTintColor] to [Colors.transparent]. + /// + /// See also: + /// * [Material.surfaceTintColor], which describes how the surface tint will + /// be applied to the background color of the dialog. + /// * [elevation], which affects the opacity of the surface tint. + /// * [shadowColor], which can be used to indicate elevation through + /// a drop shadow. + /// {@endtemplate} + final Color? surfaceTintColor; + /// {@template flutter.material.dialog.insetAnimationDuration} /// The duration of the animation to show when the system keyboard intrudes /// into the space that the dialog is placed in. @@ -155,6 +208,8 @@ class Dialog extends StatelessWidget { child: Material( color: backgroundColor ?? dialogTheme.backgroundColor ?? Theme.of(context).dialogBackgroundColor, elevation: elevation ?? dialogTheme.elevation ?? defaults.elevation!, + shadowColor: shadowColor ?? dialogTheme.shadowColor ?? defaults.shadowColor, + surfaceTintColor: surfaceTintColor ?? dialogTheme.surfaceTintColor ?? defaults.surfaceTintColor, shape: shape ?? dialogTheme.shape ?? defaults.shape!, type: MaterialType.card, clipBehavior: clipBehavior, @@ -280,6 +335,8 @@ class AlertDialog extends StatelessWidget { this.buttonPadding, this.backgroundColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.semanticLabel, this.insetPadding = _defaultInsetPadding, this.clipBehavior = Clip.none, @@ -478,9 +535,14 @@ class AlertDialog extends StatelessWidget { final Color? backgroundColor; /// {@macro flutter.material.dialog.elevation} - /// {@macro flutter.material.material.elevation} final double? elevation; + /// {@macro flutter.material.dialog.shadowColor} + final Color? shadowColor; + + /// {@macro flutter.material.dialog.surfaceTintColor} + final Color? surfaceTintColor; + /// The semantic label of the dialog used by accessibility frameworks to /// announce screen transitions when the dialog is opened and closed. /// @@ -695,6 +757,8 @@ class AlertDialog extends StatelessWidget { return Dialog( backgroundColor: backgroundColor, elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, insetPadding: insetPadding, clipBehavior: clipBehavior, shape: shape, @@ -860,6 +924,8 @@ class SimpleDialog extends StatelessWidget { this.contentPadding = const EdgeInsets.fromLTRB(0.0, 12.0, 0.0, 16.0), this.backgroundColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.semanticLabel, this.insetPadding = _defaultInsetPadding, this.clipBehavior = Clip.none, @@ -915,9 +981,14 @@ class SimpleDialog extends StatelessWidget { final Color? backgroundColor; /// {@macro flutter.material.dialog.elevation} - /// {@macro flutter.material.material.elevation} final double? elevation; + /// {@macro flutter.material.dialog.shadowColor} + final Color? shadowColor; + + /// {@macro flutter.material.dialog.surfaceTintColor} + final Color? surfaceTintColor; + /// The semantic label of the dialog used by accessibility frameworks to /// announce screen transitions when the dialog is opened and closed. /// @@ -1031,6 +1102,8 @@ class SimpleDialog extends StatelessWidget { return Dialog( backgroundColor: backgroundColor, elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, insetPadding: insetPadding, clipBehavior: clipBehavior, shape: shape, @@ -1296,6 +1369,9 @@ class _DialogDefaultsM2 extends DialogTheme { @override Color? get backgroundColor => Theme.of(context).dialogBackgroundColor; + @override + Color? get shadowColor => Theme.of(context).shadowColor; + @override TextStyle? get titleTextStyle => _textTheme.titleLarge; @@ -1330,9 +1406,14 @@ class _DialogDefaultsM3 extends DialogTheme { @override Color? get iconColor => _colors.secondary; - // TODO(darrenaustin): overlay should be handled by Material widget: https://github.com/flutter/flutter/issues/9160 @override - Color? get backgroundColor => ElevationOverlay.colorWithOverlay(_colors.surface, _colors.primary, 6.0); + Color? get backgroundColor => _colors.surface; + + @override + Color? get shadowColor => Colors.transparent; + + @override + Color? get surfaceTintColor => _colors.surfaceTint; @override TextStyle? get titleTextStyle => _textTheme.headlineSmall; diff --git a/packages/flutter/lib/src/material/dialog_theme.dart b/packages/flutter/lib/src/material/dialog_theme.dart index b3c7cd3218d80..a53afee5ca5a7 100644 --- a/packages/flutter/lib/src/material/dialog_theme.dart +++ b/packages/flutter/lib/src/material/dialog_theme.dart @@ -30,6 +30,8 @@ class DialogTheme with Diagnosticable { const DialogTheme({ this.backgroundColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.shape, this.alignment, this.iconColor, @@ -44,6 +46,12 @@ class DialogTheme with Diagnosticable { /// Overrides the default value for [Dialog.elevation]. final double? elevation; + /// Overrides the default value for [Dialog.shadowColor]. + final Color? shadowColor; + + /// Overrides the default value for [Dialog.surfaceTintColor]. + final Color? surfaceTintColor; + /// Overrides the default value for [Dialog.shape]. final ShapeBorder? shape; @@ -69,6 +77,8 @@ class DialogTheme with Diagnosticable { DialogTheme copyWith({ Color? backgroundColor, double? elevation, + Color? shadowColor, + Color? surfaceTintColor, ShapeBorder? shape, AlignmentGeometry? alignment, Color? iconColor, @@ -79,6 +89,8 @@ class DialogTheme with Diagnosticable { return DialogTheme( backgroundColor: backgroundColor ?? this.backgroundColor, elevation: elevation ?? this.elevation, + shadowColor: shadowColor ?? this.shadowColor, + surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, shape: shape ?? this.shape, alignment: alignment ?? this.alignment, iconColor: iconColor ?? this.iconColor, @@ -103,6 +115,8 @@ class DialogTheme with Diagnosticable { return DialogTheme( backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), + shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), + surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t), alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t), iconColor: Color.lerp(a?.iconColor, b?.iconColor, t), @@ -126,6 +140,8 @@ class DialogTheme with Diagnosticable { return other is DialogTheme && other.backgroundColor == backgroundColor && other.elevation == elevation + && other.shadowColor == shadowColor + && other.surfaceTintColor == surfaceTintColor && other.shape == shape && other.alignment == alignment && other.iconColor == iconColor @@ -139,6 +155,8 @@ class DialogTheme with Diagnosticable { super.debugFillProperties(properties); properties.add(ColorProperty('backgroundColor', backgroundColor)); properties.add(DoubleProperty('elevation', elevation)); + properties.add(ColorProperty('shadowColor', shadowColor)); + properties.add(ColorProperty('surfaceTintColor', surfaceTintColor)); properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); properties.add(DiagnosticsProperty('alignment', alignment, defaultValue: null)); properties.add(ColorProperty('iconColor', iconColor)); diff --git a/packages/flutter/lib/src/material/drawer.dart b/packages/flutter/lib/src/material/drawer.dart index fcafbdd5219ab..0619e6fa7f2e7 100644 --- a/packages/flutter/lib/src/material/drawer.dart +++ b/packages/flutter/lib/src/material/drawer.dart @@ -147,6 +147,8 @@ class Drawer extends StatelessWidget { super.key, this.backgroundColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.shape, this.width, this.child, @@ -168,6 +170,40 @@ class Drawer extends StatelessWidget { /// is also null, then it defaults to 16.0. final double? elevation; + /// The color used to paint a drop shadow under the drawer's [Material], + /// which reflects the drawer's [elevation]. + /// + /// If null and [ThemeData.useMaterial3] is true then no drop shadow will + /// be rendered. + /// + /// If null and [ThemeData.useMaterial3] is false then it will default to + /// [ThemeData.shadowColor]. + /// + /// See also: + /// * [Material.shadowColor], which describes how the drop shadow is painted. + /// * [elevation], which affects how the drop shadow is painted. + /// * [surfaceTintColor], which can be used to indicate elevation through + /// tinting the background color. + final Color? shadowColor; + + /// The color used as a surface tint overlay on the drawer's background color, + /// which reflects the drawer's [elevation]. + /// + /// If [ThemeData.useMaterial3] is false property has no effect. + /// + /// If null and [ThemeData.useMaterial3] is true then [ThemeData]'s + /// [ColorScheme.surfaceTint] will be used. + /// + /// To disable this feature, set [surfaceTintColor] to [Colors.transparent]. + /// + /// See also: + /// * [Material.surfaceTintColor], which describes how the surface tint will + /// be applied to the background color of the drawer. + /// * [elevation], which affects the opacity of the surface tint. + /// * [shadowColor], which can be used to indicate elevation through + /// a drop shadow. + final Color? surfaceTintColor; + /// The shape of the drawer. /// /// Defines the drawer's [Material.shape]. @@ -189,7 +225,7 @@ class Drawer extends StatelessWidget { /// {@macro flutter.widgets.ProxyWidget.child} final Widget? child; - /// The semantic label of the dialog used by accessibility frameworks to + /// The semantic label of the drawer used by accessibility frameworks to /// announce screen transitions when the drawer is opened and closed. /// /// If this label is not provided, it will default to @@ -216,6 +252,7 @@ class Drawer extends StatelessWidget { case TargetPlatform.windows: label = semanticLabel ?? MaterialLocalizations.of(context).drawerLabel; } + final bool useMaterial3 = Theme.of(context).useMaterial3; return Semantics( scopesRoute: true, namesRoute: true, @@ -226,6 +263,8 @@ class Drawer extends StatelessWidget { child: Material( color: backgroundColor ?? drawerTheme.backgroundColor, elevation: elevation ?? drawerTheme.elevation ?? 16.0, + shadowColor: shadowColor ?? drawerTheme.shadowColor ?? (useMaterial3 ? Colors.transparent : Theme.of(context).shadowColor), + surfaceTintColor: surfaceTintColor ?? drawerTheme.surfaceTintColor ?? (useMaterial3 ? Theme.of(context).colorScheme.surfaceTint : null), shape: shape ?? drawerTheme.shape, child: child, ), diff --git a/packages/flutter/lib/src/material/drawer_theme.dart b/packages/flutter/lib/src/material/drawer_theme.dart index 1aabcae4aa450..ac4277f0f8de9 100644 --- a/packages/flutter/lib/src/material/drawer_theme.dart +++ b/packages/flutter/lib/src/material/drawer_theme.dart @@ -38,6 +38,8 @@ class DrawerThemeData with Diagnosticable { this.backgroundColor, this.scrimColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.shape, this.width, }); @@ -51,6 +53,12 @@ class DrawerThemeData with Diagnosticable { /// Overrides the default value of [Drawer.elevation]. final double? elevation; + /// Overrides the default value for [Drawer.shadowColor]. + final Color? shadowColor; + + /// Overrides the default value for [Drawer.surfaceTintColor]. + final Color? surfaceTintColor; + /// Overrides the default value of [Drawer.shape]. final ShapeBorder? shape; @@ -63,6 +71,8 @@ class DrawerThemeData with Diagnosticable { Color? backgroundColor, Color? scrimColor, double? elevation, + Color? shadowColor, + Color? surfaceTintColor, ShapeBorder? shape, double? width, }) { @@ -70,6 +80,8 @@ class DrawerThemeData with Diagnosticable { backgroundColor: backgroundColor ?? this.backgroundColor, scrimColor: scrimColor ?? this.scrimColor, elevation: elevation ?? this.elevation, + shadowColor: shadowColor ?? this.shadowColor, + surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, shape: shape ?? this.shape, width: width ?? this.width, ); @@ -89,6 +101,8 @@ class DrawerThemeData with Diagnosticable { backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), scrimColor: Color.lerp(a?.scrimColor, b?.scrimColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), + shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), + surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), shape: ShapeBorder.lerp(a?.shape, b?.shape, t), width: lerpDouble(a?.width, b?.width, t), ); @@ -99,6 +113,8 @@ class DrawerThemeData with Diagnosticable { backgroundColor, scrimColor, elevation, + shadowColor, + surfaceTintColor, shape, width, ); @@ -115,6 +131,8 @@ class DrawerThemeData with Diagnosticable { && other.backgroundColor == backgroundColor && other.scrimColor == scrimColor && other.elevation == elevation + && other.shadowColor == shadowColor + && other.surfaceTintColor == surfaceTintColor && other.shape == shape && other.width == width; } @@ -125,6 +143,8 @@ class DrawerThemeData with Diagnosticable { properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); properties.add(ColorProperty('scrimColor', scrimColor, defaultValue: null)); properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); + properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); + properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(DiagnosticsProperty('shape', shape, defaultValue: null)); properties.add(DoubleProperty('width', width, defaultValue: null)); } diff --git a/packages/flutter/lib/src/material/elevated_button.dart b/packages/flutter/lib/src/material/elevated_button.dart index 93c93197b5d06..d86a298dfd60e 100644 --- a/packages/flutter/lib/src/material/elevated_button.dart +++ b/packages/flutter/lib/src/material/elevated_button.dart @@ -582,11 +582,11 @@ class _ElevatedButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get shadowColor => - ButtonStyleButton.allOrNull(_colors.shadow); + MaterialStatePropertyAll(_colors.shadow); @override MaterialStateProperty? get surfaceTintColor => - ButtonStyleButton.allOrNull(_colors.surfaceTint); + MaterialStatePropertyAll(_colors.surfaceTint); @override MaterialStateProperty? get elevation => @@ -608,23 +608,23 @@ class _ElevatedButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(_scaledPadding(context)); + MaterialStatePropertyAll(_scaledPadding(context)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + const MaterialStatePropertyAll(Size(64.0, 40.0)); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); // No default side @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(const StadiumBorder()); + const MaterialStatePropertyAll(StadiumBorder()); @override MaterialStateProperty? get mouseCursor => diff --git a/packages/flutter/lib/src/material/elevation_overlay.dart b/packages/flutter/lib/src/material/elevation_overlay.dart index 1cba0bd53f282..66719912b0ba8 100644 --- a/packages/flutter/lib/src/material/elevation_overlay.dart +++ b/packages/flutter/lib/src/material/elevation_overlay.dart @@ -6,6 +6,7 @@ import 'dart:math' as math; import 'package:flutter/widgets.dart'; +import 'colors.dart'; import 'theme.dart'; /// A utility class for dealing with the overlay color needed @@ -23,11 +24,12 @@ class ElevationOverlay { /// elevated. The amount of opacity will vary with the elevation as described /// in: https://m3.material.io/styles/color/the-color-system/color-roles. /// - /// If [surfaceTint] is not null then the returned color will be the given - /// [color] with the [surfaceTint] of the appropriate opacity applies to it. - /// Otherwise it will just return [color] unmodified. + /// If [surfaceTint] is not null and not completely transparent ([Color.alpha] + /// is 0), then the returned color will be the given [color] with the + /// [surfaceTint] of the appropriate opacity applied to it. Otherwise it will + /// just return [color] unmodified. static Color applySurfaceTint(Color color, Color? surfaceTint, double elevation) { - if (surfaceTint != null) { + if (surfaceTint != null && surfaceTint != Colors.transparent) { return Color.alphaBlend(surfaceTint.withOpacity(_surfaceTintOpacityForElevation(elevation)), color); } return color; diff --git a/packages/flutter/lib/src/material/filled_button.dart b/packages/flutter/lib/src/material/filled_button.dart index 989e7ca222d1c..f98efbdc2c428 100644 --- a/packages/flutter/lib/src/material/filled_button.dart +++ b/packages/flutter/lib/src/material/filled_button.dart @@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart'; import 'button_style.dart'; import 'button_style_button.dart'; import 'color_scheme.dart'; +import 'colors.dart'; import 'constants.dart'; import 'filled_button_theme.dart'; import 'ink_well.dart'; @@ -551,9 +552,11 @@ class _FilledButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get shadowColor => - ButtonStyleButton.allOrNull(_colors.shadow); + MaterialStatePropertyAll(_colors.shadow); - // No default surface tint color + @override + MaterialStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get elevation => @@ -575,23 +578,23 @@ class _FilledButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(_scaledPadding(context)); + MaterialStatePropertyAll(_scaledPadding(context)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + const MaterialStatePropertyAll(Size(64.0, 40.0)); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); // No default side @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(const StadiumBorder()); + const MaterialStatePropertyAll(StadiumBorder()); @override MaterialStateProperty? get mouseCursor => @@ -673,9 +676,11 @@ class _FilledTonalButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get shadowColor => - ButtonStyleButton.allOrNull(_colors.shadow); + MaterialStatePropertyAll(_colors.shadow); - // No default surface tint color + @override + MaterialStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get elevation => @@ -697,23 +702,23 @@ class _FilledTonalButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(_scaledPadding(context)); + MaterialStatePropertyAll(_scaledPadding(context)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + const MaterialStatePropertyAll(Size(64.0, 40.0)); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); // No default side @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(const StadiumBorder()); + const MaterialStatePropertyAll(StadiumBorder()); @override MaterialStateProperty? get mouseCursor => diff --git a/packages/flutter/lib/src/material/filter_chip.dart b/packages/flutter/lib/src/material/filter_chip.dart index a4e1da1898693..347facea081db 100644 --- a/packages/flutter/lib/src/material/filter_chip.dart +++ b/packages/flutter/lib/src/material/filter_chip.dart @@ -222,7 +222,7 @@ class _FilterChipDefaultsM3 extends ChipThemeData { Color? get shadowColor => Theme.of(context).colorScheme.shadow; @override - @override Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; + Color? get surfaceTintColor => Theme.of(context).colorScheme.surfaceTint; @override Color? get selectedColor => isEnabled diff --git a/packages/flutter/lib/src/material/icon_button.dart b/packages/flutter/lib/src/material/icon_button.dart index e196ec9736ea3..e173330d58bb0 100644 --- a/packages/flutter/lib/src/material/icon_button.dart +++ b/packages/flutter/lib/src/material/icon_button.dart @@ -979,7 +979,7 @@ class _IconButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get backgroundColor => - ButtonStyleButton.allOrNull(Colors.transparent); + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get foregroundColor => @@ -1019,37 +1019,41 @@ class _IconButtonDefaultsM3 extends ButtonStyle { return null; }); - // No default shadow color + @override + MaterialStateProperty? get elevation => + const MaterialStatePropertyAll(0.0); - // No default surface tint color + @override + MaterialStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); @override - MaterialStateProperty? get elevation => - ButtonStyleButton.allOrNull(0.0); + MaterialStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(const EdgeInsets.all(8.0)); + const MaterialStatePropertyAll(EdgeInsets.all(8.0)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(40.0, 40.0)); + const MaterialStatePropertyAll(Size(40.0, 40.0)); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); @override MaterialStateProperty? get iconSize => - ButtonStyleButton.allOrNull(24.0); + const MaterialStatePropertyAll(24.0); // No default side @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(const StadiumBorder()); + const MaterialStatePropertyAll(StadiumBorder()); @override MaterialStateProperty? get mouseCursor => diff --git a/packages/flutter/lib/src/material/input_chip.dart b/packages/flutter/lib/src/material/input_chip.dart index d47ee17bcdd75..cdc18a9d520a9 100644 --- a/packages/flutter/lib/src/material/input_chip.dart +++ b/packages/flutter/lib/src/material/input_chip.dart @@ -7,6 +7,7 @@ import 'package:flutter/widgets.dart'; import 'chip.dart'; import 'chip_theme.dart'; +import 'colors.dart'; import 'debug.dart'; import 'icons.dart'; import 'theme.dart'; @@ -268,10 +269,10 @@ class _InputChipDefaultsM3 extends ChipThemeData { Color? get backgroundColor => null; @override - Color? get shadowColor => null; + Color? get shadowColor => Colors.transparent; @override - @override Color? get surfaceTintColor => null; + Color? get surfaceTintColor => Colors.transparent; @override Color? get selectedColor => Theme.of(context).colorScheme.secondaryContainer; diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart index 1194a0f1bc498..67a696dd3dea6 100644 --- a/packages/flutter/lib/src/material/material.dart +++ b/packages/flutter/lib/src/material/material.dart @@ -258,12 +258,12 @@ class Material extends StatefulWidget { /// The color to paint the shadow below the material. /// - /// When [ThemeData.useMaterial3] is true, and this is null, then no drop - /// shadow will be rendered for this material. If it is non-null, then this - /// color will be used to render a drop shadow below the material. + /// If null and [ThemeData.useMaterial3] is true then [ThemeData]'s + /// [ColorScheme.shadow] will be used. If [ThemeData.useMaterial3] is false + /// then [ThemeData.shadowColor] will be used. /// - /// When [ThemeData.useMaterial3] is false, and this is null, then - /// [ThemeData.shadowColor] is used, which defaults to fully opaque black. + /// To remove the drop shadow when [elevation] is greater than 0, set + /// [shadowColor] to [Colors.transparent]. /// /// See also: /// * [ThemeData.useMaterial3], which determines the default value for this @@ -282,9 +282,9 @@ class Material extends StatefulWidget { /// /// If [ThemeData.useMaterial3] is false, then this property is not used. /// - /// If [ThemeData.useMaterial3] is true and [surfaceTintColor] is not null, - /// then it will be used to overlay the base [color] with an opacity based - /// on the [elevation]. + /// If [ThemeData.useMaterial3] is true and [surfaceTintColor] is not null and + /// not [Colors.transparent], then it will be used to overlay the base [color] + /// with an opacity based on the [elevation]. /// /// Otherwise, no surface tint will be applied. /// @@ -404,7 +404,7 @@ class _MaterialState extends State with TickerProviderStateMixin { Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); final Color? backgroundColor = _getBackgroundColor(context); - final Color? modelShadowColor = widget.shadowColor ?? (theme.useMaterial3 ? null : theme.shadowColor); + final Color modelShadowColor = widget.shadowColor ?? (theme.useMaterial3 ? theme.colorScheme.shadow : theme.shadowColor); // If no shadow color is specified, use 0 for elevation in the model so a drop shadow won't be painted. final double modelElevation = modelShadowColor != null ? widget.elevation : 0; assert( @@ -458,7 +458,7 @@ class _MaterialState extends State with TickerProviderStateMixin { clipBehavior: widget.clipBehavior, elevation: modelElevation, color: color, - shadowColor: modelShadowColor ?? const Color(0x00000000), + shadowColor: modelShadowColor, animateColor: false, child: contents, ); diff --git a/packages/flutter/lib/src/material/navigation_bar.dart b/packages/flutter/lib/src/material/navigation_bar.dart index 7fd5e24425b38..d4c78938141e0 100644 --- a/packages/flutter/lib/src/material/navigation_bar.dart +++ b/packages/flutter/lib/src/material/navigation_bar.dart @@ -67,8 +67,9 @@ class NavigationBar extends StatelessWidget { required this.destinations, this.onDestinationSelected, this.backgroundColor, - this.surfaceTintColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.height, this.labelBehavior, }) : assert(destinations != null && destinations.length >= 2), @@ -109,6 +110,22 @@ class NavigationBar extends StatelessWidget { /// and [ColorScheme.onSurface] using an [ElevationOverlay]. final Color? backgroundColor; + /// The elevation of the [NavigationBar] itself. + /// + /// If null, [NavigationBarThemeData.elevation] is used. If that + /// is also null, then if [ThemeData.useMaterial3] is true then it will + /// be 3.0 otherwise 0.0. + final double? elevation; + + /// The color used for the drop shadow to indicate elevation. + /// + /// If null, [NavigationBarThemeData.shadowColor] is used. If that + /// is also null, the default value is [Colors.transparent] which + /// indicates that no drop shadow will be displayed. + /// + /// See [Material.shadowColor] for more details on drop shadows. + final Color? shadowColor; + /// The color used as an overlay on [backgroundColor] to indicate elevation. /// /// If null, [NavigationBarThemeData.surfaceTintColor] is used. If that @@ -118,13 +135,6 @@ class NavigationBar extends StatelessWidget { /// overlay is applied. final Color? surfaceTintColor; - /// The elevation of the [NavigationBar] itself. - /// - /// If null, [NavigationBarThemeData.elevation] is used. If that - /// is also null, then if [ThemeData.useMaterial3] is true then it will - /// be 3.0 otherwise 0.0. - final double? elevation; - /// The height of the [NavigationBar] itself. /// /// If this is used in [Scaffold.bottomNavigationBar] and the scaffold is @@ -171,8 +181,9 @@ class NavigationBar extends StatelessWidget { color: backgroundColor ?? navigationBarTheme.backgroundColor ?? defaults.backgroundColor!, - surfaceTintColor: surfaceTintColor ?? navigationBarTheme.surfaceTintColor ?? defaults.surfaceTintColor, elevation: elevation ?? navigationBarTheme.elevation ?? defaults.elevation!, + shadowColor: shadowColor ?? navigationBarTheme.shadowColor ?? defaults.shadowColor, + surfaceTintColor: surfaceTintColor ?? navigationBarTheme.surfaceTintColor ?? defaults.surfaceTintColor, child: SafeArea( child: SizedBox( height: effectiveHeight, @@ -1250,6 +1261,8 @@ class _NavigationBarDefaultsM3 extends NavigationBarThemeData { @override Color? get backgroundColor => _colors.surface; + @override Color? get shadowColor => Colors.transparent; + @override Color? get surfaceTintColor => _colors.surfaceTint; @override MaterialStateProperty? get iconTheme { diff --git a/packages/flutter/lib/src/material/navigation_bar_theme.dart b/packages/flutter/lib/src/material/navigation_bar_theme.dart index 140144dcbcc14..69067f01887d9 100644 --- a/packages/flutter/lib/src/material/navigation_bar_theme.dart +++ b/packages/flutter/lib/src/material/navigation_bar_theme.dart @@ -44,8 +44,9 @@ class NavigationBarThemeData with Diagnosticable { const NavigationBarThemeData({ this.height, this.backgroundColor, - this.surfaceTintColor, this.elevation, + this.shadowColor, + this.surfaceTintColor, this.indicatorColor, this.indicatorShape, this.labelTextStyle, @@ -59,12 +60,15 @@ class NavigationBarThemeData with Diagnosticable { /// Overrides the default value of [NavigationBar.backgroundColor]. final Color? backgroundColor; - /// Overrides the default value of [NavigationBar.surfaceTintColor]. - final Color? surfaceTintColor; - /// Overrides the default value of [NavigationBar.elevation]. final double? elevation; + /// Overrides the default value of [NavigationBar.shadowColor]. + final Color? shadowColor; + + /// Overrides the default value of [NavigationBar.surfaceTintColor]. + final Color? surfaceTintColor; + /// Overrides the default value of [NavigationBar]'s selection indicator. final Color? indicatorColor; @@ -92,8 +96,9 @@ class NavigationBarThemeData with Diagnosticable { NavigationBarThemeData copyWith({ double? height, Color? backgroundColor, - Color? surfaceTintColor, double? elevation, + Color? shadowColor, + Color? surfaceTintColor, Color? indicatorColor, ShapeBorder? indicatorShape, MaterialStateProperty? labelTextStyle, @@ -103,8 +108,9 @@ class NavigationBarThemeData with Diagnosticable { return NavigationBarThemeData( height: height ?? this.height, backgroundColor: backgroundColor ?? this.backgroundColor, - surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, elevation: elevation ?? this.elevation, + shadowColor: shadowColor ?? this.shadowColor, + surfaceTintColor: surfaceTintColor ?? this.surfaceTintColor, indicatorColor: indicatorColor ?? this.indicatorColor, indicatorShape: indicatorShape ?? this.indicatorShape, labelTextStyle: labelTextStyle ?? this.labelTextStyle, @@ -126,8 +132,9 @@ class NavigationBarThemeData with Diagnosticable { return NavigationBarThemeData( height: lerpDouble(a?.height, b?.height, t), backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t), - surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), elevation: lerpDouble(a?.elevation, b?.elevation, t), + shadowColor: Color.lerp(a?.shadowColor, b?.shadowColor, t), + surfaceTintColor: Color.lerp(a?.surfaceTintColor, b?.surfaceTintColor, t), indicatorColor: Color.lerp(a?.indicatorColor, b?.indicatorColor, t), indicatorShape: ShapeBorder.lerp(a?.indicatorShape, b?.indicatorShape, t), labelTextStyle: MaterialStateProperty.lerp(a?.labelTextStyle, b?.labelTextStyle, t, TextStyle.lerp), @@ -140,8 +147,9 @@ class NavigationBarThemeData with Diagnosticable { int get hashCode => Object.hash( height, backgroundColor, - surfaceTintColor, elevation, + shadowColor, + surfaceTintColor, indicatorColor, indicatorShape, labelTextStyle, @@ -160,8 +168,9 @@ class NavigationBarThemeData with Diagnosticable { return other is NavigationBarThemeData && other.height == height && other.backgroundColor == backgroundColor - && other.surfaceTintColor == surfaceTintColor && other.elevation == elevation + && other.shadowColor == shadowColor + && other.surfaceTintColor == surfaceTintColor && other.indicatorColor == indicatorColor && other.indicatorShape == indicatorShape && other.labelTextStyle == labelTextStyle @@ -174,8 +183,9 @@ class NavigationBarThemeData with Diagnosticable { super.debugFillProperties(properties); properties.add(DoubleProperty('height', height, defaultValue: null)); properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null)); - properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(DoubleProperty('elevation', elevation, defaultValue: null)); + properties.add(ColorProperty('shadowColor', shadowColor, defaultValue: null)); + properties.add(ColorProperty('surfaceTintColor', surfaceTintColor, defaultValue: null)); properties.add(ColorProperty('indicatorColor', indicatorColor, defaultValue: null)); properties.add(DiagnosticsProperty('indicatorShape', indicatorShape, defaultValue: null)); properties.add(DiagnosticsProperty>('labelTextStyle', labelTextStyle, defaultValue: null)); diff --git a/packages/flutter/lib/src/material/outlined_button.dart b/packages/flutter/lib/src/material/outlined_button.dart index 2342ca71e6bd4..3797d538df07f 100644 --- a/packages/flutter/lib/src/material/outlined_button.dart +++ b/packages/flutter/lib/src/material/outlined_button.dart @@ -470,7 +470,7 @@ class _OutlinedButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get backgroundColor => - ButtonStyleButton.allOrNull(Colors.transparent); + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get foregroundColor => @@ -496,27 +496,31 @@ class _OutlinedButtonDefaultsM3 extends ButtonStyle { return null; }); - // No default shadow color + @override + MaterialStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); - // No default surface tint color + @override + MaterialStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get elevation => - ButtonStyleButton.allOrNull(0.0); + const MaterialStatePropertyAll(0.0); @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(_scaledPadding(context)); + MaterialStatePropertyAll(_scaledPadding(context)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + const MaterialStatePropertyAll(Size(64.0, 40.0)); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); @override MaterialStateProperty? get side => @@ -529,7 +533,7 @@ class _OutlinedButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(const StadiumBorder()); + const MaterialStatePropertyAll(StadiumBorder()); @override MaterialStateProperty? get mouseCursor => diff --git a/packages/flutter/lib/src/material/popup_menu.dart b/packages/flutter/lib/src/material/popup_menu.dart index b0689adc3365b..1518652b4d67b 100644 --- a/packages/flutter/lib/src/material/popup_menu.dart +++ b/packages/flutter/lib/src/material/popup_menu.dart @@ -38,14 +38,6 @@ const double _kMenuVerticalPadding = 8.0; const double _kMenuWidthStep = 56.0; const double _kMenuScreenPadding = 8.0; -/// Used to configure how the [PopupMenuButton] positions its popup menu. -enum PopupMenuPosition { - /// Menu is positioned over the anchor. - over, - /// Menu is positioned under the anchor. - under, -} - /// A base class for entries in a Material Design popup menu. /// /// The popup menu widget uses this interface to interact with the menu items. @@ -1025,7 +1017,7 @@ class PopupMenuButton extends StatefulWidget { this.color, this.enableFeedback, this.constraints, - this.position = PopupMenuPosition.over, + this.position, this.clipBehavior = Clip.none, }) : assert(itemBuilder != null), assert(enabled != null), @@ -1157,9 +1149,11 @@ class PopupMenuButton extends StatefulWidget { /// [offset] is used to change the position of the popup menu relative to the /// position set by this parameter. /// - /// When not set, the position defaults to [PopupMenuPosition.over] which makes the - /// popup menu appear directly over the button that was used to create it. - final PopupMenuPosition position; + /// If this property is `null`, then [PopupMenuThemeData.position] is used. If + /// [PopupMenuThemeData.position] is also `null`, then the position defaults + /// to [PopupMenuPosition.over] which makes the popup menu appear directly + /// over the button that was used to create it. + final PopupMenuPosition? position; /// {@macro flutter.material.Material.clipBehavior} /// @@ -1189,8 +1183,9 @@ class PopupMenuButtonState extends State> { final PopupMenuThemeData popupMenuTheme = PopupMenuTheme.of(context); final RenderBox button = context.findRenderObject()! as RenderBox; final RenderBox overlay = Navigator.of(context).overlay!.context.findRenderObject()! as RenderBox; + final PopupMenuPosition popupMenuPosition = widget.position ?? popupMenuTheme.position ?? PopupMenuPosition.over; final Offset offset; - switch (widget.position) { + switch (popupMenuPosition) { case PopupMenuPosition.over: offset = widget.offset; break; diff --git a/packages/flutter/lib/src/material/popup_menu_theme.dart b/packages/flutter/lib/src/material/popup_menu_theme.dart index 4479def0dd5f2..3ace02516c4ef 100644 --- a/packages/flutter/lib/src/material/popup_menu_theme.dart +++ b/packages/flutter/lib/src/material/popup_menu_theme.dart @@ -13,6 +13,14 @@ import 'theme.dart'; // Examples can assume: // late BuildContext context; +/// Used to configure how the [PopupMenuButton] positions its popup menu. +enum PopupMenuPosition { + /// Menu is positioned over the anchor. + over, + /// Menu is positioned under the anchor. + under, +} + /// Defines the visual properties of the routes used to display popup menus /// as well as [PopupMenuItem] and [PopupMenuDivider] widgets. /// @@ -43,6 +51,7 @@ class PopupMenuThemeData with Diagnosticable { this.textStyle, this.enableFeedback, this.mouseCursor, + this.position, }); /// The background color of the popup menu. @@ -67,6 +76,12 @@ class PopupMenuThemeData with Diagnosticable { /// If specified, overrides the default value of [PopupMenuItem.mouseCursor]. final MaterialStateProperty? mouseCursor; + /// Whether the popup menu is positioned over or under the popup menu button. + /// + /// When not set, the position defaults to [PopupMenuPosition.over] which makes the + /// popup menu appear directly over the button that was used to create it. + final PopupMenuPosition? position; + /// Creates a copy of this object with the given fields replaced with the /// new values. PopupMenuThemeData copyWith({ @@ -76,6 +91,7 @@ class PopupMenuThemeData with Diagnosticable { TextStyle? textStyle, bool? enableFeedback, MaterialStateProperty? mouseCursor, + PopupMenuPosition? position, }) { return PopupMenuThemeData( color: color ?? this.color, @@ -84,6 +100,7 @@ class PopupMenuThemeData with Diagnosticable { textStyle: textStyle ?? this.textStyle, enableFeedback: enableFeedback ?? this.enableFeedback, mouseCursor: mouseCursor ?? this.mouseCursor, + position: position ?? this.position, ); } @@ -104,6 +121,7 @@ class PopupMenuThemeData with Diagnosticable { textStyle: TextStyle.lerp(a?.textStyle, b?.textStyle, t), enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback, mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor, + position: t < 0.5 ? a?.position : b?.position, ); } @@ -115,6 +133,7 @@ class PopupMenuThemeData with Diagnosticable { textStyle, enableFeedback, mouseCursor, + position, ); @override @@ -131,7 +150,8 @@ class PopupMenuThemeData with Diagnosticable { && other.shape == shape && other.textStyle == textStyle && other.enableFeedback == enableFeedback - && other.mouseCursor == mouseCursor; + && other.mouseCursor == mouseCursor + && other.position == position; } @override @@ -143,6 +163,7 @@ class PopupMenuThemeData with Diagnosticable { properties.add(DiagnosticsProperty('text style', textStyle, defaultValue: null)); properties.add(DiagnosticsProperty('enableFeedback', enableFeedback, defaultValue: null)); properties.add(DiagnosticsProperty>('mouseCursor', mouseCursor, defaultValue: null)); + properties.add(EnumProperty('position', position, defaultValue: null)); } } diff --git a/packages/flutter/lib/src/material/range_slider.dart b/packages/flutter/lib/src/material/range_slider.dart index f9b62d8528a12..52c2485d5141c 100644 --- a/packages/flutter/lib/src/material/range_slider.dart +++ b/packages/flutter/lib/src/material/range_slider.dart @@ -1090,6 +1090,13 @@ class _RenderRangeSlider extends RenderBox with RelayoutWhenSystemFontsChangeMix super.detach(); } + @override + void dispose() { + _startLabelPainter.dispose(); + _endLabelPainter.dispose(); + super.dispose(); + } + double _getValueFromVisualPosition(double visualPosition) { switch (textDirection) { case TextDirection.rtl: diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart index 8ed0c0ee19f31..45ea35a11c638 100644 --- a/packages/flutter/lib/src/material/slider.dart +++ b/packages/flutter/lib/src/material/slider.dart @@ -1342,6 +1342,12 @@ class _RenderSlider extends RenderBox with RelayoutWhenSystemFontsChangeMixin { super.detach(); } + @override + void dispose() { + _labelPainter.dispose(); + super.dispose(); + } + double _getValueFromVisualPosition(double visualPosition) { switch (textDirection) { case TextDirection.rtl: diff --git a/packages/flutter/lib/src/material/text_button.dart b/packages/flutter/lib/src/material/text_button.dart index e60ae98b7f627..e1838c5929c68 100644 --- a/packages/flutter/lib/src/material/text_button.dart +++ b/packages/flutter/lib/src/material/text_button.dart @@ -514,7 +514,7 @@ class _TextButtonDefaultsM3 extends ButtonStyle { @override MaterialStateProperty? get backgroundColor => - ButtonStyleButton.allOrNull(Colors.transparent); + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get foregroundColor => @@ -540,33 +540,37 @@ class _TextButtonDefaultsM3 extends ButtonStyle { return null; }); - // No default shadow color + @override + MaterialStateProperty? get shadowColor => + const MaterialStatePropertyAll(Colors.transparent); - // No default surface tint color + @override + MaterialStateProperty? get surfaceTintColor => + const MaterialStatePropertyAll(Colors.transparent); @override MaterialStateProperty? get elevation => - ButtonStyleButton.allOrNull(0.0); + const MaterialStatePropertyAll(0.0); @override MaterialStateProperty? get padding => - ButtonStyleButton.allOrNull(_scaledPadding(context)); + MaterialStatePropertyAll(_scaledPadding(context)); @override MaterialStateProperty? get minimumSize => - ButtonStyleButton.allOrNull(const Size(64.0, 40.0)); + const MaterialStatePropertyAll(Size(64.0, 40.0)); // No default fixedSize @override MaterialStateProperty? get maximumSize => - ButtonStyleButton.allOrNull(Size.infinite); + const MaterialStatePropertyAll(Size.infinite); // No default side @override MaterialStateProperty? get shape => - ButtonStyleButton.allOrNull(const StadiumBorder()); + const MaterialStatePropertyAll(StadiumBorder()); @override MaterialStateProperty? get mouseCursor => diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart index c4197924ad767..e300186de06df 100644 --- a/packages/flutter/lib/src/material/time_picker.dart +++ b/packages/flutter/lib/src/material/time_picker.dart @@ -860,6 +860,17 @@ class _DialPainter extends CustomPainter { static const double _labelPadding = 28.0; + void dispose() { + for (final _TappableLabel label in primaryLabels) { + label.painter.dispose(); + } + for (final _TappableLabel label in secondaryLabels) { + label.painter.dispose(); + } + primaryLabels.clear(); + secondaryLabels.clear(); + } + @override void paint(Canvas canvas, Size size) { final double radius = size.shortestSide / 2.0; @@ -966,6 +977,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { late ThemeData themeData; late MaterialLocalizations localizations; late MediaQueryData media; + _DialPainter? painter; @override void didChangeDependencies() { @@ -989,6 +1001,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { @override void dispose() { _thetaController.dispose(); + painter?.dispose(); super.dispose(); } @@ -1280,6 +1293,18 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { break; } + painter?.dispose(); + painter = _DialPainter( + selectedValue: selectedDialValue, + primaryLabels: primaryLabels, + secondaryLabels: secondaryLabels, + backgroundColor: backgroundColor, + accentColor: accentColor, + dotColor: theme.colorScheme.surface, + theta: _theta.value, + textDirection: Directionality.of(context), + ); + return GestureDetector( excludeFromSemantics: true, onPanStart: _handlePanStart, @@ -1288,16 +1313,7 @@ class _DialState extends State<_Dial> with SingleTickerProviderStateMixin { onTapUp: _handleTapUp, child: CustomPaint( key: const ValueKey('time-picker-dial'), - painter: _DialPainter( - selectedValue: selectedDialValue, - primaryLabels: primaryLabels, - secondaryLabels: secondaryLabels, - backgroundColor: backgroundColor, - accentColor: accentColor, - dotColor: theme.colorScheme.surface, - theta: _theta.value, - textDirection: Directionality.of(context), - ), + painter: painter, ), ); } diff --git a/packages/flutter/lib/src/painting/flutter_logo.dart b/packages/flutter/lib/src/painting/flutter_logo.dart index f8e51808eba56..c394c108d67f6 100644 --- a/packages/flutter/lib/src/painting/flutter_logo.dart +++ b/packages/flutter/lib/src/painting/flutter_logo.dart @@ -227,6 +227,7 @@ class _FlutterLogoPainter extends BoxPainter { final FlutterLogoDecoration _config; // these are configured assuming a font size of 100.0. + // TODO(dnfield): Figure out how to dispose this https://github.com/flutter/flutter/issues/110601 late TextPainter _textPainter; late Rect _textBoundingRect; diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart index 515249ad5916c..5cf0433a6b472 100644 --- a/packages/flutter/lib/src/painting/text_painter.dart +++ b/packages/flutter/lib/src/painting/text_painter.dart @@ -222,6 +222,7 @@ class TextPainter { bool _rebuildParagraphForPaint = true; bool get _debugAssertTextLayoutIsValid { + assert(!debugDisposed); if (_paragraph == null) { throw FlutterError.fromParts([ ErrorSummary('Text layout not available'), @@ -247,6 +248,7 @@ class TextPainter { } return true; }()); + _paragraph?.dispose(); _paragraph = null; _lineMetricsCache = null; _previousCaretPosition = null; @@ -271,6 +273,7 @@ class TextPainter { return; } if (_text?.style != value?.style) { + _layoutTemplate?.dispose(); _layoutTemplate = null; } @@ -329,6 +332,7 @@ class TextPainter { } _textDirection = value; markNeedsLayout(); + _layoutTemplate?.dispose(); _layoutTemplate = null; // Shouldn't really matter, but for strict correctness... } @@ -347,6 +351,7 @@ class TextPainter { } _textScaleFactor = value; markNeedsLayout(); + _layoutTemplate?.dispose(); _layoutTemplate = null; } @@ -1060,4 +1065,33 @@ class TextPainter { assert(_debugAssertTextLayoutIsValid); return _lineMetricsCache ??= _paragraph!.computeLineMetrics(); } + + bool _disposed = false; + + /// Whether this object has been disposed or not. + /// + /// Only for use when asserts are enabled. + bool get debugDisposed { + bool? disposed; + assert(() { + disposed = _disposed; + return true; + }()); + return disposed ?? (throw StateError('debugDisposed only available when asserts are on.')); + } + + /// Releases the resources associated with this painter. + /// + /// After disposal this painter is unusable. + void dispose() { + assert(() { + _disposed = true; + return true; + }()); + _layoutTemplate?.dispose(); + _layoutTemplate = null; + _paragraph?.dispose(); + _paragraph = null; + _text = null; + } } diff --git a/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart b/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart index a00bbee91b1ea..8282b8ad6f1be 100644 --- a/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart +++ b/packages/flutter/lib/src/rendering/debug_overflow_indicator.dart @@ -114,6 +114,14 @@ mixin DebugOverflowIndicatorMixin on RenderObject { TextPainter(textDirection: TextDirection.ltr), // This label is in English. ); + @override + void dispose() { + for (final TextPainter painter in _indicatorLabel) { + painter.dispose(); + } + super.dispose(); + } + // Set to true to trigger a debug message in the console upon // the next paint call. Will be reset after each paint. bool _overflowReportNeeded = true; diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 967376f253818..91c9effa07418 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -388,6 +388,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin, _autocorrectHighlightPainter.dispose(); _selectionPainter.dispose(); _caretPainter.dispose(); + _textPainter.dispose(); super.dispose(); } diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart index 10964ce19d178..e8b96f28f2f75 100644 --- a/packages/flutter/lib/src/rendering/paragraph.dart +++ b/packages/flutter/lib/src/rendering/paragraph.dart @@ -256,6 +256,7 @@ class RenderParagraph extends RenderBox // _lastSelectableFragments may hold references to this RenderParagraph. // Release them manually to avoid retain cycles. _lastSelectableFragments = null; + _textPainter.dispose(); super.dispose(); } @@ -864,6 +865,7 @@ class RenderParagraph extends RenderBox [const Color(0xFFFFFFFF), const Color(0x00FFFFFF)], ); } + fadeSizePainter.dispose(); break; } } else { diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart index 8f97008d17224..32b699003f8ab 100644 --- a/packages/flutter/lib/src/rendering/proxy_box.dart +++ b/packages/flutter/lib/src/rendering/proxy_box.dart @@ -1515,6 +1515,13 @@ abstract class _RenderCustomClip extends RenderProxyBox { return true; }()); } + + @override + void dispose() { + _debugText?.dispose(); + _debugText = null; + super.dispose(); + } } /// Clips its child using a rectangle. diff --git a/packages/flutter/lib/src/scheduler/binding.dart b/packages/flutter/lib/src/scheduler/binding.dart index 41dce5f7ff850..d06f4bbd28710 100644 --- a/packages/flutter/lib/src/scheduler/binding.dart +++ b/packages/flutter/lib/src/scheduler/binding.dart @@ -5,7 +5,7 @@ import 'dart:async'; import 'dart:collection'; import 'dart:developer' show Flow, Timeline, TimelineTask; -import 'dart:ui' show AppLifecycleState, FramePhase, FrameTiming, PlatformDispatcher, TimingsCallback; +import 'dart:ui' show AppLifecycleState, DartPerformanceMode, FramePhase, FrameTiming, PlatformDispatcher, TimingsCallback; import 'package:collection/collection.dart' show HeapPriorityQueue, PriorityQueue; import 'package:flutter/foundation.dart'; @@ -183,6 +183,34 @@ enum SchedulerPhase { postFrameCallbacks, } +/// This callback is invoked when a request for [DartPerformanceMode] is disposed. +/// +/// See also: +/// +/// * [PerformanceModeRequestHandle] for more information on the lifecycle of the handle. +typedef _PerformanceModeCleaupCallback = VoidCallback; + +/// An opaque handle that keeps a request for [DartPerformanceMode] active until +/// disposed. +/// +/// To create a [PerformanceModeRequestHandle], use [SchedulerBinding.requestPerformanceMode]. +/// The component that makes the request is responsible for disposing the handle. +class PerformanceModeRequestHandle { + PerformanceModeRequestHandle._(_PerformanceModeCleaupCallback this._cleanup); + + _PerformanceModeCleaupCallback? _cleanup; + + /// Call this method to signal to [SchedulerBinding] that a request for a [DartPerformanceMode] + /// is no longer needed. + /// + /// This method must only be called once per object. + void dispose() { + assert(_cleanup != null); + _cleanup!(); + _cleanup = null; + } +} + /// Scheduler for running the following: /// /// * _Transient callbacks_, triggered by the system's @@ -605,6 +633,20 @@ mixin SchedulerBinding on BindingBase { return true; } + /// Asserts that there are no pending performance mode requests in debug mode. + /// + /// Throws a [FlutterError] if there are pending performance mode requests, + /// as this indicates a potential memory leak. + bool debugAssertNoPendingPerformanceModeRequests(String reason) { + assert(() { + if (_performanceMode != null) { + throw FlutterError(reason); + } + return true; + }()); + return true; + } + /// Prints the stack for where the current transient callback was registered. /// /// A transient frame callback is one that was registered with @@ -1085,6 +1127,59 @@ mixin SchedulerBinding on BindingBase { } } + DartPerformanceMode? _performanceMode; + int _numPerformanceModeRequests = 0; + + /// Request a specific [DartPerformanceMode]. + /// + /// Returns `null` if the request was not successful due to conflicting performance mode requests. + /// Two requests are said to be in conflict if they are not of the same [DartPerformanceMode] type, + /// and an explicit request for a performance mode has been made prior. + /// + /// Requestor is responsible for calling [PerformanceModeRequestHandle.dispose] when it no longer + /// requires the performance mode. + PerformanceModeRequestHandle? requestPerformanceMode(DartPerformanceMode mode) { + // conflicting requests are not allowed. + if (_performanceMode != null && _performanceMode != mode) { + return null; + } + + if (_performanceMode == mode) { + assert(_numPerformanceModeRequests > 0); + _numPerformanceModeRequests++; + } else if (_performanceMode == null) { + assert(_numPerformanceModeRequests == 0); + _performanceMode = mode; + _numPerformanceModeRequests = 1; + } + + return PerformanceModeRequestHandle._(_disposePerformanceModeRequest); + } + + /// Remove a request for a specific [DartPerformanceMode]. + /// + /// If all the pending requests have been disposed, the engine will revert to the + /// [DartPerformanceMode.balanced] performance mode. + void _disposePerformanceModeRequest() { + _numPerformanceModeRequests--; + if (_numPerformanceModeRequests == 0) { + _performanceMode = null; + PlatformDispatcher.instance.requestDartPerformanceMode(DartPerformanceMode.balanced); + } + } + + /// Returns the current [DartPerformanceMode] requested or `null` if no requests have + /// been made. + /// + /// This is only supported in debug and profile modes, returns `null` in release mode. + DartPerformanceMode? debugGetRequestedPerformanceMode() { + if (!(kDebugMode || kProfileMode)) { + return null; + } else { + return _performanceMode; + } + } + /// Called by the engine to produce a new frame. /// /// This method is called immediately after [handleBeginFrame]. It calls all diff --git a/packages/flutter/lib/src/widgets/banner.dart b/packages/flutter/lib/src/widgets/banner.dart index 406f65c7b0786..ad9ba135d9fee 100644 --- a/packages/flutter/lib/src/widgets/banner.dart +++ b/packages/flutter/lib/src/widgets/banner.dart @@ -117,14 +117,23 @@ class BannerPainter extends CustomPainter { ); bool _prepared = false; - late TextPainter _textPainter; + TextPainter? _textPainter; late Paint _paintShadow; late Paint _paintBanner; + /// Release resources held by this painter. + /// + /// After calling this method, this object is no longer usable. + void dispose() { + _textPainter?.dispose(); + _textPainter = null; + } + void _prepare() { _paintShadow = _shadow.toPaint(); _paintBanner = Paint() ..color = color; + _textPainter?.dispose(); _textPainter = TextPainter( text: TextSpan(style: textStyle, text: message), textAlign: TextAlign.center, @@ -144,8 +153,8 @@ class BannerPainter extends CustomPainter { ..drawRect(_kRect, _paintShadow) ..drawRect(_kRect, _paintBanner); const double width = _kOffset * 2.0; - _textPainter.layout(minWidth: width, maxWidth: width); - _textPainter.paint(canvas, _kRect.topLeft + Offset(0.0, (_kRect.height - _textPainter.height) / 2.0)); + _textPainter!.layout(minWidth: width, maxWidth: width); + _textPainter!.paint(canvas, _kRect.topLeft + Offset(0.0, (_kRect.height - _textPainter!.height) / 2.0)); } @override diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart index e0606556aa237..b258842b620b3 100644 --- a/packages/flutter/lib/src/widgets/routes.dart +++ b/packages/flutter/lib/src/widgets/routes.dart @@ -108,6 +108,14 @@ abstract class TransitionRoute extends OverlayRoute { Future get completed => _transitionCompleter.future; final Completer _transitionCompleter = Completer(); + /// Handle to the performance mode request. + /// + /// When the route is animating, the performance mode is requested. It is then + /// disposed when the animation ends. Requesting [DartPerformanceMode.latency] + /// indicates to the engine that the transition is latency sensitive and to delay + /// non-essential work while this handle is active. + PerformanceModeRequestHandle? _performanceModeRequestHandle; + /// {@template flutter.widgets.TransitionRoute.transitionDuration} /// The duration the transition going forwards. /// @@ -221,12 +229,17 @@ abstract class TransitionRoute extends OverlayRoute { if (overlayEntries.isNotEmpty) { overlayEntries.first.opaque = opaque; } + _performanceModeRequestHandle?.dispose(); + _performanceModeRequestHandle = null; break; case AnimationStatus.forward: case AnimationStatus.reverse: if (overlayEntries.isNotEmpty) { overlayEntries.first.opaque = false; } + _performanceModeRequestHandle ??= + SchedulerBinding.instance + .requestPerformanceMode(ui.DartPerformanceMode.latency); break; case AnimationStatus.dismissed: // We might still be an active route if a subclass is controlling the @@ -236,6 +249,8 @@ abstract class TransitionRoute extends OverlayRoute { if (!isActive) { navigator!.finalizeRoute(this); _popFinalized = true; + _performanceModeRequestHandle?.dispose(); + _performanceModeRequestHandle = null; } break; } @@ -465,6 +480,8 @@ abstract class TransitionRoute extends OverlayRoute { void dispose() { assert(!_transitionCompleter.isCompleted, 'Cannot dispose a $runtimeType twice.'); _animation?.removeStatusListener(_handleStatusChanged); + _performanceModeRequestHandle?.dispose(); + _performanceModeRequestHandle = null; if (willDisposeAnimationController) { _controller?.dispose(); } diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart index 4ce8f2fcb10e2..2d3acbfdc99e2 100644 --- a/packages/flutter/lib/src/widgets/semantics_debugger.dart +++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart @@ -339,6 +339,7 @@ class _SemanticsDebuggerPainter extends CustomPainter { ..layout(maxWidth: rect.width); textPainter.paint(canvas, Alignment.center.inscribe(textPainter.size, rect).topLeft); + textPainter.dispose(); canvas.restore(); } diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart index 94185fa872440..cbbfa8f5d4746 100644 --- a/packages/flutter/lib/src/widgets/widget_inspector.dart +++ b/packages/flutter/lib/src/widgets/widget_inspector.dart @@ -2777,6 +2777,13 @@ class _InspectorOverlayLayer extends Layer { TextPainter? _textPainter; double? _textPainterMaxWidth; + @override + void dispose() { + _textPainter?.dispose(); + _textPainter = null; + super.dispose(); + } + @override void addToScene(ui.SceneBuilder builder) { if (!selection.active) { @@ -2878,6 +2885,7 @@ class _InspectorOverlayLayer extends Layer { final TextSpan? textSpan = _textPainter?.text as TextSpan?; if (_textPainter == null || textSpan!.text != message || _textPainterMaxWidth != maxWidth) { _textPainterMaxWidth = maxWidth; + _textPainter?.dispose(); _textPainter = TextPainter() ..maxLines = _kMaxTooltipLines ..ellipsis = '...' diff --git a/packages/flutter/test/cupertino/nav_bar_transition_test.dart b/packages/flutter/test/cupertino/nav_bar_transition_test.dart index dc4dbebc38ff8..f739bc5759d28 100644 --- a/packages/flutter/test/cupertino/nav_bar_transition_test.dart +++ b/packages/flutter/test/cupertino/nav_bar_transition_test.dart @@ -9,8 +9,11 @@ // Fails with "flutter test --test-randomize-ordering-seed=456" @Tags(['no-shuffle']) +import 'dart:ui'; + import 'package:flutter/cupertino.dart'; import 'package:flutter/rendering.dart'; +import 'package:flutter/scheduler.dart'; import 'package:flutter_test/flutter_test.dart'; Future startTransitionBetween( @@ -443,6 +446,26 @@ void main() { ); }); + testWidgets('DartPerformanceMode is latency mid-animation', (WidgetTester tester) async { + DartPerformanceMode? mode; + + // before the animation starts, no requests are active. + mode = SchedulerBinding.instance.debugGetRequestedPerformanceMode(); + expect(mode, isNull); + + await startTransitionBetween(tester, fromTitle: 'Page 1'); + + // mid-transition, latency mode is expected. + await tester.pump(const Duration(milliseconds: 50)); + mode = SchedulerBinding.instance.debugGetRequestedPerformanceMode(); + expect(mode, equals(DartPerformanceMode.latency)); + + // end of transitio, go back to no requests active. + await tester.pump(const Duration(milliseconds: 500)); + mode = SchedulerBinding.instance.debugGetRequestedPerformanceMode(); + expect(mode, isNull); + }); + testWidgets('Multiple nav bars tags do not conflict if in different navigators', (WidgetTester tester) async { await tester.pumpWidget( CupertinoApp( diff --git a/packages/flutter/test/material/dialog_test.dart b/packages/flutter/test/material/dialog_test.dart index 165a253bc5d4d..9a94021ee0db8 100644 --- a/packages/flutter/test/material/dialog_test.dart +++ b/packages/flutter/test/material/dialog_test.dart @@ -140,9 +140,13 @@ void main() { testWidgets('Custom dialog elevation', (WidgetTester tester) async { const double customElevation = 12.0; + const Color shadowColor = Color(0xFF000001); + const Color surfaceTintColor = Color(0xFF000002); const AlertDialog dialog = AlertDialog( actions: [ ], elevation: customElevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, ); await tester.pumpWidget(_buildAppWithDialog(dialog)); @@ -151,6 +155,8 @@ void main() { final Material materialWidget = _getMaterialFromDialog(tester); expect(materialWidget.elevation, customElevation); + expect(materialWidget.shadowColor, shadowColor); + expect(materialWidget.surfaceTintColor, surfaceTintColor); }); testWidgets('Custom Title Text Style', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/dialog_theme_test.dart b/packages/flutter/test/material/dialog_theme_test.dart index b3018cd0fd600..a7a3c7d1f06f5 100644 --- a/packages/flutter/test/material/dialog_theme_test.dart +++ b/packages/flutter/test/material/dialog_theme_test.dart @@ -51,6 +51,8 @@ void main() { const DialogTheme( backgroundColor: Color(0xff123456), elevation: 8.0, + shadowColor: Color(0xff000001), + surfaceTintColor: Color(0xff000002), alignment: Alignment.bottomLeft, iconColor: Color(0xff654321), titleTextStyle: TextStyle(color: Color(0xffffffff)), @@ -63,6 +65,8 @@ void main() { expect(description, [ 'backgroundColor: Color(0xff123456)', 'elevation: 8.0', + 'shadowColor: Color(0xff000001)', + 'surfaceTintColor: Color(0xff000002)', 'alignment: Alignment.bottomLeft', 'iconColor: Color(0xff654321)', 'titleTextStyle: TextStyle(inherit: true, color: Color(0xffffffff))', @@ -89,11 +93,19 @@ void main() { testWidgets('Custom dialog elevation', (WidgetTester tester) async { const double customElevation = 12.0; + const Color shadowColor = Color(0xFF000001); + const Color surfaceTintColor = Color(0xFF000002); const AlertDialog dialog = AlertDialog( title: Text('Title'), actions: [ ], ); - final ThemeData theme = ThemeData(dialogTheme: const DialogTheme(elevation: customElevation)); + final ThemeData theme = ThemeData( + dialogTheme: const DialogTheme( + elevation: customElevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, + ), + ); await tester.pumpWidget( _appWithDialog(tester, dialog, theme: theme), @@ -103,6 +115,8 @@ void main() { final Material materialWidget = _getMaterialFromDialog(tester); expect(materialWidget.elevation, customElevation); + expect(materialWidget.shadowColor, shadowColor); + expect(materialWidget.surfaceTintColor, surfaceTintColor); }); testWidgets('Custom dialog shape', (WidgetTester tester) async { diff --git a/packages/flutter/test/material/drawer_theme_test.dart b/packages/flutter/test/material/drawer_theme_test.dart index da6b9e8293a00..e84f7f488f04d 100644 --- a/packages/flutter/test/material/drawer_theme_test.dart +++ b/packages/flutter/test/material/drawer_theme_test.dart @@ -30,6 +30,8 @@ void main() { backgroundColor: Color(0x00000099), scrimColor: Color(0x00000098), elevation: 5.0, + shadowColor: Color(0x00000097), + surfaceTintColor: Color(0x00000096), shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(2.0))), width: 200.0, ).debugFillProperties(builder); @@ -43,6 +45,8 @@ void main() { 'backgroundColor: Color(0x00000099)', 'scrimColor: Color(0x00000098)', 'elevation: 5.0', + 'shadowColor: Color(0x00000097)', + 'surfaceTintColor: Color(0x00000096)', 'shape: RoundedRectangleBorder(BorderSide(width: 0.0, style: none), BorderRadius.circular(2.0))', 'width: 200.0', ]); @@ -50,6 +54,7 @@ void main() { testWidgets('Default values are used when no Drawer or DrawerThemeData properties are specified', (WidgetTester tester) async { final GlobalKey scaffoldKey = GlobalKey(); + final bool useMaterial3 = ThemeData().useMaterial3; await tester.pumpWidget( MaterialApp( home: Scaffold( @@ -63,6 +68,8 @@ void main() { expect(_drawerMaterial(tester).color, null); expect(_drawerMaterial(tester).elevation, 16.0); + expect(_drawerMaterial(tester).shadowColor, useMaterial3 ? Colors.transparent : ThemeData().shadowColor); + expect(_drawerMaterial(tester).surfaceTintColor, useMaterial3 ? ThemeData().colorScheme.surfaceTint : null); expect(_drawerMaterial(tester).shape, null); expect(_scrim(tester).color, Colors.black54); expect(_drawerRenderBox(tester).size.width, 304.0); @@ -72,6 +79,8 @@ void main() { const Color backgroundColor = Color(0x00000001); const Color scrimColor = Color(0x00000002); const double elevation = 7.0; + const Color shadowColor = Color(0x00000003); + const Color surfaceTintColor = Color(0x00000004); const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const double width = 200.0; @@ -83,6 +92,8 @@ void main() { backgroundColor: backgroundColor, scrimColor: scrimColor, elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, shape: shape, width: width, ), @@ -98,6 +109,8 @@ void main() { expect(_drawerMaterial(tester).color, backgroundColor); expect(_drawerMaterial(tester).elevation, elevation); + expect(_drawerMaterial(tester).shadowColor, shadowColor); + expect(_drawerMaterial(tester).surfaceTintColor, surfaceTintColor); expect(_drawerMaterial(tester).shape, shape); expect(_scrim(tester).color, scrimColor); expect(_drawerRenderBox(tester).size.width, width); @@ -107,6 +120,8 @@ void main() { const Color backgroundColor = Color(0x00000001); const Color scrimColor = Color(0x00000002); const double elevation = 7.0; + const Color shadowColor = Color(0x00000003); + const Color surfaceTintColor = Color(0x00000004); const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const double width = 200.0; @@ -115,8 +130,8 @@ void main() { MaterialApp( theme: ThemeData( drawerTheme: const DrawerThemeData( - backgroundColor: Color(0x00000003), - scrimColor: Color(0x00000004), + backgroundColor: Color(0x00000005), + scrimColor: Color(0x00000006), elevation: 13.0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(29.0))), width: 400.0, @@ -128,6 +143,8 @@ void main() { drawer: const Drawer( backgroundColor: backgroundColor, elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, shape: shape, width: width, ), @@ -139,6 +156,8 @@ void main() { expect(_drawerMaterial(tester).color, backgroundColor); expect(_drawerMaterial(tester).elevation, elevation); + expect(_drawerMaterial(tester).shadowColor, shadowColor); + expect(_drawerMaterial(tester).surfaceTintColor, surfaceTintColor); expect(_drawerMaterial(tester).shape, shape); expect(_scrim(tester).color, scrimColor); expect(_drawerRenderBox(tester).size.width, width); @@ -148,6 +167,8 @@ void main() { const Color backgroundColor = Color(0x00000001); const Color scrimColor = Color(0x00000002); const double elevation = 7.0; + const Color shadowColor = Color(0x00000003); + const Color surfaceTintColor = Color(0x00000004); const RoundedRectangleBorder shape = RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16.0))); const double width = 200.0; @@ -156,9 +177,11 @@ void main() { MaterialApp( theme: ThemeData( drawerTheme: const DrawerThemeData( - backgroundColor: Color(0x00000003), - scrimColor: Color(0x00000004), + backgroundColor: Color(0x00000005), + scrimColor: Color(0x00000006), elevation: 13.0, + shadowColor: Color(0x00000007), + surfaceTintColor: Color(0x00000007), shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(29.0))), width: 400.0 ), @@ -168,6 +191,8 @@ void main() { backgroundColor: backgroundColor, scrimColor: scrimColor, elevation: elevation, + shadowColor: shadowColor, + surfaceTintColor: surfaceTintColor, shape: shape, width: width, ), @@ -183,6 +208,8 @@ void main() { expect(_drawerMaterial(tester).color, backgroundColor); expect(_drawerMaterial(tester).elevation, elevation); + expect(_drawerMaterial(tester).shadowColor, shadowColor); + expect(_drawerMaterial(tester).surfaceTintColor, surfaceTintColor); expect(_drawerMaterial(tester).shape, shape); expect(_scrim(tester).color, scrimColor); expect(_drawerRenderBox(tester).size.width, width); diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart index 5d65c374fceae..4fd4bfd07554c 100644 --- a/packages/flutter/test/material/icon_button_test.dart +++ b/packages/flutter/test/material/icon_button_test.dart @@ -1078,7 +1078,7 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, null); + expect(material.shadowColor, Colors.transparent); expect(material.shape, const StadiumBorder()); expect(material.textStyle, null); expect(material.type, MaterialType.button); @@ -1102,7 +1102,7 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, null); + expect(material.shadowColor, Colors.transparent); expect(material.shape, const StadiumBorder()); expect(material.textStyle, null); expect(material.type, MaterialType.button); @@ -1127,7 +1127,7 @@ void main() { expect(material.clipBehavior, Clip.none); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, null); + expect(material.shadowColor, Colors.transparent); expect(material.shape, const StadiumBorder()); expect(material.textStyle, null); expect(material.type, MaterialType.button); diff --git a/packages/flutter/test/material/icon_button_theme_test.dart b/packages/flutter/test/material/icon_button_theme_test.dart index 44fd8a6d7e228..e3a7e482b6ce2 100644 --- a/packages/flutter/test/material/icon_button_theme_test.dart +++ b/packages/flutter/test/material/icon_button_theme_test.dart @@ -32,7 +32,7 @@ void main() { expect(material.borderRadius, null); expect(material.color, Colors.transparent); expect(material.elevation, 0.0); - expect(material.shadowColor, null); + expect(material.shadowColor, Colors.transparent); expect(material.shape, const StadiumBorder()); expect(material.textStyle, null); expect(material.type, MaterialType.button); @@ -221,12 +221,12 @@ void main() { await tester.pumpWidget(buildFrame()); Material material = tester.widget(buttonMaterialFinder); - expect(material.shadowColor, null); //default + expect(material.shadowColor, Colors.transparent); //default await tester.pumpWidget(buildFrame(overallShadowColor: shadowColor)); await tester.pumpAndSettle(); // theme animation material = tester.widget(buttonMaterialFinder); - expect(material.shadowColor, null); + expect(material.shadowColor, Colors.transparent); await tester.pumpWidget(buildFrame(themeShadowColor: shadowColor)); await tester.pumpAndSettle(); // theme animation diff --git a/packages/flutter/test/material/material_test.dart b/packages/flutter/test/material/material_test.dart index 661d75ca42c97..79d911e5247a0 100644 --- a/packages/flutter/test/material/material_test.dart +++ b/packages/flutter/test/material/material_test.dart @@ -189,6 +189,58 @@ void main() { expect(log, isEmpty); }); + testWidgets('Shadow color defaults', (WidgetTester tester) async { + Widget buildWithShadow(Color? shadowColor) { + return Center( + child: SizedBox( + height: 100.0, + width: 100.0, + child: Material( + shadowColor: shadowColor, + elevation: 10, + shape: const CircleBorder(), + ), + ) + ); + } + + // Default M2 shadow color + await tester.pumpWidget( + Theme( + data: ThemeData( + useMaterial3: false, + ), + child: buildWithShadow(null), + ) + ); + await tester.pumpAndSettle(); + expect(getModel(tester).shadowColor, ThemeData().shadowColor); + + // Default M3 shadow color + await tester.pumpWidget( + Theme( + data: ThemeData( + useMaterial3: true, + ), + child: buildWithShadow(null), + ) + ); + await tester.pumpAndSettle(); + expect(getModel(tester).shadowColor, ThemeData().colorScheme.shadow); + + // Drop shadow can be turned off with a transparent color. + await tester.pumpWidget( + Theme( + data: ThemeData( + useMaterial3: true, + ), + child: buildWithShadow(Colors.transparent), + ) + ); + await tester.pumpAndSettle(); + expect(getModel(tester).shadowColor, Colors.transparent); + }); + testWidgets('Shadows animate smoothly', (WidgetTester tester) async { // This code verifies that the PhysicalModel's elevation animates over // a kThemeChangeDuration time interval. @@ -304,6 +356,23 @@ void main() { final RenderPhysicalShape noTintModel = getModel(tester); expect(noTintModel.color, equals(baseColor)); + // With transparent surfaceTintColor, it should not apply an overlay + await tester.pumpWidget( + Theme( + data: ThemeData( + useMaterial3: true, + ), + child: buildMaterial( + color: baseColor, + surfaceTintColor: Colors.transparent, + elevation: 12.0, + ), + ), + ); + await tester.pumpAndSettle(); + final RenderPhysicalShape transparentTintModel = getModel(tester); + expect(transparentTintModel.color, equals(baseColor)); + // With surfaceTintColor specified, it should not apply an overlay based // on the elevation. await tester.pumpWidget( diff --git a/packages/flutter/test/material/popup_menu_theme_test.dart b/packages/flutter/test/material/popup_menu_theme_test.dart index a37e883f5ad03..e719cd58ffefc 100644 --- a/packages/flutter/test/material/popup_menu_theme_test.dart +++ b/packages/flutter/test/material/popup_menu_theme_test.dart @@ -13,6 +13,7 @@ PopupMenuThemeData _popupMenuTheme() { shape: BeveledRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(12))), elevation: 12.0, textStyle: TextStyle(color: Color(0xffffffff), textBaseline: TextBaseline.alphabetic), + position: PopupMenuPosition.under, ); } @@ -29,6 +30,7 @@ void main() { expect(popupMenuTheme.elevation, null); expect(popupMenuTheme.textStyle, null); expect(popupMenuTheme.mouseCursor, null); + expect(popupMenuTheme.position, null); }); testWidgets('Default PopupMenuThemeData debugFillProperties', (WidgetTester tester) async { @@ -51,6 +53,7 @@ void main() { elevation: 2.0, textStyle: TextStyle(color: Color(0xffffffff)), mouseCursor: MaterialStateMouseCursor.clickable, + position: PopupMenuPosition.over, ).debugFillProperties(builder); final List description = builder.properties @@ -64,6 +67,7 @@ void main() { 'elevation: 2.0', 'text style: TextStyle(inherit: true, color: Color(0xffffffff))', 'mouseCursor: MaterialStateMouseCursor(clickable)', + 'position: over' ]); }); @@ -78,16 +82,21 @@ void main() { home: Material( child: Column( children: [ - PopupMenuButton( - key: popupButtonKey, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: popupItemKey, - child: const Text('Example'), - ), - ]; - }, + Padding( + // The padding makes sure the menu as enough space to around to + // get properly aligned when displayed (`_kMenuScreenPadding`). + padding: const EdgeInsets.all(8.0), + child: PopupMenuButton( + key: popupButtonKey, + itemBuilder: (BuildContext context) { + return >[ + PopupMenuItem( + key: popupItemKey, + child: const Text('Example'), + ), + ]; + }, + ), ), ], ), @@ -123,6 +132,11 @@ void main() { ); expect(text.style.fontFamily, 'Roboto'); expect(text.style.color, const Color(0xdd000000)); + expect(text.style.color, const Color(0xdd000000)); + + final Offset topLeftButton = tester.getTopLeft(find.byType(PopupMenuButton)); + final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); + expect(topLeftMenu, topLeftButton); }); testWidgets('Popup menu uses values from PopupMenuThemeData', (WidgetTester tester) async { @@ -138,6 +152,10 @@ void main() { child: Column( children: [ PopupMenuButton( + // The padding is used in the positioning of the menu when the + // position is `PopupMenuPosition.under`. Setting it to zero makes + // it easier to test. + padding: EdgeInsets.zero, key: popupButtonKey, itemBuilder: (BuildContext context) { return >[ @@ -181,6 +199,10 @@ void main() { ).last, ); expect(text.style, popupMenuTheme.textStyle); + + final Offset bottomLeftButton = tester.getBottomLeft(find.byType(PopupMenuButton)); + final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); + expect(topLeftMenu, bottomLeftButton); }); testWidgets('Popup menu widget properties take priority over theme', (WidgetTester tester) async { @@ -202,20 +224,26 @@ void main() { home: Material( child: Column( children: [ - PopupMenuButton( - key: popupButtonKey, - elevation: elevation, - color: color, - shape: shape, - itemBuilder: (BuildContext context) { - return >[ - PopupMenuItem( - key: popupItemKey, - textStyle: textStyle, - child: const Text('Example'), - ), - ]; - }, + Padding( + // The padding makes sure the menu as enough space to around to + // get properly aligned when displayed (`_kMenuScreenPadding`). + padding: const EdgeInsets.all(8.0), + child: PopupMenuButton( + key: popupButtonKey, + elevation: elevation, + color: color, + shape: shape, + position: PopupMenuPosition.over, + itemBuilder: (BuildContext context) { + return >[ + PopupMenuItem( + key: popupItemKey, + textStyle: textStyle, + child: const Text('Example'), + ), + ]; + }, + ), ), ], ), @@ -250,6 +278,10 @@ void main() { ).last, ); expect(text.style, textStyle); + + final Offset topLeftButton = tester.getTopLeft(find.byType(PopupMenuButton)); + final Offset topLeftMenu = tester.getTopLeft(find.byWidget(button)); + expect(topLeftMenu, topLeftButton); }); testWidgets('ThemeData.popupMenuTheme properties are utilized', (WidgetTester tester) async { diff --git a/packages/flutter/test/painting/text_painter_rtl_test.dart b/packages/flutter/test/painting/text_painter_rtl_test.dart index ea05a25834fad..916c8a94a465e 100644 --- a/packages/flutter/test/painting/text_painter_rtl_test.dart +++ b/packages/flutter/test/painting/text_painter_rtl_test.dart @@ -32,6 +32,7 @@ void main() { painter.getWordBoundary(const TextPosition(offset: 9)), const TextRange(start: 8, end: 11), ); + painter.dispose(); }); test('TextPainter - bidi overrides in LTR', () { @@ -164,6 +165,7 @@ void main() { // The list currently has one extra bogus entry (the last entry, for the // trailing U+202C PDF, should be empty but is one-pixel-wide instead). ], skip: skipExpectsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - bidi overrides in RTL', () { @@ -255,6 +257,7 @@ void main() { // The list is currently in the wrong order (so selection boxes will paint in the wrong order). skip: skipExpectsWithKnownBugs, // https://github.com/flutter/flutter/issues/87536 ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - forced line-wrapping with bidi', () { @@ -322,6 +325,7 @@ void main() { TextBox.fromLTRBD(0.0, 10.0, 10.0, 20.0, TextDirection.rtl), // Alef ], ); + painter.dispose(); }, skip: isBrowser); // https://github.com/flutter/flutter/issues/32238 test('TextPainter - line wrap mid-word', () { @@ -356,6 +360,7 @@ void main() { // horizontal offsets are one pixel off in places; vertical offsets are good skip: skipExpectsWithKnownBugs, // https://github.com/flutter/flutter/issues/87536 ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - line wrap mid-word, bidi - LTR base', () { @@ -412,6 +417,7 @@ void main() { [TextBox.fromLTRBD(70.0, 28.0, 80.0, 38.0, TextDirection.ltr)], [TextBox.fromLTRBD(80.0, 28.0, 90.0, 38.0, TextDirection.ltr)], ]); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - line wrap mid-word, bidi - RTL base', () { @@ -447,6 +453,7 @@ void main() { // The list is currently in the wrong order (so selection boxes will paint in the wrong order). skip: skipExpectsWithKnownBugs, // https://github.com/flutter/flutter/issues/87536 ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - multiple levels', () { @@ -478,6 +485,7 @@ void main() { // Also currently there's an extraneous box at the start of the list. skip: skipExpectsWithKnownBugs, // https://github.com/flutter/flutter/issues/87536 ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - getPositionForOffset - RTL in LTR', () { @@ -561,6 +569,7 @@ void main() { painter.getPositionForOffset(const Offset(100.0, 5.0)).toString(), const TextPosition(offset: 9, affinity: TextAffinity.upstream).toString(), ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - getPositionForOffset - LTR in RTL', () { @@ -606,6 +615,7 @@ void main() { painter.getPositionForOffset(const Offset(62.0, 5.0)).toString(), const TextPosition(offset: 3, affinity: TextAffinity.upstream).toString(), ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - Spaces', () { @@ -667,6 +677,7 @@ void main() { // Horizontal offsets are currently one pixel off in places; vertical offsets are good. skip: skipExpectsWithKnownBugs, // https://github.com/flutter/flutter/issues/87536 ); + painter.dispose(); }, skip: skipTestsWithKnownBugs); // https://github.com/flutter/flutter/issues/87536 test('TextPainter - empty text baseline', () { @@ -678,6 +689,7 @@ void main() { ); painter.layout(); expect(painter.computeDistanceToActualBaseline(TextBaseline.alphabetic), moreOrLessEquals(80.0, epsilon: 0.001)); + painter.dispose(); }); } diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart index 0c0c67abc221a..7d8a75a71a0d1 100644 --- a/packages/flutter/test/painting/text_painter_test.dart +++ b/packages/flutter/test/painting/text_painter_test.dart @@ -35,6 +35,7 @@ void main() { painter.layout(); caretOffset = painter.getOffsetForCaret(ui.TextPosition(offset: text.length), ui.Rect.zero); expect(caretOffset.dx, painter.width); + painter.dispose(); }); test('TextPainter caret test with WidgetSpan', () { @@ -53,6 +54,7 @@ void main() { painter.layout(); final Offset caretOffset = painter.getOffsetForCaret(ui.TextPosition(offset: painter.text!.toPlainText().length), ui.Rect.zero); expect(caretOffset.dx, painter.width); + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 test('TextPainter null text test', () { @@ -78,6 +80,7 @@ void main() { expect(caretOffset.dx, 0); caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 1), ui.Rect.zero); expect(caretOffset.dx, 0); + painter.dispose(); }); test('TextPainter caret emoji test', () { @@ -144,6 +147,7 @@ void main() { expect(caretOffset.dx, 98); // caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 23), ui.Rect.zero); expect(caretOffset.dx, 126); // end of string + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 test('TextPainter caret center space test', () { @@ -166,6 +170,7 @@ void main() { expect(caretOffset.dx, 35); caretOffset = painter.getOffsetForCaret(const ui.TextPosition(offset: 2), ui.Rect.zero); expect(caretOffset.dx, 49); + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 test('TextPainter error test', () { @@ -180,6 +185,7 @@ void main() { e.toString(), contains('TextPainter.paint called when text geometry was not yet calculated'), ); + painter.dispose(); }); test('TextPainter requires textDirection', () { @@ -203,6 +209,7 @@ void main() { ); painter.layout(); expect(painter.size, const Size(123.0, 123.0)); + painter.dispose(); }); test('TextPainter textScaleFactor test', () { @@ -220,6 +227,7 @@ void main() { ); painter.layout(); expect(painter.size, const Size(20.0, 20.0)); + painter.dispose(); }); test('TextPainter textScaleFactor null style test', () { @@ -232,6 +240,7 @@ void main() { ); painter.layout(); expect(painter.size, const Size(28.0, 28.0)); + painter.dispose(); }); test('TextPainter default text height is 14 pixels', () { @@ -242,6 +251,7 @@ void main() { painter.layout(); expect(painter.preferredLineHeight, 14.0); expect(painter.size, const Size(14.0, 14.0)); + painter.dispose(); }); test('TextPainter sets paragraph size from root', () { @@ -252,6 +262,7 @@ void main() { painter.layout(); expect(painter.preferredLineHeight, 100.0); expect(painter.size, const Size(100.0, 100.0)); + painter.dispose(); }); test('TextPainter intrinsic dimensions', () { @@ -273,6 +284,7 @@ void main() { expect(painter.size, const Size(50.0, 10.0)); expect(painter.minIntrinsicWidth, 10.0); expect(painter.maxIntrinsicWidth, 50.0); + painter.dispose(); painter = TextPainter( text: const TextSpan( @@ -286,6 +298,7 @@ void main() { expect(painter.size, const Size(50.0, 10.0)); expect(painter.minIntrinsicWidth, 50.0); expect(painter.maxIntrinsicWidth, 50.0); + painter.dispose(); painter = TextPainter( text: const TextSpan( @@ -299,6 +312,7 @@ void main() { expect(painter.size, const Size(80.0, 10.0)); expect(painter.minIntrinsicWidth, 40.0); expect(painter.maxIntrinsicWidth, 80.0); + painter.dispose(); painter = TextPainter( text: const TextSpan( @@ -312,6 +326,7 @@ void main() { expect(painter.size, const Size(110.0, 10.0)); expect(painter.minIntrinsicWidth, 70.0); expect(painter.maxIntrinsicWidth, 110.0); + painter.dispose(); painter = TextPainter( text: const TextSpan( @@ -325,6 +340,7 @@ void main() { expect(painter.size, const Size(180.0, 10.0)); expect(painter.minIntrinsicWidth, 90.0); expect(painter.maxIntrinsicWidth, 180.0); + painter.dispose(); painter = TextPainter( text: const TextSpan( @@ -338,6 +354,7 @@ void main() { expect(painter.size, const Size(180.0, 10.0)); expect(painter.minIntrinsicWidth, 90.0); expect(painter.maxIntrinsicWidth, 180.0); + painter.dispose(); }, skip: true); // https://github.com/flutter/flutter/issues/13512 test('TextPainter handles newlines properly', () { @@ -679,6 +696,7 @@ void main() { ); expect(caretOffset.dx, moreOrLessEquals(0.0, epsilon: 0.0001)); expect(caretOffset.dy, moreOrLessEquals(0.0, epsilon: 0.0001)); + painter.dispose(); }); test('TextPainter widget span', () { @@ -773,6 +791,7 @@ void main() { expect(painter.inlinePlaceholderBoxes![11], const TextBox.fromLTRBD(250, 30, 300, 60, TextDirection.ltr)); expect(painter.inlinePlaceholderBoxes![12], const TextBox.fromLTRBD(300, 30, 351, 60, TextDirection.ltr)); expect(painter.inlinePlaceholderBoxes![13], const TextBox.fromLTRBD(351, 30, 401, 60, TextDirection.ltr)); + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/87540 // Null values are valid. See https://github.com/flutter/flutter/pull/48346#issuecomment-584839221 @@ -782,6 +801,7 @@ void main() { painter.textHeightBehavior = const TextHeightBehavior(); painter.textHeightBehavior = null; + painter.dispose(); }); test('TextPainter line metrics', () { @@ -846,6 +866,7 @@ void main() { expect(lines[1].lineNumber, 1); expect(lines[2].lineNumber, 2); expect(lines[3].lineNumber, 3); + painter.dispose(); }, skip: true); // https://github.com/flutter/flutter/issues/62819 test('TextPainter caret height and line height', () { @@ -862,6 +883,7 @@ void main() { ui.Rect.zero, )!; expect(caretHeight, 50.0); + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 group('TextPainter line-height', () { @@ -886,6 +908,7 @@ void main() { expect(insets.top, insets.bottom); // The glyph box is exactly 1 logical pixel high. expect(insets.top, (20 - 1) / 2); + painter.dispose(); }); test('half-leading with small height', () { @@ -910,6 +933,7 @@ void main() { // The glyph box is exactly 10 logical pixel high (the height multiplier // does not scale the glyph). Negative leading. expect(insets.top, (1 - 10) / 2); + painter.dispose(); }); test('half-leading with leading trim', () { @@ -935,6 +959,7 @@ void main() { expect(painter.size, glyphBox.size); // The glyph box is still centered. expect(glyphBox.topLeft, Offset.zero); + painter.dispose(); }); test('TextLeadingDistribution falls back to paragraph style', () { @@ -955,6 +980,7 @@ void main() { final RelativeRect insets = RelativeRect.fromSize(glyphBox, painter.size); expect(insets.top, insets.bottom); expect(insets.top, (20 - 1) / 2); + painter.dispose(); }); test('TextLeadingDistribution does nothing if height multiplier is null', () { @@ -978,6 +1004,7 @@ void main() { const TextSelection(baseOffset: 0, extentOffset: 1), ).first.toRect(); expect(glyphBox, newGlyphBox); + painter.dispose(); }); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/87543 @@ -997,6 +1024,7 @@ void main() { // The layout should include one replacement character. expect(painter.width, equals(fontSize)); expect(exception, isNotNull); + painter.dispose(); }, skip: kIsWeb); // https://github.com/flutter/flutter/issues/87544 test('Diacritic', () { @@ -1013,6 +1041,7 @@ void main() { offset: text.length, affinity: TextAffinity.upstream), ui.Rect.zero); expect(caretOffset.dx, painter.width); + painter.dispose(); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/87545 test('TextPainter line metrics update after layout', () { @@ -1033,6 +1062,7 @@ void main() { lines = painter.computeLineMetrics(); expect(lines.length, 1); + painter.dispose(); }, skip: kIsWeb && !isCanvasKit); // https://github.com/flutter/flutter/issues/62819 test('TextPainter throws with stack trace when accessing text layout', () { @@ -1068,6 +1098,7 @@ void main() { expect(exception?.message, contains('The calls that first invalidated the text layout were:')); exception = null; + painter.dispose(); }); test('TextPainter requires layout after providing different placeholder dimensions', () { @@ -1105,6 +1136,7 @@ void main() { e.toString(), contains('TextPainter.paint called when text geometry was not yet calculated'), ); + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 test('TextPainter does not require layout after providing identical placeholder dimensions', () { @@ -1143,7 +1175,15 @@ void main() { e.toString(), isNot(contains('TextPainter.paint called when text geometry was not yet calculated')), ); + painter.dispose(); }, skip: isBrowser && !isCanvasKit); // https://github.com/flutter/flutter/issues/56308 + + test('TextPainter - debugDisposed', () { + final TextPainter painter = TextPainter(); + expect(painter.debugDisposed, false); + painter.dispose(); + expect(painter.debugDisposed, true); + }); } class MockCanvas extends Fake implements Canvas { diff --git a/packages/flutter/test/scheduler/performance_mode_test.dart b/packages/flutter/test/scheduler/performance_mode_test.dart new file mode 100644 index 0000000000000..7a44796cd0044 --- /dev/null +++ b/packages/flutter/test/scheduler/performance_mode_test.dart @@ -0,0 +1,56 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'dart:ui'; + +import 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + late SchedulerBinding binding; + + setUpAll(() { + WidgetsFlutterBinding.ensureInitialized(); + binding = SchedulerBinding.instance; + }); + + test('PerformanceModeHandler make one request', () async { + final PerformanceModeRequestHandle? requestHandle = binding.requestPerformanceMode(DartPerformanceMode.latency); + expect(requestHandle, isNotNull); + expect(binding.debugGetRequestedPerformanceMode(), equals(DartPerformanceMode.latency)); + requestHandle?.dispose(); + expect(binding.debugGetRequestedPerformanceMode(), isNull); + }); + + test('PerformanceModeHandler make conflicting requests', () async { + final PerformanceModeRequestHandle? requestHandle1 = binding.requestPerformanceMode(DartPerformanceMode.latency); + expect(requestHandle1, isNotNull); + + final PerformanceModeRequestHandle? requestHandle2 = binding.requestPerformanceMode(DartPerformanceMode.throughput); + expect(requestHandle2, isNull); + + expect(binding.debugGetRequestedPerformanceMode(), equals(DartPerformanceMode.latency)); + + requestHandle1?.dispose(); + expect(binding.debugGetRequestedPerformanceMode(), isNull); + }); + + test('PerformanceModeHandler revert only after last requestor disposed', + () async { + final PerformanceModeRequestHandle? requestHandle1 = binding.requestPerformanceMode(DartPerformanceMode.latency); + expect(requestHandle1, isNotNull); + + expect(binding.debugGetRequestedPerformanceMode(), equals(DartPerformanceMode.latency)); + + final PerformanceModeRequestHandle? requestHandle2 = binding.requestPerformanceMode(DartPerformanceMode.latency); + expect(requestHandle2, isNotNull); + + expect(binding.debugGetRequestedPerformanceMode(), equals(DartPerformanceMode.latency)); + requestHandle1?.dispose(); + expect(binding.debugGetRequestedPerformanceMode(), equals(DartPerformanceMode.latency)); + requestHandle2?.dispose(); + expect(binding.debugGetRequestedPerformanceMode(), isNull); + }); +} diff --git a/packages/flutter/test/widgets/custom_painter_test.dart b/packages/flutter/test/widgets/custom_painter_test.dart index cab5bd6a18d7a..22fe11099b16e 100644 --- a/packages/flutter/test/widgets/custom_painter_test.dart +++ b/packages/flutter/test/widgets/custom_painter_test.dart @@ -519,7 +519,7 @@ void _defineTests() { ); expect(semantics, hasSemantics(expectedSemantics, ignoreRect: true, ignoreTransform: true)); semantics.dispose(); - }); + }, skip: true); // [intended] https://github.com/flutter/flutter/issues/110107 group('diffing', () { testWidgets('complains about duplicate keys', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart index 7488a2991c2e8..f9ca40bc2e62f 100644 --- a/packages/flutter/test/widgets/semantics_test.dart +++ b/packages/flutter/test/widgets/semantics_test.dart @@ -632,7 +632,7 @@ void main() { expect(semantics, hasSemantics(expectedSemantics, ignoreId: true)); semantics.dispose(); - }); + }, skip: true); // [intended] https://github.com/flutter/flutter/issues/110107 testWidgets('Actions can be replaced without triggering semantics update', (WidgetTester tester) async { final SemanticsTester semantics = SemanticsTester(tester); diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart index c5122e5500211..ad13f45337e04 100644 --- a/packages/flutter/test/widgets/text_test.dart +++ b/packages/flutter/test/widgets/text_test.dart @@ -1070,6 +1070,7 @@ void main() { final ui.Paragraph paragraph = builder.build(); paragraph.layout(const ui.ParagraphConstraints(width: 1000)); expect(paragraph.getBoxesForRange(2, 2), isEmpty); + paragraph.dispose(); }); // Regression test for https://github.com/flutter/flutter/issues/65818 diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart index a20d6fce2445e..758b32ce0abde 100644 --- a/packages/flutter_test/lib/src/binding.dart +++ b/packages/flutter_test/lib/src/binding.dart @@ -885,6 +885,9 @@ abstract class TestWidgetsFlutterBinding extends BindingBase assert(debugAssertNoTransientCallbacks( 'An animation is still running even after the widget tree was disposed.' )); + assert(debugAssertNoPendingPerformanceModeRequests( + 'A performance mode was requested and not disposed by a test.' + )); assert(debugAssertAllFoundationVarsUnset( 'The value of a foundation debug variable was changed by the test.', debugPrintOverride: debugPrintOverride, diff --git a/packages/flutter_tools/lib/src/base/logger.dart b/packages/flutter_tools/lib/src/base/logger.dart index f80aed9bfd75e..7d4235e4bb023 100644 --- a/packages/flutter_tools/lib/src/base/logger.dart +++ b/packages/flutter_tools/lib/src/base/logger.dart @@ -722,6 +722,7 @@ class WindowsStdoutLogger extends StdoutLogger { .replaceAll('✓', '√') .replaceAll('🔨', '') .replaceAll('💪', '') + .replaceAll('⚠️', '!') .replaceAll('✏️', ''); _stdio.stdoutWrite(windowsMessage); } diff --git a/packages/flutter_tools/lib/src/commands/analyze_base.dart b/packages/flutter_tools/lib/src/commands/analyze_base.dart index 54a9ff6fe0582..cdd21a7659b3a 100644 --- a/packages/flutter_tools/lib/src/commands/analyze_base.dart +++ b/packages/flutter_tools/lib/src/commands/analyze_base.dart @@ -87,7 +87,7 @@ abstract class AnalyzeBase { return artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path; } bool get isBenchmarking => argResults['benchmark'] as bool; - String get protocolTrafficLog => argResults['protocol-traffic-log'] as String; + String? get protocolTrafficLog => argResults['protocol-traffic-log'] as String?; /// Generate an analysis summary for both [AnalyzeOnce], [AnalyzeContinuously]. static String generateErrorsMessage({ diff --git a/packages/flutter_tools/lib/src/commands/build.dart b/packages/flutter_tools/lib/src/commands/build.dart index 09fe09d9cbf51..e0fe313a1d4f0 100644 --- a/packages/flutter_tools/lib/src/commands/build.dart +++ b/packages/flutter_tools/lib/src/commands/build.dart @@ -88,11 +88,11 @@ abstract class BuildSubCommand extends FlutterCommand { ); } else { globals.printStatus( - 'Building without sound null safety', + 'Building without sound null safety ⚠️', emphasis: true, ); globals.printStatus( - 'For more information see https://dart.dev/null-safety/unsound-null-safety', + 'Dart 3 will only support sound null safety, see https://dart.dev/null-safety', ); } globals.printStatus(''); diff --git a/packages/flutter_tools/lib/src/commands/custom_devices.dart b/packages/flutter_tools/lib/src/commands/custom_devices.dart index 79b7b6778984e..96ff6e8054866 100644 --- a/packages/flutter_tools/lib/src/commands/custom_devices.dart +++ b/packages/flutter_tools/lib/src/commands/custom_devices.dart @@ -598,39 +598,39 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase { inputs = StreamQueue(nonClosingKeystrokes.stream); - final String id = await (askForString( + final String id = (await askForString( 'id', description: 'Please enter the id you want to device to have. Must contain only ' 'alphanumeric or underscore characters.', example: 'pi', validator: (String s) async => RegExp(r'^\w+$').hasMatch(s), - ) as FutureOr); + ))!; - final String label = await (askForString( + final String label = (await askForString( 'label', description: 'Please enter the label of the device, which is a slightly more verbose ' 'name for the device.', example: 'Raspberry Pi', - ) as FutureOr); + ))!; - final String sdkNameAndVersion = await (askForString( + final String sdkNameAndVersion = (await askForString( 'SDK name and version', example: 'Raspberry Pi 4 Model B+', - ) as FutureOr); + ))!; final bool enabled = await askForBool( 'enabled', description: 'Should the device be enabled?', ); - final String targetStr = await (askForString( + final String targetStr = (await askForString( 'target', description: 'Please enter the hostname or IPv4/v6 address of the device.', example: 'raspberrypi', validator: (String s) async => _isValidHostname(s) || _isValidIpAddr(s) - ) as FutureOr); + ))!; final InternetAddress? targetIp = InternetAddress.tryParse(targetStr); final bool useIp = targetIp != null; @@ -639,20 +639,20 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase { ? InternetAddress.loopbackIPv6 : InternetAddress.loopbackIPv4; - final String username = await (askForString( + final String username = (await askForString( 'username', description: 'Please enter the username used for ssh-ing into the remote device.', example: 'pi', defaultsTo: 'no username', - ) as FutureOr); + ))!; - final String remoteRunDebugCommand = await (askForString( + final String remoteRunDebugCommand = (await askForString( 'run command', description: 'Please enter the command executed on the remote device for starting ' r'the app. "/tmp/${appName}" is the path to the asset bundle.', example: r'flutter-pi /tmp/${appName}' - ) as FutureOr); + ))!; final bool usePortForwarding = await askForBool( 'use port forwarding', @@ -663,12 +663,12 @@ class CustomDevicesAddCommand extends CustomDevicesCommandBase { 'not using port forwarding.', ); - final String screenshotCommand = await (askForString( + final String screenshotCommand = (await askForString( 'screenshot command', description: 'Enter the command executed on the remote device for taking a screenshot.', example: r"fbgrab /tmp/screenshot.png && cat /tmp/screenshot.png | base64 | tr -d ' \n\t'", defaultsTo: 'no screenshotting support', - ) as FutureOr); + ))!; // SSH expects IPv6 addresses to use the bracket syntax like URIs do too, // but the IPv6 the user enters is a raw IPv6 address, so we need to wrap it. @@ -820,8 +820,8 @@ Delete a device from the config file. Future runCommand() async { checkFeatureEnabled(); - final String id = globalResults!['device-id'] as String; - if (!customDevicesConfig.contains(id)) { + final String? id = globalResults!['device-id'] as String?; + if (id == null || !customDevicesConfig.contains(id)) { throwToolExit('Couldn\'t find device with id "$id" in config at "${customDevicesConfig.configPath}"'); } diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart index 0ad140388f4b2..5b1d8f4ebdd94 100644 --- a/packages/flutter_tools/lib/src/commands/daemon.dart +++ b/packages/flutter_tools/lib/src/commands/daemon.dart @@ -1590,7 +1590,7 @@ class DebounceOperationQueue { final Map> _operationQueue = >{}; Future? _inProgressAction; - Future? queueAndDebounce( + Future queueAndDebounce( K operationType, Duration debounceDuration, Future Function() action, @@ -1599,7 +1599,7 @@ class DebounceOperationQueue { // debounce timer and return its future. if (_operationQueue[operationType] != null) { _debounceTimers[operationType]?.reset(); - return _operationQueue[operationType]; + return _operationQueue[operationType]!; } // Otherwise, put one in the queue with a timer. diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 714a8b9c32fac..9cb22e3b01f22 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -512,7 +512,7 @@ class RunCommand extends RunCommandBase { } @visibleForTesting - Future createRunner({ + Future createRunner({ required bool hotMode, required List flutterDevices, required String? applicationBinaryPath, @@ -669,12 +669,12 @@ class RunCommand extends RunCommandBase { ), ]; - final ResidentRunner runner = await (createRunner( + final ResidentRunner runner = await createRunner( applicationBinaryPath: applicationBinaryPath, flutterDevices: flutterDevices, flutterProject: flutterProject, hotMode: hotMode, - ) as FutureOr); + ); DateTime? appStartedTime; // Sync completer so the completing agent attaching to the resident doesn't diff --git a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart index 501606484a7c3..abcd5003f704e 100644 --- a/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart +++ b/packages/flutter_tools/lib/src/isolated/resident_web_runner.dart @@ -615,11 +615,11 @@ class ResidentWebRunner extends ResidentRunner { _logger!.printStatus('💪 Running with sound null safety 💪', emphasis: true); } else { _logger!.printStatus( - 'Running with unsound null safety', + 'Running without sound null safety ⚠️', emphasis: true, ); _logger!.printStatus( - 'For more information see https://dart.dev/null-safety/unsound-null-safety', + 'Dart 3 will only support sound null safety, see https://dart.dev/null-safety', ); } } diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart index 763819baca7fe..408cd84e957c6 100644 --- a/packages/flutter_tools/lib/src/run_hot.dart +++ b/packages/flutter_tools/lib/src/run_hot.dart @@ -1026,11 +1026,11 @@ class HotRunner extends ResidentRunner { globals.printStatus('💪 Running with sound null safety 💪', emphasis: true); } else { globals.printStatus( - 'Running with unsound null safety', + 'Running without sound null safety ⚠️', emphasis: true, ); globals.printStatus( - 'For more information see https://dart.dev/null-safety/unsound-null-safety', + 'Dart 3 will only support sound null safety, see https://dart.dev/null-safety', ); } globals.printStatus(''); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart index 0205a9a723d92..2322d70d26a24 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_continuously_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:fake_async/fake_async.dart'; @@ -32,13 +30,12 @@ void main() { Cache.flutterRoot = getFlutterRoot(); }); - AnalysisServer server; - Directory tempDir; - FileSystem fileSystem; - Platform platform; - ProcessManager processManager; - AnsiTerminal terminal; - Logger logger; + late Directory tempDir; + late FileSystem fileSystem; + late Platform platform; + late ProcessManager processManager; + late AnsiTerminal terminal; + late Logger logger; setUp(() { fileSystem = globals.localFileSystem; @@ -51,7 +48,6 @@ void main() { tearDown(() { tryToDelete(tempDir); - return server?.dispose(); }); @@ -88,11 +84,10 @@ void main() { await pub.get( context: PubContext.flutterTests, directory: tempDir.path, - generateSyntheticPackage: false, ); - server = AnalysisServer( - globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, + final AnalysisServer server = AnalysisServer( + globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path, [tempDir.path], fileSystem: fileSystem, platform: platform, @@ -109,6 +104,8 @@ void main() { await onDone; expect(errorCount, 0); + + await server.dispose(); }); }); @@ -126,18 +123,17 @@ void main() { await pub.get( context: PubContext.flutterTests, directory: tempDir.path, - generateSyntheticPackage: false, ); - server = AnalysisServer( - globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, - [tempDir.path], - fileSystem: fileSystem, - platform: platform, - processManager: processManager, - logger: logger, - terminal: terminal, - ); + final AnalysisServer server = AnalysisServer( + globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path, + [tempDir.path], + fileSystem: fileSystem, + platform: platform, + processManager: processManager, + logger: logger, + terminal: terminal, + ); int errorCount = 0; final Future onDone = server.onAnalyzing.where((bool analyzing) => analyzing == false).first; @@ -149,13 +145,15 @@ void main() { await onDone; expect(errorCount, greaterThan(0)); + + await server.dispose(); }); testUsingContext('Returns no errors when source is error-free', () async { const String contents = "StringBuffer bar = StringBuffer('baz');"; tempDir.childFile('main.dart').writeAsStringSync(contents); - server = AnalysisServer( - globals.artifacts.getHostArtifact(HostArtifact.engineDartSdkPath).path, + final AnalysisServer server = AnalysisServer( + globals.artifacts!.getHostArtifact(HostArtifact.engineDartSdkPath).path, [tempDir.path], fileSystem: fileSystem, platform: platform, @@ -172,6 +170,7 @@ void main() { await server.start(); await onDone; expect(errorCount, 0); + await server.dispose(); }); testUsingContext('Can run AnalysisService with customized cache location', () async { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart index 1411060073e2d..172b0511f3c0d 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_suggestion_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; @@ -22,7 +20,7 @@ import '../../src/test_flutter_command_runner.dart'; class ProjectValidatorDummy extends ProjectValidator { @override - Future> start(FlutterProject project, {Logger logger, FileSystem fileSystem}) async{ + Future> start(FlutterProject project, {Logger? logger, FileSystem? fileSystem}) async{ return [ const ProjectValidatorResult(name: 'pass', value: 'value', status: StatusProjectValidator.success), const ProjectValidatorResult(name: 'fail', value: 'my error', status: StatusProjectValidator.error), @@ -41,7 +39,7 @@ class ProjectValidatorDummy extends ProjectValidator { class ProjectValidatorSecondDummy extends ProjectValidator { @override - Future> start(FlutterProject project, {Logger logger, FileSystem fileSystem}) async{ + Future> start(FlutterProject project, {Logger? logger, FileSystem? fileSystem}) async{ return [ const ProjectValidatorResult(name: 'second', value: 'pass', status: StatusProjectValidator.success), const ProjectValidatorResult(name: 'other fail', value: 'second fail', status: StatusProjectValidator.error), @@ -59,7 +57,7 @@ class ProjectValidatorSecondDummy extends ProjectValidator { class ProjectValidatorCrash extends ProjectValidator { @override - Future> start(FlutterProject project, {Logger logger, FileSystem fileSystem}) async{ + Future> start(FlutterProject project, {Logger? logger, FileSystem? fileSystem}) async{ throw Exception('my exception'); } @@ -73,10 +71,10 @@ class ProjectValidatorCrash extends ProjectValidator { } void main() { - FileSystem fileSystem; - Terminal terminal; - ProcessManager processManager; - Platform platform; + late FileSystem fileSystem; + late Terminal terminal; + late ProcessManager processManager; + late Platform platform; group('analyze --suggestions command', () { diff --git a/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart index b8424914fecd3..2dac6cf3bea28 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/analyze_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; @@ -46,13 +44,13 @@ void main() { }); group('analyze command', () { - FileSystem fileSystem; - Platform platform; - BufferLogger logger; - FakeProcessManager processManager; - Terminal terminal; - AnalyzeCommand command; - CommandRunner runner; + late FileSystem fileSystem; + late Platform platform; + late BufferLogger logger; + late FakeProcessManager processManager; + late Terminal terminal; + late AnalyzeCommand command; + late CommandRunner runner; setUpAll(() { Cache.disableLocking(); @@ -130,8 +128,8 @@ void main() { // Absolute paths expect(inRepo([tempDir.path], fileSystem), isFalse); expect(inRepo([fileSystem.path.join(tempDir.path, 'foo')], fileSystem), isFalse); - expect(inRepo([Cache.flutterRoot], fileSystem), isTrue); - expect(inRepo([fileSystem.path.join(Cache.flutterRoot, 'foo')], fileSystem), isTrue); + expect(inRepo([Cache.flutterRoot!], fileSystem), isTrue); + expect(inRepo([fileSystem.path.join(Cache.flutterRoot!, 'foo')], fileSystem), isTrue); // Relative paths fileSystem.currentDirectory = Cache.flutterRoot; @@ -158,6 +156,7 @@ void main() { 'startColumn': 4, }, 'message': 'Prefer final for variable declarations if they are not reassigned.', + 'code': 'var foo = 123;', 'hasFix': false, }; expect(WrittenError.fromJson(json).toString(), @@ -165,11 +164,11 @@ void main() { }); } -bool inRepo(List fileList, FileSystem fileSystem) { +bool inRepo(List? fileList, FileSystem fileSystem) { if (fileList == null || fileList.isEmpty) { fileList = [fileSystem.path.current]; } - final String root = fileSystem.path.normalize(fileSystem.path.absolute(Cache.flutterRoot)); + final String root = fileSystem.path.normalize(fileSystem.path.absolute(Cache.flutterRoot!)); final String prefix = root + fileSystem.path.separator; for (String file in fileList) { file = fileSystem.path.normalize(fileSystem.path.absolute(file)); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart index beb713cde5d58..072015afb1532 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/assemble_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart index c1047888865af..b830640caf280 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_darwin_framework_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -21,9 +19,9 @@ import '../../src/fakes.dart'; import '../../src/test_build_system.dart'; void main() { - MemoryFileSystem memoryFileSystem; - Directory outputDirectory; - FakePlatform fakePlatform; + late MemoryFileSystem memoryFileSystem; + late Directory outputDirectory; + late FakePlatform fakePlatform; setUpAll(() { Cache.disableLocking(); @@ -48,7 +46,7 @@ void main() { group('build ios-framework', () { group('podspec', () { const String engineRevision = '0123456789abcdef'; - Cache cache; + late Cache cache; setUp(() { final Directory rootOverride = memoryFileSystem.directory('cache'); @@ -181,7 +179,7 @@ void main() { }); group('not on master channel', () { - FakeFlutterVersion fakeFlutterVersion; + late FakeFlutterVersion fakeFlutterVersion; setUp(() { const GitTagVersion gitTagVersion = GitTagVersion( x: 1, @@ -277,7 +275,7 @@ void main() { group('build macos-framework', () { group('podspec', () { const String engineRevision = '0123456789abcdef'; - Cache cache; + late Cache cache; setUp(() { final Directory rootOverride = memoryFileSystem.directory('cache'); @@ -410,7 +408,7 @@ void main() { }); group('not on master channel', () { - FakeFlutterVersion fakeFlutterVersion; + late FakeFlutterVersion fakeFlutterVersion; setUp(() { const GitTagVersion gitTagVersion = GitTagVersion( x: 1, @@ -504,8 +502,8 @@ void main() { }); group('XCFrameworks', () { - MemoryFileSystem fileSystem; - FakeProcessManager fakeProcessManager; + late MemoryFileSystem fileSystem; + late FakeProcessManager fakeProcessManager; setUp(() { fileSystem = MemoryFileSystem.test(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart index d18c63bc22e76..a9dafa324d87a 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ios_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -28,21 +26,21 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter @override Future> getBuildSettings( String projectPath, { - XcodeProjectBuildContext buildContext, + XcodeProjectBuildContext? buildContext, Duration timeout = const Duration(minutes: 1), }) async { return { 'PRODUCT_BUNDLE_IDENTIFIER': productBundleIdentifier ?? 'io.flutter.someProject', 'TARGET_BUILD_DIR': 'build/ios/Release-iphoneos', 'WRAPPER_NAME': 'Runner.app', - if (developmentTeam != null) 'DEVELOPMENT_TEAM': developmentTeam, + if (developmentTeam != null) 'DEVELOPMENT_TEAM': developmentTeam!, }; } /// The value of 'PRODUCT_BUNDLE_IDENTIFIER'. - final String productBundleIdentifier; + final String? productBundleIdentifier; - final String developmentTeam; + final String? developmentTeam; } final Platform macosPlatform = FakePlatform( @@ -59,8 +57,8 @@ final Platform notMacosPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - TestUsage usage; + late FileSystem fileSystem; + late TestUsage usage; setUpAll(() { Cache.disableLocking(); @@ -90,7 +88,7 @@ void main() { 'xattr', '-r', '-d', 'com.apple.FinderInfo', '/', ]); - FakeCommand setUpRsyncCommand({void Function() onRun}) { + FakeCommand setUpRsyncCommand({void Function()? onRun}) { return FakeCommand( command: const [ 'rsync', @@ -104,7 +102,7 @@ void main() { ); } - FakeCommand setUpXCResultCommand({String stdout = '', void Function() onRun}) { + FakeCommand setUpXCResultCommand({String stdout = '', void Function()? onRun}) { return FakeCommand( command: const [ 'xcrun', @@ -125,10 +123,10 @@ void main() { FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, bool simulator = false, - String deviceId, + String? deviceId, int exitCode = 0, - String stdout, - void Function() onRun, + String? stdout, + void Function()? onRun, }) { return FakeCommand( command: [ diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart index 85630849f44b3..4599e7f55fc89 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_ipa_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -28,7 +26,7 @@ class FakeXcodeProjectInterpreterWithBuildSettings extends FakeXcodeProjectInter @override Future> getBuildSettings( String projectPath, { - XcodeProjectBuildContext buildContext, + XcodeProjectBuildContext? buildContext, Duration timeout = const Duration(minutes: 1), }) async { return { @@ -53,9 +51,9 @@ final Platform notMacosPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - TestUsage usage; - FakeProcessManager fakeProcessManager; + late FileSystem fileSystem; + late TestUsage usage; + late FakeProcessManager fakeProcessManager; setUpAll(() { Cache.disableLocking(); @@ -86,7 +84,7 @@ void main() { 'xattr', '-r', '-d', 'com.apple.FinderInfo', '/', ]); - FakeCommand setUpXCResultCommand({String stdout = '', void Function() onRun}) { + FakeCommand setUpXCResultCommand({String stdout = '', void Function()? onRun}) { return FakeCommand( command: const [ 'xcrun', @@ -104,7 +102,7 @@ void main() { // Creates a FakeCommand for the xcodebuild call to build the app // in the given configuration. - FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, int exitCode = 0, void Function() onRun }) { + FakeCommand setUpFakeXcodeBuildHandler({ bool verbose = false, int exitCode = 0, void Function()? onRun }) { return FakeCommand( command: [ 'xcrun', @@ -134,7 +132,7 @@ void main() { FakeCommand exportArchiveCommand({ String exportOptionsPlist = '/ExportOptions.plist', - File cachePlist, + File? cachePlist, }) { return FakeCommand( command: [ diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart index bf8d2db8f4166..363dfcdf366fd 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_linux_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; @@ -45,9 +43,9 @@ void main() { Cache.disableLocking(); }); - FileSystem fileSystem; - ProcessManager processManager; - TestUsage usage; + late FileSystem fileSystem; + late ProcessManager processManager; + late TestUsage usage; setUp(() { fileSystem = MemoryFileSystem.test(); @@ -71,7 +69,7 @@ void main() { // Returns the command matching the build_linux call to cmake. FakeCommand cmakeCommand(String buildMode, { String target = 'x64', - void Function() onRun, + void Function()? onRun, }) { return FakeCommand( command: [ @@ -89,9 +87,9 @@ void main() { // Returns the command matching the build_linux call to ninja. FakeCommand ninjaCommand(String buildMode, { - Map environment, + Map? environment, String target = 'x64', - void Function() onRun, + void Function()? onRun, String stdout = '', }) { return FakeCommand( diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart index 245ed862bd810..acab399a12f6e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_macos_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:args/command_runner.dart'; @@ -29,7 +27,7 @@ import '../../src/test_flutter_command_runner.dart'; class FakeXcodeProjectInterpreterWithProfile extends FakeXcodeProjectInterpreter { @override - Future getInfo(String projectPath, { String projectFilename }) async { + Future getInfo(String projectPath, { String? projectFilename }) async { return XcodeProjectInfo( ['Runner'], ['Debug', 'Profile', 'Release'], @@ -62,10 +60,10 @@ final Platform notMacosPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - TestUsage usage; - FakeProcessManager fakeProcessManager; - XcodeProjectInterpreter xcodeProjectInterpreter; + late FileSystem fileSystem; + late TestUsage usage; + late FakeProcessManager fakeProcessManager; + late XcodeProjectInterpreter xcodeProjectInterpreter; setUpAll(() { Cache.disableLocking(); @@ -93,7 +91,7 @@ void main() { // Creates a FakeCommand for the xcodebuild call to build the app // in the given configuration. - FakeCommand setUpFakeXcodeBuildHandler(String configuration, { bool verbose = false, void Function() onRun }) { + FakeCommand setUpFakeXcodeBuildHandler(String configuration, { bool verbose = false, void Function()? onRun }) { final FlutterProject flutterProject = FlutterProject.fromDirectory(fileSystem.currentDirectory); final Directory flutterBuildDir = fileSystem.directory(getMacOSBuildDirectory()); return FakeCommand( diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart index 57aba7ecd519b..144ed0e1094cf 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_test.dart @@ -2,14 +2,12 @@ // 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:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/build.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; -import 'package:meta/meta.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -27,8 +25,8 @@ void main() { 'combination with "--${FlutterOptions.kSplitDebugInfoOption}"')); }); group('Fatal Logs', () { - FakeBuildCommand command; - MemoryFileSystem fs; + late FakeBuildCommand command; + late MemoryFileSystem fs; setUp(() { fs = MemoryFileSystem.test(); @@ -134,7 +132,7 @@ class FakeBuildCommand extends BuildCommand { } class FakeBuildSubcommand extends BuildSubCommand { - FakeBuildSubcommand({@required bool verboseHelp}) : super(verboseHelp: verboseHelp); + FakeBuildSubcommand({required super.verboseHelp}); @override String get description => ''; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart index 3dd5335de24b1..77aeb4888eb9e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_web_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -23,7 +21,7 @@ import '../../src/test_build_system.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; + late FileSystem fileSystem; final Platform fakePlatform = FakePlatform( environment: { 'FLUTTER_ROOT': '/', @@ -243,7 +241,7 @@ class TestWebBuildCommand extends FlutterCommand { final String description = 'Build a test executable app.'; @override - Future runCommand() async => null; + Future runCommand() async => FlutterCommandResult.fail(); @override bool get shouldRunPub => false; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart index f702f87980ce8..469555a301024 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/build_windows_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:file_testing/file_testing.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -43,10 +41,9 @@ final Platform notWindowsPlatform = FakePlatform( ); void main() { - FileSystem fileSystem; - - ProcessManager processManager; - TestUsage usage; + late FileSystem fileSystem; + late ProcessManager processManager; + late TestUsage usage; setUpAll(() { Cache.disableLocking(); @@ -75,7 +72,7 @@ void main() { // Returns the command matching the build_windows call to generate CMake // files. FakeCommand cmakeGenerationCommand({ - void Function() onRun, + void Function()? onRun, String generator = _defaultGenerator, }) { return FakeCommand( @@ -95,7 +92,7 @@ void main() { // Returns the command matching the build_windows call to build. FakeCommand buildCommand(String buildMode, { bool verbose = false, - void Function() onRun, + void Function()? onRun, String stdout = '', }) { return FakeCommand( @@ -974,7 +971,7 @@ class FakeVisualStudio extends Fake implements VisualStudio { }); @override - final String cmakePath; + final String? cmakePath; @override final String cmakeGenerator; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart index 523c3b2defd37..6cc52e3230972 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -28,13 +26,13 @@ class FakePub extends Fake implements Pub { @override Future get({ - PubContext context, - String directory, + PubContext? context, + String? directory, bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, - String flutterRootOverride, + String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, @@ -50,8 +48,8 @@ class FakePub extends Fake implements Pub { void main() { group('usageValues', () { - Testbed testbed; - FakePub fakePub; + late Testbed testbed; + late FakePub fakePub; setUpAll(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart index 3a3f057c0143c..1d23c9872e454 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/custom_devices_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:typed_data'; @@ -23,7 +21,6 @@ import 'package:flutter_tools/src/commands/custom_devices.dart'; import 'package:flutter_tools/src/custom_devices/custom_device_config.dart'; import 'package:flutter_tools/src/custom_devices/custom_devices_config.dart'; import 'package:flutter_tools/src/runner/flutter_command_runner.dart'; -import 'package:meta/meta.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -171,7 +168,7 @@ final Platform windowsPlatform = FakePlatform( ); class FakeTerminal implements Terminal { - factory FakeTerminal({Platform platform}) { + factory FakeTerminal({required Platform platform}) { return FakeTerminal._private( stdio: FakeStdio(), platform: platform @@ -179,8 +176,8 @@ class FakeTerminal implements Terminal { } FakeTerminal._private({ - this.stdio, - Platform platform + required this.stdio, + required Platform platform }) : terminal = AnsiTerminal( stdio: stdio, @@ -215,9 +212,9 @@ class FakeTerminal implements Terminal { @override Future promptForCharInput( List acceptedCharacters, { - Logger logger, - String prompt, - int defaultChoiceIndex, + required Logger logger, + String? prompt, + int? defaultChoiceIndex, bool displayAcceptedCharacters = true }) => terminal.promptForCharInput( acceptedCharacters, @@ -253,10 +250,10 @@ class FakeTerminal implements Terminal { class FakeCommandRunner extends FlutterCommandRunner { FakeCommandRunner({ - @required Platform platform, - @required FileSystem fileSystem, - @required Logger logger, - UserMessages userMessages + required Platform platform, + required FileSystem fileSystem, + required Logger logger, + UserMessages? userMessages }) : _platform = platform, _fileSystem = fileSystem, _logger = logger, @@ -285,7 +282,7 @@ class FakeCommandRunner extends FlutterCommandRunner { userMessages: _userMessages, ); // For compatibility with tests that set this to a relative path. - Cache.flutterRoot = _fileSystem.path.normalize(_fileSystem.path.absolute(Cache.flutterRoot)); + Cache.flutterRoot = _fileSystem.path.normalize(_fileSystem.path.absolute(Cache.flutterRoot!)); return super.runCommand(topLevelResults); } ); @@ -295,13 +292,13 @@ class FakeCommandRunner extends FlutterCommandRunner { /// May take platform, logger, processManager and fileSystem from context if /// not explicitly specified. CustomDevicesCommand createCustomDevicesCommand({ - CustomDevicesConfig Function(FileSystem, Logger) config, - Terminal Function(Platform) terminal, - Platform platform, - FileSystem fileSystem, - ProcessManager processManager, - Logger logger, - PrintFn usagePrintFn, + CustomDevicesConfig Function(FileSystem, Logger)? config, + Terminal Function(Platform)? terminal, + Platform? platform, + FileSystem? fileSystem, + ProcessManager? processManager, + Logger? logger, + PrintFn? usagePrintFn, bool featureEnabled = false }) { platform ??= FakePlatform(); @@ -340,13 +337,13 @@ CustomDevicesCommand createCustomDevicesCommand({ /// May take platform, logger, processManager and fileSystem from context if /// not explicitly specified. CommandRunner createCustomDevicesCommandRunner({ - CustomDevicesConfig Function(FileSystem, Logger) config, - Terminal Function(Platform) terminal, - Platform platform, - FileSystem fileSystem, - ProcessManager processManager, - Logger logger, - PrintFn usagePrintFn, + CustomDevicesConfig Function(FileSystem, Logger)? config, + Terminal Function(Platform)? terminal, + Platform? platform, + FileSystem? fileSystem, + ProcessManager? processManager, + Logger? logger, + PrintFn? usagePrintFn, bool featureEnabled = false, }) { platform ??= FakePlatform(); @@ -372,17 +369,17 @@ CommandRunner createCustomDevicesCommandRunner({ } FakeTerminal createFakeTerminalForAddingSshDevice({ - @required Platform platform, - @required String id, - @required String label, - @required String sdkNameAndVersion, - @required String enabled, - @required String hostname, - @required String username, - @required String runDebug, - @required String usePortForwarding, - @required String screenshot, - @required String apply + required Platform platform, + required String id, + required String label, + required String sdkNameAndVersion, + required String enabled, + required String hostname, + required String username, + required String runDebug, + required String usePortForwarding, + required String screenshot, + required String apply }) { return FakeTerminal(platform: platform) ..simulateStdin(id) diff --git a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart index 71cfa5b4a1861..a03cf8bc4acb2 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/daemon_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:io' as io; import 'dart:typed_data'; @@ -57,7 +55,7 @@ class FakeDaemonStreams implements DaemonStreams { } @override - void send(Map message, [ List binary ]) { + void send(Map message, [ List? binary ]) { outputs.add(DaemonMessage(message, binary != null ? Stream>.value(binary) : null)); } @@ -70,12 +68,12 @@ class FakeDaemonStreams implements DaemonStreams { } void main() { - Daemon daemon; - NotifyingLogger notifyingLogger; + late Daemon daemon; + late NotifyingLogger notifyingLogger; group('daemon', () { - FakeDaemonStreams daemonStreams; - DaemonConnection daemonConnection; + late FakeDaemonStreams daemonStreams; + late DaemonConnection daemonConnection; setUp(() { BufferLogger bufferLogger; bufferLogger = BufferLogger.test(); @@ -100,7 +98,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.version'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.version'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isNotEmpty); @@ -115,7 +113,7 @@ void main() { // Use the flutter_gallery project which has a known set of supported platforms. final String projectPath = globals.fs.path.join(getFlutterRoot(), 'dev', 'integration_tests', 'flutter_gallery'); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'daemon.getSupportedPlatforms', 'params': {'projectRoot': projectPath}, @@ -124,7 +122,7 @@ void main() { expect(response.data['id'], 0); expect(response.data['result'], isNotEmpty); - expect((response.data['result'] as Map)['platforms'], {'macos'}); + expect((response.data['result']! as Map)['platforms'], {'macos'}); }, overrides: { // Disable Android/iOS and enable macOS to make sure result is consistent and defaults are tested off. FeatureFlags: () => TestFeatureFlags(isAndroidEnabled: false, isIOSEnabled: false, isMacOSEnabled: true), @@ -137,11 +135,11 @@ void main() { ); globals.printError('daemon.logMessage test'); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage message) { - return message.data['event'] == 'daemon.logMessage' && (message.data['params'] as Map)['level'] == 'error'; + return message.data['event'] == 'daemon.logMessage' && (message.data['params']! as Map)['level'] == 'error'; }); expect(response.data['id'], isNull); expect(response.data['event'], 'daemon.logMessage'); - final Map logMessage = castStringKeyedMap(response.data['params']).cast(); + final Map logMessage = castStringKeyedMap(response.data['params'])!.cast(); expect(logMessage['level'], 'error'); expect(logMessage['message'], 'daemon.logMessage test'); }, overrides: { @@ -155,11 +153,11 @@ void main() { ); globals.printWarning('daemon.logMessage test'); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage message) { - return message.data['event'] == 'daemon.logMessage' && (message.data['params'] as Map)['level'] == 'warning'; + return message.data['event'] == 'daemon.logMessage' && (message.data['params']! as Map)['level'] == 'warning'; }); expect(response.data['id'], isNull); expect(response.data['event'], 'daemon.logMessage'); - final Map logMessage = castStringKeyedMap(response.data['params']).cast(); + final Map logMessage = castStringKeyedMap(response.data['params'])!.cast(); expect(logMessage['level'], 'warning'); expect(logMessage['message'], 'daemon.logMessage test'); }, overrides: { @@ -203,7 +201,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.shutdown'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'daemon.shutdown'})); return daemon.onExit.then((int code) async { await daemonStreams.inputs.close(); expect(code, 0); @@ -216,7 +214,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.restart'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.restart'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('appId is required')); @@ -228,7 +226,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'app.callServiceExtension', 'params': { @@ -246,7 +244,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.stop'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'app.stop'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('appId is required')); @@ -257,7 +255,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isList); @@ -271,10 +269,10 @@ void main() { final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); daemon.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(FakeAndroidDevice()); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.getDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); - final dynamic result = response.data['result']; + final Object? result = response.data['result']; expect(result, isList); expect(result, isNotEmpty); }); @@ -293,7 +291,7 @@ void main() { expect(response.data['event'], 'device.added'); expect(response.data['params'], isMap); - final Map params = castStringKeyedMap(response.data['params']); + final Map params = castStringKeyedMap(response.data['params'])!; expect(params['platform'], isNotEmpty); // the fake device has a platform of 'android-arm' }); }, overrides: { @@ -307,7 +305,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isList); @@ -321,10 +319,10 @@ void main() { final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); daemon.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(FakeAndroidDevice()); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'device.discoverDevices'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); - final dynamic result = response.data['result']; + final Object? result = response.data['result']; expect(result, isList); expect(result, isNotEmpty); expect(discoverer.discoverDevicesCalled, true); @@ -339,17 +337,17 @@ void main() { daemon.deviceDomain.addDeviceDiscoverer(discoverer); final FakeAndroidDevice device = FakeAndroidDevice(); discoverer.addDevice(device); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'device.supportsRuntimeMode', - 'params': { + 'params': { 'deviceId': 'device', 'buildMode': 'profile', }, })); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); - final dynamic result = response.data['result']; + final Object? result = response.data['result']; expect(result, true); expect(device.supportsRuntimeModeCalledBuildMode, BuildMode.profile); }); @@ -365,17 +363,17 @@ void main() { discoverer.addDevice(device); final FakeDeviceLogReader logReader = FakeDeviceLogReader(); device.logReader = logReader; - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'device.logReader.start', - 'params': { + 'params': { 'deviceId': 'device', }, })); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); expect(firstResponse.data['id'], 0); - final String logReaderId = firstResponse.data['result'] as String; + final String? logReaderId = firstResponse.data['result'] as String?; expect(logReaderId, isNotNull); // Try sending logs. @@ -387,10 +385,10 @@ void main() { // Now try to stop the log reader. expect(logReader.disposeCalled, false); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 1, 'method': 'device.logReader.stop', - 'params': { + 'params': { 'id': logReaderId, }, })); @@ -400,7 +398,7 @@ void main() { }); group('device.startApp and .stopApp', () { - FakeApplicationPackageFactory applicationPackageFactory; + late FakeApplicationPackageFactory applicationPackageFactory; setUp(() { applicationPackageFactory = FakeApplicationPackageFactory(); }); @@ -419,27 +417,27 @@ void main() { // First upload the application package. final FakeApplicationPackage applicationPackage = FakeApplicationPackage(); applicationPackageFactory.applicationPackage = applicationPackage; - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 0, 'method': 'device.uploadApplicationPackage', - 'params': { + 'params': { 'targetPlatform': 'android', 'applicationBinary': 'test_file', }, })); final DaemonMessage applicationPackageIdResponse = await broadcastOutput.firstWhere(_notEvent); expect(applicationPackageIdResponse.data['id'], 0); - expect(applicationPackageFactory.applicationBinaryRequested.basename, 'test_file'); + expect(applicationPackageFactory.applicationBinaryRequested!.basename, 'test_file'); expect(applicationPackageFactory.platformRequested, TargetPlatform.android); - final String applicationPackageId = applicationPackageIdResponse.data['result'] as String; + final String? applicationPackageId = applicationPackageIdResponse.data['result'] as String?; // Try starting the app. final Uri observatoryUri = Uri.parse('http://127.0.0.1:12345/observatory'); device.launchResult = LaunchResult.succeeded(observatoryUri: observatoryUri); - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 1, 'method': 'device.startApp', - 'params': { + 'params': { 'deviceId': 'device', 'applicationPackageId': applicationPackageId, 'debuggingOptions': DebuggingOptions.enabled(BuildInfo.debug).toJson(), @@ -448,15 +446,15 @@ void main() { final DaemonMessage startAppResponse = await broadcastOutput.firstWhere(_notEvent); expect(startAppResponse.data['id'], 1); expect(device.startAppPackage, applicationPackage); - final Map startAppResult = startAppResponse.data['result'] as Map; + final Map startAppResult = startAppResponse.data['result']! as Map; expect(startAppResult['started'], true); expect(startAppResult['observatoryUri'], observatoryUri.toString()); // Try stopping the app. - daemonStreams.inputs.add(DaemonMessage({ + daemonStreams.inputs.add(DaemonMessage({ 'id': 2, 'method': 'device.stopApp', - 'params': { + 'params': { 'deviceId': 'device', 'applicationPackageId': applicationPackageId, }, @@ -464,7 +462,7 @@ void main() { final DaemonMessage stopAppResponse = await broadcastOutput.firstWhere(_notEvent); expect(stopAppResponse.data['id'], 2); expect(device.stopAppPackage, applicationPackage); - final bool stopAppResult = stopAppResponse.data['result'] as bool; + final bool? stopAppResult = stopAppResponse.data['result'] as bool?; expect(stopAppResult, true); }, overrides: { ApplicationPackageFactory: () => applicationPackageFactory, @@ -477,7 +475,7 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('emulatorId is required')); @@ -488,8 +486,8 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - final Map params = {'emulatorId': 'device', 'coldBoot': 1}; - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch', 'params': params})); + final Map params = {'emulatorId': 'device', 'coldBoot': 1}; + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.launch', 'params': params})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['error'], contains('coldBoot is not a bool')); @@ -500,7 +498,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.getEmulators'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'emulator.getEmulators'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere(_notEvent); expect(response.data['id'], 0); expect(response.data['result'], isList); @@ -519,8 +517,8 @@ void main() { unawaited(daemonStreams.outputs.stream .firstWhere((DaemonMessage request) => request.data['method'] == 'app.exposeUrl') .then((DaemonMessage request) { - expect((request.data['params'] as Map)['url'], equals(originalUrl)); - daemonStreams.inputs.add(DaemonMessage({'id': request.data['id'], 'result': {'url': mappedUrl}})); + expect((request.data['params']! as Map)['url'], equals(originalUrl)); + daemonStreams.inputs.add(DaemonMessage({'id': request.data['id'], 'result': {'url': mappedUrl}})); }) ); @@ -534,9 +532,9 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage response) => response.data['id'] == 0); - final Map result = response.data['result'] as Map; + final Map result = response.data['result']! as Map; expect(result, isNotEmpty); expect(result['host'], '127.0.0.1'); expect(result['port'], 1234); @@ -550,9 +548,9 @@ void main() { notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'devtools.serve'})); final DaemonMessage response = await daemonStreams.outputs.stream.firstWhere((DaemonMessage response) => response.data['id'] == 0); - final Map result = response.data['result'] as Map; + final Map result = response.data['result']! as Map; expect(result, isNotEmpty); expect(result['host'], null); expect(result['port'], null); @@ -565,8 +563,8 @@ void main() { await io.IOOverrides.runWithIOOverrides(() async { final FakeSocket socket = FakeSocket(); bool connectCalled = false; - int connectPort; - ioOverrides.connectCallback = (dynamic host, int port) async { + int? connectPort; + ioOverrides.connectCallback = (Object? host, int port) async { connectCalled = true; connectPort = port; if (host == io.InternetAddress.loopbackIPv4) { @@ -579,7 +577,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); @@ -588,7 +586,7 @@ void main() { expect(connectCalled, true); expect(connectPort, 123); - final Object id = firstResponse.data['result']; + final Object? id = firstResponse.data['result']; // Can send received data as event. socket.controller.add(Uint8List.fromList([10, 11, 12])); @@ -596,22 +594,22 @@ void main() { (DaemonMessage message) => message.data['event'] != null && message.data['event'] == 'proxy.data.$id', ); expect(dataEvent.binary, isNotNull); - final List> data = await dataEvent.binary.toList(); + final List> data = await dataEvent.binary!.toList(); expect(data[0], [10, 11, 12]); // Can proxy data to the socket. - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.write', 'params': {'id': id}}, Stream>.value([21, 22, 23]))); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.write', 'params': {'id': id}}, Stream>.value([21, 22, 23]))); await pumpEventQueue(); expect(socket.addedData[0], [21, 22, 23]); // Closes the connection when disconnect request received. expect(socket.closeCalled, false); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.disconnect', 'params': {'id': id}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.disconnect', 'params': {'id': id}})); await pumpEventQueue(); expect(socket.closeCalled, true); // Sends disconnected event when socket.done completer finishes. - socket.doneCompleter.complete(); + socket.doneCompleter.complete(true); final DaemonMessage disconnectEvent = await broadcastOutput.firstWhere( (DaemonMessage message) => message.data['event'] != null && message.data['event'] == 'proxy.disconnected.$id', ); @@ -624,8 +622,8 @@ void main() { await io.IOOverrides.runWithIOOverrides(() async { final FakeSocket socket = FakeSocket(); bool connectIpv4Called = false; - int connectPort; - ioOverrides.connectCallback = (dynamic host, int port) async { + int? connectPort; + ioOverrides.connectCallback = (Object? host, int port) async { connectPort = port; if (host == io.InternetAddress.loopbackIPv4) { connectIpv4Called = true; @@ -639,7 +637,7 @@ void main() { daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); @@ -653,13 +651,13 @@ void main() { testUsingContext('proxy.connect fails if both ipv6 and ipv4 failed', () async { final TestIOOverrides ioOverrides = TestIOOverrides(); await io.IOOverrides.runWithIOOverrides(() async { - ioOverrides.connectCallback = (dynamic host, int port) => throw const io.SocketException('fail'); + ioOverrides.connectCallback = (Object? host, int port) => throw const io.SocketException('fail'); daemon = Daemon( daemonConnection, notifyingLogger: notifyingLogger, ); - daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); + daemonStreams.inputs.add(DaemonMessage({'id': 0, 'method': 'proxy.connect', 'params': {'port': 123}})); final Stream broadcastOutput = daemonStreams.outputs.stream.asBroadcastStream(); final DaemonMessage firstResponse = await broadcastOutput.firstWhere(_notEvent); @@ -671,7 +669,7 @@ void main() { }); group('notifyingLogger', () { - BufferLogger bufferLogger; + late BufferLogger bufferLogger; setUp(() { bufferLogger = BufferLogger.test(); }); @@ -713,7 +711,7 @@ void main() { }); group('daemon queue', () { - DebounceOperationQueue queue; + late DebounceOperationQueue queue; const Duration debounceDuration = Duration(seconds: 1); setUp(() { @@ -741,7 +739,7 @@ void main() { await _runFakeAsync((FakeAsync time) async { final List> operations = >[ queue.queueAndDebounce('OP1', debounceDuration, () async => 1), - Future.delayed(debounceDuration * 2).then((_) => + Future.delayed(debounceDuration * 2).then((_) => queue.queueAndDebounce('OP1', debounceDuration, () async => 2)), ]; @@ -873,42 +871,42 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { @override bool get supportsStartPaused => true; - BuildMode supportsRuntimeModeCalledBuildMode; + BuildMode? supportsRuntimeModeCalledBuildMode; @override Future supportsRuntimeMode(BuildMode buildMode) async { supportsRuntimeModeCalledBuildMode = buildMode; return true; } - DeviceLogReader logReader; + late DeviceLogReader logReader; @override FutureOr getLogReader({ - covariant ApplicationPackage app, + covariant ApplicationPackage? app, bool includePastLogs = false, }) => logReader; - ApplicationPackage startAppPackage; - LaunchResult launchResult; + ApplicationPackage? startAppPackage; + late LaunchResult launchResult; @override Future startApp( ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs = const {}, + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { startAppPackage = package; return launchResult; } - ApplicationPackage stopAppPackage; + ApplicationPackage? stopAppPackage; @override Future stopApp( ApplicationPackage app, { - String userIdentifier, + String? userIdentifier, }) async { stopAppPackage = app; return true; @@ -920,10 +918,10 @@ class FakeDeviceLogReader implements DeviceLogReader { bool disposeCalled = false; @override - int appPid; + int? appPid; @override - FlutterVmService connectedVMService; + FlutterVmService? connectedVMService; @override void dispose() { @@ -941,22 +939,22 @@ class FakeDeviceLogReader implements DeviceLogReader { class FakeDevtoolsLauncher extends Fake implements DevtoolsLauncher { FakeDevtoolsLauncher(this._serverAddress); - final DevToolsServerAddress _serverAddress; + final DevToolsServerAddress? _serverAddress; @override - Future serve() async => _serverAddress; + Future serve() async => _serverAddress; @override Future close() async {} } class FakeApplicationPackageFactory implements ApplicationPackageFactory { - TargetPlatform platformRequested; - File applicationBinaryRequested; - ApplicationPackage applicationPackage; + TargetPlatform? platformRequested; + File? applicationBinaryRequested; + ApplicationPackage? applicationPackage; @override - Future getPackageForPlatform(TargetPlatform platform, {BuildInfo buildInfo, File applicationBinary}) async { + Future getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { platformRequested = platform; applicationBinaryRequested = applicationBinary; return applicationPackage; @@ -966,11 +964,11 @@ class FakeApplicationPackageFactory implements ApplicationPackageFactory { class FakeApplicationPackage extends Fake implements ApplicationPackage {} class TestIOOverrides extends io.IOOverrides { - Future Function(dynamic host, int port) connectCallback; + late Future Function(Object? host, int port) connectCallback; @override - Future socketConnect(dynamic host, int port, - {dynamic sourceAddress, int sourcePort = 0, Duration timeout}) { + Future socketConnect(Object? host, int port, + {Object? sourceAddress, int sourcePort = 0, Duration? timeout}) { return connectCallback(host, port); } } @@ -983,10 +981,10 @@ class FakeSocket extends Fake implements io.Socket { @override StreamSubscription listen( - void Function(Uint8List event) onData, { - Function onError, - void Function() onDone, - bool cancelOnError, + void Function(Uint8List event)? onData, { + Function? onError, + void Function()? onDone, + bool? cancelOnError, }) { return controller.stream.listen(onData, onError: onError, onDone: onDone, cancelOnError: cancelOnError); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart index ca3ffe87c21f8..46bfb7fbe4a9c 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/devices_test.dart @@ -2,12 +2,12 @@ // 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:convert'; import 'package:flutter_tools/src/android/android_sdk.dart'; import 'package:flutter_tools/src/artifacts.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/devices.dart'; import 'package:flutter_tools/src/device.dart'; @@ -24,7 +24,7 @@ void main() { Cache.disableLocking(); }); - Cache cache; + late Cache cache; setUp(() { cache = Cache.test(processManager: FakeProcessManager.any()); @@ -52,7 +52,7 @@ void main() { testUsingContext("get devices' platform types", () async { final List platformTypes = Device.devicesPlatformTypes( - await globals.deviceManager.getAllConnectedDevices(), + await globals.deviceManager!.getAllConnectedDevices(), ); expect(platformTypes, ['android', 'web']); }, overrides: { @@ -133,14 +133,14 @@ webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulato } class _FakeDeviceManager extends DeviceManager { - _FakeDeviceManager(); + _FakeDeviceManager() : super(logger: testLogger, terminal: Terminal.test(), userMessages: userMessages); @override Future> getAllConnectedDevices() => Future>.value(fakeDevices.map((FakeDeviceJsonData d) => d.dev).toList()); @override - Future> refreshAllConnectedDevices({Duration timeout}) => + Future> refreshAllConnectedDevices({Duration? timeout}) => getAllConnectedDevices(); @override @@ -153,11 +153,13 @@ class _FakeDeviceManager extends DeviceManager { } class NoDevicesManager extends DeviceManager { + NoDevicesManager() : super(logger: testLogger, terminal: Terminal.test(), userMessages: userMessages); + @override Future> getAllConnectedDevices() async => []; @override - Future> refreshAllConnectedDevices({Duration timeout}) => + Future> refreshAllConnectedDevices({Duration? timeout}) => getAllConnectedDevices(); @override diff --git a/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart index a2ad7121d0a8d..90b2e6ee3c0ee 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/downgrade_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/io.dart'; @@ -20,11 +18,11 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger bufferLogger; - FakeTerminal terminal; - ProcessManager processManager; - FakeStdio stdio; + late FileSystem fileSystem; + late BufferLogger bufferLogger; + late FakeTerminal terminal; + late ProcessManager processManager; + late FakeStdio stdio; setUpAll(() { Cache.disableLocking(); @@ -224,11 +222,11 @@ class FakeTerminal extends Fake implements Terminal { _selected = selected; } - List _characters; - String _selected; + List? _characters; + late String _selected; @override - Future promptForCharInput(List acceptedCharacters, {Logger logger, String prompt, int defaultChoiceIndex, bool displayAcceptedCharacters = true}) async { + Future promptForCharInput(List acceptedCharacters, {Logger? logger, String? prompt, int? defaultChoiceIndex, bool displayAcceptedCharacters = true}) async { expect(acceptedCharacters, _characters); return _selected; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart index 4cdf7531f6c86..397b4a666ce39 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/drive_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/application_package.dart'; import 'package:flutter_tools/src/base/common.dart'; @@ -25,10 +23,10 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - FakeDeviceManager fakeDeviceManager; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late FakeDeviceManager fakeDeviceManager; setUp(() { fileSystem = MemoryFileSystem.test(); @@ -254,15 +252,15 @@ void main() { class ThrowingScreenshotDevice extends ScreenshotDevice { @override Future startApp( - ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + ApplicationPackage? package, { + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map? platformArgs, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { throwToolExit('cannot start app'); } @@ -289,15 +287,15 @@ class ScreenshotDevice extends Fake implements Device { @override Future startApp( - ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + ApplicationPackage? package, { + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map? platformArgs, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async => LaunchResult.succeeded(); @override @@ -307,13 +305,13 @@ class ScreenshotDevice extends Fake implements Device { class FakePub extends Fake implements Pub { @override Future get({ - PubContext context, - String directory, + PubContext? context, + String? directory, bool skipIfAbsent = false, bool upgrade = false, bool offline = false, bool generateSyntheticPackage = false, - String flutterRootOverride, + String? flutterRootOverride, bool checkUpToDate = false, bool shouldSkipThirdPartyGenerator = true, bool printProgress = true, @@ -324,13 +322,13 @@ class FakeDeviceManager extends Fake implements DeviceManager { List devices = []; @override - String specifiedDeviceId; + String? specifiedDeviceId; @override Future> getDevices() async => devices; @override - Future> findTargetDevices(FlutterProject flutterProject, {Duration timeout}) async => devices; + Future> findTargetDevices(FlutterProject? flutterProject, {Duration? timeout}) async => devices; } class FailingFakeFlutterDriverFactory extends Fake implements FlutterDriverFactory { @@ -348,13 +346,13 @@ class FailingFakeDriverService extends Fake implements DriverService { List arguments, Map environment, PackageConfig packageConfig, { - bool headless, - String chromeBinary, - String browserName, - bool androidEmulator, - int driverPort, - List webBrowserFlags, - List browserDimension, - String profileMemory, + bool? headless, + String? chromeBinary, + String? browserName, + bool? androidEmulator, + int? driverPort, + List? webBrowserFlags, + List? browserDimension, + String? profileMemory, }) async => 1; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart index 85d7b917e34e7..c2507e71a5d80 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/generate_localizations_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/artifacts.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -18,10 +16,10 @@ import '../../src/fake_process_manager.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Artifacts artifacts; - FakeProcessManager processManager; + late FileSystem fileSystem; + late BufferLogger logger; + late Artifacts artifacts; + late FakeProcessManager processManager; setUpAll(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart index dcd7c484ddaa4..1a544a787a209 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/ide_config_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -17,12 +15,12 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('ide_config', () { - Directory tempDir; - Directory templateDir; - Directory intellijDir; - Directory toolsDir; + late Directory tempDir; + late Directory templateDir; + late Directory intellijDir; + late Directory toolsDir; - Map getFilesystemContents([ Directory root ]) { + Map getFilesystemContents([ Directory? root ]) { final String tempPath = tempDir.absolute.path; final List paths = (root ?? tempDir).listSync(recursive: true).map((FileSystemEntity entity) { @@ -67,7 +65,7 @@ void main() { if (manifest[key] != 'dir') { tempDir.childFile(key) ..createSync(recursive: true) - ..writeAsStringSync(manifest[key]); + ..writeAsStringSync(manifest[key]!); } } } @@ -78,7 +76,7 @@ void main() { } Future updateIdeConfig({ - Directory dir, + Directory? dir, List args = const [], Map expectedContents = const {}, List unexpectedPaths = const [], diff --git a/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart index 4504abd8d1035..54810d871145b 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/install_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/file.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/android/android_device.dart'; @@ -27,7 +25,7 @@ void main() { Cache.disableLocking(); }); - FileSystem fileSystem; + late FileSystem fileSystem; setUp(() { fileSystem = MemoryFileSystem.test(); fileSystem.file('pubspec.yaml').createSync(recursive: true); @@ -114,7 +112,7 @@ class FakeApplicationPackageFactory extends Fake implements ApplicationPackageFa final ApplicationPackage app; @override - Future getPackageForPlatform(TargetPlatform platform, {BuildInfo buildInfo, File applicationBinary}) async { + Future getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { return app; } } @@ -131,13 +129,13 @@ class FakeIOSDevice extends Fake implements IOSDevice { @override Future isAppInstalled( IOSApp app, { - String userIdentifier, + String? userIdentifier, }) async => false; @override Future installApp( IOSApp app, { - String userIdentifier, + String? userIdentifier, }) async => true; } @@ -151,12 +149,12 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { @override Future isAppInstalled( AndroidApk app, { - String userIdentifier, + String? userIdentifier, }) async => false; @override Future installApp( AndroidApk app, { - String userIdentifier, + String? userIdentifier, }) async => true; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart index c6550bdffad2b..2aaa015bbda78 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/logs_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/logs.dart'; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart index 6db68d011d5fb..53ffc0d30c497 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/precache_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -16,7 +14,7 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FakeCache cache; + late FakeCache cache; setUp(() { cache = FakeCache(); @@ -429,7 +427,7 @@ class FakeCache extends Fake implements Cache { bool isUpToDateValue = false; bool clearedStampFiles = false; bool locked = false; - Set artifacts; + Set? artifacts; @override Future lock() async { @@ -455,7 +453,7 @@ class FakeCache extends Fake implements Cache { } @override - Set platformOverrideArtifacts; + Set? platformOverrideArtifacts; @override bool includeAllPlatforms = false; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart index e70fcdc5afa03..1cfa8ff6c4dcd 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/proxied_devices_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:file/memory.dart'; @@ -24,18 +22,18 @@ import '../../src/context.dart'; import '../../src/fake_devices.dart'; void main() { - Daemon daemon; - NotifyingLogger notifyingLogger; - BufferLogger bufferLogger; - FakeAndroidDevice fakeDevice; + Daemon? daemon; + late NotifyingLogger notifyingLogger; + late BufferLogger bufferLogger; + late FakeAndroidDevice fakeDevice; - FakeApplicationPackageFactory applicationPackageFactory; - MemoryFileSystem memoryFileSystem; - FakeProcessManager fakeProcessManager; + late FakeApplicationPackageFactory applicationPackageFactory; + late MemoryFileSystem memoryFileSystem; + late FakeProcessManager fakeProcessManager; group('ProxiedDevices', () { - DaemonConnection serverDaemonConnection; - DaemonConnection clientDaemonConnection; + late DaemonConnection serverDaemonConnection; + late DaemonConnection clientDaemonConnection; setUp(() { bufferLogger = BufferLogger.test(); notifyingLogger = NotifyingLogger(verbose: false, parent: bufferLogger); @@ -60,7 +58,7 @@ void main() { tearDown(() async { if (daemon != null) { - return daemon.shutdown(); + return daemon!.shutdown(); } notifyingLogger.dispose(); await serverDaemonConnection.dispose(); @@ -74,7 +72,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -95,7 +93,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -115,7 +113,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -145,7 +143,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -173,9 +171,9 @@ void main() { expect(launchResult.started, true); // The returned observatoryUri was a forwarded port, so we cannot compare them directly. - expect(launchResult.observatoryUri.path, observatoryUri.path); + expect(launchResult.observatoryUri!.path, observatoryUri.path); - expect(applicationPackageFactory.applicationBinaryRequested.readAsStringSync(), 'dummy content'); + expect(applicationPackageFactory.applicationBinaryRequested!.readAsStringSync(), 'dummy content'); expect(applicationPackageFactory.platformRequested, TargetPlatform.android_arm); expect(fakeDevice.startAppPackage, applicationPackage); @@ -197,7 +195,7 @@ void main() { ); fakeDevice = FakeAndroidDevice(); final FakePollingDeviceDiscovery discoverer = FakePollingDeviceDiscovery(); - daemon.deviceDomain.addDeviceDiscoverer(discoverer); + daemon!.deviceDomain.addDeviceDiscoverer(discoverer); discoverer.addDevice(fakeDevice); final ProxiedDevices proxiedDevices = ProxiedDevices(clientDaemonConnection, logger: bufferLogger); @@ -230,7 +228,7 @@ class FakeDaemonStreams implements DaemonStreams { } @override - void send(Map message, [ List binary ]) { + void send(Map message, [ List? binary ]) { outputs.add(DaemonMessage(message, binary != null ? Stream>.value(binary) : null)); } @@ -294,48 +292,48 @@ class FakeAndroidDevice extends Fake implements AndroidDevice { @override bool get supportsStartPaused => true; - BuildMode supportsRuntimeModeCalledBuildMode; + BuildMode? supportsRuntimeModeCalledBuildMode; @override Future supportsRuntimeMode(BuildMode buildMode) async { supportsRuntimeModeCalledBuildMode = buildMode; return true; } - DeviceLogReader logReader; + late DeviceLogReader logReader; @override FutureOr getLogReader({ - covariant ApplicationPackage app, + covariant ApplicationPackage? app, bool includePastLogs = false, }) => logReader; - ApplicationPackage startAppPackage; - LaunchResult launchResult; + ApplicationPackage? startAppPackage; + late LaunchResult launchResult; @override Future startApp( ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs = const {}, + String? mainPath, + String? route, + DebuggingOptions? debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { startAppPackage = package; return launchResult; } - ApplicationPackage stopAppPackage; + ApplicationPackage? stopAppPackage; @override Future stopApp( ApplicationPackage app, { - String userIdentifier, + String? userIdentifier, }) async { stopAppPackage = app; return true; } - List screenshot; + late List screenshot; @override Future takeScreenshot(File outputFile) { return outputFile.writeAsBytes(screenshot); @@ -347,10 +345,10 @@ class FakeDeviceLogReader implements DeviceLogReader { bool disposeCalled = false; @override - int appPid; + int? appPid; @override - FlutterVmService connectedVMService; + FlutterVmService? connectedVMService; @override void dispose() { @@ -366,12 +364,12 @@ class FakeDeviceLogReader implements DeviceLogReader { } class FakeApplicationPackageFactory implements ApplicationPackageFactory { - TargetPlatform platformRequested; - File applicationBinaryRequested; - ApplicationPackage applicationPackage; + TargetPlatform? platformRequested; + File? applicationBinaryRequested; + ApplicationPackage? applicationPackage; @override - Future getPackageForPlatform(TargetPlatform platform, {BuildInfo buildInfo, File applicationBinary}) async { + Future getPackageForPlatform(TargetPlatform platform, {BuildInfo? buildInfo, File? applicationBinary}) async { platformRequested = platform; applicationBinaryRequested = applicationBinary; return applicationPackage; @@ -382,5 +380,5 @@ class FakeApplicationPackage extends Fake implements ApplicationPackage {} class FakePrebuiltApplicationPackage extends Fake implements PrebuiltApplicationPackage { @override - File applicationPackage; + late File applicationPackage; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index 4ebcb4ff40c51..8ad2c8787dcbb 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:file/file.dart'; @@ -31,7 +29,6 @@ import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:flutter_tools/src/resident_runner.dart'; import 'package:flutter_tools/src/runner/flutter_command.dart'; import 'package:flutter_tools/src/vmservice.dart'; -import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import 'package:vm_service/vm_service.dart'; @@ -47,8 +44,8 @@ void main() { }); group('run', () { - FakeDeviceManager mockDeviceManager; - FileSystem fileSystem; + late FakeDeviceManager mockDeviceManager; + late FileSystem fileSystem; setUp(() { mockDeviceManager = FakeDeviceManager(); @@ -142,10 +139,10 @@ void main() { }); group('run app', () { - MemoryFileSystem fs; - Artifacts artifacts; - TestUsage usage; - FakeAnsiTerminal fakeTerminal; + late MemoryFileSystem fs; + late Artifacts artifacts; + late TestUsage usage; + late FakeAnsiTerminal fakeTerminal; setUpAll(() { Cache.disableLocking(); @@ -555,8 +552,8 @@ void main() { }); group('Fatal Logs', () { - TestRunCommandWithFakeResidentRunner command; - MemoryFileSystem fs; + late TestRunCommandWithFakeResidentRunner command; + late MemoryFileSystem fs; setUp(() { command = TestRunCommandWithFakeResidentRunner() @@ -666,7 +663,7 @@ void main() { }); group('dart-defines and web-renderer options', () { - List dartDefines; + late List dartDefines; setUp(() { dartDefines = []; @@ -707,7 +704,7 @@ void main() { }); group('terminal', () { - FakeAnsiTerminal fakeTerminal; + late FakeAnsiTerminal fakeTerminal; setUp(() { fakeTerminal = FakeAnsiTerminal(); @@ -877,7 +874,7 @@ void main() { expect(options.webLaunchUrl, 'http://flutter.dev'); final RegExp pattern = RegExp(r'^((http)?:\/\/)[^\s]+'); - expect(pattern.hasMatch(options.webLaunchUrl), true); + expect(pattern.hasMatch(options.webLaunchUrl!), true); }, overrides: { ProcessManager: () => FakeProcessManager.any(), Logger: () => BufferLogger.test(), @@ -889,7 +886,7 @@ class FakeDeviceManager extends Fake implements DeviceManager { List targetDevices = []; @override - String specifiedDeviceId; + String? specifiedDeviceId; @override bool hasSpecifiedAllDevices = false; @@ -903,7 +900,7 @@ class FakeDeviceManager extends Fake implements DeviceManager { } @override - Future> findTargetDevices(FlutterProject flutterProject, {Duration timeout}) async { + Future> findTargetDevices(FlutterProject? flutterProject, {Duration? timeout}) async { return targetDevices; } @@ -950,7 +947,7 @@ class FakeDevice extends Fake implements Device { @override String get id => 'fake_device'; - void _throwToolExit(int code) => throwToolExit('FakeDevice tool exit', exitCode: code); + Never _throwToolExit(int code) => throwToolExit('FakeDevice tool exit', exitCode: code); @override Future get isLocalEmulator => Future.value(_isLocalEmulator); @@ -987,7 +984,7 @@ class FakeDevice extends Fake implements Device { @override DeviceLogReader getLogReader({ - ApplicationPackage app, + ApplicationPackage? app, bool includePastLogs = false, }) { return FakeDeviceLogReader(); @@ -1002,27 +999,27 @@ class FakeDevice extends Fake implements Device { @override PlatformType get platformType => _platformType; - bool startAppSuccess; + late bool startAppSuccess; @override - DevFSWriter createDevFSWriter( - covariant ApplicationPackage app, - String userIdentifier, + DevFSWriter? createDevFSWriter( + covariant ApplicationPackage? app, + String? userIdentifier, ) { return null; } @override Future startApp( - ApplicationPackage package, { - String mainPath, - String route, - DebuggingOptions debuggingOptions, - Map platformArgs, + ApplicationPackage? package, { + String? mainPath, + String? route, + required DebuggingOptions debuggingOptions, + Map platformArgs = const {}, bool prebuiltApplication = false, bool usesTerminalUi = true, bool ipv6 = false, - String userIdentifier, + String? userIdentifier, }) async { if (startAppSuccess == false) { return LaunchResult.failed(); @@ -1045,19 +1042,18 @@ class FakeDevice extends Fake implements Device { } _throwToolExit(kSuccess); } - return null; } } class TestRunCommandWithFakeResidentRunner extends RunCommand { - FakeResidentRunner fakeResidentRunner; + late FakeResidentRunner fakeResidentRunner; @override Future createRunner({ - @required bool hotMode, - @required List flutterDevices, - @required String applicationBinaryPath, - @required FlutterProject flutterProject, + required bool hotMode, + required List flutterDevices, + required String? applicationBinaryPath, + required FlutterProject flutterProject, }) async { return fakeResidentRunner; } @@ -1077,26 +1073,26 @@ class TestRunCommandThatOnlyValidates extends RunCommand { } class FakeResidentRunner extends Fake implements ResidentRunner { - RPCError rpcError; + RPCError? rpcError; @override Future run({ - Completer connectionInfoCompleter, - Completer appStartedCompleter, + Completer? connectionInfoCompleter, + Completer? appStartedCompleter, bool enableDevTools = false, - String route, + String? route, }) async { await null; if (rpcError != null) { - throw rpcError; + throw rpcError!; } return 0; } } class DaemonCapturingRunCommand extends RunCommand { - /*late*/ Daemon daemon; - /*late*/ CapturingAppDomain appDomain; + late Daemon daemon; + late CapturingAppDomain appDomain; @override Daemon createMachineDaemon() { @@ -1108,29 +1104,29 @@ class DaemonCapturingRunCommand extends RunCommand { } class CapturingAppDomain extends AppDomain { - CapturingAppDomain(Daemon daemon) : super(daemon); + CapturingAppDomain(super.daemon); - bool /*?*/ multidexEnabled; - String /*?*/ userIdentifier; + bool? multidexEnabled; + String? userIdentifier; @override Future startApp( Device device, String projectDirectory, String target, - String route, + String? route, DebuggingOptions options, bool enableHotReload, { - File applicationBinary, - @required bool trackWidgetCreation, - String projectRootPath, - String packagesFilePath, - String dillOutputPath, + File? applicationBinary, + required bool trackWidgetCreation, + String? projectRootPath, + String? packagesFilePath, + String? dillOutputPath, bool ipv6 = false, bool multidexEnabled = false, - String isolateFilter, + String? isolateFilter, bool machine = true, - String userIdentifier, + String? userIdentifier, }) async { this.multidexEnabled = multidexEnabled; this.userIdentifier = userIdentifier; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart index 2e075d4c972b3..8c005b69decc3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/screenshot_command_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -23,7 +21,7 @@ void main() { testUsingContext('rasterizer and skia screenshots do not require a device', () async { // Throw a specific exception when attempting to make a VM Service connection to // verify that we've made it past the initial validation. - openChannelForTesting = (String url, {CompressionOptions compression, Logger logger}) async { + openChannelForTesting = (String url, {CompressionOptions? compression, Logger? logger}) async { expect(url, 'ws://localhost:8181/ws'); throw Exception('dummy'); }; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart index 97bfd1c32ac56..5e632024bfc31 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/shell_completion_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -18,7 +16,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('shell_completion', () { - FakeStdio fakeStdio; + late FakeStdio fakeStdio; setUp(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart index bd601705c2f2d..fb5d1810db604 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/symbolize_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:typed_data'; @@ -15,7 +13,6 @@ import 'package:flutter_tools/src/base/terminal.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/symbolize.dart'; import 'package:flutter_tools/src/convert.dart'; -import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import '../../src/common.dart'; @@ -24,8 +21,8 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - MemoryFileSystem fileSystem; - FakeStdio stdio; + late MemoryFileSystem fileSystem; + late FakeStdio stdio; setUpAll(() { Cache.disableLocking(); @@ -154,9 +151,9 @@ void main() { class ThrowingDwarfSymbolizationService extends Fake implements DwarfSymbolizationService { @override Future decode({ - @required Stream> input, - @required IOSink output, - @required Uint8List symbols, + required Stream> input, + required IOSink output, + required Uint8List symbols, }) async { throwToolExit('test'); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart index ecf81933ee9cd..8fa700837adb3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/test_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:convert'; @@ -12,7 +10,8 @@ import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/common.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; -import 'package:flutter_tools/src/build_info.dart'; +import 'package:flutter_tools/src/base/terminal.dart'; +import 'package:flutter_tools/src/base/user_messages.dart'; import 'package:flutter_tools/src/cache.dart'; import 'package:flutter_tools/src/commands/test.dart'; import 'package:flutter_tools/src/device.dart'; @@ -22,7 +21,6 @@ import 'package:flutter_tools/src/test/runner.dart'; import 'package:flutter_tools/src/test/test_time_recorder.dart'; import 'package:flutter_tools/src/test/test_wrapper.dart'; import 'package:flutter_tools/src/test/watcher.dart'; -import 'package:meta/meta.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -59,8 +57,8 @@ final String _packageConfigContents = json.encode({ void main() { Cache.disableLocking(); - MemoryFileSystem fs; - LoggingLogger logger; + late MemoryFileSystem fs; + late LoggingLogger logger; setUp(() { fs = MemoryFileSystem.test(); @@ -790,51 +788,47 @@ class FakeFlutterTestRunner implements FlutterTestRunner { FakeFlutterTestRunner(this.exitCode, [this.leastRunTime]); int exitCode; - Duration leastRunTime; - bool lastEnableObservatoryValue; - DebuggingOptions lastDebuggingOptionsValue; + Duration? leastRunTime; + bool? lastEnableObservatoryValue; + late DebuggingOptions lastDebuggingOptionsValue; @override Future runTests( TestWrapper testWrapper, List testFiles, { - @required DebuggingOptions debuggingOptions, - Directory workDir, + required DebuggingOptions debuggingOptions, List names = const [], List plainNames = const [], - String tags, - String excludeTags, + String? tags, + String? excludeTags, bool enableObservatory = false, bool ipv6 = false, bool machine = false, - String precompiledDillPath, - Map precompiledDillFiles, - BuildMode buildMode, - bool trackWidgetCreation = false, + String? precompiledDillPath, + Map? precompiledDillFiles, bool updateGoldens = false, - TestWatcher watcher, - int concurrency, - String testAssetDirectory, - FlutterProject flutterProject, - String icudtlPath, - Directory coverageDirectory, + TestWatcher? watcher, + required int? concurrency, + String? testAssetDirectory, + FlutterProject? flutterProject, + String? icudtlPath, + Directory? coverageDirectory, bool web = false, - String randomSeed, - @override List extraFrontEndOptions, - String reporter, - String timeout, + String? randomSeed, + String? reporter, + String? timeout, bool runSkipped = false, - int shardIndex, - int totalShards, - Device integrationTestDevice, - String integrationTestUserIdentifier, - TestTimeRecorder testTimeRecorder, + int? shardIndex, + int? totalShards, + Device? integrationTestDevice, + String? integrationTestUserIdentifier, + TestTimeRecorder? testTimeRecorder, }) async { lastEnableObservatoryValue = enableObservatory; lastDebuggingOptionsValue = debuggingOptions; if (leastRunTime != null) { - await Future.delayed(leastRunTime); + await Future.delayed(leastRunTime!); } return exitCode; @@ -842,7 +836,7 @@ class FakeFlutterTestRunner implements FlutterTestRunner { } class FakePackageTest implements TestWrapper { - List lastArgs; + List? lastArgs; @override Future main(List args) async { @@ -857,7 +851,7 @@ class FakePackageTest implements TestWrapper { } class _FakeDeviceManager extends DeviceManager { - _FakeDeviceManager(this._connectedDevices); + _FakeDeviceManager(this._connectedDevices) : super(logger: testLogger, terminal: Terminal.test(), userMessages: userMessages); final List _connectedDevices; diff --git a/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart index 5e31c7ec3dd71..1bfdb01ea8ba4 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/upgrade_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'package:args/command_runner.dart'; @@ -20,12 +18,12 @@ import '../../src/fakes.dart' show FakeFlutterVersion; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - FakeProcessManager processManager; + late FileSystem fileSystem; + late BufferLogger logger; + late FakeProcessManager processManager; UpgradeCommand command; - CommandRunner runner; - FlutterVersion flutterVersion; + late CommandRunner runner; + late FlutterVersion flutterVersion; setUpAll(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart index 27c26878e489d..b3d346dc1cbac 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; @@ -16,7 +14,6 @@ import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals.dart' as globals; import 'package:flutter_tools/src/project.dart'; import 'package:flutter_tools/src/reporting/reporting.dart'; -import 'package:meta/meta.dart'; import 'package:test/fake.dart'; import '../../src/android_common.dart'; @@ -29,7 +26,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { Cache.disableLocking(); - Future runCommandIn(String target, { List arguments }) async { + Future runCommandIn(String target, { List? arguments }) async { final BuildAarCommand command = BuildAarCommand(verboseHelp: false); final CommandRunner runner = createTestCommandRunner(command); await runner.run([ @@ -42,8 +39,8 @@ void main() { } group('Usage', () { - Directory tempDir; - TestUsage testUsage; + late Directory tempDir; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -110,8 +107,8 @@ void main() { }); group('flag parsing', () { - Directory tempDir; - FakeAndroidBuilder fakeAndroidBuilder; + late Directory tempDir; + late FakeAndroidBuilder fakeAndroidBuilder; setUp(() { fakeAndroidBuilder = FakeAndroidBuilder(); @@ -193,11 +190,11 @@ void main() { }); group('Gradle', () { - Directory tempDir; - AndroidSdk mockAndroidSdk; - String gradlew; - FakeProcessManager processManager; - String flutterRoot; + late Directory tempDir; + late AndroidSdk mockAndroidSdk; + late String gradlew; + late FakeProcessManager processManager; + late String flutterRoot; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); @@ -277,7 +274,7 @@ void main() { Future runBuildAarCommand( String target, { - List arguments, + List? arguments, }) async { final BuildAarCommand command = BuildAarCommand(verboseHelp: false); final CommandRunner runner = createTestCommandRunner(command); @@ -291,19 +288,19 @@ Future runBuildAarCommand( } class FakeAndroidBuilder extends Fake implements AndroidBuilder { - FlutterProject project; - Set androidBuildInfo; - String target; - String outputDirectoryPath; - String buildNumber; + late FlutterProject project; + late Set androidBuildInfo; + late String target; + String? outputDirectoryPath; + late String buildNumber; @override Future buildAar({ - @required FlutterProject project, - @required Set androidBuildInfo, - @required String target, - @required String outputDirectoryPath, - @required String buildNumber, + required FlutterProject project, + required Set androidBuildInfo, + required String target, + String? outputDirectoryPath, + required String buildNumber, }) async { this.project = project; this.androidBuildInfo = androidBuildInfo; diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart index 52178121c2a0f..19540e56de6ce 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; @@ -26,8 +24,8 @@ void main() { Cache.disableLocking(); group('Usage', () { - Directory tempDir; - TestUsage testUsage; + late Directory tempDir; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -108,11 +106,11 @@ void main() { }); group('Gradle', () { - Directory tempDir; - FakeProcessManager processManager; - String gradlew; - AndroidSdk mockAndroidSdk; - TestUsage testUsage; + late Directory tempDir; + late FakeProcessManager processManager; + late String gradlew; + late AndroidSdk mockAndroidSdk; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -429,7 +427,7 @@ void main() { Future runBuildApkCommand( String target, { - List arguments, + List? arguments, }) async { final BuildApkCommand command = BuildApkCommand(); final CommandRunner runner = createTestCommandRunner(command); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart index 5b5b94ac55fc3..9f2126716893c 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/android/android_builder.dart'; import 'package:flutter_tools/src/android/android_sdk.dart'; @@ -24,8 +22,8 @@ void main() { Cache.disableLocking(); group('Usage', () { - Directory tempDir; - TestUsage testUsage; + late Directory tempDir; + late TestUsage testUsage; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); @@ -87,10 +85,10 @@ void main() { }); group('Gradle', () { - Directory tempDir; - FakeProcessManager processManager; - FakeAndroidSdk fakeAndroidSdk; - TestUsage testUsage; + late Directory tempDir; + late FakeProcessManager processManager; + late FakeAndroidSdk fakeAndroidSdk; + late TestUsage testUsage; setUp(() { testUsage = TestUsage(); @@ -213,7 +211,7 @@ void main() { Future runBuildAppBundleCommand( String target, { - List arguments, + List? arguments, }) async { final BuildAppBundleCommand command = BuildAppBundleCommand(); final CommandRunner runner = createTestCommandRunner(command); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart index be306270c9a4b..772afccc56916 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:file/memory.dart'; import 'package:flutter_tools/src/base/file_system.dart'; @@ -27,8 +25,8 @@ import '../../src/test_flutter_command_runner.dart'; void main() { Cache.disableLocking(); - Directory tempDir; - FakeBundleBuilder fakeBundleBuilder; + late Directory tempDir; + late FakeBundleBuilder fakeBundleBuilder; final FileSystemStyle fileSystemStyle = globals.fs.path.separator == '/' ? FileSystemStyle.posix : FileSystemStyle.windows; @@ -46,7 +44,7 @@ void main() { return MemoryFileSystem.test(style: fileSystemStyle); } - Future runCommandIn(String projectPath, { List arguments }) async { + Future runCommandIn(String projectPath, { List? arguments }) async { final BuildBundleCommand command = BuildBundleCommand(bundleBuilder: fakeBundleBuilder); final CommandRunner runner = createTestCommandRunner(command); await runner.run([ @@ -470,14 +468,14 @@ void main() { class FakeBundleBuilder extends Fake implements BundleBuilder { @override Future build({ - @required TargetPlatform platform, - @required BuildInfo buildInfo, - FlutterProject project, - String mainPath, + required TargetPlatform platform, + required BuildInfo buildInfo, + FlutterProject? project, + String? mainPath, String manifestPath = defaultManifestPath, - String applicationKernelFilePath, - String depfilePath, - String assetDirPath, - @visibleForTesting BuildSystem buildSystem, + String? applicationKernelFilePath, + String? depfilePath, + String? assetDirPath, + @visibleForTesting BuildSystem? buildSystem, }) async {} } diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 6352dd37f2806..47ef02afd8d11 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:async'; import 'dart:convert'; import 'dart:io' as io; @@ -60,12 +58,12 @@ const String samplesIndexJson = ''' ]'''; void main() { - Directory tempDir; - Directory projectDir; - FakeFlutterVersion fakeFlutterVersion; - LoggingProcessManager loggingProcessManager; - FakeProcessManager fakeProcessManager; - BufferLogger logger; + late Directory tempDir; + late Directory projectDir; + late FakeFlutterVersion fakeFlutterVersion; + late LoggingProcessManager loggingProcessManager; + late FakeProcessManager fakeProcessManager; + late BufferLogger logger; setUpAll(() async { Cache.disableLocking(); @@ -569,7 +567,7 @@ void main() { // Expect the dependency on flutter_web_plugins exists expect(pubspec.dependencies, contains('flutter_web_plugins')); // The platform is correctly registered - final YamlMap web = ((pubspec.flutter['plugin'] as YamlMap)['platforms'] as YamlMap)['web'] as YamlMap; + final YamlMap web = ((pubspec.flutter!['plugin'] as YamlMap)['platforms'] as YamlMap)['web'] as YamlMap; expect(web['pluginClass'], 'FlutterProjectWeb'); expect(web['fileName'], 'flutter_project_web.dart'); expect(logger.errorText, isNot(contains(_kNoPlatformsMessage))); @@ -599,7 +597,7 @@ void main() { final String pluginName = projectDir.basename; expect(pubspec.dependencies, contains(pluginName)); expect(pubspec.dependencies[pluginName] is PathDependency, isTrue); - final PathDependency pathDependency = pubspec.dependencies[pluginName] as PathDependency; + final PathDependency pathDependency = pubspec.dependencies[pluginName]! as PathDependency; expect(pathDependency.path, '../'); }, overrides: { Pub: () => Pub( @@ -1158,7 +1156,7 @@ void main() { final String original = file.readAsStringSync(); final Process process = await Process.start( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, ['format', '--output=show', file.path], workingDirectory: projectDir.path, ); @@ -1255,7 +1253,7 @@ void main() { final String original = file.readAsStringSync(); final Process process = await Process.start( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, ['format', '--output=show', file.path], workingDirectory: projectDir.path, ); @@ -2548,9 +2546,9 @@ void main() { await runner.run(['create', '--no-pub', '--template=plugin', projectDir.path]); final String rawPubspec = await projectDir.childFile('pubspec.yaml').readAsString(); final Pubspec pubspec = Pubspec.parse(rawPubspec); - final Map env = pubspec.environment; - expect(env['flutter'].allows(Version(2, 5, 0)), true); - expect(env['flutter'].allows(Version(2, 4, 9)), false); + final Map env = pubspec.environment!; + expect(env['flutter']!.allows(Version(2, 5, 0)), true); + expect(env['flutter']!.allows(Version(2, 4, 9)), false); }); testUsingContext('default app uses flutter default versions', () async { @@ -3084,7 +3082,7 @@ Future _analyzeProject(String workingDir, { List expectedFailures ]; final ProcessResult exec = await Process.run( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, args, workingDirectory: workingDir, ); @@ -3124,7 +3122,7 @@ Future _getPackages(Directory workingDir) async { // While flutter test does get packages, it doesn't write version // files anymore. await Process.run( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, [ flutterToolsSnapshotPath, 'packages', @@ -3134,7 +3132,7 @@ Future _getPackages(Directory workingDir) async { ); } -Future _runFlutterTest(Directory workingDir, { String target }) async { +Future _runFlutterTest(Directory workingDir, { String? target }) async { final String flutterToolsSnapshotPath = globals.fs.path.absolute(globals.fs.path.join( '..', '..', @@ -3153,7 +3151,7 @@ Future _runFlutterTest(Directory workingDir, { String target }) async { ]; final ProcessResult exec = await Process.run( - globals.artifacts.getHostArtifact(HostArtifact.engineDartBinary).path, + globals.artifacts!.getHostArtifact(HostArtifact.engineDartBinary).path, args, workingDirectory: workingDir.path, ); @@ -3171,8 +3169,8 @@ class LoggingProcessManager extends LocalProcessManager { @override Future start( List command, { - String workingDirectory, - Map environment, + String? workingDirectory, + Map? environment, bool includeParentEnvironment = true, bool runInShell = false, ProcessStartMode mode = ProcessStartMode.normal, @@ -3193,14 +3191,14 @@ class LoggingProcessManager extends LocalProcessManager { } } -String _getStringValueFromPlist({File plistFile, String key}) { +String _getStringValueFromPlist({required File plistFile, String? key}) { final List plist = plistFile.readAsLinesSync().map((String line) => line.trim()).toList(); final int keyIndex = plist.indexOf('$key'); assert(keyIndex > 0); return plist[keyIndex+1].replaceAll('', '').replaceAll('', ''); } -bool _getBooleanValueFromPlist({File plistFile, String key}) { +bool _getBooleanValueFromPlist({required File plistFile, String? key}) { final List plist = plistFile.readAsLinesSync().map((String line) => line.trim()).toList(); final int keyIndex = plist.indexOf('$key'); assert(keyIndex > 0); diff --git a/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart b/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart index a73f7a1b198fe..c1e16e1c30d4f 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/devices_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:convert'; import 'package:args/command_runner.dart'; @@ -20,8 +18,8 @@ import '../../src/fakes.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FakeDeviceManager deviceManager; - BufferLogger logger; + late FakeDeviceManager deviceManager; + late BufferLogger logger; setUpAll(() { Cache.disableLocking(); @@ -87,10 +85,10 @@ class FakeDeviceManager extends Fake implements DeviceManager { List devices = []; @override - String specifiedDeviceId; + String? specifiedDeviceId; @override - Future> refreshAllConnectedDevices({Duration timeout}) async { + Future> refreshAllConnectedDevices({Duration? timeout}) async { return devices; } } diff --git a/packages/flutter_tools/test/commands.shard/permeable/format_test.dart b/packages/flutter_tools/test/commands.shard/permeable/format_test.dart index 942dbd266ac4a..7a154bd0604c2 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/format_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/format_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:args/command_runner.dart'; import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/cache.dart'; @@ -16,7 +14,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('format', () { - Directory tempDir; + late Directory tempDir; setUp(() { Cache.disableLocking(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart b/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart index 8b2e5532a1acb..b522f1d6b37ee 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/migrate_abandon_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -18,12 +16,12 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - Terminal terminal; - ProcessManager processManager; - Directory appDir; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late Terminal terminal; + late ProcessManager processManager; + late Directory appDir; setUp(() { fileSystem = globals.localFileSystem; diff --git a/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart b/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart index 4e1ee2dc15870..26b6b9233a7dd 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/migrate_apply_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -18,12 +16,12 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - Terminal terminal; - ProcessManager processManager; - Directory appDir; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late Terminal terminal; + late ProcessManager processManager; + late Directory appDir; setUp(() { fileSystem = globals.localFileSystem; diff --git a/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart b/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart index 1ff6acae1daa2..3df997c78a2cf 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/migrate_status_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/logger.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -18,12 +16,12 @@ import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; void main() { - FileSystem fileSystem; - BufferLogger logger; - Platform platform; - Terminal terminal; - ProcessManager processManager; - Directory appDir; + late FileSystem fileSystem; + late BufferLogger logger; + late Platform platform; + late Terminal terminal; + late ProcessManager processManager; + late Directory appDir; setUp(() { fileSystem = globals.localFileSystem; diff --git a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart index 8ca503852b29e..a145dd702724d 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - // TODO(gspencergoog): Remove this tag once this test's state leaks/test // dependencies have been fixed. // https://github.com/flutter/flutter/issues/85160 @@ -34,7 +32,7 @@ import '../../src/test_flutter_command_runner.dart'; void main() { Cache.disableLocking(); group('packages get/upgrade', () { - Directory tempDir; + late Directory tempDir; setUp(() { tempDir = globals.fs.systemTempDirectory.createTempSync('flutter_tools_packages_test.'); @@ -44,7 +42,7 @@ void main() { tryToDelete(tempDir); }); - Future createProjectWithPlugin(String plugin, { List arguments }) async { + Future createProjectWithPlugin(String plugin, { List? arguments }) async { final String projectPath = await createProject(tempDir, arguments: arguments); final File pubspec = globals.fs.file(globals.fs.path.join(projectPath, 'pubspec.yaml')); String content = await pubspec.readAsString(); @@ -60,7 +58,7 @@ void main() { return projectPath; } - Future runCommandIn(String projectPath, String verb, { List args }) async { + Future runCommandIn(String projectPath, String verb, { List? args }) async { final PackagesCommand command = PackagesCommand(); final CommandRunner runner = createTestCommandRunner(command); await runner.run([ @@ -243,7 +241,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesNumberPlugins, 0); }, overrides: { @@ -265,7 +263,7 @@ void main() { final String exampleProjectPath = globals.fs.path.join(projectPath, 'example'); final PackagesCommand command = await runCommandIn(exampleProjectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesNumberPlugins, 1); }, overrides: { @@ -285,7 +283,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesProjectModule, false); }, overrides: { @@ -305,7 +303,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesProjectModule, true); }, overrides: { @@ -334,7 +332,7 @@ void main() { androidManifest.writeAsStringSync(updatedAndroidManifestString); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v1'); }, overrides: { @@ -354,7 +352,7 @@ void main() { removeGeneratedFiles(projectPath); final PackagesCommand command = await runCommandIn(projectPath, 'get'); - final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; + final PackagesGetCommand getCommand = command.subcommands['get']! as PackagesGetCommand; expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v2'); }, overrides: { @@ -439,8 +437,8 @@ void main() { }); group('packages test/pub', () { - FakeProcessManager processManager; - FakeStdio mockStdio; + late FakeProcessManager processManager; + late FakeStdio mockStdio; setUp(() { processManager = FakeProcessManager.empty(); diff --git a/packages/flutter_tools/test/commands.shard/permeable/script_test.dart b/packages/flutter_tools/test/commands.shard/permeable/script_test.dart index 65869d9b2858b..a28cd5cfa2f13 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/script_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/script_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'dart:io'; import 'package:flutter_tools/src/cache.dart'; diff --git a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart index b905b8aaa240b..ae507da6b5235 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/upgrade_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:flutter_tools/src/base/file_system.dart'; import 'package:flutter_tools/src/base/io.dart'; import 'package:flutter_tools/src/base/platform.dart'; @@ -23,10 +21,10 @@ import '../../src/test_flutter_command_runner.dart'; void main() { group('UpgradeCommandRunner', () { - FakeUpgradeCommandRunner fakeCommandRunner; - UpgradeCommandRunner realCommandRunner; - FakeProcessManager processManager; - FakePlatform fakePlatform; + late FakeUpgradeCommandRunner fakeCommandRunner; + late UpgradeCommandRunner realCommandRunner; + late FakeProcessManager processManager; + late FakePlatform fakePlatform; const GitTagVersion gitTagVersion = GitTagVersion( x: 1, y: 2, @@ -349,7 +347,7 @@ void main() { }); testUsingContext('does not throw on unknown tag, official branch, force', () async { - fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: null); + fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234'); final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta'); final Future result = fakeCommandRunner.runCommand( @@ -369,7 +367,7 @@ void main() { testUsingContext('does not throw tool exit with uncommitted changes and force', () async { final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta'); - fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: null); + fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234'); fakeCommandRunner.willHaveUncommittedChanges = true; final Future result = fakeCommandRunner.runCommand( @@ -389,7 +387,7 @@ void main() { testUsingContext("Doesn't throw on known tag, beta branch, no force", () async { final FakeFlutterVersion flutterVersion = FakeFlutterVersion(channel: 'beta'); - fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: null); + fakeCommandRunner.remoteVersion = FakeFlutterVersion(frameworkRevision: '1234'); final Future result = fakeCommandRunner.runCommand( force: false, @@ -407,9 +405,9 @@ void main() { }); group('full command', () { - FakeProcessManager fakeProcessManager; - Directory tempDir; - File flutterToolState; + late FakeProcessManager fakeProcessManager; + late Directory tempDir; + late File flutterToolState; setUp(() { Cache.disableLocking(); @@ -470,10 +468,10 @@ class FakeUpgradeCommandRunner extends UpgradeCommandRunner { bool willHaveUncommittedChanges = false; bool alreadyUpToDate = false; - FlutterVersion remoteVersion; + late FlutterVersion remoteVersion; @override - Future fetchLatestVersion({FlutterVersion localVersion}) async => remoteVersion; + Future fetchLatestVersion({FlutterVersion? localVersion}) async => remoteVersion; @override Future hasUncommittedChanges() async => willHaveUncommittedChanges; diff --git a/packages/flutter_tools/test/general.shard/commands/build_test.dart b/packages/flutter_tools/test/general.shard/commands/build_test.dart index ad90b8c8b7768..cc72bb264083c 100644 --- a/packages/flutter_tools/test/general.shard/commands/build_test.dart +++ b/packages/flutter_tools/test/general.shard/commands/build_test.dart @@ -69,8 +69,8 @@ void main() { ); FakeBuildSubCommand().test(unsound); - expect( - testLogger.statusText, contains('Building without sound null safety')); + expect(testLogger.statusText, + contains('Building without sound null safety ⚠️')); testLogger.clear(); FakeBuildSubCommand().test(sound); diff --git a/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart b/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart index fc78c098773a0..1e7386de36eaf 100644 --- a/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart +++ b/packages/flutter_tools/test/web.shard/sdk_web_configuration_test.dart @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// @dart = 2.8 - import 'package:dwds/dwds.dart'; import 'package:file/file.dart'; import 'package:file/memory.dart'; @@ -13,10 +11,10 @@ import 'package:flutter_tools/src/isolated/sdk_web_configuration.dart'; import '../src/common.dart'; void main() { - FileSystem fileSystem; + late FileSystem fileSystem; group('Flutter SDK configuration for web', () { - SdkConfiguration configuration; + late SdkConfiguration configuration; setUp(() async { fileSystem = MemoryFileSystem.test(); diff --git a/packages/integration_test/test/binding_test.dart b/packages/integration_test/test/binding_test.dart index 79e2b6b4a2dad..b8ad8fe1ff095 100644 --- a/packages/integration_test/test/binding_test.dart +++ b/packages/integration_test/test/binding_test.dart @@ -39,6 +39,7 @@ Future main() async { )); expect(tester.binding, binding); binding.reportData = {'answer': 42}; + await tester.pump(); }); testWidgets('hitTesting works when using setSurfaceSize', (WidgetTester tester) async {